{"version":3,"sources":["utils/StringCommaCoder.js","components/Dialog.js","models/layers/LayerInfo.js","utils/LocalStorageHelper.js","utils/DeepMerge.js","components/Search/utils/FeatureStyle.js","models/Click.js","components/FeatureInfo/FeaturePropsParsing.js","components/Search/searchResults/SearchResultsDatasetFeatureDetails.js","components/HajkThemeProvider.js","components/Window.js","utils/Delay.js","utils/Validator.js","components/FeatureInfo/FeaturePropsFilters.js","components/Alert.js","utils/KMLWriter.js","components/PanelHeader.js","components/Search/Search.js","components/App.js","components/SrShortcuts/SrShortcuts.js","models/AppModel.js","models/SearchModel.js","models/Plugin.js","utils/ConfigMapper.js","utils/CoordinateSystemLoader.js","models/layers/WMSLayer.js","models/layers/WMTSLayer.js","models/layers/VectorLayer.js","models/SnapHelper.js","components/FeatureInfo/FeatureInfoContainer.js","components/CookieNotice.js","components/Introduction.js","components/Announcement/Announcement.js","components/PluginWindows.js","components/Search/SearchBar.js","components/Search/searchResults/SearchResultsContainer.js","components/Search/searchResults/SearchResultsList.js","components/Search/searchResults/SearchResultsDataset.js","components/Search/searchResults/SearchResultsDatasetFeature.js","components/Search/searchResults/SearchResultsPreview.js","components/Search/searchResults/SearchResultsDatasetSummary.js","components/Search/searchResults/SearchResultsDownloadMenu.js","components/Search/SearchTools.js","components/Search/SearchSettings.js","components/Search/MapViewModel.js","components/Search/utils/KmlExport.js","components/Search/utils/XLSXExport.js","controls/Zoom.js","controls/User.js","controls/Rotate.js","controls/ScaleLine.js","controls/Attribution.js","controls/MapCleaner.js","controls/MapResetter.js","controls/MapSwitcher.js","controls/Information.js","controls/PresetLinks.js","components/Drawer/DrawerToggleButtons.js","controls/ThemeToggler.js","reportWebVitals.js","index.js","utils/FetchWrapper.js","../src lazy /^/.*/.js$/ groupOptions: {} namespace object","utils/IsMobile.js"],"names":["encodeCommas","string","replace","decodeCommas","Dialog","state","open","text","handleChange","name","event","setState","target","value","handleClose","e","stopPropagation","props","onClose","handleAbort","onAbort","handleDialogClick","__html","dangerouslySetInnerHTML","this","getHtml","classes","options","prompt","className","container","noValidate","autoComplete","onSubmit","preventDefault","id","label","textField","onChange","margin","autoFocus","header","headerText","fullScreen","document","body","clientWidth","aria-labelledby","renderDialogContent","renderPromptInput","onClick","buttonText","abortText","Component","withStyles","theme","display","flexWrap","marginLeft","spacing","marginRight","width","dense","marginTop","menu","LayerInfo","properties","attribution","caption","infoOwner","infoText","infoTitle","infoUrl","infoUrlText","infoVisible","infoClickSortType","infoClickSortDesc","infoClickSortProperty","information","legend","legendIcon","searchDisplayName","searchShortDisplayName","searchGeometryField","searchOutputFormat","searchPropertyName","searchUrl","layerType","hideExpandArrow","LocalStorageHelper","mapName","key","defaults","JSON","parse","window","localStorage","getItem","error","setItem","stringify","deepMerge","isObject","obj","objects","reduce","prev","Object","keys","forEach","pVal","oVal","Array","isArray","concat","FeatureStyle","fillColor","displayFillColor","strokeColor","displayStrokeColor","selectionStrokeColor","selectionFillColor","textFillColor","selectionTextFill","textStrokeColor","selectionTextStroke","fontSize","highlightStrokeColor","highlightFillColor","highlightTextFill","highlightTextStroke","getFeatureStyle","feature","type","isValidNumber","n","Number","isFinite","parseInt","scale","markerImg","anchor","isPoint","getGeometry","Point","textAlign","offsetY","settings","iconColor","svgString","defaultMarker","btoa","multiplier","Style","fill","Fill","color","stroke","Stroke","image","Icon","src","length","Text","textBaseline","font","featureTitle","overflow","offsetX","rotation","getDefaultSearchResultStyle","Circle","radius","shortFeatureTitle","enableLabelOnHighlight","getSortParser","sortType","a","trim","sortFeatures","layer","features","layerInfo","getProperties","sortOptions","desc","prop","parser","sort","b","localeCompare","getFeaturesFromJson","response","jsonData","parsed","layerProjection","viewProjection","GeoJSON","parserOptions","crs","dataProjection","featureProjection","parsedFeatures","map","jsonFeature","parsedJsonFeature","readFeature","getId","setId","layerName","ol_uid","push","readJsonFeatures","getSource","getProjection","f","handleClick","evt","callback","querySelector","style","cursor","promises","getView","getCode","getLayers","getArray","filter","TileLayer","ImageLayer","get","promise","coordinate","resolution","getResolution","currentZoom","getZoom","referenceSystem","subLayersToQuery","layersInfo","getMinZoom","getMaxZoom","subLayers","values","visibleSubLayersArray","getParams","split","visibleSubLayersSet","Set","subLayer","queryable","has","queryableSubLayer","params","FEATURE_COUNT","INFO_FORMAT","QUERY_LAYERS","join","serverType_","FI_POINT_TOLERANCE","FI_LINE_TOLERANCE","FI_POLYGON_TOLERANCE","WITH_GEOMETRY","url","getFeatureInfoUrl","hfetch","query","then","requestResponse","Promise","all","responses","featurePromises","headers","json","undefined","catch","err","console","WMSGetFeatureInfo","readFeatures","getFeaturesFromGml","forEachFeatureAtPixel","pixel","hitTolerance","bindMapClickEvent","on","clickLock","size","Paragraph","root","marginBottom","Typography","StyledTableRow","backgroundColor","palette","action","hover","TableRow","StyledTableContainer","TableContainer","StyledPaper","padding","background","default","Paper","StyledTypography","h1","fontWeight","h2","h3","h4","h5","h6","fontStyle","FeaturePropsParsing","children","isHeader","variant","align","level","str","start","match","result","test","ex","placeholder","substring","includes","propertyName","pluginName","propertyValue","pendingPromises","FeaturePropFilters","applyFilters","globalObserver","getListeners","resolve","reject","publish","payload","matched","condition","content","attributes","replaceAll","k","v","title","href","URL","encodeURI","r","extractPropertiesFromJson","property","mergeFeaturePropsWithMarkdown","markdown","resolvedPromisesWithComponents","rehypePlugins","allowDangerousHtml","rehypeRaw","remarkPlugins","gfm","components","p","child","index","externalComponent","hasOwnProperty","hr","table","component","thead","tbody","tr","td","th","div","blockquote","SearchResultsDatasetFeatureDetails","infoBox","componentDidMount","getInfoBox","componentDidUpdate","prevProps","shouldRenderCustomInfoBox","getHtmlItemInfoBox","getDefaultInfoBox","source","infobox","setProperties","featurePropsParsing","setMarkdownAndProperties","MarkdownComponent","renderDefaultInfoBox","renderTableCell","position","textToRender","paddingRight","tableCell","entries","row","handleTogglerPressed","nextFeatureIndex","setActiveFeature","getFeatureIndex","findIndex","renderFeatureToggler","numFeaturesInCollection","currentFeatureIndex","buttonLeftDisabled","buttonRightDisabled","item","alignItems","justify","togglerButton","disabled","aria-label","renderFeatureTitle","noWrap","headerTypography","app","appModel","config","mapConfig","tools","find","t","enableFeatureToggler","shouldRenderToggler","allFeatureDetailsContainer","headerContainer","xs","md","React","PureComponent","paddingLeft","wordBreak","maxWidth","paddingTop","minWidth","getTheme","customTheme","colorScheme","preferredColorSchemeFromMapConfig","userPreferredColorScheme","matchMedia","matches","getColorScheme","colors","preferredColorScheme","hardCodedDefaults","active","shape","borderRadius","themeFromMapConfig","primary","main","primaryColor","secondary","secondaryColor","HajkThemeProvider","activeTools","useState","setTheme","muiTheme","createMuiTheme","toggleMUITheme","newTheme","Rnd","prototype","onDragStart","data","disableDrag","bounds","boundary","parent","getParent","parentRect","getBoundingClientRect","parentLeft","left","parentTop","top","bodyRect","offsetLeft","offsetTop","right","offsetWidth","resizable","bottom","offsetHeight","height","innerWidth","innerHeight","HTMLElement","boundaryRect","boundaryLeft","boundaryTop","updateOffsetFromParent","offset","offsetFromParent","Window","prevState","setTimeout","windowRef","current","focus","close","latestWidth","rnd","getSelfElement","fit","updatePosition","x","Math","round","y","clientHeight","mode","reset","enlarge","parseFloat","h","c","parentElement","o","maximize","onMaximize","onResize","allowMaximizedWindow","getIsMobile","getElementById","minimize","onMinimize","windows","createRef","addEventListener","subscribe","layerswitcherConfig","showBreadcrumbs","spaceForBreadcrumbs","areBreadcrumbsActivated","getMaxWindowHeight","w","i","zIndex","resizingEnabled","draggingEnabled","customPanelHeaderButtons","resizeBottom","resizeBottomLeft","resizeBottomRight","resizeLeft","resizeRight","resizeTop","resizeTopLeft","resizeTopRight","isMobile","bringToFront","onMouseDown","onMouseOver","ref","onDragStop","d","rect","getClientRects","onResizeStop","direction","delta","cancel","disableDragging","enableResizing","bottomLeft","bottomRight","topLeft","topRight","minHeight","tabIndex","clsx","panelContent","panelContentDisplayContents","customHeaderButtons","localObserver","scrollable","nonScrollable","maxHeight","onDisplay","defaultProps","paper","boxShadow","shadows","pointerEvents","breakpoints","down","flexDirection","userSelect","outline","light","flex","overflowY","delay","ms","isValidLayerId","isNaN","filters","input","args","shift","indexOf","inFilter","argsStart","filterName","substr","cleanString","execFilter","func","apply","warn","s","targetKey","add","numDecimals","Error","toFixed","toLocaleString","withString","RegExp","defaultValue","addAlias","trueValue","falseValue","Date","toLocaleDateString","toLocaleTimeString","days","date","setDate","getDate","hours","setTime","getTime","toUpperCase","toLowerCase","charAt","slice","i1","i2","searchFor","AlertView","alert","dialogTitle","message","aria-describedby","componentToHex","hex","toString","colorToArray","res","reg","exec","toKmlColor","g","rgbToHex","floor","toKmlString","strs","coords","coordinates","coordString","lines","line","point","transform","from","to","clone","getStyle","setStyle","createXML","WKT","doc","getImage","getScale","getSize","getSrc","getStroke","getColor","getWidth","getFill","getText","description","namn","template","filterProperties","writeFeature","MultiPoint","LineString","MultiLineString","multiLine","Polygon","polygon","MultiPolygon","multiPolygon","geometryType","PanelHeader","renderCustomHeaderButtons","buttonInfo","HeaderActionIcon","icon","onClickCallback","shouldRenderCustomHeaderButtons","borderColor","xsDown","borderBottom","justifyContent","Search","defaultSearchOptions","searchInVisibleLayers","wildcardAtStart","wildcardAtEnd","matchCase","activeSpatialFilter","maxResultsPerDataset","searchImplementedPluginsLoaded","searchSources","searchResults","featureCollections","errors","autocompleteList","searchString","searchFromAutoComplete","searchActive","autoCompleteOpen","loading","searchOptions","failedWFSFetchMessage","resultPanelCollapsed","timer","delayBeforeAutoSearch","searchImplementedPlugins","featuresToFilter","Observer","snackbarKey","defaultSearchTools","enabled","enablePolygonSearch","toolTipTitle","onClickEventName","enableRadiusSearch","enableSelectSearch","enableExtentSearch","initMapViewModel","mapViewModel","MapViewModel","initExportHandlers","kmlExport","KmlExport","XLSXExport","resetFeaturesToFilter","setFeaturesToFilter","arrayOfFeatures","bindSubscriptions","enqueueSnackbar","anchorOrigin","vertical","horizontal","doFeaturesSearch","closeSnackbar","doSearch","getPluginsConfToUseSearchInterface","plugins","plugin","searchImplemented","searchInterface","getSearchMethods","tryBindSearchMethods","methods","getFunctionality","getResults","pluginsHavingCorrectSearchMethods","displayPluginMissingCrucialMethodsWarning","getSearchImplementedPlugins","pluginsConfToUseSearchInterface","searchBoundPlugins","getExternalSearchTools","searchImplementedSearchTools","searchImplementedPlugin","toolWithFunctionality","getSearchTools","searchTools","handlePotentialUrlQuerySearch","getSourcesByIds","sourceIds","searchModel","getSources","q","urlParams","sources","handleOnClear","showSearchResults","handleSearchInput","reason","autocompleteEntry","isUserInput","handleOnAutocompleteInputChange","clearTimeout","updateAutocompleteList","updateSearchOptions","refreshFeatureStyle","set","handleOnClickOrKeyboardSearch","hasEnoughCharsForSearch","activeElement","blur","setSearchSources","handleSearchBarKeyPress","which","keyCode","getAutoCompleteFetchSettings","fetchSettings","getSearchOptions","autocompleteWildcardAtStart","getPossibleCombinations","initiator","getArrayWithSearchWords","splitAndTrimOnCommas","escapeRegExp","sortSearchFieldsOnFeature","searchFields","wordsInTextField","matchedSearchFields","word","sf","searchFieldMatch","unMatchedSearchFields","getSortedAutocompleteEntry","searchFieldOrder","featureProperty","propertyAsString","getAutocompleteDataset","featureCollection","dataset","origin","sortSearchFieldsOnFeatures","flattenAndSortAutoCompleteList","resultsPerDataset","sortAutocompleteList","flat","flatAutocompleteArray","numeric","getMergeResultsFromAllSources","results","fetchResultFromSearchModel","fetchOptions","searchStringEncapsuled","getCleanedSearchString","getVisibleSearchLayers","allSettled","fetchResultsFromPlugins","status","removeCollectionsWithoutFeatures","fc","getFeatureLabels","startsWith","endsWith","getPotentialWFSErrorMessage","reducerFn","featureTitleString","df","displayField","displayFields","shortDisplayFields","filterFeaturesWithGeometry","extractFeaturesFromFeatureCollections","getNumResults","numResults","autoCompleteResult","prepareAutocompleteList","anySearchImplementedPlugins","getSearchResultsFetchSettings","getUserCustomFetchSettings","numSourcesWithResults","spacesPerSource","max","min","autoCompleteList","shortenAutoCompleteList","shortenedAutoComplete","groupedAutoComplete","groupObjArrayByProp","group","array","grouped","searchOptionsFromModel","toggleCollapseSearchResults","clean","inputRoot","withSnackbar","App","canRenderCustomDrawer","activeDrawerContentFromLocalStorage","activeDrawerOnStart","some","tool","getDrawerPermanentFromLocalStorage","getActiveDrawerContentFromLocalStorage","hasAnyToolbarTools","activeTool","togglePermanent","drawerPermanent","getMap","updateSize","handleMouseEnter","drawerMouseOverLock","handleMouseLeave","renderDrawerHeader","drawerTitle","drawerButtons","db","activeDrawerContent","logoUrl","logoLight","logoDark","logo","logoBox","alt","drawerGrid","wrap","smDown","drawerLockButton","onMouseEnter","onMouseLeave","renderAllDrawerContent","drawerContentContainer","drawerContent","role","renderDrawerContent","drawerPermanentFromLocalStorage","canRenderDefaultDrawer","activeDrawerContentState","drawerVisible","drawerVisibleMobile","mapClickDataResult","AppModel","createMap","addSearchModel","addLayers","loadPlugins","getPlugins","getDrawerPlugins","ButtonIcon","MapIcon","order","bindHandlers","passive","alertMessage","button","newState","infoclickOptions","highlight","search","renderElsewhere","String","showMapResetter","mapresetter","showMapSwitcher","activeMap","showCookieNotice","defaultCookieNoticeMessage","isString","defaultCookieNoticeUrl","maxSnack","anchorOriginBottomCenter","snackbarContainerBottom","anchorOriginTopCenter","snackbarContainerTop","containerRoot","snackBarContainerRoot","appConfig","announcements","currentMap","cslx","flexBox","shiftedLeft","pointerEventsOnChildren","initialActiveButton","renderSearchComponent","leftColumn","rightColumn","controlsColumn","showUserAvatar","userDetails","showThemeToggler","renderInformationPlugin","footer","windowsContainer","renderInfoclickWindow","getBothDrawerAndWidgetPlugins","ModalProps","hideBackdrop","disableEnforceFocus","onEscapeKeyDown","keepMounted","onBackdropClick","drawerBackground","experimentalIntroductionEnabled","experimentalIntroductionSteps","border","appBar","drawerHeader","mixins","toolbar","lineHeight","drawerLiveContent","widgetItem","SrShortcuts","shortcuts","setShortcuts","useEffect","addShortCuts","shortcutsArray","shortcut","link","decorateConfig","coordinateSystemLoader","CoordinateSystemLoader","projections","layersFromParams","cqlFiltersFromParams","register","getProj4","allResolutions","resolutions","extraPrintResolutions","windowComponent","closeWindow","currentWindow","sortOrder","dir","prom","module","toolConfig","plug","toolOptions","addPlugin","Plugin","translateConfig","interactionsOptions","altShiftDragRotate","onFocusOnly","doubleClickZoom","keyboard","mouseWheelZoom","shiftDragZoom","dragPan","pinchRotate","pinchZoom","zoomDelta","zoomDuration","Map","controls","interactions","defaultInteractions","layers","overlays","view","View","center","extent","constrainOnlyCenter","constrainResolution","maxZoom","minZoom","projection","units","zoom","newZoom","snapHelper","SnapHelper","searchResultFeatures","infoclickFeatures","searchConfigIndex","SearchModel","clearing","setVisible","layerItem","layerConfig","configMapper","ConfigMapper","proxy","mapWMSConfig","WMSLayer","addLayer","mapWMTSConfig","WMTSLayer","mapVectorConfig","WFSVectorLayer","matchedLayers","layersConfig","lookupLayer","groups","expand","layerSwitcherConfig","lookup","baselayers","infoclickConfig","flattern","drawOrder","sortedKey","visibleAtStart","layerId","cqlFilter","addMapLayer","addHighlightLayer","strokeWidth","strokeColorAsArray","fillColorAsArray","highlightSource","VectorSource","highlightLayer","VectorLayer","abs","clear","addFeature","geom","setCenter","getCenter","getExtent","urlSearchParams","Boolean","z","l","decodeURIComponent","searchTool","wfslayers","configSpecificSearchLayers","editTool","wfstlayers","configSpecificEditLayers","activeServices","layerSwitcherTool","wmslayers","wmtslayers","vectorlayers","arcgislayers","allLayers","overrideGlobalSearchConfig","selectedSources","flatMap","wmslayerId","sl","pid","aliasDict","geometryField","outputFormat","serverType","visibleForGroups","as","service","overrideGlobalEditConfig","mergeConfig","fromEntries","URLSearchParams","location","searchPluginOptions","WFS","abort","controller","rawResults","searchSource","fetchResponses","fetchResponse","responsePromises","successfulResponses","olFeatures","GML2","GML3","GML32","Or","searchField","IsLike","wordsArray","OrFilters","And","isLikeFilters","getPossibleSearchCombinations","possibleSearchCombinations","numWords","joinedWord","stringArray","wordsBeforeCurrent","ii","currentWord","wordsAfterCurrent","searchCombinations","combination","srsName","geometryName","maxFeatures","comparisonFilters","spatialFilters","finalFilters","searchFilters","searchWordsForCombination","wordInCombination","Within","Intersects","geometry","getType","fromCircle","flatCoordinates","splice","featureTypes","node","writeGetFeature","xmlString","XMLSerializer","serializeToString","AbortController","request","credentials","signal","method","searchProxy","spec","getLegendUrl","legendUrl","getIndex","geoserverLegendOptions","qgisOptions","theGlue","version","projCode","Projection","code","axisOrientation","srsOrCrs","visible","opacity","minMaxZoomAlertOnToggleOnly","singleTile","hidpi","customRatio","imageFormat","crossOrigin","LAYERS","CQL_FILTER","FORMAT","infoFormat","VERSION","tiled","layersInfoObject","mapLayersInfo","timeSliderStart","timeSliderEnd","featureType","displayName","format","wrapX","matrixSet","matrixIds","dataFormat","filterable","filterAttribute","filterComparer","filterValue","typename","srsname","bbox","sldStyle","sldText","sldUrl","proj4","defs","definition","proxyUrl","onTileLoadError","onTileLoadOk","onImageError","layerSource","previousErrorExtent","currentErrorExtent","equals","refresh","validInfo","attributions","cacheSize","transition","overrideLayerSourceParams","tileGrid","TileGrid","ratio","ImageWMS","TileWMS","getLayerType","featureInformationCallback","success","getLayer","feature_count","encodeURIComponent","assign","Url","wmtsLayerProperties","axisMode","WMTSTileGrid","WMTS","updateMapViewResolutions","setView","vectorLayerProperties","showLabels","applySldTextOnLayer","sldObject","SLDReader","sldLayer","featureTypeStyle","featuretypestyles","olFunction","convertResolution","viewResolution","viewCenter","getPointResolution","imageLoadedCallback","changed","allFeatures","vectorSource","loader","loadData","createUrl","strategy","loadingStrategy","strategyAll","bboxStrategy","renderMode","getCoordinates","setCoordinates","coord","gmlFormat","reprojectFeatures","filterMethod","usp","Infinity","getAllFeatures","addFeatures","getFilteredFeatures","activePlugins","updatePending","getVisible","snap","Snap","addInteraction","snapInteractions","removeInteraction","delete","FeatureInfoContainer","selectedIndex","showFeatureInMap","stepLeft","newIndex","updateFeatureInformation","stepRight","getToggler","toggler","togglerButtonRightContainer","fullWidth","typography","togglerButtonLeftContainer","getMarkdownFromLocalInfoBox","getAGSCompatibleLayer","getFeatureProperties","getValue","getFeaturesAsDefaultTable","isReadyToShowInfo","shortcodes","renderFeatureInformation","featureInfo","gutterBottom","j","tableBody","selected","columnKey","columnValue","featureInfoLoaded","alignContent","infoContainer","featureInfoContainer","verticalAlign","borderRight","divider","borderLeft","useStyles","makeStyles","textButton","contrastText","CookieNotice","useSnackbar","persist","arePropsEqual","nextProps","propTypes","object","isRequired","memo","Introduction","forceShow","initialStep","stepsEnabled","steps","predefinedSteps","intro","element","disableSteps","filteredSteps","onExit","exitOnOverlayClick","nextLabel","prevLabel","doneLabel","Announcement","maps","mapFilter","browsers","detect","browserFilter","now","startTime","stopTime","validStartTime","validStopTime","timeFilter","showOnlyOnce","aShownIds","sShownIds","localStorageFilter","timeout","autoHideDuration","renderSnackbar","PluginWindows","CustomPopper","useTheme","smallScreen","useMediaQuery","popperOptions","modifiers","computeStyle","gpuAcceleration","preventOverflow","boundariesElement","hide","placement","CustomPaper","borderTop","SearchBar","drawActive","panelCollapsed","moreOptionsId","moreOptionsOpen","selectSourcesOpen","getOriginBasedIcon","originIconWrapper","removeCommasAndSpaces","getMatches","regex","getAllStartingIndexForOccurencesInString","toSearchFor","toSearchIn","regexp","getHighlightedAutoCompleteEntryElement","lastHighlightInformation","renderHighlightedAutocompleteEntry","highlightInformation","countOfHighlightInformation","getHighlightedACE","searchWord","autocompleteTypography","getPlaceholder","labelPostfix","searchBarPlaceholder","renderSearchResultList","renderAutoComplete","freeSolo","PopperComponent","PaperComponent","clearOnEscape","selectOnFocus","blurOnSelect","disableClearable","onInputChange","getOptionSelected","option","renderOption","getOptionLabel","renderInput","renderAutoCompleteInputField","renderFailedWFSFetchWarning","errorMessage","disableUnderline","showFailedWFSMessage","expandMessage","onKeyPress","InputLabelProps","shrink","InputProps","notched","endAdornment","searchContainer","searchCollapsed","elevation","withTheme","withWidth","SearchResultsContainer","activeFeature","activeFeatureCollection","filteredFeatureCollections","filteredFeatures","sumOfResults","filterInputFieldOpen","featureCollectionFilter","featureFilter","sortingMenuAnchorEl","featureCollectionSortingStrategy","featureSortingStrategy","showTools","selectedFeatures","filterInputTimer","lastFeatureFilter","lastFeatureCollectionFilter","delayBeforeFilterCommit","searchResultTools","render","renderFilterTool","enableResultsFiltering","renderSortTool","enableResultsSorting","renderClearTool","enableResultsSelectionClearing","renderDownloadTool","enableResultsDownloading","sortingStrategies","appliesTo","featureIds","showFeatureDetails","getPotentialSingleHit","componentWillUnmount","unsubscribe","featureId","getFeatureCollectionFromFeatureId","onClickName","handleActiveFeatureChange","handleFilterTextFieldInputChange","filterInput","updateViewFilters","handleFilterUpdate","addFeatureToSelected","updateMapView","removeFeatureFromSelected","featureIndex","getSelectedFeatureIndex","getSelectedCollection","appendSelectedFeaturesCollection","updatedCollections","unshift","clearViewFilters","renderFilterInputField","showClearFilterButton","filterInputFieldContainer","getFilteredFeatureCollections","isFilterActive","getSortingStrategiesApplyingToView","handleSortingMenuItemClick","clearAllSelectedFeaturesInView","sourceId","onSelectedFeaturesView","renderSortingMenu","currentSortingStrategies","anchorEl","filterActive","filterHelpText","headerButtons","badgeContent","invisible","sortHelpText","currentTarget","collectionsToDownload","getCollectionsToDownload","allToolsDisabled","renderSearchResultListTools","in","hidden","Fragment","nextFeature","nextCollection","shouldZoomToFeature","featureIsSelected","getNextFeatureInfo","setActiveFeatureCollection","showCorrespondingWMSLayers","alreadyVisibleSubLayers","subLayersToShow","values_","handleFeatureCollectionClick","sortFeatureCollections","featureCollectionsAtoZSorted","totalFeatures","reverse","keyPressIsEnter","currentFeatureIds","renderBreadCrumbs","featureCollectionTitle","shouldRenderFeatureCollectionDetails","shouldRenderFeatureDetails","separator","breadCrumbLinks","onKeyDown","renderHeaderInfoBar","renderSearchResultsHeader","shouldRenderHeaderInfoBar","tallHeaderContainer","sortedFeatureCollections","shouldRenderSelectedCollection","enableSelectedFeaturesCollection","collectionsToRender","severity","searchResultListWrapper","enableFeaturePreview","up","SearchResultsList","handleSingleSearchResult","handleOnFeatureClick","handleOnFeatureKeyPress","renderSearchResultDatasetSummary","showResultsLimitReachedWarning","renderSearchResultDataset","searchResultList","disableTouchRipple","searchResultListItem","aria-controls","SearchResultsDataset","previewFeature","previewAnchorEl","delayBeforeShowingPreview","previewTimer","shouldComponentUpdate","prevFeatureFilter","numFeatures","prevNumFeatures","setPreviewFeature","resetPreview","getSortedFeatures","featuresAtoZSorted","renderFeatureDetails","renderFeatureList","sortedFeatures","featureList","featureListItem","visibleInMap","renderSearchResultPreview","renderDatasetDetails","SearchResultsDatasetFeature","renderShowInMapCheckbox","helpText","checked","handleCheckboxToggle","checkedIcon","renderOriginBasedIcon","shouldRenderCheckbox","SearchResultsPreview","renderFeaturePreview","preview","previewPaper","transformOrigin","disableRestoreFocus","previewHeaderContainer","previewContentContainer","datasetContainer","datasetDetailsContainer","fade","SearchResultsDatasetSummary","numberOfResultsToDisplay","shouldDisplayWarning","numberMatched","numberReturned","renderDatasetSummary","displayWarning","summaryContainer","warningChip","warning","dark","SearchResultsDownloadMenu","handleXLSXDownloadClick","handleKMLDownloadClick","renderMenuTogglerButton","menuTogglerButton","renderDownloadMenu","enabledDownloadOptions","downloadOptions","downloadOption","menuItemIcon","SearchTools","settingsDialog","handleMenuItemClick","getEnabledTools","renderSettingsDialog","createPortal","enabledTools","aria-haspopup","getContentAnchorEl","SearchSettings","showSearchSourcesFilter","localUpdateSearchOptions","control","labelId","multiple","renderValue","chips","chip","ctrlKeyPressed","lastFeaturesInfo","featureStyle","resultsLayer","getDrawStyleSettings","drawStrokeColor","drawFillColor","getNewVectorSource","getNewVectorLayer","getVisibleLayers","visibleLayers","l_id","initMapLayers","resultSource","showResultFeaturesInMap","drawSource","drawLayer","getDrawStyle","clearMap","zoomToFeatures","addFeaturesToResultsLayer","setSelectedStyle","addAndHighlightFeatureInSearchResultLayer","updateFeaturesAfterFilterChange","setHighLightedStyle","zoomToFeature","searchInCurrentExtent","enableSelectFeaturesSearch","toggleDraw","forEachFeature","removeFeature","getFeatureById","fitMapToSearchResult","currentExtent","fitMapToExtent","resetStyleForFeaturesInResultSource","getFeatures","drawSourceHasFeatures","drawStyleSettings","mapFeature","getFeatureFromResultSourceById","createEmpty","extend","extentToZoomTo","isEmpty","featuresInfo","fid","removeDrawInteraction","removeSelectListeners","draw","freehand","Draw","stopClick","handleDrawFeatureAdded","calculateExtent","extentIsFinite","Feature","fromExtent","handleSearchInCurrentExtentError","un","addSelectListeners","handleSelectFeatureClick","handleKeyDown","handleKeyUp","removeEventListener","export","exportFeatures","gjFeature","Blob","info","transformed","circleRadius","setGeometry","getRadius","getGeometryName","postData","saveAs","styleObj","pointRadius","CircleStyle","pointColor","strokeDash","getLineDash","exportItems","workBook","XLSX","utils","book_new","fileName","sheet","sheetName","book_append_sheet","writeFile","groupedFeatures","exportArray","aoa_to_sheet","getKeys","featureProperties","ZoomControl","zoomByDelta","getAnimating","cancelAnimations","animate","duration","easing","easeOut","avatar","getTooltipString","User","RotateControl","useRef","getRotation","setRotation","subscribeToRotation","ScaleLineControl","formatScale","scaleLineControl","ScaleLine","addControl","mpu","getMetersPerUnit","scaleBadge","scaleLine","renderScaleBadge","AttributionControl","attributionControl","Attribution","tipLabel","whiteSpace","textShadow","MapCleaner","mapcleaner","MapResetter","MapSwitcher","renderMenuItems","menuItems","mapConfigurationTitle","selectedMap","mapConfigurationName","pathname","mapserviceBase","userSpecificMaps","handleLoading","resp","mapselector","aria-owns","Information","dialogOpen","handleOnClick","showInfoOnce","renderDialog","Preset","isValidMapLink","mapLink","getMapInfoFromMapLink","queryParams","handleItemClick","presetUrl","openDialog","flyTo","presetList","closeDialog","toggleMapLayers","abortDialog","layerShouldBeVisible","layerSwitcherLayers","common","white","DrawerToggleButtons","activeButton","setActiveButton","exclusive","removeItem","renderToggleButton","ThemeToggler","reportWebVitals","onPerfEntry","Function","getCLS","getFID","getFCP","getLCP","getTTFB","initHFetch","networkErrorMessage","parseErrorMessage","renderError","ReactDOM","cacheBuster","appConfigResponse","initFetchWrapper","searchParams","defaultMap","useMapService","useNewApi","experimentalNewApi","fetchMapConfig","configUrl","mapConfigResponse","customThemeResponse","setKeyName","buildConfig","layersConfigResponse","noLayerSwitcherMessage","errMsg","defaultOptions","FetchWrapper","urlRegex","isJqueryAjax","hash","process","REACT_APP_GIT_HASH","useCacheBuster","REACT_APP_USE_CACHE_BUSTER","ruleWithWildCard","partKeys","optionOverrides","matchesUrlPart","overrides","xhrFields","withCredentials","useOptionOverrides","applyOptionOverrides","translateToJqueryAjaxOptions","mapserviceBaseUri","fetchWrapper","originalFetch","updateConfig","jqueryAjaxWrapper","fetch","fw","Request","overrideOptions","originalJqueryAjax","wrapJqueryAjax","jqueryObject","ajax","xJqueryAjax","jw","webpackAsyncContext","req","__webpack_require__","ids","exports"],"mappings":"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zB,KAED,4BAA6B,CAC5B,KAED,4BAA6B,CAC5B,KAED,2BAA4B,CAC3B,KAED,4BAA6B,CAC5B,KAED,4BAA6B,CAC5B,KAED,4BAA6B,CAC5B,KAED,uBAAwB,CACvB,KAED,0BAA2B,CAC1B,KAED,6BAA8B,CAC7B,KAED,qBAAsB,CACrB,KAED,qBAAsB,CACrB,KAED,aAAc,CACb,KAED,uBAAwB,CACvB,KAED,oBAAqB,CACpB,KAED,mBAAoB,CACnB,KACA,KAED,wBAAyB,CACxB,KACA,KAED,oBAAqB,CACpB,KACA,KAED,uBAAwB,CACvB,KACA,EACA,KAED,qBAAsB,CACrB,KAED,0BAA2B,CAC1B,KAED,yBAA0B,CACzB,KAED,+BAAgC,CAC/B,KAED,iCAAkC,CACjC,KAED,8BAA+B,CAC9B,KAED,+BAAgC,CAC/B,KAED,6BAA8B,CAC7B,KACA,IAED,kCAAmC,CAClC,KACA,KAED,iCAAkC,CACjC,KACA,IAED,gCAAiC,CAChC,KACA,IAED,mCAAoC,CACnC,KACA,IAED,wCAAyC,CACxC,KACA,KAED,uCAAwC,CACvC,KACA,IAED,6BAA8B,CAC7B,KACA,EACA,GACA,IAED,kCAAmC,CAClC,KACA,EACA,KAED,iCAAkC,CACjC,KACA,IAED,mCAAoC,CACnC,KACA,EACA,GACA,GACA,IAED,wCAAyC,CACxC,KACA,KAED,uCAAwC,CACvC,KACA,EACA,GACA,IAED,kDAAmD,CAClD,KACA,EACA,IAED,yCAA0C,CACzC,KACA,EACA,IAED,4CAA6C,CAC5C,KACA,EACA,KAED,uCAAwC,CACvC,KACA,GACA,IAED,4CAA6C,CAC5C,KACA,KAED,mDAAoD,CACnD,KACA,GACA,KAED,2CAA4C,CAC3C,KACA,GACA,KAED,+CAAgD,CAC/C,KACA,EACA,GACA,GACA,GACA,IAED,oDAAqD,CACpD,KACA,IAED,4CAA6C,CAC5C,KACA,KAED,kEAAmE,CAClE,KACA,KAED,0DAA2D,CAC1D,KACA,KAED,uDAAwD,CACvD,KACA,KAED,6DAA8D,CAC7D,KACA,EACA,IAED,iEAAkE,CACjE,KACA,EACA,GACA,IAED,8DAA+D,CAC9D,KACA,KAED,uDAAwD,CACvD,KACA,KAED,0DAA2D,CAC1D,KACA,KAED,8DAA+D,CAC9D,KACA,KAED,uDAAwD,CACvD,KACA,KAED,mDAAoD,CACnD,KACA,IAED,gEAAiE,CAChE,KACA,EACA,GACA,KAED,2DAA4D,CAC3D,KACA,IAED,wDAAyD,CACxD,KACA,KAED,mDAAoD,CACnD,KACA,IAED,uDAAwD,CACvD,KACA,KAED,sDAAuD,CACtD,KACA,IAED,qDAAsD,CACrD,KACA,IAED,yDAA0D,CACzD,KACA,KAED,6DAA8D,CAC7D,KACA,KAED,6CAA8C,CAC7C,KACA,KAED,4DAA6D,CAC5D,KACA,KAED,oDAAqD,CACpD,KACA,KAED,yBAA0B,CACzB,KACA,EACA,EACA,EACA,EACA,IAED,8BAA+B,CAC9B,KACA,EACA,GACA,KAED,6BAA8B,CAC7B,KACA,EACA,EACA,EACA,IAED,yCAA0C,CACzC,KACA,EACA,EACA,KAED,2BAA4B,CAC3B,KACA,IAED,gCAAiC,CAChC,KACA,KAED,+BAAgC,CAC/B,KACA,KAED,yBAA0B,CACzB,KACA,EACA,GACA,GACA,GACA,IAED,8BAA+B,CAC9B,KACA,GACA,KAED,6BAA8B,CAC7B,KACA,EACA,GACA,KAED,+CAAgD,CAC/C,KACA,KAED,uCAAwC,CACvC,KACA,EACA,IAED,6BAA8B,CAC7B,KACA,GACA,IAED,kCAAmC,CAClC,KACA,KAED,mDAAoD,CACnD,KACA,KAED,uBAAwB,CACvB,KACA,EACA,EACA,EACA,EACA,IAED,oCAAqC,CACpC,KACA,IAED,6CAA8C,CAC7C,KACA,IAED,6CAA8C,CAC7C,KACA,IAED,iCAAkC,CACjC,KACA,IAED,4BAA6B,CAC5B,KACA,KAED,6BAA8B,CAC7B,KACA,EACA,KAED,sCAAuC,CACtC,KACA,EACA,KAED,4BAA6B,CAC5B,KACA,KAED,yCAA0C,CACzC,KACA,EACA,EACA,IAED,2CAA4C,CAC3C,KACA,KAED,wCAAyC,CACxC,KACA,GACA,KAED,iCAAkC,CACjC,KACA,IAED,6BAA8B,CAC7B,KACA,KAED,kCAAmC,CAClC,KACA,IAED,2BAA4B,CAC3B,KACA,EACA,EACA,EACA,GACA,IAED,iCAAkC,CACjC,KACA,KAED,uBAAwB,CACvB,KACA,EACA,IAED,4BAA6B,CAC5B,KACA,KAED,2BAA4B,CAC3B,KACA,EACA,KAED,mCAAoC,CACnC,KACA,EACA,GACA,GACA,GACA,IAED,uCAAwC,CACvC,KACA,EACA,GACA,IAED,gDAAiD,CAChD,KACA,KAED,uDAAwD,CACvD,KACA,KAED,oDAAqD,CACpD,KACA,KAED,+CAAgD,CAC/C,KACA,KAED,sDAAuD,CACtD,KACA,EACA,IAED,yCAA0C,CACzC,KACA,KAED,2CAA4C,CAC3C,KACA,KAED,oDAAqD,CACpD,KACA,KAED,+CAAgD,CAC/C,KACA,KAED,6CAA8C,CAC7C,KACA,KAED,6CAA8C,CAC7C,KACA,GACA,GACA,GACA,IAED,kDAAmD,CAClD,KACA,IAED,iDAAkD,CACjD,KACA,GACA,IAED,kDAAmD,CAClD,KACA,KAED,qDAAsD,CACrD,KACA,KAED,uCAAwC,CACvC,KACA,IAED,4CAA6C,CAC5C,KACA,KAED,2CAA4C,CAC3C,KACA,IAED,kDAAmD,CAClD,KACA,KAED,2CAA4C,CAC3C,KACA,EACA,EACA,EACA,GACA,IAED,gDAAiD,CAChD,KACA,KAED,+CAAgD,CAC/C,KACA,EACA,EACA,EACA,GACA,IAED,2DAA4D,CAC3D,KACA,EACA,EACA,IAED,mDAAoD,CACnD,KACA,KAED,oDAAqD,CACpD,KACA,EACA,GACA,KAED,kDAAmD,CAClD,KACA,KAED,qDAAsD,CACrD,KACA,KAED,mDAAoD,CACnD,KACA,EACA,EACA,IAED,uDAAwD,CACvD,KACA,EACA,EACA,KAED,kDAAmD,CAClD,KACA,EACA,EACA,KAED,sDAAuD,CACtD,KACA,EACA,IAED,qDAAsD,CACrD,KACA,KAED,gDAAiD,CAChD,KACA,KAED,iCAAkC,CACjC,KACA,GACA,IAED,sCAAuC,CACtC,KACA,KAED,qCAAsC,CACrC,KACA,KAED,+BAAgC,CAC/B,KACA,GACA,IAED,oCAAqC,CACpC,KACA,KAED,mCAAoC,CACnC,KACA,KAED,qCAAsC,CACrC,KACA,EACA,EACA,KAED,oCAAqC,CACpC,KACA,KAED,2BAA4B,CAC3B,KACA,EACA,EACA,EACA,GACA,IAED,iCAAkC,CACjC,KACA,KAED,gCAAiC,CAChC,KACA,GACA,IAED,+BAAgC,CAC/B,KACA,EACA,EACA,EACA,IAED,+BAAgC,CAC/B,KACA,GACA,IAED,oCAAqC,CACpC,KACA,KAED,mCAAoC,CACnC,KACA,GACA,KAED,qCAAsC,CACrC,KACA,IAED,0CAA2C,CAC1C,KACA,KAED,yCAA0C,CACzC,KACA,KAED,+BAAgC,CAC/B,KACA,KAED,qCAAsC,CACrC,KACA,EACA,IAED,yCAA0C,CACzC,KACA,EACA,IAED,wDAAyD,CACxD,KACA,KAED,qCAAsC,CACrC,KACA,KAED,oCAAqC,CACpC,KACA,KAED,gEAAiE,CAChE,KACA,EACA,KAED,wDAAyD,CACxD,KACA,EACA,KAED,sDAAuD,CACtD,KACA,KAED,mEAAoE,CACnE,KACA,EACA,EACA,IAED,sDAAuD,CACtD,KACA,EACA,KAED,kDAAmD,CAClD,KACA,EACA,IAED,0DAA2D,CAC1D,KACA,EACA,KAED,6CAA8C,CAC7C,KACA,GACA,IAED,0CAA2C,CAC1C,KACA,IAED,0CAA2C,CAC1C,KACA,IAED,iCAAkC,CACjC,KACA,EACA,EACA,GACA,GACA,IAED,uBAAwB,CACvB,KAED,uBAAwB,CACvB,KACA,KAED,0BAA2B,CAC1B,KAED,oCAAqC,CACpC,KAED,uBAAwB,CACvB,KAED,mBAAoB,CACnB,KAED,0BAA2B,CAC1B,IAED,sBAAuB,CACtB,IAED,uBAAwB,CACvB,KAED,gCAAiC,CAChC,KAED,8BAA+B,CAC9B,KAED,uBAAwB,CACvB,MAGF,SAASytD,EAAoBC,GAC5B,IAAIC,EAAoBv5C,EAAEpU,EAAK0tD,GAC9B,OAAOxpD,QAAQqE,UAAUvE,MAAK,WAC7B,IAAI5P,EAAI,IAAIimB,MAAM,uBAAyBqzC,EAAM,KAEjD,MADAt5D,EAAEqsC,KAAO,mBACHrsC,KAIR,IAAIw5D,EAAM5tD,EAAI0tD,GAAMl4D,EAAKo4D,EAAI,GAC7B,OAAO1pD,QAAQC,IAAIypD,EAAIjyC,MAAM,GAAG3b,IAAI2tD,EAAoBv5D,IAAI4P,MAAK,WAChE,OAAO2pD,EAAoBn4D,MAG7Bi4D,EAAoBxzD,KAAO,WAC1B,OAAOD,OAAOC,KAAK+F,IAEpBytD,EAAoBj4D,GAAK,IACzB++B,EAAOs5B,QAAUJ,G,gCC58BjB,4FAKO,IAAMr3C,EAAW3B,IAEjB,SAASA,IACd,OAAOrb,OAAO+Y,WAAa,O","file":"static/js/main.958aecaf.chunk.js","sourcesContent":["export function encodeCommas(string) {\n return !string ? string : string.replace(/,/g, \"%2C\");\n}\n\nexport function decodeCommas(string) {\n return !string ? string : string.replace(/%2C/g, \",\");\n}\n","import React, { Component } from \"react\";\nimport propTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport Button from \"@material-ui/core/Button\";\n\nimport ReactDialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogContentText from \"@material-ui/core/DialogContentText\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport TextField from \"@material-ui/core/TextField\";\n\nconst styles = (theme) => ({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n },\n textField: {\n marginLeft: theme.spacing(1),\n marginRight: theme.spacing(1),\n width: 200,\n },\n dense: {\n marginTop: 19,\n },\n menu: {\n width: 200,\n },\n});\n\nclass Dialog extends Component {\n state = {\n open: false,\n text: \"\",\n };\n\n static propTypes = {\n classes: propTypes.object.isRequired,\n onClose: propTypes.func.isRequired,\n open: propTypes.bool.isRequired,\n options: propTypes.object.isRequired,\n };\n\n /*\n * If the lifecycle of the component is not controlled by itself\n * the render method can be used to make the component\n * update its state when props changes.\n *\n * It is not recommended to mutate the state of this component\n * if the keys have the same name, it will duplicate the update event and\n * the last prop value will be taken.\n *\n * NOTE: this method is considered safer than using legacy componentWillRecieveProps.\n *\n * @param {object} props - new props\n * @param {object} state - current state\n * @return {object} state - updated state\n */\n static getDerivedStateFromProps(props, state) {\n return {\n open: props.open,\n };\n }\n\n handleChange = (name) => (event) => {\n this.setState({\n [name]: event.target.value,\n });\n };\n\n handleClose = (e) => {\n e.stopPropagation();\n this.props.onClose(this.state.text);\n };\n\n handleAbort = (e) => {\n e.stopPropagation();\n this.props.onAbort(this.state.text);\n };\n\n handleDialogClick = (e) => {\n e.stopPropagation();\n return false;\n };\n\n getHtml(text) {\n return {\n __html: text,\n };\n }\n\n renderDialogContent(text) {\n if (typeof text === \"string\") {\n return (\n \n \n \n );\n } else {\n return text;\n }\n }\n\n renderPromptInput() {\n const { classes, options } = this.props;\n if (!options.prompt) return null;\n\n return (\n {\n e.preventDefault();\n this.props.onClose(this.state.text);\n return false;\n }}\n >\n \n \n );\n }\n\n render() {\n const { options } = this.props;\n\n var text = \"\",\n header = \"\";\n\n if (options) {\n header = options.headerText;\n text = options.text;\n }\n\n var fullScreen = document.body.clientWidth < 600;\n\n return (\n \n {header}\n \n {this.renderDialogContent(text)}\n {this.renderPromptInput()}\n \n \n \n {options.abortText ? (\n \n ) : null}\n \n \n );\n }\n}\n\nexport default withStyles(styles)(Dialog);\n","export default class LayerInfo {\n constructor(properties) {\n this.attribution = properties.attribution;\n this.caption = properties.caption;\n this.infoOwner = properties.infoOwner;\n this.infoText = properties.infoText;\n this.infoTitle = properties.infoTitle;\n this.infoUrl = properties.infoUrl;\n this.infoUrlText = properties.infoUrlText;\n this.infoVisible = properties.infoVisible;\n this.infoClickSortType = properties.infoClickSortType;\n this.infoClickSortDesc = properties.infoClickSortDesc;\n this.infoClickSortProperty = properties.infoClickSortProperty;\n this.information = properties.information;\n this.legend = properties.legend;\n this.legendIcon = properties.legendIcon;\n this.searchDisplayName = properties.searchDisplayName;\n this.searchShortDisplayName = properties.searchShortDisplayName;\n this.searchGeometryField = properties.searchGeometryField;\n this.searchOutputFormat = properties.searchOutputFormat;\n this.searchPropertyName = properties.searchPropertyName;\n this.searchUrl = properties.searchUrl;\n this.layerType = properties.layerType;\n this.hideExpandArrow = properties.hideExpandArrow;\n }\n}\n","/**\n * HOW TO USE THIS HELPER\n * Import this helper wherever you want to use the get/set methods.\n * This helper is initiated once, on export, and we set the key name\n * once (in index.js), so you don't have to worry about the details.\n * Just get/set whatever you want.\n *\n * Please not however that THERE IS A TWIST HERE TO THE USUAL LOCALSTORAGE\n * behavior!\n *\n * A. This helper is map-specific. That means that ALL SETTINGS RELEATED TO A\n * MAPCONFIG WILL BE HELD IN ONE KEY/VALUE PAIR IN LOCALSTOREGE.\n * B. Because we only have one value to play with for all the settings, and\n * LocalStorage stores values as string, we utilized JSON.stringify and JSON.parse.\n *\n * === Example for map config 'map_1' ===\n * We can use this helper as follows.\n *\n * === Storing map-specific data ===\n * LocalStorageHelper.set(\"foobar\", [1,2,3]);\n *\n * This will create/modify the following in browser's LocalStorage:\n * map_options_map_1: \"{\\\"foobar\\\":[1,2,3]}\"\n * If there were any other keys (except \"foobar\") THEY WON'T BE TOUCHED!\n *\n * === Retrieving map-specific data ===\n * LocalStorageHelper.get(\"foobar\", \"default value\")\n *\n * This can do one of two things:\n * - if there was a key named \"foobar\" for current entry, we'll get the JSON.parsed results\n * - if there was no entry named \"foobar\", we'll get \"default value\" back\n */\nclass LocalStorageHelper {\n mapName = \"map_options_unknown_map\";\n /**\n * @summary We want each map to have its own settings in LS, so we use mapConfig's name\n * as a key for the LS property.\n * @description This will normally be called once, when the map is initiated. All subsequent\n * use (getting and setting values) will read this key's value.\n *\n * @param {string} [mapName=\"unknown_map\"]\n * @memberof LocalStorageHelper\n */\n setKeyName(mapName = \"unknown_map\") {\n this.mapName = `map_options_${mapName}`;\n }\n\n /**\n * @summary Get map-specific settings from LocalStorage for the given key, fallback to supplied default\n * if parsing not possible.\n *\n * @param {*} key\n * @param {*} [defaults={}]\n * @returns\n * @memberof\n */\n get(key, defaults = {}) {\n try {\n // Return a shallow merged objects with\n return {\n ...defaults, // …supplied defaults, that can be overwritten by…\n ...JSON.parse(window.localStorage.getItem(this.mapName))[\n key // …whatever exists in local storage for the specified key\n ],\n };\n } catch (error) {\n // If parsing failed, return defaults\n return defaults;\n }\n }\n /**\n * @summary Save any JSON-able value to a specified key in a local storage object specific to current map\n *\n * @param {*} key Name of the key inside the JSON object\n * @param {*} value Value that the key will be set to\n * @memberof\n */\n set(key, value) {\n window.localStorage.setItem(\n this.mapName, // Use a map-specific name as key for LocalStorage setting\n JSON.stringify({\n ...JSON.parse(window.localStorage.getItem(this.mapName)),\n [key]: value,\n })\n );\n }\n}\n\n// Export singleton instance\nexport default new LocalStorageHelper();\n","/**\n * Performs a deep merge of objects and returns new object. Does not modify\n * objects (immutable) and merges arrays via concatenation.\n *\n * @param {...object} objects - Objects to merge\n * @returns {object} New object with merged key/values\n */\nexport function deepMerge(...objects) {\n const isObject = (obj) => obj && typeof obj === \"object\";\n\n return objects.reduce((prev, obj) => {\n Object.keys(obj).forEach((key) => {\n const pVal = prev[key];\n const oVal = obj[key];\n\n if (Array.isArray(pVal) && Array.isArray(oVal)) {\n prev[key] = pVal.concat(...oVal);\n } else if (isObject(pVal) && isObject(oVal)) {\n prev[key] = deepMerge(pVal, oVal);\n } else {\n prev[key] = oVal;\n }\n });\n\n return prev;\n }, {});\n}\n","import { Stroke, Style, Circle, Fill, Text, Icon } from \"ol/style\";\nimport { Point } from \"ol/geom.js\";\n\nexport default class FeatureStyle {\n #options;\n #defaultDisplayStyleSettings;\n #defaultSelectionStyleSettings;\n #defaultHighlightStyleSettings;\n #enableLabelOnHighlight;\n\n constructor(options) {\n this.#options = options;\n this.#enableLabelOnHighlight = options.enableLabelOnHighlight ?? true;\n this.#defaultDisplayStyleSettings = this.#getDefaultDisplayStyleSettings();\n this.#defaultSelectionStyleSettings =\n this.#getDefaultSelectionStyleSettings();\n this.#defaultHighlightStyleSettings =\n this.#getDefaultHighlightStyleSettings();\n }\n\n #getDefaultDisplayStyleSettings = () => {\n const fillColor = this.#options.displayFillColor ?? \"rgba(74,144,226,0.15)\";\n const strokeColor =\n this.#options.displayStrokeColor ?? \"rgba(74,144,226,0.4)\";\n\n return {\n strokeColor: strokeColor,\n fillColor: fillColor,\n };\n };\n\n #getDefaultSelectionStyleSettings = () => {\n const strokeColor =\n this.#options.selectionStrokeColor ?? \"rgba(74,144,226,0.8)\";\n const fillColor =\n this.#options.selectionFillColor ?? \"rgba(74,144,226,0.3)\";\n const textFillColor =\n this.#options.selectionTextFill ?? \"rgba(63,122,190,1)\";\n const textStrokeColor =\n this.#options.selectionTextStroke ?? \"rgba(255,255,255,1)\";\n const fontSize = 12;\n\n return {\n strokeColor: strokeColor,\n fillColor: fillColor,\n textFillColor: textFillColor,\n textStrokeColor: textStrokeColor,\n fontSize: fontSize,\n };\n };\n\n #getDefaultHighlightStyleSettings = () => {\n const strokeColor =\n this.#options.highlightStrokeColor ?? \"rgba(245,166,35,0.8)\";\n const fillColor = this.#options.highlightFillColor ?? \"rgba(245,166,35,0)\";\n const textFillColor =\n this.#options.highlightTextFill ?? \"rgba(214,143,28,1)\";\n const textStrokeColor =\n this.#options.highlightTextStroke ?? \"rgba(255,255,255,1)\";\n const fontSize = 15;\n\n return {\n strokeColor: strokeColor,\n fillColor: fillColor,\n textFillColor: textFillColor,\n textStrokeColor: textStrokeColor,\n fontSize: fontSize,\n };\n };\n\n getFeatureStyle = (feature, type) => {\n // Helper for the cumbersome type check: scale and anchor values, when unset in admin,\n // will consist of empty strings, perfectly legal but unusable in our case. So we must ensure\n // that the value we get can be parsed to a finite number, else fallback to something else.\n const isValidNumber = (n) => Number.isFinite(parseInt(n));\n\n const { scale, markerImg } = this.#options;\n const anchor = this.#options.anchor ?? [];\n\n const isPoint = feature?.getGeometry() instanceof Point;\n const textAlign = isPoint ? \"left\" : \"center\";\n const offsetY = isPoint ? -50 : -10;\n\n const settings =\n !type || type === \"selection\"\n ? this.#defaultSelectionStyleSettings\n : this.#defaultHighlightStyleSettings;\n\n // Create new color to be used for icons: start with fill color but make sure that it's\n // _not_ transparent by setting the alpha channel value to 0.8. Unfortunately Safari doesn't\n // support lookbehind, so we must do it this way. Basically we do:\n // \"rgba(x,y,z,ź)\" => \"rgba(x,y,z,0.8)\"\n const iconColor = settings.fillColor.replace(/,[\\d.]*\\)/, \",0.8)\");\n\n // Default SVG icon to be used as marker. Placed here so we can grab the current style's fill color.\n const svgString = ``;\n const defaultMarker = `data:image/svg+xml;base64,${window.btoa(svgString)}`; // We need base64 for kml-exports to work.\n // For the 'highlight' style, we want the marker icon to be 30% larger than other styles\n const multiplier = type === \"highlight\" ? 1.3 : 1;\n\n return new Style({\n fill: new Fill({\n color: settings.fillColor,\n }),\n stroke: new Stroke({\n color: settings.strokeColor,\n width: 2,\n }),\n image: new Icon({\n anchor: [\n isValidNumber(anchor[0]) ? anchor[0] : 0.5,\n isValidNumber(anchor[1]) ? anchor[1] : 1,\n ],\n scale: (isValidNumber(scale) ? scale : 1) * multiplier,\n src: markerImg?.length > 0 ? markerImg : defaultMarker,\n }),\n ...(this.#enableLabelOnHighlight && {\n text: new Text({\n textAlign: textAlign,\n textBaseline: \"middle\",\n font: `${settings.fontSize}pt \"Roboto\", sans-serif`,\n fill: new Fill({\n color: settings.textFillColor,\n }),\n text: feature.featureTitle,\n overflow: true,\n stroke: new Stroke({\n color: settings.textStrokeColor,\n width: 3,\n }),\n offsetX: 0,\n offsetY: offsetY,\n rotation: 0,\n scale: 1,\n }),\n }),\n });\n };\n\n getDefaultSearchResultStyle = (feature) => {\n const settings = this.#defaultSelectionStyleSettings;\n\n const fill = new Fill({\n color: this.#defaultDisplayStyleSettings.fillColor,\n });\n\n const stroke = new Stroke({\n color: this.#defaultDisplayStyleSettings.strokeColor,\n width: 2,\n });\n return new Style({\n fill: fill,\n stroke: stroke,\n image: new Circle({\n fill: fill,\n stroke: stroke,\n radius: 10,\n }),\n ...(this.#enableLabelOnHighlight && {\n text: new Text({\n textAlign: \"center\",\n textBaseline: \"middle\",\n font: `10pt \"Roboto\", sans-serif`,\n fill: new Fill({\n color: settings.textFillColor,\n }),\n text: feature.shortFeatureTitle,\n overflow: true,\n stroke: new Stroke({\n color: settings.textStrokeColor,\n width: 3,\n }),\n offsetX: 0,\n offsetY: 0,\n rotation: 0,\n scale: 1,\n }),\n }),\n });\n };\n}\n","import GeoJSON from \"ol/format/GeoJSON\";\nimport TileLayer from \"ol/layer/Tile\";\nimport ImageLayer from \"ol/layer/Image\";\nimport WMSGetFeatureInfo from \"ol/format/WMSGetFeatureInfo\";\nimport { hfetch } from \"utils/FetchWrapper\";\n\nfunction query(map, layer, evt) {\n const coordinate = evt.coordinate;\n const resolution = map.getView().getResolution();\n const currentZoom = map.getView().getZoom();\n const referenceSystem = map.getView().getProjection().getCode();\n let subLayersToQuery = [];\n\n // Query only those layers that a) have a layersInfo property, and\n // b) are currently displayed. Please note that checking for visibility\n // is not enough, we must also respect the min/max zoom level settings, #836.\n if (\n layer.layersInfo &&\n layer.getMinZoom() <= currentZoom &&\n currentZoom <= layer.getMaxZoom()\n ) {\n const subLayers = Object.values(layer.layersInfo);\n // First we must get the string containing the active sub-layers in this\n // group-layer.\n const visibleSubLayersString =\n layer.getSource().getParams()[\"LAYERS\"] || \"\";\n // The string will contain the layers, separated with a comma. We'll split\n // the string to get an array.\n const visibleSubLayersArray = visibleSubLayersString.split(\",\");\n // Then we'll create a Set from the array. The Set will allow us to\n // check wether a sub-layer should be queried or not in a simple manner.\n const visibleSubLayersSet = new Set(visibleSubLayersArray);\n // Then we'll loop trough the subLayers that should be queried, and make sure\n // to remove layers that are 1. Not queryable, or 2. Not visible.\n subLayersToQuery = subLayers\n .filter(\n (subLayer) =>\n subLayer.queryable === true && visibleSubLayersSet.has(subLayer.id)\n ) // QUERY_LAYERS must not include anything that's not in LAYERS, see https://github.com/hajkmap/Hajk/issues/211\n .map((queryableSubLayer) => {\n return queryableSubLayer.id;\n });\n }\n\n if (subLayersToQuery.length > 0) {\n let params = {\n FEATURE_COUNT: 100,\n INFO_FORMAT: layer.getSource().getParams().INFO_FORMAT,\n QUERY_LAYERS: subLayersToQuery.join(\",\"),\n };\n\n // See #852. Without this, it's almost impossible to get a result from QGIS Server.\n // TODO: This could be expanded and made an admin setting - I'm not sure that 50 px\n // will work for everyone.\n // The WITH_GEOMETRY is necessary to make QGIS Server send back the feature's geometry\n // in the response.\n // See: https://docs.qgis.org/3.16/en/docs/server_manual/services.html#wms-withgeometry.\n if (layer.getSource().serverType_ === \"qgis\") {\n params = {\n ...params,\n FI_POINT_TOLERANCE: 50,\n FI_LINE_TOLERANCE: 50,\n FI_POLYGON_TOLERANCE: 50,\n WITH_GEOMETRY: true,\n };\n }\n\n const url = layer\n .getSource()\n .getFeatureInfoUrl(coordinate, resolution, referenceSystem, params);\n return hfetch(url);\n } else {\n return false;\n }\n}\n\nfunction getSortParser(sortType) {\n if (sortType === \"number\") {\n return parseInt;\n } else if (sortType === \"string\") {\n return (a) => {\n return a ? a.trim() : \"\";\n };\n } else {\n return (a) => {\n return a;\n };\n }\n}\n\nfunction getSortMethod(options) {\n if (options.type === \"number\") {\n return (a, b) => {\n return (\n (options.desc ? -1 : 1) *\n (options.parser(a.getProperties()[options.prop]) -\n options.parser(b.getProperties()[options.prop]))\n );\n };\n } else {\n return (a, b) => {\n return (\n (options.desc ? -1 : 1) *\n options\n .parser(a.getProperties()[options.prop])\n .localeCompare(options.parser(b.getProperties()[options.prop]))\n );\n };\n }\n}\n\nfunction sortFeatures(layer, features) {\n if (!features || features.length <= 1) {\n return;\n }\n const layerInfo = layer.getProperties().layerInfo;\n if (!layerInfo.infoClickSortProperty) {\n return;\n }\n\n const sortType = layerInfo.infoClickSortType || \"string\";\n const sortOptions = {\n type: sortType,\n desc: layerInfo.infoClickSortDesc ?? true,\n prop: layerInfo.infoClickSortProperty.trim(),\n parser: getSortParser(sortType),\n };\n\n features.sort(getSortMethod(sortOptions));\n}\n\n// Function similar to GeoJSON().readFeatures, with the subtle difference that we set an\n// id if it is missing on the parsed feature. The missing id occurs when parsing features from\n// arcGis for some reason.\nfunction readJsonFeatures(jsonData, layerProjection, viewProjection) {\n const parser = new GeoJSON();\n\n // If the response from WMS service contains a CRS (GeoServer), the feature parser\n // will use it be default to determine the features' projection.\n // However, if it's empty (QGIS Server), we must tell the parser which projection\n // should be used for the features and which projection our View is in.\n const parserOptions = jsonData.crs\n ? {}\n : {\n dataProjection: layerProjection,\n featureProjection: viewProjection,\n };\n\n const parsedFeatures = [];\n // jsonData will always be a featureCollection, hence we must map over all\n // features in the collection.\n jsonData.features.map((jsonFeature) => {\n // Lets parse the feature...\n const parsedJsonFeature = parser.readFeature(jsonFeature, parserOptions);\n // And check if we have an id...\n if (!parsedJsonFeature.getId()) {\n // If we don't, we set the id to the layerName, and a random id\n // so that featureInfo knows when we clicked a new feature in\n // the same layer.\n parsedJsonFeature.setId(\n `${jsonFeature.layerName}.${parsedJsonFeature.ol_uid}`\n );\n }\n // Push the feature to the array of parsed features\n return parsedFeatures.push(parsedJsonFeature);\n });\n // And return it\n return parsedFeatures;\n}\n\nfunction getFeaturesFromJson(response, jsonData) {\n const layerProjection = response.layer.getSource().getProjection();\n const viewProjection = response.viewProjection;\n const parsed = readJsonFeatures(jsonData, layerProjection, viewProjection);\n if (parsed && parsed.length > 0) {\n parsed.forEach((f) => {\n f.layer = response.layer;\n });\n sortFeatures(response.layer, parsed);\n return parsed;\n } else {\n return [];\n }\n}\n\nfunction getFeaturesFromGml(response, text) {\n let wmsGetFeatureInfo = new WMSGetFeatureInfo();\n //let doc = new DOMParser().parseFromString(text, \"text/xml\");\n let parsed = wmsGetFeatureInfo.readFeatures(text);\n if (parsed && parsed.length > 0) {\n parsed.forEach((f) => {\n f.layer = response.layer;\n });\n sortFeatures(response.layer, parsed);\n return parsed;\n } else {\n return [];\n }\n}\n\n/**\n * Query the map for features when the user clicks the map.\n * The approach is to stack all the queryable WMS-requests and return a promise with a pointer to the referring layer.\n * When the requests are done the features are parsed and given the original layer reference.\n * Vector layers are added with the features at pixel method and given the original layer reference as well.\n */\nexport function handleClick(evt, map, callback) {\n document.querySelector(\"body\").style.cursor = \"progress\";\n const promises = [];\n const viewProjection = map.getView().getProjection().getCode();\n map\n .getLayers()\n .getArray()\n // Now we have an array with all layers added to our map, let's narrow down a bit\n .filter(\n (layer) =>\n // Only certain layer types are relevant\n (layer instanceof TileLayer || layer instanceof ImageLayer) &&\n // And only if they're currently visible (no reason to query hidden layers)\n layer.get(\"visible\") === true\n )\n // For each layer that's left in the array\n .forEach((layer) => {\n // Query the layer, will return a Promise (Fetch call)\n // or false, if there was no need to fetch.\n const promise = query(map, layer, evt);\n // If query() didn't return false, we have a real Promise\n if (promise !== false) {\n promises.push(\n promise.then((response) => {\n return {\n layer: layer,\n requestResponse: response,\n viewProjection: viewProjection,\n };\n })\n );\n }\n });\n\n Promise.all(promises).then((responses) => {\n const featurePromises = [];\n const features = [];\n responses.forEach((response) => {\n const type = response.requestResponse.headers\n .get(\"Content-Type\")\n .split(\";\")[0];\n switch (type) {\n case \"application/geojson\":\n case \"application/json\":\n featurePromises.push(\n response.requestResponse\n .json()\n .then((jsonData) => {\n if (\n jsonData !== undefined &&\n jsonData &&\n jsonData.features &&\n jsonData.features.length > 0\n ) {\n features.push(...getFeaturesFromJson(response, jsonData));\n }\n })\n .catch((err) => {\n console.error(\n \"GetFeatureInfo couldn't retrieve correct data for the clicked object.\",\n err\n );\n })\n );\n break;\n case \"text/xml\":\n case \"application/vnd.ogc.gml\": {\n featurePromises.push(\n response.requestResponse\n .text()\n .then((text) => {\n features.push(...getFeaturesFromGml(response, text));\n })\n .catch((err) => {\n console.error(\n \"GetFeatureInfo couldn't retrieve correct data for the clicked object. \"\n );\n })\n );\n break;\n }\n default:\n break;\n }\n });\n\n Promise.all(featurePromises).then(() => {\n map.forEachFeatureAtPixel(\n evt.pixel,\n (feature, layer) => {\n if (\n layer &&\n (layer.get(\"queryable\") === true ||\n layer.get(\"type\") === \"searchResultLayer\")\n ) {\n feature.layer = layer;\n features.push(feature);\n }\n },\n {\n hitTolerance: 10,\n }\n );\n\n document.querySelector(\"body\").style.cursor = \"initial\";\n callback({\n features: features,\n evt: evt,\n });\n });\n });\n}\n\nexport function bindMapClickEvent(map, callback) {\n // We must use a custom \"clickLock\" mechanism, as opposed to the\n // previous attempts (map.getInteraction().getArray() and looking\n // for certain values in each Interaction's constructor.name).\n //\n // The previous method (checking prototype's name) was\n // unreliable as Webpack uglifies the class names,\n // hence the constructors we're comparing against\n // don't have their usual names.\n //\n // Please see issue #591 for more info.\n //\n // The 'clickLock' Set is added to Map in appModel.createMap(),\n // so by the time we bind this handler, we can be sure that\n // map.clickLock already exists.\n\n // Bind the \"singleclick\" event of OL Map\n map.on(\"singleclick\", (evt) => {\n // Handle click only if there no plugin wants to lock\n // the click interaction currently\n map.clickLock.size === 0 && handleClick(evt, map, callback);\n });\n}\n","import React from \"react\";\nimport ReactMarkdown from \"react-markdown\";\nimport rehypeRaw from \"rehype-raw\";\nimport { withStyles } from \"@material-ui/core\";\nimport gfm from \"remark-gfm\";\nimport FeaturePropFilters from \"./FeaturePropsFilters\";\nimport {\n Divider,\n Link,\n Paper,\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n Typography,\n} from \"@material-ui/core\";\n\nconst Paragraph = withStyles((theme) => ({\n root: {\n marginBottom: \"1.1rem\",\n },\n}))(Typography);\n\n// Styled Table Row Component, makes every second row in a Table colored\nconst StyledTableRow = withStyles((theme) => ({\n root: {\n \"&:nth-of-type(even)\": {\n backgroundColor: theme.palette.action.hover,\n },\n },\n}))(TableRow);\n\nconst StyledTableContainer = withStyles((theme) => ({\n root: {\n marginBottom: \"1.1rem\",\n },\n}))(TableContainer);\n\nconst StyledPaper = withStyles((theme) => ({\n root: {\n padding: theme.spacing(1),\n marginBottom: \"1.1rem\",\n backgroundColor: theme.palette.background.default,\n \"& p\": {\n marginBottom: \"0\",\n },\n },\n}))(Paper);\n\nconst StyledTypography = withStyles((theme) => ({\n h1: {\n fontSize: \"1.6rem\",\n fontWeight: \"500\",\n marginBottom: \"0.375rem\",\n },\n h2: {\n fontSize: \"1.4rem\",\n fontWeight: \"500\",\n marginBottom: \"0.018rem\",\n },\n h3: {\n fontSize: \"1.2rem\",\n fontWeight: \"500\",\n },\n h4: {\n fontSize: \"1rem\",\n fontWeight: \"500\",\n },\n h5: {\n fontSize: \"0.875rem\",\n fontWeight: \"500\",\n },\n h6: {\n fontSize: \"0.875rem\",\n fontWeight: \"400\",\n fontStyle: \"italic\",\n },\n}))(Typography);\n\nexport default class FeaturePropsParsing {\n constructor(settings) {\n this.globalObserver = settings.globalObserver;\n this.options = settings.options;\n\n // Two arrays that will hold pending promises and their resolved values, respectively.\n this.pendingPromises = [];\n this.resolvedPromisesWithComponents = [];\n\n this.markdown = null;\n this.properties = null; // Will hold the property values from the clicked feature\n\n // Default to true to ensure backwards compatibility with old configs that predominately use HTML\n this.allowDangerousHtml = this.options.allowDangerousHtml ?? true;\n\n // Here we define the components used by ReactMarkdown, see https://github.com/remarkjs/react-markdown#appendix-b-components\n this.components = {\n p: (props) => {\n if (!props.children) {\n return null;\n }\n\n const r = props.children.map((child, index) => {\n // Initiate a holder for external components. If a regex matches below,\n // this variable will be filled with correct value.\n let externalComponent = null;\n\n if (child && typeof child === \"string\") {\n // This helper is passed to ReactMarkdown at render. At this stage,\n // we expect that the only remaining {stuff} will contain digits, and\n // that those numbers represent element index in this.resolvedPromisesWithComponents.\n // Let's try to match the regex for a number within curly brackets.\n const match = child.match(/{(\\d+)}/);\n if (\n match &&\n this.resolvedPromisesWithComponents.hasOwnProperty(match[1])\n ) {\n // If matched, replace the placeholder with the corresponding component.\n externalComponent = this.resolvedPromisesWithComponents[match[1]];\n }\n }\n // If externalComponent isn't null anymore, render it. Else, just render the children.\n return externalComponent || child;\n });\n\n return {r};\n },\n hr: () => ,\n a: ({ children, href, title }) => {\n return children ? (\n \n {children}\n \n ) : null;\n },\n h1: this.#markdownHeaderComponent,\n h2: this.#markdownHeaderComponent,\n h3: this.#markdownHeaderComponent,\n h4: this.#markdownHeaderComponent,\n h5: this.#markdownHeaderComponent,\n h6: this.#markdownHeaderComponent,\n table: ({ children, className, style }) => {\n return (\n \n \n {children}\n
\n
\n );\n },\n thead: ({ children }) => {\n return {children};\n },\n tbody: ({ children }) => {\n return {children};\n },\n tr: ({ children }) => {\n return {children};\n },\n td: this.#markdownTableCellComponent,\n th: this.#markdownTableCellComponent,\n style: ({ children }) => {\n return ;\n },\n div: ({ children, className, style }) => {\n return (\n
\n {children}\n
\n );\n },\n blockquote: (props) => {\n return {props.children};\n },\n };\n }\n\n #markdownTableCellComponent = ({ children, style, isHeader, className }) => {\n return (\n \n {children}\n \n );\n };\n\n #markdownHeaderComponent = ({ level, children }) => {\n return (\n {children}\n );\n };\n\n #valueFromJson = (str) => {\n if (typeof str !== \"string\") return false;\n const jsonStart = /^\\[|^\\{(?!\\{)/;\n const jsonEnds = {\n \"[\": /]$/,\n \"{\": /}$/,\n };\n const start = str.match(jsonStart);\n const jsonLike = start && jsonEnds[start[0]].test(str);\n var result = false;\n\n if (jsonLike) {\n try {\n result = JSON.parse(str);\n } catch (ex) {\n result = false;\n }\n } else {\n result = false;\n }\n\n return result;\n };\n\n #getPropertyValueForPlaceholder = (placeholder) => {\n // First strip the curly brackets, e.g. {foobar} -> foobar\n placeholder = placeholder.substring(1, placeholder.length - 1);\n\n // Placeholders to be fetch from external components will include \"@@\", and\n // they need to be treated differently from \"normal\" placeholders (sans @@).\n if (placeholder.includes(\"@@\") && !placeholder.includes(\"@@@\")) {\n // Extract the property and plugins names from the placeholder.\n const [propertyName, pluginName] = placeholder.split(\"@@\");\n\n // Grab the actual value of this placeholder from the properties collections\n const propertyValue = this.properties[propertyName];\n\n // If they key was not found in the properties object, or the value is empty, we can't go on.\n if (\n propertyValue === undefined ||\n propertyValue === null ||\n propertyValue.trim() === \"\"\n ) {\n return \"\";\n } else {\n // Now we know 1) property value of the placeholder and 2) which plugin will take care of it.\n // Next we want to call #fetchExternal, that immediately returns a Promise, and push that\n // promise into an array of promises. Later on, we will want to get the value from this\n // fulfilled promise, so one key aspect here is to keep track of which promise value should\n // go where. We will do it the easy way: when the promise is pushed into an array, push\n // returns the new array length. That means that this recently pushed element will have\n // an index of n-1. We use this fact by returning a string, \"{n-1}\" back to the Markdown string.\n // That way, in the final step of Markdown parsing, we will be able to replace each \"{n-1}\" with\n // the contents of the correct element in the resolved promises array.\n\n return `{${\n this.pendingPromises.push(\n this.#fetchExternal(propertyValue, pluginName)\n ) - 1\n }}`;\n }\n } else if (placeholder.includes(\"|\")) {\n return FeaturePropFilters.applyFilters(this.properties, placeholder);\n }\n // Just a \"normal\" placeholder, e.g. {foobar}\n else {\n // Attempt to grab the actual value from the Properties collection, if not found, fallback to empty string.\n // Note that we must replace equal sign in property value, else we'd run into trouble, see #812.\n\n return (\n // What you see on the next line is what we call \"hängslen och livrem\" in Sweden.\n // (The truth is it's all needed - this.properties may not be an Array, it may not have a key named\n // \"placeholder\", but if it does, we can't be sure that it will have the replace() method (as only Strings have it).)\n this.properties?.[placeholder]?.replace?.(/=/g, \"&equal;\") || // If replace() exists, it's a string, so we can revert our equal signs.\n this.properties[placeholder] || // If not a string, return the value as-is…\n \"\" // …unless it's undefined - in that case, return an empty string.\n );\n }\n };\n\n #fetchExternal = (propertyValue, pluginName) => {\n // If there are listeners for the current plugin that we parsed out here…\n if (\n this.globalObserver.getListeners(`core.info-click-${pluginName}`).length >\n 0\n ) {\n return new Promise((resolve, reject) => {\n // …let's return a Promise that will publish an event to the\n // requested plugin. The listening plugin will use the payload,\n // together with resolve/reject to fulfill the Promise.\n this.globalObserver.publish(`core.info-click-${pluginName}`, {\n payload: propertyValue,\n resolve,\n reject,\n });\n });\n } else {\n return null;\n }\n };\n\n /**\n * @summary The evaluator helper used in the final stage of markdown string\n * parsing. Extracts tags and either keeps the content (if value evaluates)\n * to true, or removes it from the markdown string.\n *\n * @param {*} args\n * @returns {string} Value inside the condition (if evaluated to true), or an empty string.\n */\n #conditionalReplacer = (...args) => {\n // Extract the regex named capture groups, they will be the last argument\n // when .replace() calls this helper.\n // Expect matched to contain 'condition', 'attributes' and 'content'.\n const matched = args[args.length - 1];\n\n // Do different things, depending on 'condition'\n switch (matched.condition) {\n case \"if\":\n // Append a new line to the content that (perhaps)\n // will be returned. If we return a content, we must\n // ensure that new line is added, because we stripped\n // all ending new lines (after ) in the regex.\n matched.content += \"\\n\";\n\n // Handle or \n if (matched.attributes?.includes(\"=\")) {\n // Turn \"FOO=\\\"BAR\\\"\" into k = \"FOO\" and v = \"BAR\"\n let [k, v] = matched.attributes\n .split(\"=\") // Create an array\n .map((e) => e.replaceAll('\"', \"\").trim()); // Remove double quotes and whitespace\n\n // Using truthy equal below: we want 2 and \"2\" to be seen as equal.\n // eslint-disable-next-line eqeqeq\n if (k == v) {\n return matched.content;\n } else {\n return \"\";\n }\n }\n // Handle - if it exits, evaluate to true and show content\n else if (matched.attributes?.trim().length > 0) {\n return matched.content;\n }\n // Handle (i.e. do not render because the attribute to evaluate is falsy)\n else {\n return \"\";\n }\n // For any other condition, leave as-is (could be HTML tag)\n default:\n return args[0];\n }\n };\n\n /**\n * @summary Ensure that the href part in Markdown links is well-formatted\n * @description Href in Markdown should be UTF8 formatted and have whitespace\n * escaped (with %20). The easiest way to ensure proper formatting is using the\n * URL object. But the constructor of URL will crash if the string provided is\n * not a proper path (e.g. lacks the protocol part). So we use try-catch to\n * catch such occurrences, and in those cases, we return the anchor pretty much unchanged.\n *\n * @param {*} args\n * @returns\n */\n #markdownHrefEncoder = (...args) => {\n // The named capture groups will be the last parameter\n const matched = args[args.length - 1];\n\n // Anchor text and title are simple\n const text = matched.text;\n const title = matched.title ? \" \" + matched.title : \"\";\n\n // Anchor href will require some more work.\n let href = matched.href;\n\n try {\n // Try creating a new URL from the matched href.\n // Invoking new URL will escape any special characters and ensure\n // that we provide a well-formatted URL to the MarkDown.\n href = new URL(href);\n } catch (error) {\n // If the URL creation failed for some reason (e.g. if a.href was empty,\n // or if it was a relative path), fall back to using the provided\n // string as-is, but remember to remove the leading and closing parentheses\n // that our regex included in the match and encode the URL (i.e. still\n // transform 'dir/file åäö.pdf' to 'dir/file%20%C3%A5%C3%A4%C3%B6.pdf').\n href = encodeURI(href);\n }\n\n // Prepare a nice MD Anchor string\n const r = `[${text}](${href}${title})`;\n return r;\n };\n\n /**\n * Converts a JSON-string of properties into a properties object\n * @param {str} properties\n * @returns {object}\n */\n extractPropertiesFromJson = (properties) => {\n Object.keys(properties).forEach((property) => {\n var jsonData = this.#valueFromJson(properties[property]);\n if (jsonData) {\n delete properties[property];\n properties = { ...properties, ...jsonData };\n }\n });\n return properties;\n };\n\n setMarkdownAndProperties({ markdown, properties }) {\n this.markdown = markdown;\n this.properties = properties;\n return this;\n }\n\n /**\n * @summary Use Markdown from settings, apply conditional rendering and\n * values from properties, and return a React component.\n *\n * @description There are three things going on here:\n * 1. The markdown is used as a template, anything between { and } gets replaced\n * with the real value from properties object, or is left empty.\n * 2. Next we apply conditional rendering, where conditions are between {{ and }} while\n * content is between {{condition}} and {{/condition}}.\n * Currently, if-condition is the only one supported, but more might become available.\n * Depending on the condition value, replacing can occur within our markdown string.\n * 3. The final markdown string is passed to the ReactMarkdown component.\n *\n * @param {str} markdown\n * @param {object} properties\n * @returns {object} ReactMarkdown component\n */\n mergeFeaturePropsWithMarkdown = async () => {\n if (this.markdown && typeof this.markdown === \"string\") {\n // this.markdown is a string that contains placeholders for our future values.\n // The placeholders are surrounded by curly brackets ({ & }).\n // The regex below will match all placeholders.\n // The loop below extracts all placeholders and replaces them with actual values\n // current feature's property collection.\n // Match any word character, range of unicode characters (åäö etc), @ sign, dash or dot\n (this.markdown.match(/{[\\s\\w\\u00C0-\\u00ff@\\-|,'.():]+}/g) || []).forEach(\n (placeholder) => {\n // placeholder is a string, e.g. \"{intern_url_1@@documenthandler}\" or \"{foobar}\"\n // Let's replace all occurrences of the placeholder like this:\n // {foobar} -> Some nice FoobarValue\n // {intern_url_1@@documenthandler} -> {n} // n is element index in the array that will hold Promises from external components\n this.markdown = this.markdown.replace(\n placeholder,\n this.#getPropertyValueForPlaceholder(placeholder)\n );\n }\n );\n\n // this.markdown will now contain actual values instead of properties, OR\n // references to elements in the this.resolvedPromises array. The latter will\n // be the only remaining occurrences of numbers surrounded by curly brackets.\n\n // Next step is to find all \"conditional tags\" (i.e. {{if foo=\"bar\"}}baz{{/if}})\n // and apply the replacer function on all matches.\n // The regex string below does the following:\n // Split each match into 3 named capture groups:\n // - \"condition\": the word between {{ and whitespace, \"if\" in this example\n // - \"attributes\": whatever follows the condition, until we see a }}, 'foo=\"bar\"'\n // - \"content\": anything after }} but before {{/ and whatever was the result in group one, \"baz\"\n // Note that the match will include one line ending. That's because _if_ we find a match\n // and will remove it, we must remove the line ending too, otherwise we would break the Markdown\n // formatting if only certain strings were to be removed, but all line endings would remain.\n this.markdown = this.markdown.replace(\n /{{(?\\w+)[\\s/]?(?[^}}]+)?}}(?[^{{]+)?(?:{{\\/\\1}}\\n?)/gi,\n this.#conditionalReplacer\n );\n\n // Special precautious must be taken to accommodate white space in Markdown links. We can\n // of course force our Hajk admins to write correctly formatted links (with URL encoded spaces),\n // but many times we can not control the URL if it comes from outside source. E.g. imagine this\n // infoclick setup:\n // [{anchorText}]({anchorLink})\n // Depending on values in the database, this can end up as something like this:\n // [This is a link](https://www.example.com/Some PDF file we link to.pdf)\n // This will not render correctly, only \"https://www.example.com/Some\" will become the\n // href part of the anchor. What we want instead is our MarkDown to contain:\n // [This is a link](https://www.example.com/Some%20PDF%20file%20we%20link%20to.pdf)\n // The following regex does just that.\n this.markdown = this.markdown.replace(\n /\\[(?[^[]+)\\]\\((?[^\")]+)(?\".*\")?\\)/gm,\n this.#markdownHrefEncoder\n );\n\n // Back in #getPropertyValueForPlaceholder we encode all equal signs (\"=\") as \"&equal;\",\n // to ensure we don't run into the issue described in #812 when we do the conditional check.\n // Now is a good time to revert that encoding back into an equal sign.\n this.markdown = this.markdown.replace(/&equal;/g, \"=\");\n\n // The final step is to await for all promises that might exist (if we fetch from\n // external components) to fulfill. We can't render before that!\n this.resolvedPromisesWithComponents = await Promise.all(\n this.pendingPromises\n );\n\n // If admin wants to allow HTML in Markdown, add rehypeRaw plugin.\n // Note that the gfm plugin is always added: it gives access to Table syntax.\n const rehypePlugins = this.allowDangerousHtml ? [rehypeRaw] : [];\n\n // Now, when promises are fulfilled, we can render. One of the render's helpers\n // will make use of the results in this.resolvedPromises, so that's why we had to wait.\n return (\n <ReactMarkdown\n remarkPlugins={[gfm]} // GitHub Formatted Markdown adds support for Tables in MD\n rehypePlugins={rehypePlugins} // Needed to parse HTML, activated in admin\n components={this.components} // Custom renderers for components, see definition in this.components\n children={this.markdown} // Our MD, as a text string\n />\n );\n }\n };\n}\n","import React from \"react\";\nimport FeaturePropsParsing from \"../../FeatureInfo/FeaturePropsParsing\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport {\n Table,\n TableBody,\n TableRow,\n TableCell,\n TableContainer,\n Typography,\n Grid,\n Button,\n Tooltip,\n} from \"@material-ui/core\";\nimport ArrowLeftIcon from \"@material-ui/icons/ArrowLeft\";\nimport ArrowRightIcon from \"@material-ui/icons/ArrowRight\";\n\nconst styles = (theme) => ({\n tableCell: {\n paddingLeft: 0,\n wordBreak: \"break-all\",\n width: \"50%\",\n },\n allFeatureDetailsContainer: {\n maxWidth: \"100%\",\n paddingLeft: theme.spacing(1),\n paddingRight: theme.spacing(1),\n },\n headerTypography: {\n maxWidth: \"100%\",\n fontSize: 18,\n },\n headerContainer: {\n paddingTop: theme.spacing(1),\n },\n togglerButton: {\n minWidth: 26,\n padding: 0,\n },\n});\n\nclass SearchResultsDatasetFeatureDetails extends React.PureComponent {\n state = {\n infoBox: null,\n };\n\n constructor(props) {\n super(props);\n\n this.featurePropsParsing = new FeaturePropsParsing({\n globalObserver: props.app.globalObserver,\n options:\n props.app.appModel.config.mapConfig.tools.find(\n (t) => t.type === \"infoclick\"\n )?.options || [], // featurePropsParsing needs to know if FeatureInfo is configured to allow HTML or not, so we pass on its' options\n });\n }\n\n componentDidMount = () => {\n this.getInfoBox();\n };\n\n componentDidUpdate = (prevProps) => {\n const { feature } = this.props;\n const prevFeature = prevProps.feature;\n if (feature !== prevFeature) {\n this.getInfoBox();\n }\n };\n\n getInfoBox = () => {\n if (this.shouldRenderCustomInfoBox()) {\n this.getHtmlItemInfoBox();\n } else {\n this.getDefaultInfoBox();\n }\n };\n\n shouldRenderCustomInfoBox = () => {\n const { feature } = this.props;\n const source = feature.source ?? this.props.source;\n return source.infobox && source.infobox !== \"\";\n };\n\n getHtmlItemInfoBox = () => {\n const { feature } = this.props;\n const source = feature.source ?? this.props.source;\n feature.setProperties(\n this.featurePropsParsing.extractPropertiesFromJson(\n feature.getProperties()\n )\n );\n this.featurePropsParsing\n .setMarkdownAndProperties({\n markdown: source.infobox,\n properties: feature.getProperties(),\n })\n .mergeFeaturePropsWithMarkdown()\n .then((MarkdownComponent) => {\n this.setState({ infoBox: MarkdownComponent });\n });\n };\n\n getDefaultInfoBox = () => {\n this.setState({ infoBox: this.renderDefaultInfoBox() });\n };\n\n renderTableCell = (content, position) => {\n const { classes } = this.props;\n const textToRender = Array.isArray(content) ? content.join(\", \") : content;\n return (\n <TableCell\n align={position}\n style={position === \"right\" ? { paddingRight: 0 } : null}\n className={classes.tableCell}\n >\n {textToRender}\n </TableCell>\n );\n };\n\n renderDefaultInfoBox = () => {\n const { feature } = this.props;\n return (\n <TableContainer>\n <Table size=\"small\">\n <TableBody>\n {Object.entries(feature.getProperties()).map((row) => {\n // feature.getProperties() can contain values of any data type\n // (whatever is set on the current feature). But since we can not\n // render e.g. Date or Point objects, we must do the following check\n // and only allow String, Number or Array:\n return typeof row[1] === \"string\" ||\n typeof row[1] === \"number\" ||\n Array.isArray(row[1]) ? (\n <TableRow key={row[0]}>\n {this.renderTableCell(row[0])}\n {this.renderTableCell(row[1], \"right\")}\n </TableRow>\n ) : null;\n })}\n </TableBody>\n </Table>\n </TableContainer>\n );\n };\n\n handleTogglerPressed = (nextFeatureIndex) => {\n const { setActiveFeature, features } = this.props;\n const nextFeature = features[nextFeatureIndex];\n setActiveFeature(nextFeature);\n };\n\n getFeatureIndex = (feature, features) => {\n return (\n features?.findIndex((f) => {\n return f.getId() === feature.getId();\n }) ?? -1\n );\n };\n\n renderFeatureToggler = () => {\n const { feature, classes, features } = this.props;\n const numFeaturesInCollection = features.length;\n const currentFeatureIndex = this.getFeatureIndex(feature, features);\n\n const buttonLeftDisabled = currentFeatureIndex - 1 < 0;\n const buttonRightDisabled =\n currentFeatureIndex + 1 >= numFeaturesInCollection;\n\n return (\n <Grid container item alignItems=\"center\" justify=\"space-between\">\n <Grid item>\n <Tooltip\n title={\n !buttonLeftDisabled\n ? \"Visa föregående objekt i resultatlistan\"\n : \"\"\n }\n >\n <span>\n <Button\n size=\"small\"\n variant=\"outlined\"\n className={classes.togglerButton}\n disabled={buttonLeftDisabled}\n onClick={() =>\n this.handleTogglerPressed(currentFeatureIndex - 1)\n }\n aria-label=\"show-previous-feature\"\n id=\"step-left\"\n >\n <ArrowLeftIcon\n fontSize=\"small\"\n color={buttonLeftDisabled ? \"disabled\" : \"action\"}\n />\n </Button>\n </span>\n </Tooltip>\n </Grid>\n <Grid item>\n <Tooltip\n title={\n !buttonRightDisabled ? \"Visa nästa objekt i resultatlistan\" : \"\"\n }\n >\n <span>\n <Button\n size=\"small\"\n variant=\"outlined\"\n className={classes.togglerButton}\n disabled={buttonRightDisabled}\n onClick={() =>\n this.handleTogglerPressed(currentFeatureIndex + 1)\n }\n aria-label=\"show-next-feature\"\n id=\"step-left\"\n >\n <ArrowRightIcon\n fontSize=\"small\"\n color={buttonRightDisabled ? \"disabled\" : \"action\"}\n />\n </Button>\n </span>\n </Tooltip>\n </Grid>\n </Grid>\n );\n };\n\n renderFeatureTitle = () => {\n const { feature, classes } = this.props;\n return (\n <Typography\n noWrap\n className={classes.headerTypography}\n component=\"div\"\n variant=\"button\"\n align=\"left\"\n >\n {feature.featureTitle}\n </Typography>\n );\n };\n\n render() {\n const { classes, features, enableFeatureToggler } = this.props;\n const { infoBox } = this.state;\n const shouldRenderToggler =\n (enableFeatureToggler ?? true) && features?.length > 1;\n return (\n <Grid container className={classes.allFeatureDetailsContainer}>\n <Grid container alignItems=\"center\" className={classes.headerContainer}>\n <Grid\n item\n xs={shouldRenderToggler ? 9 : 12}\n md={shouldRenderToggler ? 10 : 12}\n >\n {this.renderFeatureTitle()}\n </Grid>\n {shouldRenderToggler && (\n <Grid item xs={3} md={2}>\n {this.renderFeatureToggler()}\n </Grid>\n )}\n </Grid>\n {infoBox && (\n <Grid item xs={12}>\n {infoBox}\n </Grid>\n )}\n </Grid>\n );\n }\n}\nexport default withStyles(styles)(SearchResultsDatasetFeatureDetails);\n","import React, { useState } from \"react\";\nimport { MuiThemeProvider, createMuiTheme } from \"@material-ui/core/styles\";\nimport CssBaseline from \"@material-ui/core/CssBaseline\";\nimport App from \"./App\";\n\nimport { deepMerge } from \"../utils/DeepMerge\";\n\n/**\n * @summary Helper, used to determine if user's browser prefers dark mode.\n *\n * @param {*} preferredColorSchemeFromMapConfig\n * @returns {String} \"dark\" or \"light\"\n */\nfunction getColorScheme(preferredColorSchemeFromMapConfig, customTheme) {\n // First of all, see if admins have provided a customTheme.json, where\n // the light/dark mode value is set. If it is, this will override any\n // other logic, which means we're not interested in user's or OS's preference.\n if ([\"light\", \"dark\"].includes(customTheme?.palette?.type)) {\n return customTheme.palette.type;\n }\n\n // If there's no global override, we can go on and\n // check if there already is a user preferred value in local storage.\n const userPreferredColorScheme = window.localStorage.getItem(\n \"userPreferredColorScheme\"\n );\n\n let colorScheme = null; // Will hold the return value\n\n // If there's already a valid user preference in local storage…\n if ([\"light\", \"dark\"].includes(userPreferredColorScheme)) {\n colorScheme = userPreferredColorScheme; // …use it.\n } else {\n // Else, find out what admin has set in map config…\n switch (\n preferredColorSchemeFromMapConfig // If setting in admin is…\n ) {\n case \"dark\": // …dark, use it,\n colorScheme = \"dark\";\n break;\n case \"light\": // …light, use it.\n colorScheme = \"light\";\n break;\n default:\n // If there's no preference yet in neither local storage nor admin…\n colorScheme =\n window?.matchMedia(\"(prefers-color-scheme: dark)\").matches === true // …check if browser prefers dark mode…\n ? \"dark\" // …if so, use dark mode…\n : \"light\"; // … else go for light.\n break;\n }\n }\n\n return colorScheme;\n}\n\n/**\n * Helper function that creates a MUI theme by merging\n * hard-coded values (in this function), with custom values\n * (obtained from customTheme.json in /public).\n * This way, user can customize look and feel of application\n * AFTER it has been build with webpack, by simply tweaking\n * values in customTheme.json.\n *\n * @param {Object} config Map config that, among other objects, contains the default MUI theme\n * @param {Object} customTheme An object with the custom theme, obtained via fetch from customTheme.json\n * @returns {Object} A complete, ready to used theme object\n */\nfunction getTheme(config, customTheme) {\n const colorScheme = getColorScheme(\n config.mapConfig.map.colors?.preferredColorScheme,\n customTheme\n );\n // Setup some app-wide defaults that differ from MUI's defaults:\n const hardCodedDefaults = {\n palette: {\n type: colorScheme,\n action: {\n active: colorScheme === \"dark\" ? \"#fff\" : \"rgba(0, 0, 0, 0.87)\",\n },\n },\n shape: {\n borderRadius: 2,\n },\n };\n\n // Allow even more customization by reading values from each map config\n const themeFromMapConfig = {\n palette: {\n primary: {\n main: config.mapConfig.map.colors.primaryColor, // primary: blue // <- Can be done like this (don't forget to import blue from \"@material-ui/core/colors/blue\"!)\n },\n secondary: {\n main: config.mapConfig.map.colors.secondaryColor, // secondary: { main: \"#11cb5f\" } // <- Or like this\n },\n },\n };\n\n // Create the merged theme object by:\n const mergedTheme = deepMerge(\n hardCodedDefaults, // Using the hardcoded default…\n customTheme, // … overriding them with stuff from customTheme.json (app-wide customizations, common for each maps)…\n themeFromMapConfig // … and finally overriding them with map-specific customizations.\n );\n\n return mergedTheme;\n}\n\nconst HajkThemeProvider = ({ activeTools, config, customTheme }) => {\n // Keep the app's theme in state so it can be changed dynamically.\n const [theme, setTheme] = useState(getTheme(config, customTheme));\n\n // Handles theme toggling\n const toggleMUITheme = () => {\n // If there's a override in customTheme.json, toggling is not possible.\n if (customTheme?.palette?.type) return;\n\n // Toggle the current value from theme's palette\n let userPreferredColorScheme =\n theme.palette.type === \"light\" ? \"dark\" : \"light\";\n\n // Save for later in browser's local storage\n window.localStorage.setItem(\n \"userPreferredColorScheme\",\n userPreferredColorScheme\n );\n\n // Create a new theme object by taking the current theme\n // and merging with the latest theme type value\n const newTheme = deepMerge(theme, {\n palette: {\n type: userPreferredColorScheme,\n action: {\n active:\n userPreferredColorScheme === \"dark\"\n ? \"#fff\"\n : \"rgba(0, 0, 0, 0.87)\",\n },\n },\n });\n\n // Finally, save the new theme object in state. This will cause re-render,\n // and effectively take the new theme type value into action.\n setTheme(newTheme);\n };\n\n // Take the theme object from state and generate a MUI-theme\n const muiTheme = createMuiTheme(theme);\n\n // Render, pass through some stuff into App.\n return (\n <MuiThemeProvider theme={muiTheme}>\n <CssBaseline />\n <App\n activeTools={activeTools}\n config={config}\n theme={muiTheme}\n toggleMUITheme={toggleMUITheme} // Pass the toggle handler, so we can call it from another component later on\n />\n </MuiThemeProvider>\n );\n};\n\nexport default HajkThemeProvider;\n","import React from \"react\";\nimport propTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport PanelHeader from \"./PanelHeader\";\nimport { Rnd } from \"react-rnd\";\nimport { isMobile, getIsMobile } from \"../utils/IsMobile.js\";\nimport FeatureInfoContainer from \"./FeatureInfo/FeatureInfoContainer.js\";\nimport clsx from \"clsx\";\n\nconst zIndexStart = 1000;\n// Patch the RND component's onDragStart method with the ability to disable drag by its internal state.\n// This is necessary so we can disable/enable drag at any time.\n//\n// Please note that since we override the onDragStart on prototype level, we must ensure that it's\n// kept up-to-date with the current version, see https://github.com/bokuweb/react-rnd/blob/master/src/index.tsx\n// for latest version of this method.\n//\n// TODO: Perhaps there's no need to disable drag at any time anymore, so this override could be removed?\n//\nRnd.prototype.onDragStart = function (e, data) {\n if (this.state.disableDrag) {\n return false;\n }\n\n if (this.props.onDragStart) {\n this.props.onDragStart(e, data);\n }\n if (!this.props.bounds) return;\n const parent = this.getParent();\n const scale = this.props.scale;\n let boundary;\n if (this.props.bounds === \"parent\") {\n boundary = parent;\n } else if (this.props.bounds === \"body\") {\n const parentRect = parent.getBoundingClientRect();\n const parentLeft = parentRect.left;\n const parentTop = parentRect.top;\n const bodyRect = document.body.getBoundingClientRect();\n const left =\n -(parentLeft - parent.offsetLeft * scale - bodyRect.left) / scale;\n const top = -(parentTop - parent.offsetTop * scale - bodyRect.top) / scale;\n const right =\n (document.body.offsetWidth - this.resizable.size.width * scale) / scale +\n left;\n const bottom =\n (document.body.offsetHeight - this.resizable.size.height * scale) /\n scale +\n top;\n return this.setState({ bounds: { top, right, bottom, left } });\n } else if (this.props.bounds === \"window\") {\n if (!this.resizable) return;\n const parentRect = parent.getBoundingClientRect();\n const parentLeft = parentRect.left;\n const parentTop = parentRect.top;\n const left = -(parentLeft - parent.offsetLeft * scale) / scale;\n const top = -(parentTop - parent.offsetTop * scale) / scale;\n const right =\n (window.innerWidth - this.resizable.size.width * scale) / scale + left;\n const bottom =\n (window.innerHeight - this.resizable.size.height * scale) / scale + top;\n return this.setState({ bounds: { top, right, bottom, left } });\n } else {\n boundary = document.querySelector(this.props.bounds);\n }\n if (!(boundary instanceof HTMLElement) || !(parent instanceof HTMLElement)) {\n return;\n }\n const boundaryRect = boundary.getBoundingClientRect();\n const boundaryLeft = boundaryRect.left;\n const boundaryTop = boundaryRect.top;\n const parentRect = parent.getBoundingClientRect();\n const parentLeft = parentRect.left;\n const parentTop = parentRect.top;\n const left = (boundaryLeft - parentLeft) / scale;\n const top = boundaryTop - parentTop;\n if (!this.resizable) return;\n this.updateOffsetFromParent();\n const offset = this.offsetFromParent;\n this.setState({\n bounds: {\n top: top - offset.top,\n right:\n left +\n (boundary.offsetWidth - this.resizable.size.width) -\n offset.left / scale,\n bottom:\n top + (boundary.offsetHeight - this.resizable.size.height) - offset.top,\n left: left - offset.left / scale,\n },\n });\n};\n\nconst styles = (theme) => {\n return {\n window: {\n zIndex: zIndexStart + document.windows.length,\n position: \"absolute\",\n background: theme.palette.background.paper,\n boxShadow: theme.shadows[24],\n borderRadius: theme.shape.borderRadius,\n overflow: \"hidden\",\n pointerEvents: \"all\",\n [theme.breakpoints.down(\"xs\")]: {\n borderRadius: \"0\",\n position: \"fixed !important\",\n },\n },\n panelContent: {\n display: \"flex\",\n position: \"absolute\",\n top: 0,\n left: 0,\n bottom: 0,\n right: 0,\n flexDirection: \"column\",\n userSelect: \"none\",\n outline: \"none\",\n '& a:not([class*=\"Mui\"])': {\n color: theme.palette.primary.light,\n },\n },\n panelContentDisplayContents: {\n display: \"contents\",\n },\n content: {\n flex: \"1\",\n overflowY: \"auto\",\n padding: \"10px\",\n cursor: \"default !important\",\n },\n nonScrollable: {\n overflowY: \"hidden\",\n padding: \"0px\",\n },\n };\n};\n\nclass Window extends React.PureComponent {\n static propTypes = {\n children: propTypes.object,\n classes: propTypes.object.isRequired,\n color: propTypes.string,\n features: propTypes.array,\n globalObserver: propTypes.object.isRequired,\n height: propTypes.oneOfType([propTypes.number, propTypes.string])\n .isRequired,\n layerswitcherConfig: propTypes.object,\n map: propTypes.object,\n mode: propTypes.string.isRequired,\n onClose: propTypes.func.isRequired,\n onDisplay: propTypes.func,\n onResize: propTypes.func,\n open: propTypes.bool.isRequired,\n position: propTypes.string.isRequired,\n title: propTypes.string.isRequired,\n width: propTypes.number.isRequired,\n };\n\n static defaultProps = {\n draggingEnabled: true,\n resizingEnabled: true,\n allowMaximizedWindow: false,\n scrollable: true,\n };\n\n constructor(props) {\n super(props);\n document.windows.push(this);\n this.windowRef = React.createRef();\n this.state = {\n left: 0,\n top: 0,\n width: 300,\n height: this.props.height === \"dynamic\" ? \"auto\" : 400,\n };\n\n window.addEventListener(\"resize\", () => {\n if (this.state.mode === \"maximized\") {\n this.fit(document.getElementById(\"windows-container\"));\n } else {\n this.updatePosition();\n }\n });\n }\n\n componentDidUpdate = (prevProps, prevState) => {\n if (prevProps.open === false && this.props.open === true) {\n //This is ugly but there is a timing problem further down somewhere (i suppose?).\n //componentDidUpdate is run before the render is actually fully completed and the DOM is ready\n setTimeout(() => {\n this.windowRef.current.focus();\n }, 200);\n }\n };\n\n componentDidMount() {\n const { globalObserver } = this.props;\n if (globalObserver) {\n globalObserver.subscribe(\"core.appLoaded\", () => {\n this.updatePosition();\n });\n globalObserver.subscribe(\"core.drawerToggled\", () => {\n this.updatePosition();\n });\n globalObserver.subscribe(\"core.dialogOpen\", (open) => {\n this.rnd.setState({\n disableDrag: open,\n });\n });\n }\n }\n\n /**\n * In LayerSwitcher plugin's settings, there's an option that allows\n * user to show or hide the so called \"breadcrumbs\": small boxes, one\n * for each active layer, that show up at the bottom of the screen.\n *\n * If breadcrumbs are activated, we should ensure that our Windows\n * don't hide breadcrumbs, by reducing Windows' default height slightly.\n *\n * This helper is used to determine whether breadcrumbs are activated\n * or not.\n *\n * @returns boolean\n * @memberof Window\n */\n areBreadcrumbsActivated() {\n return this.props.layerswitcherConfig &&\n this.props.layerswitcherConfig.hasOwnProperty(\"options\")\n ? this.props.layerswitcherConfig.options.showBreadcrumbs\n : false;\n }\n\n getMaxWindowHeight() {\n if (this.rnd === undefined) return 400;\n const parent = this.rnd.getSelfElement().parentElement;\n const spaceForBreadcrumbs = this.areBreadcrumbsActivated() ? 42 : 0;\n const h =\n parent.clientHeight - // Maximum height of parent element\n 16 - // Reduce height with top margin\n 16 - // Reduce height with bottom margin\n 62 - // Reduce with space for Search bar\n spaceForBreadcrumbs; // If Breadcrumbs are active, make space for them as well\n return h;\n }\n\n updatePosition() {\n const { width, height, position } = this.props;\n const parent = this.rnd.getSelfElement().parentElement;\n\n //FIXME: JW - Not the best solution for parent resize to set top/left to 0/0, but it ensures we don't get a window outside of the parent\n this.left = 16; // Make sure we respect padding\n this.top = 16 + 62; // Respect top padding + don't overlap Drawer Toggle buttons\n this.width = width || 400;\n this.height = height || 300;\n\n // If \"auto\" height is set, it means we want the Window to take up maximum space available\n if (this.props.height !== \"dynamic\" && this.height === \"auto\") {\n this.height = this.getMaxWindowHeight();\n }\n\n // If Window renders on the right, there are some things that we need to compensate for\n if (position === \"right\") {\n this.left = parent.getBoundingClientRect().width - width - 16 - 56; // -16 to take care of usual right padding, -56 to not cover the Control buttons that are on the right\n }\n\n // Mobile screens are another special case: here our Window should take up max space available\n if (getIsMobile()) {\n this.left = 0;\n this.top = 0;\n this.height = window.innerHeight;\n this.width = document.body.clientWidth;\n }\n\n this.left = this.left !== undefined ? this.left : 16;\n\n this.setState(\n {\n left: this.left,\n top: this.top,\n width: this.width,\n height: this.height,\n mode: \"window\",\n },\n () => {\n this.rnd.updatePosition({\n y: Math.round(this.top),\n x: Math.round(this.left),\n });\n }\n );\n }\n\n close = (e) => {\n const { onClose, globalObserver, title } = this.props;\n this.latestWidth = this.rnd.getSelfElement().clientWidth;\n if (onClose) onClose();\n\n globalObserver.publish(\"core.closeWindow\", title);\n };\n\n fit = (target) => {\n this.rnd.updatePosition({\n x: Math.round(target.getBoundingClientRect().left),\n y: Math.round(target.getBoundingClientRect().top),\n });\n this.rnd.setState({\n disableDrag: true,\n });\n this.setState({\n width: target.clientWidth,\n height: target.clientHeight,\n mode: \"maximized\",\n });\n };\n\n reset = () => {\n this.rnd.updatePosition({\n y: Math.round(this.top),\n x: Math.round(this.left),\n });\n this.rnd.setState({\n disableDrag: false,\n });\n this.setState({\n width: this.width,\n height: this.height,\n mode: \"window\",\n });\n };\n\n enlarge = () => {\n let t = parseFloat(this.top);\n let h = parseFloat(this.height);\n let c = this.rnd.getSelfElement().parentElement.getBoundingClientRect();\n let o = t + h;\n\n if (o > c.bottom) {\n this.top = this.top - o + c.bottom;\n }\n\n this.rnd.updatePosition({\n y: Math.round(this.top),\n });\n this.rnd.setState({\n disableDrag: false,\n });\n this.setState({\n height: this.height,\n mode: \"window\",\n });\n };\n\n maximize = () => {\n const {\n globalObserver,\n onMaximize,\n onResize,\n allowMaximizedWindow,\n title,\n } = this.props;\n\n getIsMobile() && this.rnd.updatePosition({ y: 0 });\n\n switch (this.state.mode) {\n case \"minimized\":\n // Enlarge back to \"window\" mode\n if (this.height === \"dynamic\") {\n this.height = \"auto\";\n }\n this.enlarge();\n break;\n case \"window\":\n // If already in \"window\" mode, fill the viewport\n allowMaximizedWindow &&\n this.fit(document.getElementById(\"windows-container\"));\n break;\n case \"maximized\":\n // If already \"maximized\" mode, switch back to \"window\"\n this.reset(document.getElementById(\"windows-container\"));\n break;\n default:\n break;\n }\n\n // Run callbacks\n typeof onMaximize === \"function\" && onMaximize();\n typeof onResize === \"function\" && onResize();\n\n globalObserver.publish(\"core.maximizeWindow\", title);\n };\n\n minimize = () => {\n const { globalObserver, onMinimize, onResize, title } = this.props;\n\n getIsMobile() &&\n this.rnd.updatePosition({\n y: Math.round(window.innerHeight - 42),\n });\n\n // Don't matter the current mode – just collapse\n this.height = this.state.height;\n this.setState({\n height: 0,\n mode: \"minimized\",\n });\n\n // Run callbacks\n typeof onMinimize === \"function\" && onMinimize();\n typeof onResize === \"function\" && onResize();\n\n globalObserver.publish(\"core.minimizeWindow\", title);\n };\n\n bringToFront() {\n document.windows\n .sort((a, b) => (a === this ? 1 : b === this ? -1 : 0))\n .forEach((w, i) => {\n if (w.rnd) {\n w.rnd.getSelfElement().style.zIndex = zIndexStart + i;\n }\n });\n }\n\n render() {\n const {\n children,\n classes,\n color,\n features,\n open,\n title,\n resizingEnabled,\n draggingEnabled,\n allowMaximizedWindow,\n customPanelHeaderButtons,\n } = this.props;\n const { left, top, width, height } = this.state;\n\n let resizeBottom = true,\n resizeBottomLeft = true,\n resizeBottomRight = true,\n resizeLeft = true,\n resizeRight = true,\n resizeTop = true,\n resizeTopLeft = true,\n resizeTopRight = true;\n\n if (isMobile) {\n resizeBottom =\n resizeBottomLeft =\n resizeBottomRight =\n resizeRight =\n resizeTopLeft =\n resizeTopRight =\n resizeLeft =\n false;\n } else {\n if (this.state.mode === \"maximized\") {\n resizeBottom =\n resizeBottomLeft =\n resizeBottomRight =\n resizeRight =\n resizeTop =\n resizeTopLeft =\n resizeTopRight =\n resizeLeft =\n false;\n }\n if (this.state.mode === \"minimized\") {\n resizeBottom =\n resizeBottomLeft =\n resizeBottomRight =\n resizeTop =\n resizeTopLeft =\n resizeTopRight =\n resizeLeft =\n false;\n }\n\n if (!resizingEnabled) {\n resizeBottom =\n resizeBottomLeft =\n resizeBottomRight =\n resizeRight =\n resizeTop =\n resizeTopLeft =\n resizeTopRight =\n resizeLeft =\n false;\n }\n }\n\n this.bringToFront();\n return (\n <Rnd\n onMouseDown={(e) => {\n this.bringToFront();\n }}\n onMouseOver={(e) => e.stopPropagation()} // If this bubbles, we'll have Tooltip show up even when we're only on Window. FIXME: Not needed when we change the rendering order.\n ref={(c) => {\n this.rnd = c;\n }}\n style={{\n display: open ? \"block\" : \"none\",\n }}\n onDragStop={(e, d) => {\n const rect = this.rnd.getSelfElement().getClientRects()[0];\n if (rect) {\n this.left = rect.left;\n this.top = rect.top;\n this.right =\n window.innerWidth - (this.left + parseFloat(this.width));\n }\n }}\n onResizeStop={(e, direction, ref, delta, position) => {\n this.width = ref.style.width;\n if (this.state.mode !== \"minimized\") {\n this.height = ref.style.height;\n }\n this.setState({\n width: ref.style.width,\n height: ref.style.height,\n });\n if (this.props.onResize) this.props.onResize();\n }}\n cancel=\"section,nav\"\n bounds={\"#windows-container\"}\n disableDragging={!draggingEnabled || false || getIsMobile()}\n enableResizing={{\n bottom: resizeBottom,\n bottomLeft: resizeBottomLeft,\n bottomRight: resizeBottomRight,\n left: resizeLeft,\n right: resizeRight,\n top: resizeTop,\n topLeft: resizeTopLeft,\n topRight: resizeTopRight,\n }}\n className={classes.window}\n minWidth={200}\n minHeight={this.state.mode === \"minimized\" ? 42 : 100}\n size={{\n width: width,\n height: height,\n }}\n default={{\n x: left,\n y: top,\n width: width,\n height: height,\n }}\n >\n <div\n tabIndex=\"0\"\n ref={this.windowRef}\n className={clsx(\n classes.panelContent,\n this.props.height === \"dynamic\"\n ? classes.panelContentDisplayContents\n : null\n )}\n >\n <PanelHeader\n allowMaximizedWindow={allowMaximizedWindow}\n color={color}\n customHeaderButtons={customPanelHeaderButtons}\n globalObserver={this.props.globalObserver}\n localObserver={this.props.localObserver}\n onClose={this.close}\n onMaximize={this.maximize}\n onMinimize={this.minimize}\n mode={this.state.mode}\n title={title}\n />\n <section\n className={clsx(\n classes.content,\n this.props.scrollable ? null : classes.nonScrollable\n )}\n style={{\n // Ensure to set maxHeight to ensure that we can scroll inside the container\n maxHeight:\n this.getMaxWindowHeight() - (isMobile === false ? 50 : -30), // Super-hack special case for small screens\n }}\n >\n {features && features.length > 0 ? (\n <FeatureInfoContainer\n features={this.props.features}\n options={this.props.options}\n onDisplay={this.props.onDisplay}\n globalObserver={this.props.globalObserver}\n key={\n Array.isArray(this.props.features) &&\n this.props.features.length > 0\n ? this.props.features[0].getId()\n : 0\n }\n />\n ) : (\n children\n )}\n </section>\n </div>\n </Rnd>\n );\n }\n}\n\nexport default withStyles(styles)(Window);\n","export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n","export const isValidLayerId = (id) => {\n return (\n !Number.isNaN(Number(id)) || // … and the name is either a Number…\n /^[a-f0-9]{32}$/i.test(id) || // … or an MD5 string (which was used in the NodeJS backend)\n /^[a-z0-9]{6}$/i.test(id) // … or a 6 characters long alphanumeric string (which is the new default for layers created in NodeJS backend)\n );\n};\n","class PropFilters {\n constructor() {\n this.filters = {};\n return this;\n }\n\n applyFilters(properties, input) {\n let args = input.split(\"|\");\n const key = args.shift().trim();\n\n let value = null;\n\n if (key.indexOf(\"'\") === 0) {\n // handle raw data, not from props. Can be good to have, especially when testing.\n // example: {'2021-06-03T13:04:12Z'|date}\n value = key.substring(1, key.length - 1);\n } else {\n value = properties[key];\n if (!value) {\n value = \"\";\n }\n }\n\n args.forEach((inFilter) => {\n // This is where we handle chained filters.\n const argsStart = inFilter.indexOf(\"(\");\n let filterName = inFilter;\n let args = [];\n\n if (argsStart > -1) {\n filterName = inFilter.substr(0, argsStart);\n args = inFilter\n .substring(argsStart + 1, inFilter.indexOf(\")\"))\n .split(\",\");\n args.forEach((v, i, a) => {\n a[i] = this.cleanString(v.trim());\n });\n }\n\n value = this.execFilter(filterName, value, args);\n });\n\n return value;\n }\n\n execFilter(filterName, value, args) {\n const filter = this.get(filterName);\n\n if (filter) {\n try {\n return filter.func.apply(this, [value, ...args]);\n } catch (err) {\n console.warn(\n `FeaturePropFilters: Could not apply filter '${filterName}' on value ${value} with args ${args},`,\n err\n );\n }\n }\n\n return value;\n }\n\n cleanString(s) {\n // Free the strings contained inside ''\n if (s.indexOf(\"'\") === 0) {\n s = s.substring(1, s.length - 1);\n }\n return s;\n }\n\n get(key) {\n if (this.filters[key]) {\n return this.filters[key];\n } else {\n console.warn(\n `FeaturePropFilters: Could not find filter with name '${key}'`\n );\n }\n return null;\n }\n\n add(key, f) {\n this.filters[key] = {\n func: f,\n };\n }\n\n addAlias(key, targetKey) {\n this.add(key, this.get(targetKey).func);\n }\n}\n\nconst filters = new PropFilters();\n\n// ---- Add filters below -----------------------------------------------------\n\n/*\n roundToDecimals\n Example:\n {'45.32465456'|roundToDecimals(2)}\n outputs: 45,32\n*/\nfilters.add(\"roundToDecimals\", function (value, numDecimals) {\n if (isNaN(value) || isNaN(numDecimals)) {\n throw new Error(\"Arguments should be numbers\");\n }\n return parseFloat(value.toFixed(parseInt(numDecimals))).toLocaleString();\n});\n\n/*\n replace\n Example:\n {'This is working BAD!!'|replace('BAD','GOOD')}\n outputs: This is working GOOD!!\n*/\nfilters.add(\"replace\", function (value, replace, withString) {\n return value.replace(new RegExp(replace, \"gm\"), withString);\n});\n\n/*\n default/fallback\n Example:\n {''|default('No value found')}\n outputs: No value\n*/\nfilters.add(\"default\", function (value, defaultValue) {\n return value === \"\" ? defaultValue : value;\n});\nfilters.addAlias(\"fallback\", \"default\");\n\n/*\n equals\n Example:\n {'true'|equals('true', 'yes', 'no')}\n outputs: yes\n*/\nfilters.add(\"equals\", function (value, test, trueValue, falseValue) {\n return value === test ? trueValue : falseValue || value;\n});\n\n/*\n notEquals\n Example:\n {'false'|notEquals('true', 'This value is not true', 'This value is true')}\n outputs: This value is not false\n*/\nfilters.add(\"notEquals\", function (value, test, falseValue, trueValue) {\n return value !== test ? falseValue : trueValue || value;\n});\n\n/*\n datetime\n Example:\n {'2021-06-03T13:04:12Z'|datetime}\n outputs: 2021-06-03 13:04:12\n*/\nfilters.add(\"datetime\", function (value) {\n const date = typeof value === \"string\" ? new Date(value) : value;\n return date.toLocaleString();\n});\n\n/*\n date\n Example:\n {'2021-06-03T13:04:12Z'|date}\n outputs: 2021-06-03\n*/\nfilters.add(\"date\", function (value) {\n const date = typeof value === \"string\" ? new Date(value) : value;\n return date.toLocaleDateString();\n});\n\n/*\n time\n Example:\n {'2021-06-03T13:04:12Z'|time}\n outputs: 13:04:12\n*/\nfilters.add(\"time\", function (value) {\n const date = typeof value === \"string\" ? new Date(value) : value;\n return date.toLocaleTimeString();\n});\n\n/*\n dateAddDays\n Example:\n {'2021-06-03T13:04:12Z'|dateAddDays(1)|datetime}\n outputs: 2021-06-04 13:04\n Note: negative value will substract days\n*/\nfilters.add(\"dateAddDays\", function (value, days) {\n const date = typeof value === \"string\" ? new Date(value) : value;\n date.setDate(date.getDate() + parseFloat(days));\n return date;\n});\n\n/*\n dateAddHours\n Example:\n {'2021-06-03T13:04:12Z'|dateAddHours(1)|datetime}\n outputs: 2021-06-03 14:04\n Note: negative value will substract hours\n*/\nfilters.add(\"dateAddHours\", function (value, hours) {\n const date = typeof value === \"string\" ? new Date(value) : value;\n date.setTime(date.getTime() + parseFloat(hours) * 60 * 60 * 1000);\n return date;\n});\n\n/*\n formatNumber\n Example:\n {'98000'|formatNumber}\n outputs: 98 000\n*/\nfilters.add(\"formatNumber\", function (value) {\n if (isNaN(value)) {\n throw new Error(\"Argument should be a number\");\n }\n return Number(value).toLocaleString();\n});\n\n/*\n toUpper\n Example:\n {'testing'|toUpper}\n outputs: TESTING\n*/\nfilters.add(\"toUpper\", function (value) {\n return value.toUpperCase();\n});\n\n/*\n toLower\n Example:\n {'TESTING'|toLower}\n outputs: testing\n*/\nfilters.add(\"toLower\", function (value) {\n return value.toLowerCase();\n});\n\n/*\n capitalize\n Example:\n {'testing'|capitalize}\n outputs: Testing\n*/\nfilters.add(\"capitalize\", function (value) {\n return value.charAt(0).toUpperCase() + value.slice(1);\n});\n\n/*\n substr\n Example:\n {'abcdef'|substr(2,4)}\n outputs: cdef\n*/\nfilters.add(\"substr\", function (value, i1, i2) {\n return value.substr(i1, i2);\n});\n\n/*\n substring\n Example:\n {'abcdef'|substring(2,4)}\n outputs: cd\n*/\nfilters.add(\"substring\", function (value, i1, i2) {\n return value.substring(i1, i2);\n});\n\n/*\n left\n Example:\n {'probably_useful'|left('_')}\n outputs: probably\n*/\nfilters.add(\"left\", function (value, searchFor) {\n return value.split(searchFor)[0];\n});\n\n/*\n left\n Example:\n {'probably_useful'|right('_')}\n outputs: useful\n*/\nfilters.add(\"right\", function (value, searchFor) {\n const i = value.indexOf(searchFor);\n return i > -1 ? value.substring(i + searchFor.length, value.length) : value;\n});\n\n/*\n trim\n Example:\n {' padded string '|trim}\n outputs: 'padded string'\n*/\nfilters.add(\"trim\", function (value) {\n return value.trim();\n});\n\nexport default filters;\n","import React from \"react\";\nimport propTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport Button from \"@material-ui/core/Button\";\nimport Dialog from \"@material-ui/core/Dialog\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\n\nconst styles = (theme) => {\n return {};\n};\n\nclass AlertView extends React.PureComponent {\n state = {};\n\n static propTypes = {\n classes: propTypes.object.isRequired,\n message: propTypes.any.isRequired,\n open: propTypes.bool.isRequired,\n parent: propTypes.object.isRequired,\n title: propTypes.string.isRequired,\n };\n\n static defaultProps = {\n message: \"Meddelande saknas\",\n title: \"Titel saknas\",\n };\n\n handleClose = (e) => {\n this.props.parent.setState({\n alert: false,\n });\n };\n\n render() {\n const { open, dialogTitle, message } = this.props;\n return (\n <Dialog\n open={open}\n onClose={this.handleClose}\n aria-labelledby=\"alert-dialog-title\"\n aria-describedby=\"alert-dialog-description\"\n >\n <DialogTitle id=\"alert-dialog-title\">\n {dialogTitle || \"Meddelande\"}\n </DialogTitle>\n <DialogContent>{message}</DialogContent>\n <DialogActions>\n <Button onClick={this.handleClose} color=\"primary\" autoFocus>\n Ok\n </Button>\n </DialogActions>\n </Dialog>\n );\n }\n}\n\nexport default withStyles(styles)(AlertView);\n","import WKT from \"ol/format/WKT.js\";\nimport { Icon, Stroke, Fill } from \"ol/style.js\";\nimport {\n Point,\n MultiPoint,\n Polygon,\n MultiPolygon,\n LineString,\n MultiLineString,\n} from \"ol/geom.js\";\n\nfunction componentToHex(c) {\n var hex = c.toString(16);\n return hex.length === 1 ? \"0\" + hex : hex;\n}\n\nfunction rgbToHex(r, g, b) {\n return componentToHex(r) + componentToHex(g) + componentToHex(b);\n}\n\nfunction colorToArray(color, type) {\n var res = [],\n reg = type === \"rgb\" ? /rgb\\((.+)\\)/ : /rgba\\((.+)\\)/;\n\n if (Array.isArray(color)) {\n res = color;\n } else {\n res = reg\n .exec(color)[1]\n .split(\",\")\n .map((a) => parseFloat(a));\n if (type === \"rgb\") {\n res.push(1);\n }\n }\n\n return res;\n}\n\nfunction toKmlColor(color) {\n var s, r, g, b, o;\n if (color) {\n let res;\n if (Array.isArray(color)) {\n res = color;\n } else {\n if (/^rgba/.test(color)) {\n res = colorToArray(color, \"rgba\");\n } else if (/^rgb/.test(color)) {\n res = colorToArray(color, \"rgb\");\n }\n }\n if (Array.isArray(res)) {\n s = rgbToHex(res[0], res[1], res[2]);\n } else {\n s = color = color.replace(\"#\", \"\");\n }\n r = s.substr(0, 2);\n g = s.substr(2, 2);\n b = s.substr(4, 2);\n o = \"ff\";\n if (res && res[3]) {\n o = Math.floor(res[3] * 255).toString(16);\n }\n return o + b + g + r;\n }\n}\n\nfunction toKmlString(str, type) {\n var strs = [],\n a,\n b;\n\n switch (type) {\n case \"point\":\n str = str.replace(/^POINT\\(/, \"\").replace(/\\)$/, \"\");\n str = str.replace(/^POINT Z\\(/, \"\").replace(/\\)$/, \"\");\n str = str.replace(/^MULTIPOINT\\(/, \"\").replace(/\\)$/, \"\");\n str = str.replace(/^MULTIPOINT Z\\(/, \"\").replace(/\\)$/, \"\");\n break;\n case \"line\":\n str = str.replace(/^LINESTRING\\(/, \"\").replace(/\\)$/, \"\");\n str = str.replace(/^LINESTRING Z\\(/, \"\").replace(/\\)$/, \"\");\n break;\n case \"polygon\":\n strs = str.split(\"),(\");\n str = \"\";\n strs.forEach((coords, i) => {\n if (i === 0) {\n coords = coords.replace(/^POLYGON\\(\\(/, \"\").replace(/\\)$/, \"\");\n coords = coords.replace(/^POLYGON Z\\(\\(/, \"\").replace(/\\)$/, \"\");\n str += \"<outerBoundaryIs>\";\n str += \"<LinearRing>\";\n str += \"<coordinates>\" + coords + \"</coordinates>\";\n str += \"</LinearRing>\";\n str += \"</outerBoundaryIs>\";\n } else {\n coords = coords.replace(/\\)/g, \"\");\n str += \"<innerBoundaryIs>\";\n str += \"<LinearRing>\";\n str += \"<coordinates>\" + coords + \"</coordinates>\";\n str += \"</LinearRing>\";\n str += \"</innerBoundaryIs>\";\n }\n });\n break;\n case \"multiPolygon\":\n a = str.split(\")),((\");\n str = \"\";\n a.forEach((coords, t) => {\n if (t === 0) {\n coords = coords.replace(/^MULTIPOLYGON\\(\\(/, \"\").replace(/\\)$/, \"\");\n coords = coords\n .replace(/^MULTIPOLYGON Z\\(\\(\\(/, \"\")\n .replace(/\\)$/, \"\");\n }\n\n b = coords.split(\"),(\");\n\n str += \"<Polygon>\";\n b.forEach((coordinates, i) => {\n coordinates = coordinates\n .replace(/\\)/g, \"\")\n .split(\",\")\n .map((coordString) => {\n var coords = coordString.split(\" \");\n return coords[0] + \" \" + coords[1];\n });\n\n if (i === 0) {\n str += \"<outerBoundaryIs>\";\n str += \"<LinearRing>\";\n str += \"<coordinates>\" + coordinates + \"</coordinates>\";\n str += \"</LinearRing>\";\n str += \"</outerBoundaryIs>\";\n } else {\n str += \"<innerBoundaryIs>\";\n str += \"<LinearRing>\";\n str += \"<coordinates>\" + coordinates + \"</coordinates>\";\n str += \"</LinearRing>\";\n str += \"</innerBoundaryIs>\";\n }\n });\n str += \"</Polygon>\";\n });\n break;\n case \"multiLine\":\n str = str.replace(/^MULTILINESTRING\\(/, \"\").replace(/\\)$/, \"\");\n str = str.replace(/^MULTILINESTRING Z\\(/, \"\").replace(/\\)$/, \"\");\n let lines = str.split(\"),\");\n lines = lines.map((line) => {\n return line.replace(/[()]/g, \"\");\n });\n lines.forEach((line) => {\n str += `<LineString><coordinates>${line}</coordinates></LineString>`;\n });\n break;\n default:\n break;\n }\n\n return str\n .replace(/ /g, \"_\")\n .replace(/,/g, \" \")\n .replace(/_/g, \",\")\n .replace(/\\(/g, \"\")\n .replace(/\\)/g, \"\");\n}\n\nfunction point(f) {\n var str = \"\";\n str += \"<Point>\";\n str += \"<coordinates>\" + toKmlString(f, \"point\") + \"</coordinates>\";\n str += \"</Point>\";\n return str;\n}\n\nfunction line(f) {\n var str = \"\";\n str += \"<LineString>\";\n str += \"<coordinates>\" + toKmlString(f, \"line\") + \"</coordinates>\";\n str += \"</LineString>\";\n return str;\n}\n\nfunction polygon(f) {\n var str = \"\";\n str += \"<Polygon>\";\n str += toKmlString(f, \"polygon\");\n str += \"</Polygon>\";\n return str;\n}\n\nfunction multiPolygon(f) {\n var str = \"\";\n str += \"<MultiGeometry>\";\n str += toKmlString(f, \"multiPolygon\");\n str += \"</MultiGeometry>\";\n return str;\n}\n\nfunction multiLine(f) {\n var str = \"\";\n str += \"<MultiGeometry>\";\n str += toKmlString(f, \"multiLine\");\n str += \"</MultiGeometry>\";\n return str;\n}\n\nfunction safeInject(string) {\n string = string.toString();\n return string.replace(/<\\/?[^>]+(>|$)|&/g, \"\");\n}\n\nfunction filterProperties(template, properties) {\n var props = {};\n Object.keys(properties).forEach((property) => {\n var regExp = new RegExp(`{export:${property}}`);\n if (regExp.test(template)) {\n props[property] = properties[property];\n }\n });\n return props;\n}\n\nexport function transform(features, from, to) {\n return features.map((feature) => {\n var c = feature.clone(),\n style = Array.isArray(feature.getStyle())\n ? feature.getStyle()[1]\n : feature.getStyle();\n c.getGeometry().transform(from, to);\n c.setStyle(style);\n c.caption = feature.caption;\n c.infobox = feature.infobox;\n return c;\n });\n}\n\nexport function createXML(features, name) {\n var header = \"\",\n parser = new WKT(),\n doc = \"\";\n\n header +=\n '<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">';\n doc += \"<Document>\";\n doc += \"<name>\" + name + \"</name>\";\n\n doc += \"<Folder>\";\n doc += \"<name>\" + name + \"</name>\";\n doc += \"<open>0</open>\";\n\n features.forEach((feature, i) => {\n var style = Array.isArray(feature.getStyle())\n ? feature.getStyle()[1] || feature.getStyle()[0]\n : feature.getStyle();\n\n doc += '<Style id=\"' + i + '\">';\n if (style.getImage() instanceof Icon) {\n const scale =\n style?.getImage()?.getScale() ?? style.getImage().getSize()[0] / 32;\n doc += \"<IconStyle>\";\n doc += \"<scale>\" + scale + \"</scale>\";\n doc += \"<Icon>\";\n doc += \"<href>\" + style.getImage().getSrc() + \"</href>\";\n doc += \"</Icon>\";\n doc += \"</IconStyle>\";\n }\n\n if (style.getStroke() instanceof Stroke) {\n doc += \"<LineStyle>\";\n doc += \"<color>\" + toKmlColor(style.getStroke().getColor()) + \"</color>\";\n doc += \"<width>\" + style.getStroke().getWidth() + \"</width>\";\n doc += \"</LineStyle>\";\n }\n\n if (style.getFill() instanceof Fill) {\n doc += \"<PolyStyle>\";\n doc += \"<color>\" + toKmlColor(style.getFill().getColor()) + \"</color>\";\n doc += \"</PolyStyle>\";\n }\n\n doc += \"</Style>\";\n });\n\n features.forEach((feature, i) => {\n var style = Array.isArray(feature.getStyle())\n ? feature.getStyle()[1] || feature.getStyle()[0]\n : feature.getStyle();\n\n var text = style.getText() ? style.getText().getText() : \"\";\n\n var description = feature.getProperties().description || \"\",\n name =\n feature.getProperties().namn ||\n feature.getProperties().name ||\n feature.caption ||\n text;\n\n if (!description && feature.getProperties()) {\n description = \"<table>\";\n let properties = feature.getProperties();\n\n if (feature.infobox) {\n properties = filterProperties(feature.infobox, properties);\n }\n\n Object.keys(properties).forEach((property) => {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n description += \"<tr>\";\n description += \"<td>\" + property + \"</td>\";\n description += \"<td>\" + safeInject(properties[property]) + \"</td>\";\n description += \"</tr>\";\n }\n });\n\n description += \"</table>\";\n }\n\n doc += \"<Placemark>\";\n doc += \"<name>\" + (name || \"Ritobjekt \" + (i + 1)) + \"</name>\";\n doc +=\n \"<description>\" +\n (description || \"Ritobjekt \" + (i + 1)) +\n \"</description>\";\n doc += \"<styleUrl>#\" + i + \"</styleUrl>\";\n\n if (feature.getGeometry() instanceof Point) {\n doc += point(parser.writeFeature(feature));\n }\n if (feature.getGeometry() instanceof MultiPoint) {\n doc += point(parser.writeFeature(feature));\n }\n if (feature.getGeometry() instanceof LineString) {\n doc += line(parser.writeFeature(feature));\n }\n if (feature.getGeometry() instanceof MultiLineString) {\n doc += multiLine(parser.writeFeature(feature));\n }\n if (feature.getGeometry() instanceof Polygon) {\n doc += polygon(parser.writeFeature(feature));\n }\n if (feature.getGeometry() instanceof MultiPolygon) {\n doc += multiPolygon(parser.writeFeature(feature));\n }\n\n if (feature.getProperties().style) {\n doc += \"<ExtendedData>\";\n doc += '<Data name=\"style\">';\n doc += \"<value>\" + feature.getProperties().style + \"</value>\";\n doc += \"</Data>\";\n if (feature.getProperties().geometryType) {\n doc += '<Data name=\"geometryType\">';\n doc += \"<value>\" + feature.getProperties().geometryType + \"</value>\";\n doc += \"</Data>\";\n }\n doc += \"</ExtendedData>\";\n }\n doc += \"</Placemark>\";\n });\n\n doc += \"</Folder>\";\n doc += \"</Document>\";\n header += doc;\n header += \"</kml>\";\n\n return header;\n}\n","import React, { Component } from \"react\";\nimport propTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport CloseIcon from \"@material-ui/icons/Close\";\nimport FullscreenIcon from \"@material-ui/icons/Fullscreen\";\nimport FullscreenExitIcon from \"@material-ui/icons/FullscreenExit\";\nimport AspectRatioIcon from \"@material-ui/icons/AspectRatio\";\nimport { Hidden, Typography, IconButton, Box } from \"@material-ui/core\";\n\nconst styles = (theme) => {\n return {\n header: {\n padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`,\n borderBottom: `4px solid ${theme.palette.primary.main}`,\n userSelect: \"none\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n minHeight: 46,\n },\n };\n};\n\nclass PanelHeader extends Component {\n static propTypes = {\n allowMaximizedWindow: propTypes.bool.isRequired,\n classes: propTypes.object.isRequired,\n color: propTypes.string,\n mode: propTypes.oneOf([\"window\", \"maximized\", \"minimized\"]),\n onClose: propTypes.func.isRequired,\n onMaximize: propTypes.func.isRequired,\n onMinimize: propTypes.func.isRequired,\n title: propTypes.string.isRequired,\n };\n\n renderCustomHeaderButtons = () => {\n const { customHeaderButtons } = this.props;\n return customHeaderButtons.map((buttonInfo, index) => {\n const HeaderActionIcon = buttonInfo.icon.type;\n const description = buttonInfo.description;\n return (\n <IconButton\n key={index}\n onClick={buttonInfo.onClickCallback}\n size=\"small\"\n >\n <Typography variant=\"srOnly\">{description}</Typography>\n <HeaderActionIcon />\n </IconButton>\n );\n });\n };\n\n shouldRenderCustomHeaderButtons = () => {\n const { customHeaderButtons } = this.props;\n return customHeaderButtons && customHeaderButtons.length > 0;\n };\n\n render() {\n const { allowMaximizedWindow, classes, mode } = this.props;\n return (\n <header\n className={classes.header}\n style={{ borderColor: this.props.color }} // Allow for dynamic override of accent border color\n >\n <Typography component=\"h1\" variant=\"button\" align=\"left\" noWrap={true}>\n {this.props.title}\n </Typography>\n <Box display=\"flex\" component=\"nav\">\n {this.shouldRenderCustomHeaderButtons() &&\n this.renderCustomHeaderButtons()}\n {mode !== \"maximized\" && // If window isn't in fit screen mode currently…\n (mode === \"minimized\" ? ( // … but it's minimized…\n <IconButton size=\"small\" onClick={this.props.onMaximize}>\n <Typography variant=\"srOnly\">Maximera fönster</Typography>\n <FullscreenIcon // …render the maximize icon.\n />\n </IconButton>\n ) : (\n // If it's already in \"window\" mode though, render the minimize icon.\n <IconButton size=\"small\" onClick={this.props.onMinimize}>\n <Typography variant=\"srOnly\">Minimera fönster</Typography>\n <FullscreenExitIcon />\n </IconButton>\n ))}\n <Hidden xsDown>\n {allowMaximizedWindow && ( // If we're not on mobile and config allows fit-to-screen…\n <IconButton size=\"small\" onClick={this.props.onMaximize}>\n <Typography variant=\"srOnly\">Maximera fönster</Typography>\n <AspectRatioIcon // … render the action button. Note: it will remain the same…\n />\n </IconButton>\n )}\n </Hidden>\n <IconButton size=\"small\" onClick={this.props.onClose}>\n <Typography variant=\"srOnly\">Stäng fönster</Typography>\n <CloseIcon />\n </IconButton>\n </Box>\n </header>\n );\n }\n}\n\nexport default withStyles(styles)(PanelHeader);\n","import React from \"react\";\nimport SearchBar from \"./SearchBar\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { withSnackbar } from \"notistack\";\nimport Observer from \"react-event-observer\";\nimport EditIcon from \"@material-ui/icons/Edit\";\nimport Crop54Icon from \"@material-ui/icons/Crop54\";\nimport TouchAppIcon from \"@material-ui/icons/TouchApp\";\nimport RadioButtonUncheckedIcon from \"@material-ui/icons/RadioButtonUnchecked\";\nimport SettingsIcon from \"@material-ui/icons/Settings\";\nimport MapViewModel from \"./MapViewModel\";\nimport KmlExport from \"./utils/KmlExport\";\nimport XLSXExport from \"./utils/XLSXExport\";\nimport { encodeCommas, decodeCommas } from \"../../utils/StringCommaCoder\";\nimport LocalStorageHelper from \"../../utils/LocalStorageHelper\";\n\nconst styles = () => ({\n inputRoot: {\n width: \"100%\",\n },\n});\n\nclass Search extends React.PureComponent {\n defaultSearchOptions = {\n enableLabelOnHighlight: true,\n searchInVisibleLayers: false,\n wildcardAtStart: false,\n wildcardAtEnd: true,\n matchCase: false,\n activeSpatialFilter: \"intersects\",\n maxResultsPerDataset: !isNaN(this.props.options.maxResultsPerDataset)\n ? this.props.options.maxResultsPerDataset\n : 100,\n };\n\n state = {\n searchImplementedPluginsLoaded: false,\n searchSources: [],\n searchResults: { featureCollections: [], errors: [] },\n autocompleteList: [],\n searchString: \"\",\n searchFromAutoComplete: false,\n searchActive: \"\",\n autoCompleteOpen: false,\n loading: false,\n searchOptions: LocalStorageHelper.get(\n \"searchOptions\",\n this.defaultSearchOptions\n ),\n failedWFSFetchMessage: \"\",\n resultPanelCollapsed: false,\n };\n\n // Used for setTimeout/clearTimeout, in order to delay update of autocomplete when user is typing\n timer = null;\n\n // Amount of time before autocomplete is updated\n delayBeforeAutoSearch =\n isNaN(this.props.options.delayBeforeAutoSearch) === false\n ? this.props.options.delayBeforeAutoSearch\n : 500;\n\n searchImplementedPlugins = [];\n featuresToFilter = [];\n localObserver = Observer();\n\n snackbarKey = null;\n\n defaultSearchTools = [\n {\n name: \"Sök med polygon\",\n icon: <EditIcon />,\n type: \"Polygon\",\n enabled: this.props.options.enablePolygonSearch ?? true,\n toolTipTitle:\n \"Genomför en sökning i ett område genom att rita en polygon.\",\n onClickEventName: \"search.spatialSearchActivated\",\n },\n {\n name: \"Sök med radie\",\n icon: <RadioButtonUncheckedIcon />,\n type: \"Circle\",\n enabled: this.props.options.enableRadiusSearch ?? true,\n toolTipTitle: \"Genomför en sökning i ett område genom att rita en cirkel\",\n onClickEventName: \"search.spatialSearchActivated\",\n },\n {\n name: \"Sök med objekt\",\n icon: <TouchAppIcon />,\n type: \"Select\",\n enabled: this.props.options.enableSelectSearch ?? true,\n toolTipTitle:\n \"Genomför en sökning genom att välja en eller flera områden i kartan.\",\n onClickEventName: \"search.spatialSearchActivated\",\n },\n {\n name: \"Sök inom vyn\",\n icon: <Crop54Icon />,\n type: \"Extent\",\n enabled: this.props.options.enableExtentSearch ?? true,\n toolTipTitle: \"Genomför en sökning i hela det område som kartan visar.\",\n onClickEventName: \"search.spatialSearchActivated\",\n },\n {\n name: \"Sökinställningar\",\n icon: <SettingsIcon />,\n type: \"SETTINGS\",\n toolTipTitle: \"Ändra sökinställningarna.\",\n onClickEventName: \"\",\n },\n ];\n\n constructor(props) {\n super(props);\n this.map = props.map;\n this.searchModel = props.app.appModel.searchModel;\n this.globalObserver = props.app.globalObserver;\n this.initMapViewModel();\n this.initExportHandlers();\n this.bindSubscriptions();\n }\n\n initMapViewModel = () => {\n const { app } = this.props;\n this.mapViewModel = new MapViewModel({\n // Init the MapViewModel using merged options from both\n // Admin UI (\"options\") and user's setting (\"this.state.options\")\n options: {\n ...this.props.options,\n ...this.state.searchOptions,\n },\n localObserver: this.localObserver,\n map: this.map,\n app: app,\n });\n };\n\n initExportHandlers = () => {\n this.kmlExport = new KmlExport({\n options: this.props.options,\n localObserver: this.localObserver,\n map: this.map,\n });\n this.XLSXExport = new XLSXExport({\n options: this.props.options,\n localObserver: this.localObserver,\n });\n };\n\n resetFeaturesToFilter = () => {\n this.featuresToFilter = [];\n };\n\n setFeaturesToFilter = (arrayOfFeatures) => {\n this.featuresToFilter = arrayOfFeatures;\n };\n\n bindSubscriptions = () => {\n this.localObserver.subscribe(\"on-draw-start\", (type) => {\n if (type === \"Circle\") {\n this.snackbarKey = this.props.enqueueSnackbar(\n \"Tryck i kartan där du vill ha centrumpunkten, dra sedan utåt och släpp.\",\n {\n variant: \"information\",\n anchorOrigin: { vertical: \"bottom\", horizontal: \"center\" },\n }\n );\n } else if (type === \"Polygon\") {\n this.snackbarKey = this.props.enqueueSnackbar(\n \"Tryck en gång i kartan för varje nod i polygonen. Genomför sökningen genom att trycka på den sista noden en gång till.\",\n {\n variant: \"information\",\n anchorOrigin: { vertical: \"bottom\", horizontal: \"center\" },\n }\n );\n }\n this.setState({ searchActive: \"draw\" });\n });\n this.localObserver.subscribe(\"on-draw-end\", (feature) => {\n this.doFeaturesSearch([feature]);\n });\n this.localObserver.subscribe(\"on-select-search-start\", () => {\n this.snackbarKey = this.props.enqueueSnackbar(\n \"Tryck på den yta i kartan där du vill genomföra en sökning. Håll in CTRL för att välja flera ytor.\",\n {\n variant: \"information\",\n anchorOrigin: { vertical: \"bottom\", horizontal: \"center\" },\n }\n );\n\n this.setState({ searchActive: \"selectSearch\" });\n });\n this.localObserver.subscribe(\"on-search-selection-done\", (features) => {\n this.doFeaturesSearch(features);\n });\n this.localObserver.subscribe(\"search-within-extent\", (features) => {\n this.setState({ searchActive: \"extentSearch\" });\n this.doFeaturesSearch(features);\n });\n this.localObserver.subscribe(\"minimizeSearchResultList\", () => {\n this.setState({ resultPanelCollapsed: false });\n });\n this.localObserver.subscribe(\"extent-search-failed\", () => {\n this.snackbarKey = this.props.enqueueSnackbar(\n \"Ett problem uppstod vid sökning i området. Kontakta systemadministratören.\",\n {\n variant: \"warning\",\n anchorOrigin: { vertical: \"top\", horizontal: \"center\" },\n }\n );\n });\n };\n\n doFeaturesSearch = (features) => {\n this.props.closeSnackbar(this.snackbarKey);\n this.setFeaturesToFilter(features);\n this.doSearch();\n };\n\n getPluginsConfToUseSearchInterface = () => {\n const { app } = this.props;\n return Object.values(app.appModel.plugins).filter((plugin) => {\n return (\n plugin.options.searchImplemented &&\n plugin.searchInterface.getSearchMethods\n );\n });\n };\n\n tryBindSearchMethods = (plugins) => {\n return plugins.map((plugin) => {\n return plugin.searchInterface.getSearchMethods.then((methods) => {\n plugin.searchInterface.getFunctionality = methods?.getFunctionality;\n plugin.searchInterface.getResults = methods?.getResults;\n return plugin;\n });\n });\n };\n\n pluginsHavingCorrectSearchMethods = (plugins) => {\n return plugins.filter((plugin) => {\n const getResults = plugin.searchInterface.getResults;\n const getFunctionality = plugin.searchInterface.getFunctionality;\n if (!getResults || !getFunctionality) {\n this.displayPluginMissingCrucialMethodsWarning(plugin);\n }\n return getResults && getFunctionality;\n });\n };\n\n displayPluginMissingCrucialMethodsWarning = (plugin) => {\n console.warn(\n `${\n plugin.type ?? \"<Plugin type missing>\"\n } is marked as a search-plugin, but is missing the getResults() and/or getFunctionality() method(s) in it's searchInterface.\n\n Because of this, the search component will not make use of this plugin. \n \n If you intend to use this plugin as a search-plugin, make sure to implement both methods. \n If you do not intend to use this plugin within the search component, please update plugin-config so that searchImplemented = false.`\n );\n };\n\n //For a plugin to use the searchInterface, following must be met\n //Must have option searchImplemented = true in tool-config\n //Must \"inject\" a method called getSearchMethods returning a promise on the object plugin.searchInterface\n //The object searchInterface is put onto the plugin upon loading in App.js\n //Promise must be resolved into object with two methods getResults and getFunctionality\n\n getSearchImplementedPlugins = () => {\n const pluginsConfToUseSearchInterface =\n this.getPluginsConfToUseSearchInterface();\n const searchBoundPlugins = this.tryBindSearchMethods(\n pluginsConfToUseSearchInterface\n );\n return Promise.all(searchBoundPlugins).then((plugins) => {\n return this.pluginsHavingCorrectSearchMethods(plugins);\n });\n };\n\n getExternalSearchTools = (searchImplementedSearchTools) => {\n // TODO (To discuss)\n // We demand that getFunctionality is implemented, but we do not demand that\n // the method returns a \"correct\" object. If the method return a null-ish\n // value we simply discard the extra functionality. Maybe we shouldn't demand that\n // getFunctionality is implemented?\n return searchImplementedSearchTools\n .filter((searchImplementedPlugin) => {\n return searchImplementedPlugin.searchInterface.getFunctionality();\n })\n .map((toolWithFunctionality) => {\n return toolWithFunctionality.searchInterface.getFunctionality();\n });\n };\n\n getSearchTools = (searchImplementedSearchTools) => {\n return this.defaultSearchTools.concat(\n this.getExternalSearchTools(searchImplementedSearchTools)\n );\n };\n\n componentDidMount = () => {\n this.globalObserver.subscribe(\"core.appLoaded\", () => {\n this.getSearchImplementedPlugins().then((searchImplementedPlugins) => {\n this.setState(\n {\n searchImplementedPluginsLoaded: true,\n searchImplementedPlugins: searchImplementedPlugins,\n searchTools: this.getSearchTools(searchImplementedPlugins),\n },\n () => {\n this.handlePotentialUrlQuerySearch();\n }\n );\n });\n });\n };\n\n getSourcesByIds = (sourceIds) => {\n return this.searchModel\n .getSources()\n .filter((source) => sourceIds.indexOf(source.id) > -1);\n };\n\n handlePotentialUrlQuerySearch = () => {\n const { appModel } = this.props.app;\n // Grab the (already decoded) URL param values\n const q = appModel.config.urlParams.get(\"q\")?.trim(); // Use of \"?.\" will return either a String or undefined\n const s = appModel.config.urlParams.get(\"s\")?.trim(); // (As opposed to null which would be the return value of get() otherwise!).\n\n // Check so that we have a searchString in the url (q)\n if (q !== undefined && q.length > 0) {\n // Initializing sources to an empty array\n // (The model will search in all sources if searchSources is set to [])\n let sources = [];\n // If source parameter is set in url (s)\n // Get the sources corresponding to the ids\n if (s !== undefined && s.length > 0) {\n const sourceIds = s.split(\",\");\n sources = this.getSourcesByIds(sourceIds);\n }\n // Update state according to searchString and sources from url\n // and do a search.\n this.setState({ searchString: q, searchSources: sources }, () => {\n this.doSearch();\n });\n }\n };\n\n handleOnClear = () => {\n this.setState({\n searchString: \"\",\n searchActive: \"\",\n showSearchResults: false,\n searchResults: { featureCollections: [], errors: [] },\n failedWFSFetchMessage: \"\",\n resultPanelCollapsed: false,\n loading: false,\n });\n this.resetFeaturesToFilter();\n this.localObserver.publish(\"clearMapView\");\n };\n\n handleSearchInput = (event, value, reason) => {\n let searchString = value?.autocompleteEntry || value || \"\";\n\n if (searchString !== \"\") {\n this.setState(\n {\n searchString: searchString,\n searchFromAutoComplete: true,\n searchActive: \"input\",\n },\n () => {\n this.doSearch();\n }\n );\n } else {\n this.setState({\n searchString: searchString,\n });\n }\n };\n\n isUserInput = (searchString, reason) => {\n // Reason equals \"reset\" when input is changed programmatically\n // This catches user click on clear (searchString === 0)\n return (\n (searchString.length === 0 && reason === \"reset\") || reason === \"input\"\n );\n };\n\n handleOnAutocompleteInputChange = (event, searchString, reason) => {\n if (this.isUserInput(searchString, reason)) {\n clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.localObserver.publish(\"clearMapView\");\n this.setState(\n {\n autoCompleteOpen: searchString.length >= 3,\n autocompleteList: [],\n loading: searchString.length >= 3,\n showSearchResults: false,\n searchString: searchString,\n resultPanelCollapsed: false,\n },\n () => {\n if (this.state.searchString.length >= 3) {\n this.updateAutocompleteList(this.state.searchString);\n } else {\n this.setState({\n autocompleteList: [],\n });\n }\n }\n );\n }, this.delayBeforeAutoSearch);\n\n // Announce the input change, so other plugins can be notified\n this.globalObserver.publish(\"search.searchPhraseChanged\", searchString);\n }\n };\n\n updateSearchOptions = (searchOptions) => {\n // Ensure that the latest search options are in state\n this.setState({ searchOptions });\n\n // We need to re-initiate the FeatureStyle only if some specific\n // settings have changed (those that effect the style that renders\n // result features to the OL searchResults source).\n const isStyleRefreshNeeded =\n searchOptions.enableLabelOnHighlight !==\n this.state.searchOptions.enableLabelOnHighlight;\n\n // Refresh the Feature Style, if needed\n isStyleRefreshNeeded &&\n this.mapViewModel.refreshFeatureStyle({\n enableLabelOnHighlight: searchOptions.enableLabelOnHighlight,\n });\n\n // Always save the current settings to local storage, so it can be\n // retrieved on app reload.\n LocalStorageHelper.set(\"searchOptions\", searchOptions);\n };\n\n handleOnClickOrKeyboardSearch = () => {\n if (this.hasEnoughCharsForSearch()) {\n this.setState({ searchFromAutoComplete: false }, () => {\n // Get rid of the on-screen keyboard on mobile devices\n document.activeElement.blur();\n this.doSearch();\n });\n }\n };\n\n setSearchSources = (sources) => {\n this.setState({\n searchSources: sources,\n });\n };\n\n handleSearchBarKeyPress = (event) => {\n if (event.which === 13 || event.keyCode === 13) {\n if (event.target.id === \"searchInputField\") {\n this.handleOnClickOrKeyboardSearch();\n }\n }\n };\n\n getAutoCompleteFetchSettings = () => {\n const { options } = this.props;\n let fetchSettings = { ...this.searchModel.getSearchOptions() }; //Getting default-options when fetching auto\n fetchSettings = {\n ...fetchSettings,\n wildcardAtStart: options.autocompleteWildcardAtStart || false,\n getPossibleCombinations: true,\n initiator: \"autocomplete\",\n };\n return fetchSettings;\n };\n\n getArrayWithSearchWords = (searchString) => {\n let tempStringArray = this.splitAndTrimOnCommas(searchString);\n return tempStringArray.join(\" \").split(\" \");\n };\n\n splitAndTrimOnCommas = (searchString) => {\n return searchString.split(\",\").map((string) => {\n return string.trim();\n });\n };\n\n escapeRegExp = (string) => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"); // $& means the whole matched string\n };\n\n sortSearchFieldsOnFeature = (searchFields, feature, wordsInTextField) => {\n const matchedSearchFields = [];\n\n // We loop over each word in the input field first to ensure\n // that we don't mess upp the order of the displayFields...\n wordsInTextField.forEach((word) => {\n // then we get the searchFields that has not been matched yet\n searchFields\n .filter((sf) => !matchedSearchFields.includes(sf))\n // and loop over these...\n .forEach((sf) => {\n // to find searchFields matching the current word...\n const searchFieldMatch = RegExp(\n `^${this.escapeRegExp(word)}\\\\W*`,\n \"i\"\n ).test(feature.get(sf) || \"\");\n // If we find a match, and the matched searchField\n // returns a feature prop which is not undefined...\n if (feature.get(sf)) {\n // we add the searchField to the array of matched\n // searchFields.\n if (searchFieldMatch) {\n matchedSearchFields.push(sf);\n }\n }\n });\n });\n\n // The function should return ALL searchField (no matter if\n // they have been matched or not. Therefore we get the searchFields\n // that have not been matched)...\n const unMatchedSearchFields = searchFields.filter(\n (sf) => !matchedSearchFields.includes(sf) && feature.get(sf)\n );\n // And concatenate the matched searchFields with the unMatched searchFields.\n return matchedSearchFields.concat(unMatchedSearchFields);\n };\n\n getSortedAutocompleteEntry = (feature) => {\n let autocompleteEntry = \"\";\n feature.searchFieldOrder.map((sf, index) => {\n const featureProperty = feature.get(sf);\n const propertyAsString =\n typeof featureProperty === \"string\"\n ? featureProperty\n : featureProperty.toString();\n if (index === feature.searchFieldOrder.length - 1) {\n return (autocompleteEntry = autocompleteEntry.concat(\n encodeCommas(propertyAsString)\n ));\n } else {\n return (autocompleteEntry = autocompleteEntry.concat(\n `${encodeCommas(propertyAsString)}, `\n ));\n }\n });\n return autocompleteEntry;\n };\n\n getAutocompleteDataset = (featureCollection) => {\n return featureCollection.value.features.map((feature) => {\n const dataset = featureCollection.source.caption;\n const origin = featureCollection.origin;\n const autocompleteEntry = this.getSortedAutocompleteEntry(feature);\n return {\n dataset,\n autocompleteEntry,\n origin,\n };\n });\n };\n\n sortSearchFieldsOnFeatures = (featureCollection, wordsInTextField) => {\n featureCollection.value.features.forEach((feature) => {\n feature.searchFieldOrder = this.sortSearchFieldsOnFeature(\n featureCollection.source.searchFields,\n feature,\n wordsInTextField\n );\n });\n };\n\n flattenAndSortAutoCompleteList = (searchResults) => {\n let wordsInTextField = this.getArrayWithSearchWords(\n this.state.searchString\n );\n\n const resultsPerDataset = searchResults.featureCollections.map(\n (featureCollection) => {\n this.sortSearchFieldsOnFeatures(featureCollection, wordsInTextField);\n // The final filter is to ensure that we get rid of objects that lack\n // the 'autocompleteEntry' property, which is necessary for the\n // MUI Autocomplete component.\n return this.getAutocompleteDataset(featureCollection).filter(\n (e) => e.autocompleteEntry\n );\n }\n );\n\n // Now we have an Array of Arrays, one per dataset. For the Autocomplete component\n // however, we need just one Array, so let's flatten the results:\n\n return this.sortAutocompleteList(resultsPerDataset.flat());\n };\n\n sortAutocompleteList = (flatAutocompleteArray) => {\n return flatAutocompleteArray.sort((a, b) =>\n decodeCommas(a.autocompleteEntry).localeCompare(\n decodeCommas(b.autocompleteEntry),\n undefined,\n { numeric: true }\n )\n );\n };\n\n getMergeResultsFromAllSources = (results) => {\n return results.reduce(\n (searchResults, result) => {\n searchResults.featureCollections =\n searchResults.featureCollections.concat(\n result.value.featureCollections\n );\n searchResults.errors = searchResults.errors.concat(result.value.errors);\n return searchResults;\n },\n { errors: [], featureCollections: [] }\n );\n };\n\n fetchResultFromSearchModel = async (fetchOptions) => {\n // Check if the searchString is encapsuled with quotation marks\n const searchStringIsEncapsuled = this.searchStringEncapsuled();\n\n // If the searchString is encapsuled with quotation marks (meaning that the user is\n // searching for an exacts phrase, we want to disable potential wildcards in the\n // fetchOptions.\n if (searchStringIsEncapsuled) {\n fetchOptions = {\n ...fetchOptions,\n wildcardAtStart: false,\n wildcardAtEnd: false,\n };\n }\n\n // Potential quotation marks in the searchString must be removed before\n // we perform the search.\n const searchString = this.getCleanedSearchString();\n\n let { searchSources } = this.state;\n\n if (searchSources.length === 0) {\n searchSources = this.searchModel.getSources();\n }\n\n if (this.state.searchOptions.searchInVisibleLayers) {\n searchSources = this.mapViewModel.getVisibleSearchLayers();\n }\n\n let active = true;\n const promise = this.searchModel.getResults(\n searchString,\n searchSources,\n fetchOptions\n );\n\n return Promise.allSettled([\n promise,\n ...this.fetchResultsFromPlugins(fetchOptions),\n ])\n .then((results) => {\n results = results.filter((result) => result.status !== \"rejected\");\n results = this.removeCollectionsWithoutFeatures(results);\n let searchResults = this.getMergeResultsFromAllSources(results);\n // It's possible to handle any errors in the UI by checking if Search Model returned any\n searchResults.errors.length > 0 &&\n console.error(\"Autocomplete error: \", searchResults.errors);\n\n // Prepare all features so that they do have titles/short titles\n searchResults.featureCollections.forEach((fc) => {\n fc.value.features.forEach((f) => {\n const { featureTitle, shortFeatureTitle } = this.getFeatureLabels(\n f,\n fc.source\n );\n f.featureTitle = featureTitle;\n f.shortFeatureTitle = shortFeatureTitle;\n });\n });\n\n return searchResults;\n })\n .catch((error) => {\n console.error(\"Autocomplete error: \", error);\n\n // Also, set \"open\" state variable to false, which\n // abort the \"loading\" state of Autocomplete.\n if (active) {\n this.setState({\n open: false,\n });\n }\n });\n };\n\n // Returns true if the searchString is encapsuled in quotation marks.\n searchStringEncapsuled = () => {\n const { searchString } = this.state;\n return searchString.startsWith('\"') && searchString.endsWith('\"');\n };\n\n // Removes potential quotation marks from the searchString\n getCleanedSearchString = () => {\n const { searchString } = this.state;\n return searchString.replace(/\"/g, \"\");\n };\n\n getPotentialWFSErrorMessage = (searchResults) => {\n return searchResults.errors.length === 0\n ? ``\n : `OBS: Kunde inte hämta data från: `.concat(\n searchResults.errors\n .map((error, index) => {\n return index === searchResults.errors.length - 1\n ? error.source.caption\n : `${error.source.caption}, `;\n })\n .join(\"\")\n );\n };\n\n async doSearch() {\n this.setState({ loading: true });\n const fetchOptions = this.getSearchResultsFetchSettings();\n const searchResults = await this.fetchResultFromSearchModel(fetchOptions);\n const failedWFSFetchMessage =\n this.getPotentialWFSErrorMessage(searchResults);\n\n this.setState({\n searchResults,\n showSearchResults: true,\n loading: false,\n autoCompleteOpen: false,\n failedWFSFetchMessage,\n resultPanelCollapsed: false,\n });\n\n let features = this.extractFeaturesFromFeatureCollections(\n searchResults.featureCollections\n );\n\n features = this.filterFeaturesWithGeometry(features);\n\n // If we got more than 1 result, publish event below\n if (features.length !== 1) {\n this.localObserver.publish(\"map.addFeaturesToResultsLayer\", features);\n }\n // If we get a single search-result, we add it to the map in the searchResultList-component instead,\n // unless clean mode is true. In that case, there's another event we want to publish.\n else if (this.props.app.appModel.config.mapConfig.map.clean === true) {\n const feature = features[0];\n\n this.localObserver.publish(\n \"map.addAndHighlightFeatureInSearchResultLayer\",\n {\n feature,\n }\n );\n }\n }\n\n getFeatureLabels = (feature, source) => {\n if (feature.featureTitle && feature.shortFeatureTitle) {\n return {\n featureTitle: feature.featureTitle,\n shortFeatureTitle: feature.shortFeatureTitle,\n };\n }\n\n const reducerFn = (featureTitleString, df) => {\n let displayField = feature.get(df);\n if (Array.isArray(displayField)) {\n displayField = displayField.join(\", \");\n }\n if (displayField) {\n if (featureTitleString.length > 0) {\n featureTitleString = featureTitleString.concat(` | ${displayField}`);\n } else {\n featureTitleString = displayField.toString();\n }\n }\n return featureTitleString;\n };\n\n // Prepare the title be using the defined displayFields. Note that this\n // can not be left empty: it is used as input to the MUI Autocomplete component\n // and supplying an empty string is not allowed here. See also the\n // comment on shortFeatureTitle below.\n const featureTitle =\n source.displayFields?.reduce(reducerFn, \"\") || \"Visningsfält saknas\";\n\n // Also, try to prepare the short title. It's possible that\n // this array is not defined though, and in that case, we want\n // an empty label as shortFeatureTitle.\n const shortFeatureTitle =\n source.shortDisplayFields?.reduce(reducerFn, \"\") || \"\";\n return { featureTitle, shortFeatureTitle };\n };\n\n filterFeaturesWithGeometry = (features) => {\n return features.filter((feature) => {\n return feature.getGeometry() != null;\n });\n };\n\n extractFeaturesFromFeatureCollections = (featureCollections) => {\n // Let's return an Array of features. While we're on it,\n // let's also decorate each feature with two properties,\n // featureTitle and shortFeature title, so they're ready to\n // use when we're styling the features in the ol.Source.\n return featureCollections\n .map((fc) => {\n return fc.value.features.map((f) => {\n return f;\n });\n })\n .flat();\n };\n\n getNumResults = (searchResults) => {\n let numResults = 0;\n searchResults.featureCollections.forEach((fc) => {\n numResults += fc.value.features.length;\n });\n return numResults;\n };\n\n updateAutocompleteList = async () => {\n let fetchOptions = this.getAutoCompleteFetchSettings();\n let autoCompleteResult = await this.fetchResultFromSearchModel(\n fetchOptions\n );\n\n this.setState({\n autocompleteList: this.prepareAutocompleteList(autoCompleteResult),\n loading: false,\n });\n };\n\n anySearchImplementedPlugins = () => {\n return (\n this.state.searchImplementedPlugins &&\n this.state.searchImplementedPlugins.length === 0\n );\n };\n\n fetchResultsFromPlugins = (fetchOptions) => {\n const { searchString } = this.state;\n if (this.anySearchImplementedPlugins()) {\n return [];\n }\n return this.state.searchImplementedPlugins.reduce((promises, plugin) => {\n if (plugin.searchInterface.getResults) {\n //Had to make a deep clone to not directly manipulate the reference from plugin\n promises.push(\n plugin.searchInterface\n .getResults(searchString, fetchOptions)\n .then((res) => {\n return {\n errors: res.errors,\n featureCollections: res.featureCollections,\n };\n })\n );\n return promises;\n }\n return promises;\n }, []);\n };\n\n hasEnoughCharsForSearch = () => {\n const { searchString } = this.state;\n // It may seem small with 1 character, but we must allow users to force\n // a search. Please note that this will not be invoked for autocomplete\n // searches (they still need to be at least 3 characters to start searching).\n // This will however allow for search terms such as \"K4*\", which can well\n // be a valid prefix for some attribute value, and users must be able to\n // search for that.\n // However, >=1 means that we don't allow completely empty searches.\n return searchString.length >= 1;\n };\n\n getSearchResultsFetchSettings = () => {\n return {\n ...this.getUserCustomFetchSettings(this.searchModel.getSearchOptions()),\n initiator: \"search\",\n };\n };\n\n removeCollectionsWithoutFeatures = (results) => {\n return results.map((res) => {\n let featureCollections = res.value.featureCollections.filter(\n (featureCollection) => {\n return featureCollection.value.features.length > 0;\n }\n );\n res.value.featureCollections = featureCollections;\n return res;\n });\n };\n\n prepareAutocompleteList = (searchResults) => {\n let maxSlots = 7;\n let numSourcesWithResults = searchResults.featureCollections.length;\n\n if (numSourcesWithResults > maxSlots) {\n searchResults.featureCollections = searchResults.featureCollections.slice(\n 0,\n maxSlots\n );\n }\n\n let numResults = 0;\n searchResults.featureCollections.forEach((fc) => {\n numResults += fc.value.features.length;\n });\n\n let spacesPerSource = Math.max(\n 1,\n Math.min(\n Math.floor(numResults / numSourcesWithResults),\n Math.floor(maxSlots / numSourcesWithResults)\n )\n );\n\n const autoCompleteList = this.flattenAndSortAutoCompleteList(searchResults);\n\n if (numResults > maxSlots) {\n // The list must be shortened before we return\n return this.shortenAutoCompleteList(autoCompleteList, spacesPerSource);\n }\n return autoCompleteList;\n };\n\n shortenAutoCompleteList = (autoCompleteList, spacesPerSource) => {\n let shortenedAutoComplete = [];\n\n const groupedAutoComplete = this.groupObjArrayByProp(\n autoCompleteList,\n \"dataset\"\n );\n\n for (const group in groupedAutoComplete) {\n shortenedAutoComplete = [\n ...shortenedAutoComplete,\n ...groupedAutoComplete[group].slice(0, spacesPerSource),\n ];\n }\n return shortenedAutoComplete;\n };\n\n groupObjArrayByProp = (array, property) => {\n return array.reduce((grouped, obj) => {\n if (!grouped[obj[property]]) {\n grouped[obj[property]] = [];\n }\n grouped[obj[property]].push(obj);\n return grouped;\n }, {});\n };\n\n getUserCustomFetchSettings = (searchOptionsFromModel) => {\n const {\n activeSpatialFilter,\n matchCase,\n wildcardAtEnd,\n wildcardAtStart,\n maxResultsPerDataset,\n } = this.state.searchOptions;\n return {\n ...searchOptionsFromModel,\n activeSpatialFilter: activeSpatialFilter,\n getPossibleCombinations: this.state.searchFromAutoComplete ? false : true,\n featuresToFilter: this.featuresToFilter || [],\n matchCase: matchCase,\n wildcardAtStart: wildcardAtStart,\n wildcardAtEnd: wildcardAtEnd,\n maxResultsPerDataset: maxResultsPerDataset,\n };\n };\n\n toggleCollapseSearchResults = () => {\n this.setState({ resultPanelCollapsed: !this.state.resultPanelCollapsed });\n };\n\n render() {\n const { classes } = this.props;\n const {\n searchString,\n searchActive,\n searchResults,\n autocompleteList,\n autoCompleteOpen,\n showSearchResults,\n loading,\n searchOptions,\n searchSources,\n searchTools,\n failedWFSFetchMessage,\n resultPanelCollapsed,\n } = this.state;\n\n return (\n this.state.searchImplementedPluginsLoaded &&\n this.props.app.appModel.config.mapConfig.map.clean === false && (\n <SearchBar\n classes={{\n root: classes.inputRoot,\n }}\n escapeRegExp={this.escapeRegExp}\n localObserver={this.localObserver}\n searchTools={searchTools}\n searchResults={searchResults}\n handleSearchInput={this.handleSearchInput}\n searchString={searchString}\n searchActive={searchActive}\n handleOnClickOrKeyboardSearch={this.handleOnClickOrKeyboardSearch}\n autoCompleteOpen={autoCompleteOpen}\n showSearchResults={showSearchResults}\n resultPanelCollapsed={resultPanelCollapsed}\n toggleCollapseSearchResults={this.toggleCollapseSearchResults}\n handleOnAutocompleteInputChange={this.handleOnAutocompleteInputChange}\n handleOnClear={this.handleOnClear}\n autocompleteList={autocompleteList}\n searchModel={this.searchModel}\n searchOptions={searchOptions}\n updateSearchOptions={this.updateSearchOptions}\n setSearchSources={this.setSearchSources}\n loading={loading}\n searchSources={searchSources}\n handleSearchBarKeyPress={this.handleSearchBarKeyPress}\n getArrayWithSearchWords={this.getArrayWithSearchWords}\n failedWFSFetchMessage={failedWFSFetchMessage}\n {...this.props}\n />\n )\n );\n }\n}\nexport default withStyles(styles)(withSnackbar(Search));\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport cslx from \"clsx\";\nimport { SnackbarProvider } from \"notistack\";\nimport Observer from \"react-event-observer\";\nimport { isMobile } from \"../utils/IsMobile\";\nimport SrShortcuts from \"../components/SrShortcuts/SrShortcuts\";\nimport AppModel from \"../models/AppModel.js\";\n\nimport Window from \"./Window.js\";\nimport CookieNotice from \"./CookieNotice\";\nimport Introduction from \"./Introduction\";\nimport Announcement from \"./Announcement/Announcement\";\nimport Alert from \"./Alert\";\nimport PluginWindows from \"./PluginWindows\";\n\nimport Search from \"./Search/Search.js\";\n\nimport Zoom from \"../controls/Zoom\";\nimport User from \"../controls/User\";\nimport Rotate from \"../controls/Rotate\";\nimport ScaleLine from \"../controls/ScaleLine\";\nimport Attribution from \"../controls/Attribution.js\";\nimport MapCleaner from \"../controls/MapCleaner\";\nimport MapResetter from \"../controls/MapResetter\";\nimport MapSwitcher from \"../controls/MapSwitcher\";\nimport Information from \"../controls/Information\";\nimport PresetLinks from \"../controls/PresetLinks\";\n\nimport DrawerToggleButtons from \"../components/Drawer/DrawerToggleButtons\";\n\nimport {\n Box,\n Divider,\n Drawer,\n Grid,\n Hidden,\n IconButton,\n Tooltip,\n Typography,\n} from \"@material-ui/core\";\n\nimport LockIcon from \"@material-ui/icons/Lock\";\nimport LockOpenIcon from \"@material-ui/icons/LockOpen\";\nimport MapIcon from \"@material-ui/icons/Map\";\nimport ThemeToggler from \"../controls/ThemeToggler\";\n\n// A global that holds our windows, for use see components/Window.js\ndocument.windows = [];\n\nconst DRAWER_WIDTH = 250;\n\nconst styles = (theme) => {\n return {\n map: {\n zIndex: 1,\n position: \"absolute\",\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n border: \"2px solid transparent\",\n \"&:focus-visible\": {\n border: \"2px solid black\",\n },\n },\n flexBox: {\n position: \"absolute\",\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n padding: theme.spacing(2),\n display: \"flex\",\n flexDirection: \"column\",\n pointerEvents: \"none\",\n },\n windowsContainer: {\n position: \"absolute\",\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n },\n pointerEventsOnChildren: {\n \"& > *\": {\n pointerEvents: \"auto\",\n },\n },\n drawerContent: {\n height: \"inherit\",\n },\n header: {\n zIndex: theme.zIndex.appBar,\n maxHeight: theme.spacing(8),\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"flex-start\",\n \"& > *\": {\n marginBottom: theme.spacing(2),\n },\n [theme.breakpoints.down(\"xs\")]: {\n zIndex: 3,\n marginLeft: -theme.spacing(2),\n marginRight: -theme.spacing(2),\n marginTop: -theme.spacing(2),\n maxHeight: theme.spacing(6),\n boxShadow: theme.shadows[3],\n backgroundColor: theme.palette.background.paper,\n },\n },\n main: {\n zIndex: 2,\n flex: 1,\n display: \"flex\",\n },\n leftColumn: {\n flex: 1,\n },\n rightColumn: {\n paddingLeft: theme.spacing(2),\n paddingRight: theme.spacing(2),\n },\n controlsColumn: {\n display: \"flex\",\n flexDirection: \"column\",\n [theme.breakpoints.down(\"xs\")]: {\n marginTop: theme.spacing(2),\n },\n },\n footer: {\n zIndex: 3,\n display: \"flex\",\n justifyContent: \"flex-end\",\n height: 25,\n \"& > *\": {\n marginLeft: theme.spacing(1),\n },\n },\n drawerBackground: {\n width: DRAWER_WIDTH,\n backgroundColor: theme.palette.background.default,\n },\n drawerHeader: {\n display: \"flex\",\n alignItems: \"center\",\n padding: theme.spacing(0, 2),\n ...theme.mixins.toolbar,\n justifyContent: \"space-between\",\n backgroundColor: theme.palette.background.paper,\n },\n drawerContentContainer: {\n backgroundColor: theme.palette.background.paper,\n height: \"100%\",\n overflow: \"auto\",\n },\n drawerLockButton: {\n margin: -12,\n },\n logoBox: {\n padding: theme.spacing(1, 2),\n height: theme.spacing(6),\n },\n logo: {\n height: theme.spacing(4),\n },\n drawerGrid: {\n padding: theme.spacing(1, 2),\n backgroundColor: theme.palette.background.paper,\n minHeight: theme.spacing(6),\n },\n drawerTitle: {\n padding: theme.spacing(1, 0),\n lineHeight: 0,\n },\n drawerLiveContent: {\n backgroundColor: theme.palette.background.default,\n },\n widgetItem: {\n width: \"220px\",\n },\n snackBarContainerRoot: {\n [theme.breakpoints.down(\"xs\")]: {\n pointerEvents: \"none\",\n // Getting around notistack bug, can't reach snackItem.\n \"& div > div > div > div\": {\n pointerEvents: \"auto\",\n },\n },\n },\n snackbarContainerBottom: {\n [theme.breakpoints.down(\"xs\")]: {\n bottom: \"35px\",\n },\n },\n snackbarContainerTop: {\n [theme.breakpoints.down(\"xs\")]: {\n top: \"18px\",\n },\n },\n // IMPORTANT: shiftedLeft definition must be the last one, as styles are applied in that order via JSS\n shiftedLeft: {\n left: DRAWER_WIDTH,\n },\n };\n};\n\n/**\n * The main React Component of Hajk. Rendered by index.js.\n *\n * @class App\n * @extends {React.PureComponent}\n */\nclass App extends React.PureComponent {\n static propTypes = {\n /** List of plugins that has been activated in this instance of Hajk */\n activeTools: PropTypes.array.isRequired,\n /** CSS class declarations used in this component */\n classes: PropTypes.object.isRequired,\n /** Contains activeMap, layersConfig as well as objects that hold appConfig and mapConfig*/\n config: PropTypes.object.isRequired,\n };\n\n canRenderCustomDrawer = (activeDrawerContentFromLocalStorage, tools) => {\n if (\n !activeDrawerContentFromLocalStorage ||\n activeDrawerContentFromLocalStorage === \"plugins\"\n ) {\n // If nothing was found in local storage, fall back to map config setting\n activeDrawerContentFromLocalStorage =\n this.props.config.mapConfig.map.activeDrawerOnStart;\n }\n\n const localStorageToolFoundInMapConfig = tools.some((tool) => {\n return (\n typeof activeDrawerContentFromLocalStorage === \"string\" &&\n tool.type.toLowerCase() ===\n activeDrawerContentFromLocalStorage.toLowerCase()\n );\n });\n\n return (\n localStorageToolFoundInMapConfig &&\n activeDrawerContentFromLocalStorage &&\n activeDrawerContentFromLocalStorage !== \"plugins\"\n );\n };\n\n getDrawerPermanentFromLocalStorage = () => {\n return window.localStorage.getItem(\"drawerPermanent\") !== null\n ? window.localStorage.getItem(\"drawerPermanent\") === \"true\"\n ? true\n : false\n : null;\n };\n\n getActiveDrawerContentFromLocalStorage = () => {\n return window.localStorage.getItem(\"activeDrawerContent\") !== null\n ? window.localStorage.getItem(\"activeDrawerContent\")\n : null;\n };\n\n constructor(props) {\n super(props);\n\n const drawerPermanentFromLocalStorage =\n this.getDrawerPermanentFromLocalStorage();\n const activeDrawerContentFromLocalStorage =\n this.getActiveDrawerContentFromLocalStorage();\n const canRenderDefaultDrawer = this.hasAnyToolbarTools();\n\n const canRenderCustomDrawer = this.canRenderCustomDrawer(\n activeDrawerContentFromLocalStorage,\n props.config.mapConfig.tools\n );\n\n //Check if we have customContent to render in drawer\n //if we can render customContent, use it set the drawer content.\n //if we cant render customContent fall back to mapconfig\n //Finally, fall back to 'plugins', the standard tools panel.\n //This fall back avoids rendering an empty drawer in the case that draw is set to visible but there is no drawer content in local storage.\n\n const activeDrawerContentState = canRenderCustomDrawer\n ? activeDrawerContentFromLocalStorage !== null &&\n activeDrawerContentFromLocalStorage !== \"plugins\"\n ? activeDrawerContentFromLocalStorage\n : this.props.config.mapConfig.map.activeDrawerOnStart\n : canRenderDefaultDrawer\n ? \"plugins\"\n : null;\n\n // First check if we have anything to render at all and in case we haven't -> do not show drawer\n // If on a mobile device, the drawer should never be permanent.\n // If not on mobile, if cookie is not null, use it to show/hide Drawer.\n // If cookie is not null, use it to show/hide Drawer.\n // If cookie however is null, fall back to the values from config.\n // Finally, fall back to \"false\" if no cookie or config is found.\n const drawerPermanent =\n activeDrawerContentState === null\n ? false\n : isMobile\n ? false\n : drawerPermanentFromLocalStorage !== null\n ? drawerPermanentFromLocalStorage\n : (props.config.mapConfig.map.drawerVisible &&\n props.config.mapConfig.map.drawerPermanent) ||\n false;\n\n // First check if we have anything to render at all and in case we haven't -> do not show drawer\n // If on a mobile device, and a config property for if the drawer should initially be open is set, base the drawer state on this.\n // Otherwise if cookie for \"drawerPermanent\" is not null, use it to control Drawer visibility,\n // If there a no cookie settings, use the config drawVisible setting.\n // Finally, don't show the drawer.\n const drawerVisible =\n activeDrawerContentState === null\n ? false\n : isMobile &&\n props.config.mapConfig.map.drawerVisibleMobile !== undefined\n ? props.config.mapConfig.map.drawerVisibleMobile\n : drawerPermanentFromLocalStorage !== null\n ? drawerPermanentFromLocalStorage\n : props.config.mapConfig.map.drawerVisible || false;\n\n this.state = {\n alert: false,\n drawerButtons: [],\n loading: false,\n mapClickDataResult: {},\n drawerVisible: drawerVisible,\n drawerPermanent: drawerPermanent,\n activeDrawerContent: activeDrawerContentState,\n drawerMouseOverLock: false,\n };\n\n //if drawer is visible at start - ensure the activeDrawerContent is set to current content\n if (drawerVisible && drawerPermanent && activeDrawerContentState !== null) {\n window.localStorage.setItem(\n \"activeDrawerContent\",\n activeDrawerContentState\n );\n }\n\n this.globalObserver = new Observer();\n this.appModel = new AppModel(props.config, this.globalObserver);\n }\n\n hasAnyToolbarTools = () => {\n const { config, activeTools } = this.props;\n return config.mapConfig.tools.some((tool) => {\n return (\n tool.options.target === \"toolbar\" &&\n activeTools\n .map((activeTool) => activeTool.toLowerCase())\n .includes(tool.type.toLowerCase())\n );\n });\n };\n\n componentDidMount() {\n var promises = this.appModel\n .createMap()\n .addSearchModel()\n .addLayers()\n .loadPlugins(this.props.activeTools);\n Promise.all(promises).then(() => {\n this.setState(\n {\n tools: this.appModel.getPlugins(),\n },\n () => {\n // If there's at least one plugin that renders in the Drawer Map Tools List,\n // tell the Drawer to add a toggle button for the map tools\n this.appModel.getDrawerPlugins().length > 0 &&\n this.globalObserver.publish(\"core.addDrawerToggleButton\", {\n value: \"plugins\",\n ButtonIcon: MapIcon,\n caption: \"Kartverktyg\",\n drawerTitle: \"Kartverktyg\",\n order: 0,\n renderDrawerContent: function () {\n return null; // Nothing specific should be rendered - this is a special case!\n },\n });\n\n // Tell everyone that we're done loading (in case someone listens)\n this.globalObserver.publish(\"core.appLoaded\");\n }\n );\n });\n this.bindHandlers();\n }\n\n componentDidCatch(error) {}\n\n bindHandlers() {\n // Register a handle to prevent pinch zoom on mobile devices.\n document.body.addEventListener(\n \"touchmove\",\n (event) => {\n // If this event would result in changing scale …\n // scale is always undefined on Android so we need to handle it, otherwise we loose the ability to scroll.\n // For the prevention pinch-zoom on Android. Check index.css\n if (event.scale !== undefined && event.scale !== 1) {\n // …cancel it.\n event.preventDefault();\n }\n // Else, allow all non-scale-changing touch events, e.g.\n // we still want scroll to work.\n },\n { passive: false } // Explicitly tell the browser that we will preventDefault inside this handler,\n // which is important for smooth scrolling to work correctly.\n );\n\n // Register various global listeners.\n this.globalObserver.subscribe(\"infoClick.mapClick\", (results) => {\n this.setState({\n mapClickDataResult: results,\n });\n });\n\n this.globalObserver.subscribe(\"core.alert\", (message) => {\n this.setState({\n alert: true,\n alertMessage: message,\n });\n });\n\n this.globalObserver.subscribe(\"core.hideDrawer\", () => {\n // If Drawer is currently permanent,\n // flip the permanent toggle. Please note that\n // this will do some fixes, flip the state value\n // and, finally, invoke this function (core.hideDrawer) again\n // (but with new value for drawerPermanent this time!).\n if (this.state.drawerPermanent) {\n this.togglePermanent();\n } else {\n this.setState({ drawerVisible: false });\n\n // Also, tell the Drawer Buttons Component to unset active button\n this.globalObserver.publish(\"core.unsetActiveButton\");\n }\n });\n\n this.globalObserver.subscribe(\"core.onlyHideDrawerIfNeeded\", () => {\n // Invoked when user clicks any of the Plugin buttons in Drawer,\n // this is needed as we don't want to toggle the Drawer in this\n // case, but only hide it IF it's not permanent.\n // This differs from the \"normal\" hideDrawer event, that will\n // ensure that Drawer is hidden - no matter the permanent state -\n // as it will first flip the drawerPermanent value (if needed), prior\n // to closing.\n if (this.state.drawerPermanent === false) {\n this.setState({ drawerVisible: false });\n // Also, tell the Drawer Buttons Component to unset active button\n this.globalObserver.publish(\"core.unsetActiveButton\");\n }\n });\n\n this.globalObserver.subscribe(\"core.drawerContentChanged\", (v) => {\n if (v !== null) {\n this.setState({ drawerVisible: true, activeDrawerContent: v });\n } else {\n this.globalObserver.publish(\"core.hideDrawer\");\n }\n });\n\n this.globalObserver.subscribe(\"core.addDrawerToggleButton\", (button) => {\n const newState = [...this.state.drawerButtons, button];\n this.setState({ drawerButtons: newState });\n });\n\n /**\n * TODO: Implement correctly a way to remove features from map click\n * results when layer visibility is changed. The current implementation\n * has problems with group layers: if we have a group layer and toggle\n * its visibility, the features are not removed from infoclick window.\n */\n // this.appModel\n // .getMap()\n // .getLayers()\n // .getArray()\n // .forEach((layer) => {\n // layer.on(\"change:visible\", (e) => {\n // const layer = e.target;\n // if (Array.isArray(this.state.mapClickDataResult.features)) {\n // this.state.mapClickDataResult.features.forEach((feature) => {\n // if (feature.layer === layer) {\n // const o = { ...this.state.mapClickDataResult };\n // o.features = o.features.filter((f) => f !== feature);\n // this.setState({\n // mapClickDataResult: o,\n // });\n // }\n // });\n // }\n // });\n // });\n\n // TODO: More plugins could use this - currently only Snap helper registers though\n this.appModel\n .getMap()\n .getLayers()\n .getArray()\n .forEach((layer) => {\n layer.on(\"change:visible\", (e) => {\n this.globalObserver.publish(\"core.layerVisibilityChanged\", e);\n });\n });\n }\n\n renderInfoclickWindow() {\n // Check if admin wants Infoclick to be active\n const infoclickOptions = this.props.config.mapConfig.tools.find(\n (t) => t.type === \"infoclick\"\n )?.options;\n\n // The 'open' prop, below, will control whether the Window is\n // currently visible or not. The 'open' property itself\n // depends on whether there are Features to display or not.\n //\n // That, in turn, depends on what's in the current state of 'mapClickDataResult'.\n //\n // It will be changed each time user clicks on map (as we have it registered\n // like that in Click.js), so we can be confident that __after each user\n // click we do have the most current results in our state__.\n //\n // Note however that which layers are included is controlled by\n // __layer visibility at the time the click event happens!__\n //\n // As soon as user starts to show/hide layers __after__ the click, our\n // 'mapClickDataResult' may contain results from hidden layers (or not\n // contain results from layers activated after the click occurred).\n //\n // This may or may not be a bug (depending on how we see it), and may\n // be fixed in the future.\n\n return (\n infoclickOptions !== undefined && (\n <Window\n open={this.state.mapClickDataResult?.features?.length > 0} // Will show window only if there are any features to show\n globalObserver={this.globalObserver}\n title={infoclickOptions.title || \"Infoclick\"}\n position={infoclickOptions.position || \"right\"}\n mode=\"window\"\n width={infoclickOptions.width || 400}\n height={infoclickOptions.height || 300}\n features={this.state.mapClickDataResult?.features}\n options={\n this.appModel.config.mapConfig.tools.find(\n (t) => t.type === \"infoclick\"\n )?.options\n }\n map={this.appModel.getMap()}\n onDisplay={(feature) => {\n this.appModel.highlight(feature);\n }}\n onClose={() => {\n this.appModel.highlight(false);\n this.setState({\n mapClickDataResult: undefined,\n });\n }}\n />\n )\n );\n }\n\n /**\n * Flip the @this.state.drawerPermanent switch, then preform some\n * more work to ensure the OpenLayers canvas has the correct\n * canvas size.\n *\n * @memberof App\n */\n togglePermanent = (e) => {\n this.setState({ drawerPermanent: !this.state.drawerPermanent }, () => {\n // Viewport size has changed, hence we must tell OL\n // to refresh canvas size.\n this.appModel.getMap().updateSize();\n\n // If Drawer has been \"(un)permanented\", our #windows-container size has changed.\n // To ensure that our Windows still are inside the container, we dispach an\n // event that all Windows subscribe to.\n this.globalObserver.publish(\"core.drawerToggled\");\n\n // Save current state of drawerPermanent to LocalStorage, so app reloads to same state\n window.localStorage.setItem(\n \"drawerPermanent\",\n this.state.drawerPermanent\n );\n\n // If user clicked on Toggle Permanent and the result is,\n // that this.state.drawerPermanent===false, this means that we\n // have exited the permanent mode. In this case, we also\n // want to ensure that Drawer is hidden (otherwise we would\n // just \"un-permanent\" the Drawer, but it would still be visible).\n this.state.drawerPermanent === false &&\n this.globalObserver.publish(\"core.hideDrawer\");\n });\n };\n\n handleMouseEnter = (e) => {\n this.setState({ drawerMouseOverLock: true });\n };\n\n handleMouseLeave = (e) => {\n this.setState({ drawerMouseOverLock: false });\n };\n\n renderSearchComponent() {\n // FIXME: We should get config from somewhere else now when Search is part of Core\n if (\n this.appModel.plugins.search &&\n this.appModel.plugins.search.options.renderElsewhere !== true\n ) {\n return (\n <Search\n map={this.appModel.getMap()}\n app={this}\n options={this.appModel.plugins.search.options} // FIXME: We should get config from somewhere else now when Search is part of Core\n />\n );\n } else {\n return null;\n }\n }\n\n renderInformationPlugin() {\n const c = this.appModel.config.mapConfig.tools.find(\n (t) => t.type === \"information\"\n );\n\n return (\n c !== undefined &&\n c.hasOwnProperty(\"options\") && <Information options={c.options} />\n );\n }\n\n isString(s) {\n return s instanceof String || typeof s === \"string\";\n }\n\n renderDrawerHeader = () => {\n const { classes, config } = this.props;\n const drawerTitle = this.state.drawerButtons.find(\n (db) => db.value === this.state.activeDrawerContent\n )?.drawerTitle;\n\n // We need to be able to grab different logos depending\n // on light/dark mode theme\n const logoUrl =\n (this.props.theme.palette.type === \"light\" // If light theme active…\n ? config.mapConfig.map.logoLight // …grab light logo,\n : config.mapConfig.map.logoDark) || // …else grab dark logo.\n config.mapConfig.map.logo || // If neither was set, try to see if we have the legacy admin parameter.\n \"logo.png\"; // If we didn't have this either, fallback to hard-coded value.\n\n return (\n <>\n <Box className={classes.logoBox}>\n <img alt=\"\" src={logoUrl} className={classes.logo} />\n </Box>\n <Divider />\n <Grid\n className={classes.drawerGrid}\n item\n container\n wrap=\"nowrap\"\n direction=\"row\"\n justify=\"space-between\"\n alignItems=\"center\"\n >\n <Grid item>\n <Typography variant=\"button\" className={classes.drawerTitle}>\n {drawerTitle}\n </Typography>\n </Grid>\n {/** Hide Lock button in mobile mode - there's not screen estate to permanently lock Drawer on mobile viewports*/}\n <Grid item>\n <Hidden smDown>\n <Tooltip\n title={\n (this.state.drawerPermanent ? \"Lås upp\" : \"Lås fast\") +\n \" verktygspanelen\"\n }\n >\n <IconButton\n className={classes.drawerLockButton}\n onClick={this.togglePermanent}\n onMouseEnter={this.handleMouseEnter}\n onMouseLeave={this.handleMouseLeave}\n >\n {this.state.drawerPermanent ? (\n this.state.drawerMouseOverLock ? (\n <LockOpenIcon />\n ) : (\n <LockIcon />\n )\n ) : this.state.drawerMouseOverLock ? (\n <LockIcon />\n ) : (\n <LockOpenIcon />\n )}\n </IconButton>\n </Tooltip>\n </Hidden>\n </Grid>\n </Grid>\n </>\n );\n };\n\n renderAllDrawerContent = () => {\n const { classes } = this.props;\n\n return (\n <div id=\"drawer-content\" className={classes.drawerContentContainer}>\n <Box\n key=\"plugins\"\n className={classes.drawerContent}\n display={\n this.state.activeDrawerContent === \"plugins\" ? \"unset\" : \"none\"\n }\n >\n <nav role=\"navigation\" id=\"plugin-buttons\" />\n </Box>\n {this.state.drawerButtons.map((db) => {\n return (\n <Box\n key={db.value}\n className={classes.drawerContent}\n display={\n this.state.activeDrawerContent === db.value ? \"unset\" : \"none\"\n }\n >\n {db.renderDrawerContent()}\n </Box>\n );\n })}\n </div>\n );\n };\n\n render() {\n const { classes, config } = this.props;\n\n // If clean===true, some components won't be rendered below\n const clean = config.mapConfig.map.clean;\n\n // Let admin decide whether MapResetter should be shown, but show it\n // always on clean mode maps.\n const showMapResetter = clean === true || config.mapConfig.map.mapresetter;\n\n const showMapSwitcher =\n clean === false && config.activeMap !== \"simpleMapConfig\";\n const showCookieNotice =\n config.mapConfig.map.showCookieNotice !== undefined\n ? config.mapConfig.map.showCookieNotice\n : true;\n\n const defaultCookieNoticeMessage = this.isString(\n this.props.config.mapConfig.map.defaultCookieNoticeMessage\n )\n ? this.props.config.mapConfig.map.defaultCookieNoticeMessage\n : undefined;\n\n const defaultCookieNoticeUrl = this.isString(\n this.props.config.mapConfig.map.defaultCookieNoticeUrl\n )\n ? this.props.config.mapConfig.map.defaultCookieNoticeUrl\n : undefined;\n\n return (\n <SnackbarProvider\n maxSnack={3}\n classes={{\n anchorOriginBottomCenter: classes.snackbarContainerBottom,\n anchorOriginTopCenter: classes.snackbarContainerTop,\n containerRoot: classes.snackBarContainerRoot,\n }}\n anchorOrigin={{\n vertical: \"top\",\n horizontal: \"center\",\n }}\n >\n <>\n {this.props.config.appConfig?.announcements &&\n Array.isArray(this.props.config.appConfig.announcements) &&\n this.props.config.appConfig.announcements.length > 0 && (\n <Announcement\n announcements={this.props.config.appConfig.announcements}\n currentMap={this.props.config.activeMap}\n />\n )}\n {clean === false && showCookieNotice && (\n <CookieNotice\n globalObserver={this.globalObserver}\n defaultCookieNoticeMessage={defaultCookieNoticeMessage}\n defaultCookieNoticeUrl={defaultCookieNoticeUrl}\n />\n )}\n <Alert\n open={this.state.alert}\n message={this.state.alertMessage}\n parent={this}\n title=\"Meddelande\"\n />\n <SrShortcuts globalObserver={this.globalObserver}></SrShortcuts>\n <div\n id=\"appBox\"\n className={cslx(classes.flexBox, {\n [classes.shiftedLeft]:\n this.state.drawerPermanent && clean === false,\n })}\n >\n <header\n id=\"header\"\n className={cslx(classes.header, classes.pointerEventsOnChildren)}\n >\n {clean === false && (\n <DrawerToggleButtons\n drawerButtons={this.state.drawerButtons}\n globalObserver={this.globalObserver}\n initialActiveButton={\n this.state.drawerVisible\n ? this.state.activeDrawerContent\n : null\n }\n />\n )}\n {/* Render Search even if clean === false: Search contains logic to handle clean inside the component. */}\n {this.renderSearchComponent()}\n </header>\n <main className={classes.main}>\n <div\n id=\"left-column\"\n className={cslx(\n classes.leftColumn,\n classes.pointerEventsOnChildren\n )}\n ></div>\n <div\n id=\"right-column\"\n className={cslx(\n classes.rightColumn,\n classes.pointerEventsOnChildren\n )}\n ></div>\n\n <div\n id=\"controls-column\"\n className={cslx(\n classes.controlsColumn,\n classes.pointerEventsOnChildren\n )}\n >\n <Zoom map={this.appModel.getMap()} />\n {clean === false &&\n this.appModel.config.mapConfig.map.showUserAvatar ===\n true && (\n <User userDetails={this.appModel.config.userDetails} />\n )}\n <div id=\"plugin-control-buttons\"></div>\n {showMapResetter && (\n <MapResetter\n mapConfig={this.appModel.config.mapConfig}\n map={this.appModel.getMap()}\n />\n )}\n <Rotate map={this.appModel.getMap()} />\n {showMapSwitcher && <MapSwitcher appModel={this.appModel} />}\n {clean === false && <MapCleaner appModel={this.appModel} />}\n {clean === false && <PresetLinks appModel={this.appModel} />}\n {clean === false && (\n <ThemeToggler\n showThemeToggler={\n this.appModel.config.mapConfig.map.showThemeToggler\n }\n toggleMUITheme={this.props.toggleMUITheme}\n />\n )}\n {clean === false && this.renderInformationPlugin()}\n </div>\n </main>\n <footer\n className={cslx(classes.footer, classes.pointerEventsOnChildren)}\n >\n <ScaleLine map={this.appModel.getMap()} />\n <Attribution map={this.appModel.getMap()} />\n </footer>\n </div>\n <div\n id=\"map\"\n tabIndex=\"0\"\n role=\"application\"\n className={cslx(classes.map, {\n [classes.shiftedLeft]:\n this.state.drawerPermanent && clean === false,\n })}\n ></div>\n <div\n id=\"windows-container\"\n className={cslx(\n classes.pointerEventsOnChildren,\n classes.windowsContainer,\n {\n [classes.shiftedLeft]:\n this.state.drawerPermanent && clean === false,\n }\n )}\n >\n {this.renderInfoclickWindow()}\n <PluginWindows\n plugins={this.appModel.getBothDrawerAndWidgetPlugins()}\n />\n </div>\n {clean !== true && ( // NB: Special case here, important with !== true, because there is an edge-case where clean===undefined, and we don't want to match on that!\n <Drawer\n open={this.state.drawerVisible}\n ModalProps={{\n hideBackdrop: this.state.drawerPermanent, //Don't show backdrop if drawer is permanent\n disableEnforceFocus: true, //Dont enforce focus to be able to handle elements underneath modal\n onEscapeKeyDown: () => {\n this.globalObserver.publish(\"core.hideDrawer\");\n },\n style: {\n //Needs to be set to be able to handle elements underneath modal\n position: this.state.drawerPermanent ? \"initial\" : \"fixed\",\n },\n keepMounted: true, //Ensure we dont have to render plugins more than once - UnMounting every time is slow\n onBackdropClick: () => {\n this.globalObserver.publish(\"core.hideDrawer\");\n },\n }}\n variant=\"temporary\"\n classes={{\n paper: classes.drawerBackground,\n }}\n >\n {this.renderDrawerHeader()}\n <Divider />\n {this.renderAllDrawerContent()}\n </Drawer>\n )}\n {clean === false && (\n <Introduction\n experimentalIntroductionEnabled={\n this.appModel.config.appConfig.experimentalIntroductionEnabled\n }\n experimentalIntroductionSteps={\n this.appModel.config.appConfig.experimentalIntroductionSteps\n }\n globalObserver={this.globalObserver}\n />\n )}\n </>\n </SnackbarProvider>\n );\n }\n}\n\nexport default withStyles(styles)(App);\n","import React, { useEffect, useState } from \"react\";\nimport { List, ListItem, Link } from \"@material-ui/core\";\n\n/*\n * @summary Small component to render a shortcut-menu high up in the DOM for screen readers\n * @description The purpose of the component is to make the site more accessible by giving screen readers\n * the option to skip \"forward\" to any interesting sections instead of reading the DOM from the top\n *\n * Using globalobserver anyone can add shortcuts for screen readers high up in the DOM\n * publish array of objects [{title : {title of shortcut}, link : {link to nodeId}}] to core.addSrShortcuts\n * to add shortcuts.\n *\n * @class SrShortcuts\n */\nconst SrShortcuts = ({ globalObserver }) => {\n const [shortcuts, setShortcuts] = useState([]);\n useEffect(() => {\n globalObserver.subscribe(\"core.addSrShortcuts\", addShortCuts);\n });\n\n const addShortCuts = (shortcutsArray) => {\n setShortcuts([...shortcuts, ...shortcutsArray]);\n };\n\n return (\n <List className=\"sr-only\">\n {shortcuts.map((shortcut) => {\n return (\n <ListItem key={shortcut.link}>\n <Link href={shortcut.link}>{shortcut.title}</Link>\n </ListItem>\n );\n })}\n </List>\n );\n};\n\nexport default SrShortcuts;\n","import SearchModel from \"./SearchModel\";\nimport Plugin from \"./Plugin.js\";\nimport ConfigMapper from \"./../utils/ConfigMapper.js\";\nimport CoordinateSystemLoader from \"./../utils/CoordinateSystemLoader.js\";\nimport { isMobile } from \"./../utils/IsMobile.js\";\n// import ArcGISLayer from \"./layers/ArcGISLayer.js\";\n// import DataLayer from \"./layers/DataLayer.js\";\nimport WMSLayer from \"./layers/WMSLayer.js\";\nimport WMTSLayer from \"./layers/WMTSLayer.js\";\nimport WFSVectorLayer from \"./layers/VectorLayer.js\";\nimport { bindMapClickEvent } from \"./Click.js\";\nimport { defaults as defaultInteractions } from \"ol/interaction\";\nimport { Map, View } from \"ol\";\n// TODO: Uncomment and ensure they show as expected\n// import {\n// defaults as defaultControls,\n// Attribution,\n// Control,\n// FullScreen, // TODO: Consider implementation\n// MousePosition, // TODO: Consider implementation, perhaps in a separate plugin\n// OverviewMap // TODO: Consider implementation\n// Rotate,\n// ScaleLine\n// Zoom,\n// ZoomSlider,\n// ZoomToExtent\n// } from \"ol/control\";\nimport { register } from \"ol/proj/proj4\";\nimport VectorLayer from \"ol/layer/Vector\";\nimport VectorSource from \"ol/source/Vector\";\nimport { Icon, Fill, Stroke, Style } from \"ol/style.js\";\nimport SnapHelper from \"./SnapHelper\";\nimport { hfetch } from \"utils/FetchWrapper\";\n\nclass AppModel {\n /**\n * Initialize new AddModel\n * @param object Config\n * @param Observer observer\n */\n constructor(config, globalObserver) {\n this.map = undefined;\n this.windows = [];\n this.plugins = {};\n this.activeTool = undefined;\n this.config = config;\n this.decorateConfig();\n this.coordinateSystemLoader = new CoordinateSystemLoader(\n config.mapConfig.projections\n );\n this.globalObserver = globalObserver;\n this.layersFromParams = [];\n this.cqlFiltersFromParams = {};\n register(this.coordinateSystemLoader.getProj4());\n this.hfetch = hfetch;\n }\n\n decorateConfig() {\n // .allResolutions should be used when creating layers etc\n // It will also be used in the print plugin to be able to print in higher resolutions.\n this.config.mapConfig.map.allResolutions = [\n ...this.config.mapConfig.map.resolutions,\n ...(this.config.mapConfig.map.extraPrintResolutions ?? []),\n ];\n }\n\n registerWindowPlugin(windowComponent) {\n this.windows.push(windowComponent);\n }\n\n invokeCloseOnAllWindowPlugins() {\n this.windows.forEach((window) => {\n window.closeWindow();\n });\n }\n\n onWindowOpen(currentWindow) {\n this.windows\n .filter((window) => window !== currentWindow)\n .forEach((window) => {\n if (window.position === currentWindow.position || isMobile) {\n window.closeWindow();\n }\n });\n }\n\n /**\n * Add plugin to this tools property of loaded plugins.\n * @internal\n */\n addPlugin(plugin) {\n this.plugins[plugin.type] = plugin;\n }\n\n /**\n * Get loaded plugins\n * @returns Array<Plugin>\n */\n getPlugins() {\n return Object.keys(this.plugins).reduce((v, key) => {\n return [...v, this.plugins[key]];\n }, []);\n }\n\n /**\n * A plugin may have the 'target' option. Currently we use three\n * targets: toolbar, left and right. Toolbar means it's a\n * plugin that will be visible in Drawer list. Left and right\n * are Widget plugins, that on large displays show on left/right\n * side of the map viewport, while on small screens change its\n * appearance and end up as Drawer list plugins too.\n *\n * This method filters out those plugins that should go into\n * the Drawer or Widget list and returns them.\n *\n * It is used in AppModel to initiate all plugins' Components,\n * so whatever is returned here will result in a render() for\n * that plugin. That is the reason why 'search' is filtered out\n * from the results: we render Search plugin separately in App,\n * and we don't want a second render invoked from here.\n *\n * @returns array of Plugins\n * @memberof AppModel\n */\n getBothDrawerAndWidgetPlugins() {\n const r = this.getPlugins()\n .filter((plugin) => {\n return [\"toolbar\", \"left\", \"right\", \"control\", \"hidden\"].includes(\n plugin.options.target\n );\n })\n .sort((a, b) => a.sortOrder - b.sortOrder);\n return r;\n }\n\n getDrawerPlugins() {\n return this.getPlugins().filter((plugin) => {\n return [\"toolbar\"].includes(plugin.options.target);\n });\n }\n\n /**\n * Dynamically load plugins from the configured plugins folder.\n * Assumed that a folder exists with the same name as the requested plugin.\n * There must also be a file present with the same name as well.\n * @param {Array} - List of plugins to be loaded.\n * @returns {Array} - List of promises to be resolved for.\n */\n loadPlugins(plugins) {\n const promises = [];\n plugins.forEach((plugin) => {\n const dir = [\"Search\"].includes(plugin) ? \"components\" : \"plugins\";\n const prom = import(`../${dir}/${plugin}/${plugin}.js`)\n .then((module) => {\n const toolConfig =\n this.config.mapConfig.tools.find(\n (plug) => plug.type.toLowerCase() === plugin.toLowerCase()\n ) || {};\n\n const toolOptions =\n toolConfig && toolConfig.options ? toolConfig.options : {};\n\n const sortOrder = toolConfig.hasOwnProperty(\"index\")\n ? Number(toolConfig.index)\n : 0;\n\n if (Object.keys(toolConfig).length > 0) {\n this.addPlugin(\n new Plugin({\n map: this.map,\n app: this,\n type: plugin.toLowerCase(),\n searchInterface: {},\n sortOrder: sortOrder,\n options: toolOptions,\n component: module.default,\n })\n );\n }\n })\n .catch((err) => {\n console.error(err);\n });\n promises.push(prom);\n });\n return promises;\n }\n\n /**\n * Initialize open layers map\n * @return {ol.Map} map\n */\n createMap() {\n const config = this.translateConfig();\n\n // Prepare OL interactions options, refer to https://openlayers.org/en/latest/apidoc/module-ol_interaction.html#.defaults.\n // We use conditional properties to ensure that only existing keys are set. The rest\n // will fallback to defaults from OL. (The entire interactionsOptions object, as well as all its properties are optional\n // according to OL documentation, so there's no need to set stuff that won't be needed.)\n const interactionsOptions = {\n ...(config.map.hasOwnProperty(\"altShiftDragRotate\") && {\n altShiftDragRotate: config.map.altShiftDragRotate,\n }),\n ...(config.map.hasOwnProperty(\"onFocusOnly\") && {\n onFocusOnly: config.map.onFocusOnly,\n }),\n ...(config.map.hasOwnProperty(\"doubleClickZoom\") && {\n doubleClickZoom: config.map.doubleClickZoom,\n }),\n ...(config.map.hasOwnProperty(\"keyboard\") && {\n keyboard: config.map.keyboard,\n }),\n ...(config.map.hasOwnProperty(\"mouseWheelZoom\") && {\n mouseWheelZoom: config.map.mouseWheelZoom,\n }),\n ...(config.map.hasOwnProperty(\"shiftDragZoom\") && {\n shiftDragZoom: config.map.shiftDragZoom,\n }),\n ...(config.map.hasOwnProperty(\"dragPan\") && {\n dragPan: config.map.dragPan,\n }),\n ...(config.map.hasOwnProperty(\"pinchRotate\") && {\n pinchRotate: config.map.pinchRotate,\n }),\n ...(config.map.hasOwnProperty(\"pinchZoom\") && {\n pinchZoom: config.map.pinchZoom,\n }),\n ...(!Number.isNaN(Number.parseInt(config.map.zoomDelta)) && {\n zoomDelta: config.map.zoomDelta,\n }),\n ...(!Number.isNaN(Number.parseInt(config.map.zoomDuration)) && {\n zoomDuration: config.map.zoomDuration,\n }),\n };\n\n this.map = new Map({\n controls: [\n // new FullScreen({ target: document.getElementById(\"controls-column\") }),\n // new Rotate({ target: document.getElementById(\"controls-column\") }),\n // new MousePosition({\n // target: document.querySelector(\"#root > div > footer\")\n // }),\n // new OverviewMap({\n // target: document.querySelector(\"#root > div > footer\"),\n // view: new View({\n // projection: config.map.projection\n // })\n // })\n ],\n interactions: defaultInteractions(interactionsOptions),\n layers: [],\n target: config.map.target,\n overlays: [],\n view: new View({\n center: config.map.center,\n extent: config.map.extent.length > 0 ? config.map.extent : undefined, // backend will always write extent as an Array, so basic \"config.map.extent || undefined\" wouldn't work here\n constrainOnlyCenter: config.map.constrainOnlyCenter, // If true, the extent constraint will only apply to the view center and not the whole extent.\n constrainResolution: config.map.constrainResolution, // If true, the view will always animate to the closest zoom level after an interaction; false means intermediary zoom levels are allowed.\n maxZoom: config.map.maxZoom || 24,\n minZoom: config.map.minZoom || 0,\n projection: config.map.projection,\n resolutions: config.map.resolutions,\n units: \"m\",\n zoom: config.map.zoom,\n }),\n });\n\n // Create throttled zoomEnd event\n let currentZoom = this.map.getView().getZoom();\n\n this.map.on(\"moveend\", (e) => {\n // using moveend to create a throttled zoomEnd event\n // instead of using change:resolution to minimize events being fired.\n const newZoom = this.map.getView().getZoom();\n if (currentZoom !== newZoom) {\n this.globalObserver.publish(\"core.zoomEnd\", { zoom: newZoom });\n currentZoom = newZoom;\n }\n });\n\n // Add Snap Helper to the Map\n this.map.snapHelper = new SnapHelper(this);\n\n // Add the clickLock set. Its primary use is to disable infoclick action\n // when some other plugin (such as Draw or Measure) is active (in that case\n // we want the plugin to handle click - not to show infoclick).\n // It's easy to think that this is only needed if Infoclick plugin is active\n // in map config - but that is not the case:\n // A lot of plugins rely on the 'clickLock' property to exist on Map,\n // and to be a Set (we use .has()).\n // So, we create the Set no matter what:\n this.map.clickLock = new Set();\n\n // FIXME: Potential miss here: don't we want to register click on search results\n // But we register the Infoclick handler only if the plugin exists in map config:\n // even if Infoclick plugin is inactive? Currently search won't register clicks in\n // map without infoclick, which seems as an unnecessary limitation.\n if (config.tools.some((tool) => tool.type === \"infoclick\")) {\n bindMapClickEvent(this.map, (mapClickDataResult) => {\n // We have to separate features coming from the searchResult-layer\n // from the rest, since we want to render this information in the\n // search-component rather than in the featureInfo-component.\n const searchResultFeatures = mapClickDataResult.features.filter(\n (feature) => {\n return feature?.layer.get(\"type\") === \"searchResultLayer\";\n }\n );\n const infoclickFeatures = mapClickDataResult.features.filter(\n (feature) => {\n return feature?.layer.get(\"type\") !== \"searchResultLayer\";\n }\n );\n\n // If there are any results from search layer, send an event about that.\n if (searchResultFeatures.length > 0) {\n this.globalObserver.publish(\n \"infoClick.searchResultLayerClick\",\n searchResultFeatures // Clicked features sent to the search-component for display\n );\n }\n\n // Do the same for regular infoclick results from WMS layers\n if (infoclickFeatures.length > 0) {\n // Note that infoclick.mapClick seems to have a different interface…\n this.globalObserver.publish(\"infoClick.mapClick\", {\n ...mapClickDataResult, // as it requires the entire object, not just \"features\", like infoClick.searchResultLayerClick.\n features: infoclickFeatures, // Hence, we send everything from mapClickDataResult, but replace the features property.\n });\n }\n });\n }\n return this;\n }\n\n getMap() {\n return this.map;\n }\n\n addSearchModel() {\n // TODO: Move configuration somewhere else, shouldn't be plugin-dependent.\n\n // See if Search is configured in map config\n const searchConfigIndex = this.config.mapConfig.tools.findIndex(\n (t) => t.type === \"search\"\n );\n\n // If it is, go on and add the search model to App model\n if (searchConfigIndex !== -1) {\n this.searchModel = new SearchModel(\n this.config.mapConfig.tools[searchConfigIndex].options,\n this.getMap(),\n this\n );\n }\n\n // Either way, return self, so we can go on and chain more methods on App model\n return this;\n }\n\n clear() {\n this.clearing = true;\n this.highlight(false);\n this.map\n .getLayers()\n .getArray()\n .forEach((layer) => {\n if (\n layer.getProperties &&\n layer.getProperties().layerInfo &&\n layer.getProperties().layerInfo.layerType === \"layer\"\n ) {\n if (layer.layerType === \"group\") {\n this.globalObserver.publish(\"layerswitcher.hideLayer\", layer);\n } else {\n layer.setVisible(false);\n }\n }\n });\n setTimeout(() => {\n this.clearing = false;\n }, 100);\n }\n\n addMapLayer(layer) {\n const configMapper = new ConfigMapper(this.config.appConfig.proxy);\n let layerItem, layerConfig;\n switch (layer.type) {\n case \"wms\":\n layerConfig = configMapper.mapWMSConfig(layer, this.config);\n layerItem = new WMSLayer(\n layerConfig.options,\n this.config.appConfig.proxy,\n this.globalObserver\n );\n this.map.addLayer(layerItem.layer);\n break;\n case \"wmts\":\n layerConfig = configMapper.mapWMTSConfig(layer, this.config);\n layerItem = new WMTSLayer(\n layerConfig.options,\n this.config.appConfig.proxy,\n this.map\n );\n this.map.addLayer(layerItem.layer);\n break;\n case \"vector\":\n layerConfig = configMapper.mapVectorConfig(layer);\n layerItem = new WFSVectorLayer(\n layerConfig.options,\n this.config.appConfig.proxy,\n this.map\n );\n this.map.addLayer(layerItem.layer);\n break;\n // case \"arcgis\":\n // layerConfig = configMapper.mapArcGISConfig(layer);\n // layer = new ArcGISLayer(layerConfig);\n // break;\n // case \"data\":\n // layerConfig = configMapper.mapDataConfig(layer);\n // layer = new DataLayer(layerConfig);\n // break;\n default:\n break;\n }\n }\n\n lookup(layers, type) {\n var matchedLayers = [];\n layers.forEach((layer) => {\n const layerConfig = this.config.layersConfig.find(\n (lookupLayer) => lookupLayer.id === layer.id\n );\n layer.layerType = type;\n // Use the general value for infobox if not present in map config.\n if (layerConfig !== undefined && layerConfig.type === \"vector\") {\n if (!layer.infobox && layerConfig) {\n layer.infobox = layerConfig.infobox;\n }\n }\n matchedLayers.push({\n ...layerConfig,\n ...layer,\n });\n });\n return matchedLayers;\n }\n\n expand(groups) {\n var result = [];\n groups.forEach((group) => {\n result = [...result, ...group.layers];\n if (group.groups) {\n result = [...result, ...this.expand(group.groups)];\n }\n });\n return result;\n }\n\n flattern(layerSwitcherConfig) {\n const layers = [\n ...this.lookup(layerSwitcherConfig.options.baselayers, \"base\"),\n ...this.lookup(this.expand(layerSwitcherConfig.options.groups), \"layer\"),\n ];\n\n return layers;\n }\n\n addLayers() {\n const layerSwitcherConfig = this.config.mapConfig.tools.find(\n (tool) => tool.type === \"layerswitcher\"\n ),\n infoclickConfig = this.config.mapConfig.tools.find(\n (t) => t.type === \"infoclick\"\n );\n\n // Prepare layers\n this.layers = this.flattern(layerSwitcherConfig);\n // FIXME: Use map instead?\n Object.keys(this.layers)\n .sort((a, b) => this.layers[a].drawOrder - this.layers[b].drawOrder)\n .map((sortedKey) => this.layers[sortedKey])\n .forEach((layer) => {\n if (this.layersFromParams.length > 0) {\n layer.visibleAtStart = this.layersFromParams.some(\n (layerId) => layerId === layer.id\n );\n }\n layer.cqlFilter = this.cqlFiltersFromParams[layer.id] || null;\n this.addMapLayer(layer);\n });\n\n // FIXME: Move to infoClick instead. All other plugins create their own layers.\n if (infoclickConfig !== undefined) {\n this.addHighlightLayer(infoclickConfig.options);\n }\n\n return this;\n }\n\n addHighlightLayer(options) {\n const { anchor, scale, src, strokeColor, strokeWidth, fillColor } = options;\n const strokeColorAsArray = strokeColor && [\n strokeColor.r,\n strokeColor.g,\n strokeColor.b,\n strokeColor.a,\n ];\n const fillColorAsArray = fillColor && [\n fillColor.r,\n fillColor.g,\n fillColor.b,\n fillColor.a,\n ];\n this.highlightSource = new VectorSource();\n this.highlightLayer = new VectorLayer({\n source: this.highlightSource,\n style: new Style({\n stroke: new Stroke({\n color: strokeColorAsArray || [200, 0, 0, 0.7],\n width: strokeWidth || 4,\n }),\n fill: new Fill({\n color: fillColorAsArray || [255, 0, 0, 0.1],\n }),\n image: new Icon({\n anchor: [anchor[0] || 0.5, anchor[1] || 1],\n scale: scale || 0.15,\n src: src || \"marker.png\",\n }),\n }),\n });\n this.map.addLayer(this.highlightLayer);\n }\n\n getCenter(e) {\n return [e[0] + Math.abs(e[2] - e[0]) / 2, e[1] + Math.abs(e[3] - e[1]) / 2];\n }\n\n highlight(feature) {\n if (this.highlightSource) {\n this.highlightSource.clear();\n if (feature) {\n this.highlightSource.addFeature(feature);\n if (window.innerWidth < 600) {\n let geom = feature.getGeometry();\n if (geom) {\n this.map.getView().setCenter(this.getCenter(geom.getExtent()));\n }\n }\n }\n }\n }\n\n /**\n * @summary Merges two objects.\n *\n * @param {*} mapConfig\n * @param {*} urlSearchParams\n * @returns {*} a Result of overwriting a with values from b\n * @memberof AppModel\n */\n mergeConfig(mapConfig, urlSearchParams) {\n // clean is used to strip the UI of all elements so we get a super clean viewport back, without any plugins\n const clean =\n Boolean(urlSearchParams.hasOwnProperty(\"clean\")) &&\n urlSearchParams.clean !== \"false\" &&\n urlSearchParams.clean !== \"0\";\n\n // f contains our CQL Filters\n const f = urlSearchParams.f;\n\n // Merge query params to the map config from JSON\n let x = parseFloat(urlSearchParams.x),\n y = parseFloat(urlSearchParams.y),\n z = parseInt(urlSearchParams.z, 10),\n l = undefined;\n if (typeof urlSearchParams.l === \"string\") {\n l = urlSearchParams.l.split(\",\");\n }\n\n if (Number.isNaN(x)) {\n x = mapConfig.map.center[0];\n }\n if (Number.isNaN(y)) {\n y = mapConfig.map.center[1];\n }\n if (Number.isNaN(z)) {\n z = mapConfig.map.zoom;\n }\n\n mapConfig.map.clean = clean;\n mapConfig.map.center[0] = x;\n mapConfig.map.center[1] = y;\n mapConfig.map.zoom = z;\n\n if (l) {\n this.layersFromParams = l;\n }\n\n if (f) {\n // Filters come as a URI encoded JSON object, so we must parse it first\n this.cqlFiltersFromParams = JSON.parse(decodeURIComponent(f));\n }\n\n return mapConfig;\n }\n /**\n * @summary If supplied argument, v, is a string and is longer then 0, return an encoded value of v. Else return undefined.\n *\n * @param {*} v\n * @returns\n * @memberof AppModel\n */\n returnStringOrUndefined(v) {\n return typeof v === \"string\" && v.trim().length > 0 ? v : undefined;\n }\n\n overrideGlobalSearchConfig(searchTool, wfslayers) {\n const configSpecificSearchLayers = searchTool.options.layers;\n const searchLayers = wfslayers.filter((layer) => {\n if (configSpecificSearchLayers.find((x) => x.id === layer.id)) {\n return layer;\n } else {\n return undefined;\n }\n });\n return searchLayers;\n }\n\n overrideGlobalEditConfig(editTool, wfstlayers) {\n const configSpecificEditLayers = editTool.options.activeServices;\n const editLayers = wfstlayers.filter((layer) => {\n if (configSpecificEditLayers.find((x) => x.id === layer.id)) {\n return layer;\n } else {\n return undefined;\n }\n });\n return editLayers;\n }\n\n translateConfig() {\n if (\n this.config.mapConfig.hasOwnProperty(\"map\") &&\n this.config.mapConfig.map.hasOwnProperty(\"title\")\n ) {\n document.title = this.config.mapConfig.map.title; // TODO: add opt-out in admin to cancel this override behaviour.\n }\n\n const layerSwitcherTool = this.config.mapConfig.tools.find((tool) => {\n return tool.type === \"layerswitcher\";\n });\n\n const searchTool = this.config.mapConfig.tools.find((tool) => {\n return tool.type === \"search\";\n });\n\n const editTool = this.config.mapConfig.tools.find((tool) => {\n return tool.type === \"edit\";\n });\n\n let layers = {};\n\n if (layerSwitcherTool) {\n layers.wmslayers = this.config.layersConfig.wmslayers || [];\n layers.wfslayers = this.config.layersConfig.wfslayers || [];\n layers.wfstlayers = this.config.layersConfig.wfstlayers || [];\n layers.wmtslayers = this.config.layersConfig.wmtslayers || [];\n layers.vectorlayers = this.config.layersConfig.vectorlayers || [];\n layers.arcgislayers = this.config.layersConfig.arcgislayers || [];\n\n layers.wmslayers.forEach((l) => (l.type = \"wms\"));\n layers.wmtslayers.forEach((l) => (l.type = \"wmts\"));\n layers.wfstlayers.forEach((l) => (l.type = \"edit\"));\n layers.vectorlayers.forEach((l) => (l.type = \"vector\"));\n layers.arcgislayers.forEach((l) => (l.type = \"arcgis\"));\n\n let allLayers = [\n ...layers.wmslayers,\n ...layers.wmtslayers,\n ...layers.vectorlayers,\n ...layers.wfstlayers,\n ...layers.arcgislayers,\n ];\n\n this.config.layersConfig = allLayers;\n }\n\n if (searchTool) {\n // Take a look at all available wfslayers in layers repository,\n // but let the search tool only see those that are specified in searchTool.options\n const wfslayers = this.overrideGlobalSearchConfig(\n searchTool,\n layers.wfslayers\n );\n\n // See if admin wants to expose any WMS layers. selectedSources will\n // in that case be an array that will hold the IDs of corresponding layers\n // (that can be found in our layers.wmslayers array). In there, a properly\n // configured WMS layer that is to be searchable will have certain search-related\n // settings active (such as name of the geometry column or URL to the WFS service).\n const wmslayers = searchTool.options.selectedSources?.flatMap(\n (wmslayerId) => {\n // Find the corresponding layer\n const layer = layers.wmslayers.find((l) => l.id === wmslayerId);\n\n // Look into the layersInfo array - it will contain sublayers. We must\n // expose each one of them as a WFS service.\n return layer.layersInfo.map((sl) => {\n return {\n id: sl.id,\n pid: layer.id, // Relevant for group layers: will hold the actual OL layer name, not only current sublayer\n caption: sl.caption,\n url: sl.searchUrl || layer.url,\n layers: [sl.id],\n searchFields:\n typeof sl.searchPropertyName === \"string\"\n ? sl.searchPropertyName.split(\",\")\n : [],\n infobox: sl.infobox || \"\",\n aliasDict: \"\",\n displayFields:\n typeof sl.searchDisplayName === \"string\"\n ? sl.searchDisplayName.split(\",\")\n : [],\n shortDisplayFields:\n typeof sl.searchShortDisplayName === \"string\"\n ? sl.searchShortDisplayName.split(\",\")\n : [],\n geometryField: sl.searchGeometryField || \"geom\",\n outputFormat: sl.searchOutputFormat || \"GML3\",\n serverType: layer.serverType || \"geoserver\",\n };\n });\n }\n );\n\n // Spread the WMS search layers onto the array with WFS search sources,\n // from now on they're equal to our code.\n Array.isArray(wmslayers) && wfslayers.push(...wmslayers);\n\n searchTool.options.sources = wfslayers;\n }\n\n // This is for backwards compatibility prior to adding locking WFST edit layers with AD.\n // This code handles if activeServices does not have an object with \"id\", \"visibleForGroups\"\n if (editTool) {\n if (editTool.options.activeServices === null) {\n editTool.options.sources = [];\n } else {\n if (\n editTool.options.activeServices &&\n editTool.options.activeServices.length !== 0\n ) {\n if (\n typeof editTool.options.activeServices[0].visibleForGroups ===\n \"undefined\"\n ) {\n // If activeService does not have an object with \"id\", \"visibleForGroups\", add it\n let as = [];\n for (let i = 0; i < editTool.options.activeServices.length; i++) {\n let service = {\n id: editTool.options.activeServices[i],\n visibleForGroups: [],\n };\n as.push(service);\n }\n editTool.options.activeServices = as;\n }\n\n let wfstlayers = this.overrideGlobalEditConfig(\n editTool,\n layers.wfstlayers\n );\n editTool.options.sources = wfstlayers;\n layers.wfstlayers = wfstlayers;\n } else {\n editTool.options.sources = [];\n }\n }\n }\n\n return this.mergeConfig(\n this.config.mapConfig,\n Object.fromEntries(new URLSearchParams(document.location.search))\n );\n }\n}\n\nexport default AppModel;\n","import { GeoJSON, WFS } from \"ol/format\";\nimport GML2 from \"ol/format/GML2\";\nimport GML3 from \"ol/format/GML3\";\nimport GML32 from \"ol/format/GML32\";\n\nimport IsLike from \"ol/format/filter/IsLike\";\nimport Or from \"ol/format/filter/Or\";\nimport And from \"ol/format/filter/And\";\nimport Intersects from \"ol/format/filter/Intersects\";\nimport Within from \"ol/format/filter/Within\";\nimport { fromCircle } from \"ol/geom/Polygon\";\n\n// import { arraySort } from \"../utils/ArraySort\";\nimport { decodeCommas } from \"../utils/StringCommaCoder\";\nimport { hfetch } from \"utils/FetchWrapper\";\n\nconst ESCAPE_CHAR = \"!\";\nconst SINGLE_CHAR = \".\";\nconst WILDCARD_CHAR = \"*\";\n\nclass SearchModel {\n // Public field declarations (why? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Defining_classes)\n\n // Private fields (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields#Private_fields)\n #searchOptions = {\n activeSpatialFilter: \"intersects\", // Make it possible to control which filter is used\n featuresToFilter: [], // features, who's geometries will be read and used to limit the search extent\n maxResultsPerDataset: 100, // how many results to get (at most), per dataset\n matchCase: false, // should search be case sensitive?\n wildcardAtStart: false, // should the search string start with the wildcard character?\n wildcardAtEnd: true, // should the search string be end with the wildcard character?\n };\n\n #componentOptions;\n #searchSources;\n #map;\n #app;\n\n #controllers = []; // Holder Array for Promises' AbortControllers\n #wfsParser = new WFS();\n #possibleSearchCombinations = new Map(); // Will hold a set of possible search combinations, so we don't have to re-create them for each source\n\n constructor(searchPluginOptions, map, app) {\n // Validate\n if (!searchPluginOptions || !map || !app) {\n throw new Error(\n \"One of the required parameters for SearchModel is missing.\"\n );\n }\n\n this.#componentOptions = searchPluginOptions; // FIXME: Options, currently from search plugin\n this.#map = map; // The OpenLayers map instance\n this.#app = app; // Supplies appConfig and globalObserver\n this.#searchSources = this.#componentOptions.sources;\n }\n\n /**\n * @summary The main public method of the Search model. Ensures that the search string\n * is trimmed form whitespace and that the return value is standardized (object of collections and errors).\n *\n * @returns {Object} Contains feature collections and error\n *\n * @memberof SearchModel\n */\n getResults = async (\n searchString,\n searchSources = this.getSources(),\n searchOptions = this.getSearchOptions()\n ) => {\n const { featureCollections, errors } = await this.#getRawResults(\n searchString.trim(), // Ensure that the search string isn't surrounded by whitespace\n searchSources,\n searchOptions\n );\n\n return { featureCollections, errors };\n };\n\n abort = () => {\n if (this.#controllers.length > 0) {\n this.#controllers.forEach((controller) => {\n controller.abort();\n });\n }\n\n // Clean up our list of AbortControllers\n this.#controllers = [];\n return true;\n };\n\n getSearchOptions = () => {\n return this.#searchOptions;\n };\n\n getSources = () => {\n return this.#searchSources;\n };\n\n #getRawResults = async (\n searchString = \"\",\n searchSources = this.getSources(),\n searchOptions = null\n ) => {\n // If searchSources is explicitly provided as an empty Array, something's wrong. Abort.\n if (Array.isArray(searchSources) && searchSources.length === 0) {\n throw new Error(\"No search sources selected, aborting.\");\n }\n\n // If searchSources is something else than an Array, use the default search sources.\n if (Array.isArray(searchSources) === false) {\n console.warn(\"searchSources empty, resetting to default.\", searchSources);\n searchSources = this.getSources();\n }\n\n // Will hold our Promises, one for each search source\n const promises = [];\n\n // Will hold the end results\n let rawResults = null;\n\n // Ensure that we've cleaned obsolete AbortControllers before we put new ones there\n this.#controllers = [];\n\n const viewProjection = this.#map.getView().getProjection().getCode();\n\n // Loop through all defined search sources\n searchSources.forEach((searchSource) => {\n // Expect the Promise and an AbortController from each Source\n const { promise, controller } = this.#lookup(\n searchString,\n searchSource,\n searchOptions\n );\n\n // If #lookup returned actual Promise and Controller objects, push\n // them to our array of promises. Important that we don't push empty\n // values to the array, hence this check!\n if (promise !== null && controller !== null) {\n // Push promises to local Array so we can act when all Promises have resolved\n promises.push(promise);\n\n // Also, put AbortController to the global collection of controllers, so we can abort searches at any time\n this.#controllers.push(controller);\n }\n });\n\n // Start fetching, allow both fulfilled and rejected Promises\n const fetchResponses = await Promise.allSettled(promises);\n\n // fetchedResponses will be an array of Promises in object form.\n // Each object will have a \"status\" and a \"value\" property.\n const responsePromises = await Promise.allSettled(\n fetchResponses.map((fetchResponse, i) => {\n // We look at the status and filter out only those that fulfilled.\n if (fetchResponse.status === \"rejected\")\n return Promise.reject(\"Could not fetch\");\n // If we requested GeoJSON, we can try parsing it with\n // the Promise's body's .json() method.\n switch (searchSources[i].outputFormat) {\n case \"application/json\":\n case \"application/vnd.geo+json\":\n return fetchResponse.value.json();\n // Otherwise we should expect XML, which needs to be parsed\n // as text\n case \"GML2\":\n case \"GML3\":\n case \"GML32\":\n return fetchResponse.value.text();\n default:\n return Promise.reject(\"Output format now allowed\");\n }\n })\n );\n\n // Prepare two arrays that will hold our successful and\n // failed responses\n const successfulResponses = [];\n const errors = [];\n\n // Investigate each response and put in the correct collection,\n // depending on if it succeeded or failed.\n responsePromises.forEach((r, i) => {\n if (r.status === \"fulfilled\") {\n r.source = searchSources[i];\n r.origin = \"WFS\";\n successfulResponses.push(r);\n } else if ((r) => r.status === \"rejected\") {\n r.source = searchSources[i];\n r.origin = \"WFS\";\n errors.push(r);\n }\n });\n\n // Do some magic on our valid results\n successfulResponses.forEach((r) => {\n // FIXME: Investigate if this sorting is really needed, and if so,\n // if we can find some Unicode variant and not only for Swedish characters.\n // FIXME: NB: This can't be done like this as it only works for GeoJSON\n // responses. GML won't have an object assigned to r.value, so there won't\n // be any \"features\" that can be sorted like this (in GML response, the r.value\n // is a XML string).\n // if (r.value?.features?.length > 0) {\n // arraySort({\n // array: r.value.features,\n // index: r.source.searchFields[0],\n // });\n // }\n\n switch (r.source.outputFormat) {\n case \"application/json\":\n case \"application/vnd.geo+json\": {\n // If the CRS object is lacking in the GeoJSON response, we can\n // safely assume that the geometries are in the standard-compilant\n // WGS84 (EPSG:4326).\n const parserOptions = r.value.crs\n ? {}\n : {\n dataProjection: \"EPSG:4326\", //FIXME: Only valid for GeoJSON responses!\n featureProjection: viewProjection,\n };\n\n // Parse the GeoJSON object, optionally supplying the options if needed (see above ^)\n const olFeatures = new GeoJSON().readFeatures(r.value, parserOptions);\n r.value = { features: olFeatures };\n break;\n }\n case \"GML2\":\n case \"GML3\":\n case \"GML32\": {\n let parser = null;\n if (r.source.outputFormat === \"GML2\") {\n parser = new GML2();\n } else if (r.source.outputFormat === \"GML3\") {\n parser = new GML3();\n } else if (r.source.outputFormat === \"GML32\") {\n parser = new GML32();\n }\n const olFeatures = parser.readFeatures(r.value);\n r.value = { features: olFeatures };\n break;\n }\n\n default:\n throw new Error(\"Unknown output format\");\n }\n });\n\n // Return an object with out results and errors\n rawResults = { featureCollections: successfulResponses, errors };\n\n return rawResults;\n };\n\n #getOrFilter = (word, searchSource, searchOptions) => {\n let orFilter = new Or(\n ...searchSource.searchFields.map((searchField) => {\n return this.#getIsLikeFilter(searchField, word, searchOptions);\n })\n );\n return orFilter;\n };\n\n #getIsLikeFilter = (searchField, word, searchOptions) => {\n return new IsLike(\n searchField,\n word,\n WILDCARD_CHAR, // wildcard char\n SINGLE_CHAR, // single char\n ESCAPE_CHAR, // escape char\n searchOptions.matchCase // match case\n );\n };\n\n #getSearchFilters = (wordsArray, searchSource, searchOptions) => {\n if (searchSource.searchFields.length > 1) {\n let OrFilters = wordsArray.map((word) => {\n return this.#getOrFilter(word, searchSource, searchOptions);\n });\n if (OrFilters.length > 1) {\n return new And(...OrFilters);\n } else {\n return OrFilters[0];\n }\n } else {\n let isLikeFilters = wordsArray.map((word) => {\n return this.#getIsLikeFilter(\n searchSource.searchFields[0],\n word,\n searchOptions\n );\n });\n if (isLikeFilters.length > 1) {\n return new And(...isLikeFilters);\n } else {\n return isLikeFilters[0];\n }\n }\n };\n\n #getStringArray = (searchString) => {\n let tempStringArray = this.#splitAndTrimOnCommas(searchString);\n return tempStringArray.join(\" \").split(\" \");\n };\n\n #splitAndTrimOnCommas = (searchString) => {\n return searchString.split(\",\").map((string) => {\n return string.trim();\n });\n };\n\n #escapeSpecialChars = (string) => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"!$&\"); // $& means the whole matched string\n };\n\n getPossibleSearchCombinations = (searchString) => {\n // See if we've already created possible search combos for the specified string,\n // if so, do an early return\n if (this.#possibleSearchCombinations.has(searchString)) {\n return Array.from(this.#possibleSearchCombinations.get(searchString));\n }\n\n // Looks like the specified string hasn't been requested yet: let's create\n // an array of possible combos.\n const possibleSearchCombinations = new Set();\n const wordsInTextField = this.#getStringArray(searchString);\n const numWords = wordsInTextField.length;\n\n // If the string contains a comma, we must add the string as is\n // otherwise we might miss cases where the user wants to search\n // for a property with a comma.\n if (searchString.includes(\",\")) {\n possibleSearchCombinations.add([searchString]);\n }\n\n // If the user has typed more than five words, we only create\n // one string containing all words to avoid sending humongous\n // requests to geoServer.\n if (numWords > 5) {\n const joinedWord = wordsInTextField.join().replace(/,/g, \" \");\n possibleSearchCombinations.add([joinedWord]);\n return Array.from(possibleSearchCombinations);\n }\n\n possibleSearchCombinations.add(wordsInTextField);\n\n if (numWords > 1) {\n for (let i = 0; i < numWords; i++) {\n this.#getPossibleForwardCombinations(\n i,\n wordsInTextField,\n possibleSearchCombinations\n );\n }\n }\n\n // Let's save the results for later use - we don't want to re-create\n // the possible combos array for the same search string\n this.#possibleSearchCombinations.set(\n searchString,\n possibleSearchCombinations\n );\n\n return Array.from(possibleSearchCombinations);\n };\n\n #getPossibleForwardCombinations = (\n index,\n stringArray,\n possibleSearchCombinations\n ) => {\n const wordsBeforeCurrent = stringArray.slice(0, index);\n\n for (let ii = index; ii < stringArray.length - 1; ii++) {\n const currentWord = stringArray\n .slice(index, ii + 2)\n .join()\n .replace(/,/g, \" \");\n\n const wordsAfterCurrent = stringArray.slice(ii + 2);\n\n possibleSearchCombinations.add([\n ...wordsBeforeCurrent,\n currentWord,\n ...wordsAfterCurrent,\n ]);\n }\n };\n\n #addPotentialWildCards = (word, searchOptions) => {\n word = searchOptions.wildcardAtStart ? `*${word}` : word;\n word = searchOptions.wildcardAtEnd ? `${word}*` : word;\n return word;\n };\n\n #decodePotentialSpecialChars = (searchCombinations) => {\n return searchCombinations.map((combination) => {\n return combination.map((word) => {\n // Replace all occurrences of a backslash with 2 backslashes (which will be seen\n // by GeoServer as \"one escaped backslash\"). Hence the 4 backslashes in replacement string,\n // they are basically two escaped backslashes after each other.\n return decodeCommas(word).replace(/\\\\/g, \"\\\\\\\\\");\n });\n });\n };\n\n #lookup = (searchString, searchSource, searchOptions) => {\n const srsName = this.#map.getView().getProjection().getCode();\n const geometryName =\n searchSource.geometryField || searchSource.geometryName || \"geom\";\n const maxFeatures = searchOptions.maxResultsPerDataset;\n let comparisonFilters = null;\n let spatialFilters = null;\n let finalFilters = null;\n let possibleSearchCombinations = [];\n\n // In order to do a textual search, we must have both a search phrase\n // and at least one search field (else there's no way to know where to search!)\n if (searchString !== \"\" && searchSource.searchFields.length > 0) {\n if (searchOptions.getPossibleCombinations) {\n possibleSearchCombinations =\n this.getPossibleSearchCombinations(searchString);\n } else {\n possibleSearchCombinations.push(\n this.#splitAndTrimOnCommas(searchString)\n );\n }\n\n possibleSearchCombinations = this.#decodePotentialSpecialChars(\n possibleSearchCombinations\n );\n\n const searchFilters = possibleSearchCombinations.map((combination) => {\n let searchWordsForCombination = combination.map((wordInCombination) => {\n wordInCombination = this.#escapeSpecialChars(wordInCombination);\n wordInCombination = this.#addPotentialWildCards(\n wordInCombination,\n searchOptions\n );\n return wordInCombination;\n });\n return this.#getSearchFilters(\n searchWordsForCombination,\n searchSource,\n searchOptions\n );\n });\n\n comparisonFilters =\n searchFilters.length > 1 ? new Or(...searchFilters) : searchFilters[0];\n }\n\n // If searchOptions contain any features, we should filter the results\n // using those features.\n if (searchOptions.featuresToFilter.length > 0) {\n // First determine which spatial filter should be used:\n const activeSpatialFilter =\n searchOptions.activeSpatialFilter === \"within\" ? Within : Intersects;\n // Next, loop through supplied features and create the desired filter\n spatialFilters = searchOptions.featuresToFilter.map((feature) => {\n // If the drawn feature that we want to use as a filter happens to be an\n // OpenLayers Circle feature, we must convert it to a polygon. (GML only\n // accepts the following operands: Point, LineString, Polygon, Envelope.)\n // If it's not a Circle however, let's clone the geometry, to avoid\n // modifying the geometry that belongs to the feature that will be used\n // throughout the loop (see also \"Fix for QGIS\" below).\n const geometry =\n feature.getGeometry().getType() === \"Circle\"\n ? fromCircle(feature.getGeometry())\n : feature.getGeometry().clone();\n\n // Fix for QGIS Server: for some unknown reasons QGIS doesn't want the Polygon\n // to be closed. We fix it by basically removing the last two elements of the\n // flatCoordinates array, effectively eliminating the last point of the polygon.\n // See also: https://github.com/hajkmap/Hajk/issues/882#issuecomment-956099289\n searchSource.serverType === \"qgis\" &&\n geometry.flatCoordinates.splice(-2, 2);\n return new activeSpatialFilter(geometryName, geometry, srsName);\n });\n\n // If one feature was supplied, we end up with one filter. Let's use it.\n // But if more features were supplied, we must combine them into an Or filter.\n spatialFilters =\n spatialFilters.length > 1\n ? new Or(...spatialFilters)\n : spatialFilters[0];\n }\n\n // Finally, let's combine the text and spatial filters into\n // one filter that will be sent with the request.\n if (comparisonFilters !== null && spatialFilters !== null) {\n // We have both text and spatial filters - let's combine them with an And filter.\n finalFilters = new And(comparisonFilters, spatialFilters);\n } else if (comparisonFilters !== null) {\n finalFilters = comparisonFilters;\n } else if (spatialFilters !== null) {\n finalFilters = spatialFilters;\n }\n\n // Before we actually send a fetch request, we must ensure\n // that it won't be empty, i.e. we must have at least one filter.\n // The reason where this can be empty is if _user tries to do a\n // textual search on a layer that lacks searchFields_. Those layers\n // are still usable (we don't need to defined searchFields for spatial\n // searches), so admins may have setup a layer like this. And in that\n // case, it's crucial that we don't do a GetFeature to the WFS that doesn't\n // contain any filters.\n // The return value of this method must be an object that contains a promise\n // and controller property (because the return value is used in a destruction\n // assignment later on), hence this odd return, instead of just a null value.\n if (finalFilters === null) {\n return { promise: null, controller: null };\n }\n\n // Prepare the options for the upcoming request.\n const options = {\n featureTypes: searchSource.layers,\n srsName: srsName,\n outputFormat: searchSource.outputFormat,\n geometryName: geometryName,\n maxFeatures: maxFeatures,\n filter: finalFilters,\n };\n\n const node = this.#wfsParser.writeGetFeature(options);\n const xmlSerializer = new XMLSerializer();\n const xmlString = xmlSerializer.serializeToString(node);\n const controller = new AbortController();\n const signal = controller.signal;\n\n const request = {\n credentials: \"same-origin\",\n signal: signal,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"text/xml\",\n },\n body: xmlString,\n };\n const promise = hfetch(\n this.#app.config.appConfig.searchProxy + searchSource.url,\n request\n );\n\n return { promise, controller };\n };\n}\n\nexport default SearchModel;\n","class Plugin {\n constructor(spec) {\n this.searchInterface = spec.searchInterface;\n this.map = spec.map;\n this.app = spec.app;\n this.type = spec.type;\n this.options = spec.options;\n this.component = spec.component;\n this.sortOrder = spec.sortOrder || 0;\n }\n}\n\nexport default Plugin;\n","import { Projection } from \"ol/proj\";\n\nexport default class ConfigMapper {\n constructor(proxy) {\n this.proxy = proxy;\n }\n\n mapWMSConfig(args, properties) {\n function getLegendUrl(layer) {\n let legendUrl = \"\";\n\n // If there's no legend URL specified, we'll need to get it from our WMS\n if (args.legend === \"\") {\n /**\n * A layer can have multiple styles, so when getting Legend Graphic, it's important\n * to get it for the currently selected style.\n */\n\n // First get index if we're dealing with array\n let getIndex =\n args.layersInfo !== null\n ? args.layersInfo.findIndex((l) => l.id === layer)\n : null;\n // Next, use that index to grab correct style and save its name for later use\n let style =\n args.layersInfo !== null &&\n getIndex >= 0 &&\n args.layersInfo[getIndex].style;\n\n let geoserverLegendOptions = \"\";\n let qgisOptions = \"\";\n\n if (args.serverType === \"geoserver\") {\n /**\n * GeoServer allows finer control over the legend appearance via the vendor parameter LEGEND_OPTIONS.\n * See: https://docs.geoserver.org/latest/en/user/services/wms/get_legend_graphic/index.html#controlling-legend-appearance-with-legend-options\n */\n // Use custom legend options if specified by admin\n geoserverLegendOptions = properties.mapConfig.map.hasOwnProperty(\n \"geoserverLegendOptions\"\n )\n ? \"&LEGEND_OPTIONS=\" +\n properties.mapConfig.map.geoserverLegendOptions\n : \"\";\n }\n\n // QGIS Server requires the SERVICE parameter to be set, see issue #880.\n if (args.serverType === \"qgis\") {\n qgisOptions = \"&SERVICE=WMS\";\n }\n\n // If layers URL already includes a query string separator (ie question mark), we want\n // to append the remaining values with &.\n const theGlue = args.url.includes(\"?\") ? \"&\" : \"?\";\n\n legendUrl = `${proxy}${args.url}${theGlue}REQUEST=GetLegendGraphic&VERSION=1.0.0&FORMAT=image/png&LAYER=${layer}&STYLE=${style}${geoserverLegendOptions}${qgisOptions}`;\n }\n // If there's a legend URL specified in admin, use it as is\n else {\n legendUrl = args.legend;\n }\n\n // If 'legend' URL doesn't start with \"http\", add \"https://\" prior 'legend', else let it be as is\n const protocol = /^http/.test(legendUrl) ? \"\" : \"https://\";\n return protocol + legendUrl;\n }\n\n function getLegends() {\n return args.layers.map((layer) => {\n return {\n url: getLegendUrl(layer),\n description: \"Teckenförklaring\",\n };\n });\n }\n\n function mapLayersInfo(layersInfo, infobox) {\n if (Array.isArray(layersInfo)) {\n return layersInfo.reduce((layersInfoObject, layerInfo) => {\n layersInfoObject[layerInfo.id] = layerInfo;\n if (!layerInfo.legend) {\n layersInfoObject[layerInfo.id].legend = getLegendUrl(layerInfo.id);\n }\n if (infobox?.length) {\n layersInfoObject[layerInfo.id].infobox = infobox;\n }\n\n return layersInfoObject;\n }, {});\n }\n }\n\n let proxy = this.proxy || \"\";\n\n // We can not assume that args.projection is sat,\n // and if it's not, we should fall back to map config's projection.\n let projection =\n args.projection !== null\n ? args.projection\n : properties.mapConfig.map.projection;\n\n // WMS 1.3.0 requires a custom Projection object, as we need to specify 'axisOrientation'\n if (args.version === \"1.3.0\") {\n // Create a new Projection\n let projCode = projection;\n projection = new Projection({\n code: projCode,\n axisOrientation: \"neu\",\n extent: properties.mapConfig.map.extent,\n });\n }\n\n // In the GetMap operation the srs parameter is called crs in 1.3.0,\n // see: https://docs.geoserver.org/latest/en/user/services/wms/basics.html#differences-between-wms-versions\n const srsOrCrs = args.version === \"1.3.0\" ? \"CRS\" : \"SRS\";\n\n if (args.minZoom === 0 && args.maxZoom === 0) {\n // backend returns 0 if not set in past\n args.minZoom = undefined;\n args.maxZoom = undefined;\n }\n\n let config = {\n type: \"wms\",\n options: {\n id: args.id,\n url: (this.proxy || \"\") + args.url,\n name: args.id, // FIXME: Should this be \"args.caption\"?\n layerType: args.layerType,\n caption: args.caption,\n visible: args.visibleAtStart,\n opacity: args.opacity || 1,\n maxZoom: args.maxZoom,\n minZoom: args.minZoom,\n minMaxZoomAlertOnToggleOnly: args.minMaxZoomAlertOnToggleOnly,\n infoClickSortType: args.infoClickSortType,\n infoClickSortDesc: args.infoClickSortDesc,\n infoClickSortProperty: args.infoClickSortProperty,\n information: args.infobox,\n resolutions: properties.mapConfig.map.allResolutions,\n projection: projection || \"EPSG:3006\",\n origin: properties.mapConfig.map.origin,\n extent: properties.mapConfig.map.extent,\n singleTile: args.singleTile || false,\n hidpi: args.hidpi,\n customRatio: args.customRatio,\n imageFormat: args.imageFormat || \"image/png\",\n serverType:\n args.serverType === \"arcgis\"\n ? \"mapserver\"\n : args.serverType || \"geoserver\",\n crossOrigin: properties.mapConfig.map.crossOrigin || \"anonymous\",\n attribution: args.attribution,\n searchUrl: args.searchUrl,\n searchPropertyName: args.searchPropertyName,\n searchDisplayName: args.searchDisplayName,\n searchShortDisplayName: args.searchShortDisplayName,\n searchOutputFormat: args.searchOutputFormat,\n searchGeometryField: args.searchGeometryField,\n legend: getLegends(),\n legendIcon: args.legendIcon,\n params: {\n LAYERS: args.layers.join(\",\"),\n ...(args.cqlFilter && { CQL_FILTER: args.cqlFilter }), // nice way to add property only if needed\n FORMAT: args.imageFormat,\n INFO_FORMAT: args.infoFormat,\n VERSION: args.version || \"1.1.1\",\n [srsOrCrs]: projection || \"EPSG:3006\",\n TILED: args.tiled,\n STYLES: Array.isArray(args.layersInfo)\n ? args.layersInfo.map((l) => l.style || \"\").join(\",\")\n : null,\n },\n layersInfo: mapLayersInfo(args.layersInfo, args.infobox),\n infoVisible: args.infoVisible || false,\n infoTitle: args.infoTitle,\n infoText: args.infoText,\n infoUrl: args.infoUrl,\n infoUrlText: args.infoUrlText,\n infoOwner: args.infoOwner,\n hideExpandArrow: args.hideExpandArrow,\n timeSliderStart: args.timeSliderStart,\n timeSliderEnd: args.timeSliderEnd,\n },\n };\n\n if (args.searchFields && args.searchFields[0]) {\n config.options.search = {\n url: (this.proxy || \"\") + args.url.replace(\"wms\", \"wfs\"),\n featureType:\n args.layers[0].split(\":\")[1] || args.layers[0].split(\":\")[0],\n propertyName: args.searchFields.join(\",\"),\n displayName: args.displayFields\n ? args.displayFields\n : args.searchFields[0] || \"Sökträff\",\n srsName: properties.mapConfig.map.projection || \"EPSG:3006\",\n serverType: config.options.serverType,\n };\n }\n\n return config;\n }\n\n mapWMTSConfig(args, properties) {\n if (args.minZoom === 0 && args.maxZoom === 0) {\n args.minZoom = undefined;\n args.maxZoom = undefined;\n }\n\n var config = {\n type: \"wmts\",\n options: {\n id: args.id,\n name: args.id,\n layerType: args.layerType,\n caption: args.caption,\n visible: args.visibleAtStart !== false,\n extent: properties.mapConfig.map.extent,\n queryable: false,\n opacity: args.opacity || 1,\n maxZoom: args.maxZoom,\n minZoom: args.minZoom,\n format: \"image/png\",\n crossOrigin: properties.mapConfig.map.crossOrigin || \"anonymous\",\n wrapX: false,\n url: args.url,\n layer: args.layer,\n matrixSet: args.matrixSet,\n style: args.style,\n projection: args.projection,\n origin: args.origin,\n resolutions: args.resolutions,\n matrixIds: args.matrixIds,\n attribution: args.attribution,\n legend: args.legend,\n legendIcon: args.legendIcon,\n infoVisible: args.infoVisible || false,\n infoTitle: args.infoTitle,\n infoText: args.infoText,\n infoUrl: args.infoUrl,\n infoUrlText: args.infoUrlText,\n infoOwner: args.infoOwner,\n hideExpandArrow: args.hideExpandArrow,\n timeSliderStart: args.timeSliderStart,\n timeSliderEnd: args.timeSliderEnd,\n },\n };\n return config;\n }\n\n mapDataConfig(args) {\n var config = {\n type: \"data\",\n options: {\n id: args.id,\n url: (this.proxy || \"\") + args.url,\n name: args.id,\n layerType: args.layerType,\n caption: args.caption,\n visible: args.visibleAtStart,\n opacity: 1,\n queryable: args.queryable !== false,\n extent: args.extent,\n projection: args.projection,\n },\n };\n\n return config;\n }\n\n mapVectorConfig(args) {\n var config = {\n type: \"vector\",\n options: {\n attribution: args.attribution,\n caption: args.caption,\n content: args.content,\n dataFormat: args.dataFormat,\n filterable: args.filterable,\n filterAttribute: args.filterAttribute,\n filterComparer: args.filterComparer,\n filterValue: args.filterValue,\n icon: args.legend,\n id: args.id,\n infoOwner: args.infoOwner,\n information: args.infobox,\n infoText: args.infoText,\n infoTitle: args.infoTitle,\n infoUrl: args.infoUrl,\n infoUrlText: args.infoUrlText,\n infoVisible: args.infoVisible || false,\n infoClickSortType: args.infoClickSortType,\n infoClickSortDesc: args.infoClickSortDesc,\n infoClickSortProperty: args.infoClickSortProperty,\n layerType: args.layerType,\n legend: [\n {\n url: args.legend,\n description: args.caption,\n },\n ],\n legendIcon: args.legendIcon,\n maxZoom: args.maxZoom,\n minZoom: args.minZoom,\n name: args.id,\n opacity: args.opacity,\n params: {\n service: \"WFS\",\n request: \"GetFeature\",\n version: args.version || \"1.1.0\",\n outputFormat:\n args.dataFormat === \"GeoJSON\" // If GeoJSON,\n ? \"application/json\" // set correct outputFormat (see https://docs.geoserver.org/latest/en/user/services/wfs/outputformats.html)\n : args.version === \"1.0.0\" // else (if dataFormat is not GeoJSON), check which WFS version we have and\n ? \"GML2\" // use the GML2 parser for WFS 1.0.0, or\n : \"GML3\", // GML3 for version > 1.0.0 (again, see above link).\n typename: args.layer,\n srsname: args.projection,\n bbox: \"\",\n },\n projection: args.projection,\n queryable: args.queryable,\n sldStyle: args.sldStyle,\n sldText: args.sldText,\n sldUrl: args.sldUrl,\n url: args.url,\n visible: args.visibleAtStart,\n timeSliderStart: args.timeSliderStart,\n timeSliderEnd: args.timeSliderEnd,\n },\n };\n\n return config;\n }\n\n mapArcGISConfig(args) {\n function getLegendUrl() {\n if (!Array.isArray(args.legend)) {\n if (/^data/.test(args.legend)) {\n args.legend = args.legend.split(\"#\");\n } else if (!/^http/.test(args.legend)) {\n args.legend = \"https://\" + args.legend;\n }\n }\n return args.legend;\n }\n\n var config = {\n type: \"arcgis\",\n options: {\n id: args.id,\n url: args.url,\n name: args.id,\n layerType: args.layerType,\n caption: args.caption,\n visible: args.visibleAtStart,\n queryable: args.queryable !== false,\n singleTile: args.singleTile !== false,\n extent: args.extent,\n information: args.infobox,\n projection: args.projection,\n opacity: args.opacity,\n attribution: args.attribution,\n params: {\n LAYERS: \"show:\" + args.layers.join(\",\"),\n },\n legend: [\n {\n url: getLegendUrl(args),\n description: \"Teckenförklaring\",\n },\n ],\n infoVisible: args.infoVisible || false,\n infoTitle: args.infoTitle,\n infoText: args.infoText,\n infoUrl: args.infoUrl,\n infoUrlText: args.infoUrlText,\n infoOwner: args.infoOwner,\n hideExpandArrow: args.hideExpandArrow,\n timeSliderStart: args.timeSliderStart,\n timeSliderEnd: args.timeSliderEnd,\n },\n };\n\n return config;\n }\n}\n","import proj4 from \"proj4\";\n\nfunction add(projection) {\n proj4.defs(projection.code, projection.definition);\n}\n\nexport default class CoordinateSystemLoader {\n constructor(config) {\n if (Array.isArray(config)) {\n config.forEach((projection) => {\n add(projection);\n });\n }\n }\n\n getProj4() {\n return proj4;\n }\n}\n","import TileGrid from \"ol/tilegrid/TileGrid\";\nimport ImageLayer from \"ol/layer/Image\";\nimport TileLayer from \"ol/layer/Tile\";\nimport ImageWMS from \"ol/source/ImageWMS\";\nimport TileWMS from \"ol/source/TileWMS\";\nimport GeoJSON from \"ol/format/GeoJSON\";\nimport LayerInfo from \"./LayerInfo.js\";\nimport { equals } from \"ol/extent\";\nimport { delay } from \"../../utils/Delay\";\nimport { hfetch, overrideLayerSourceParams } from \"utils/FetchWrapper\";\n\nclass WMSLayer {\n constructor(config, proxyUrl, globalObserver) {\n this.proxyUrl = proxyUrl;\n this.globalObserver = globalObserver;\n this.validInfo = true;\n this.legend = config.legend;\n this.attribution = config.attribution;\n this.layerInfo = new LayerInfo(config);\n this.subLayers = config.params[\"LAYERS\"].split(\",\");\n\n let source = {\n url: config.url,\n params: config.params,\n projection: config.projection,\n serverType: config.serverType,\n crossOrigin: config.crossOrigin,\n imageFormat: config.imageFormat,\n attributions: config.attribution,\n cacheSize: this.subLayers.length > 1 ? 32 : 2048,\n transition: this.subLayers.length > 1 ? 0 : 100,\n };\n\n if (config.hidpi !== null) {\n source.hidpi = config.hidpi;\n }\n\n overrideLayerSourceParams(source);\n\n const minZoom = config?.minZoom >= 0 ? config.minZoom : undefined;\n const maxZoom = config?.maxZoom >= 0 ? config.maxZoom : undefined;\n\n if (\n config.resolutions &&\n config.resolutions.length > 0 &&\n config.origin &&\n config.origin.length > 0\n ) {\n source.tileGrid = new TileGrid({\n resolutions: config.resolutions,\n origin: config.origin,\n });\n source.extent = config.extent;\n }\n\n if (config.singleTile) {\n if (config.customRatio >= 1) {\n source.ratio = config.customRatio;\n }\n this.layer = new ImageLayer({\n name: config.name,\n visible: config.visible,\n caption: config.caption,\n opacity: config.opacity,\n source: new ImageWMS(source),\n layerInfo: this.layerInfo,\n url: config.url,\n timeSliderStart: config?.timeSliderStart,\n timeSliderEnd: config?.timeSliderEnd,\n minZoom: minZoom,\n maxZoom: maxZoom,\n minMaxZoomAlertOnToggleOnly:\n config.minMaxZoomAlertOnToggleOnly || false,\n });\n } else {\n this.layer = new TileLayer({\n name: config.name,\n visible: config.visible,\n caption: config.caption,\n opacity: config.opacity,\n source: new TileWMS(source),\n layerInfo: this.layerInfo,\n url: config.url,\n timeSliderStart: config?.timeSliderStart,\n timeSliderEnd: config?.timeSliderEnd,\n minZoom: minZoom,\n maxZoom: maxZoom,\n minMaxZoomAlertOnToggleOnly:\n config.minMaxZoomAlertOnToggleOnly || false,\n });\n }\n\n this.layer.layersInfo = config.layersInfo;\n this.layer.subLayers = this.subLayers;\n this.layer.layerType = this.getLayerType();\n this.layer.getSource().set(\"url\", config.url);\n this.type = \"wms\";\n this.bindHandlers();\n }\n\n // If the layerType is set as a base-layer in the config-mapper,\n // it should be kept as a base-layer, *even if it has sub-layers*.\n // The old behavior (before this commit) was that the base-layer was\n // \"transformed\" to a \"group-layer\" if it had more than one subLayer.\n // Since base-layers might be constructed with several subLayers, we\n // shouldn't do that transformation... If the baseLayer is transformed\n // to a \"group-layer\" we will get several errors, since the baseLayers\n // does not contain all necessary information to render a \"group-layer\".\n getLayerType() {\n // Destruct the layerType from the layerInfo\n const { layerType } = this.layerInfo;\n // Check if the type is set to \"base\", and if it is,\n // return \"base\". If it is not, we check if we have more than\n // one subLayer; if we do, we return \"group\", and otherwise it is\n // a regular \"layer\".\n return layerType === \"base\"\n ? \"base\"\n : this.subLayers.length > 1\n ? \"group\"\n : \"layer\";\n }\n\n /**\n * Bind handlers for TileWMS and ImageWMS\n * @instance\n */\n bindHandlers() {\n const layerSource = this.layer.getSource();\n if (layerSource instanceof TileWMS) {\n layerSource.on(\"tileloaderror\", this.onTileLoadError);\n layerSource.on(\"tileloadend\", this.onTileLoadOk);\n }\n if (layerSource instanceof ImageWMS) {\n layerSource.on(\"imageloaderror\", this.onImageError);\n }\n }\n\n /**\n * Triggers when a tile fails to load.\n * @instance\n */\n onTileLoadError = () => {\n this.globalObserver.publish(\"layerswitcher.wmsLayerLoadStatus\", {\n id: this.layer.get(\"name\"),\n status: \"loaderror\",\n });\n };\n\n /**\n * Triggers when a tile loads.\n * @instance\n */\n onTileLoadOk = () => {\n this.globalObserver.publish(\"layerswitcher.wmsLayerLoadStatus\", {\n id: this.layer.get(\"name\"),\n status: \"ok\",\n });\n };\n\n /**\n * If we get an error while loading Image we try to refresh it once per extent.\n * This check is needed because we don't want to get stuck in an endless loop in case image repeatedly fails\n * @instance\n */\n onImageError = async (e) => {\n const layerSource = this.layer.getSource();\n const previousErrorExtent = e.target.get(\"previousErrorExtent\") || [];\n const currentErrorExtent = e.image.extent;\n if (!equals(previousErrorExtent, currentErrorExtent)) {\n await delay(300); //Delay refresh of layers who caused error to not throttle the canvas and get new errors\n layerSource.refresh();\n }\n e.target.set(\"previousErrorExtent\", currentErrorExtent);\n };\n\n /**\n * Load feature information.\n * @instance\n * @param {external:\"ol.feature\"} feature\n * @return {external:\"ol.style\"} style\n */\n getFeatureInformation(params) {\n try {\n this.validInfo = true;\n this.featureInformationCallback = params.success;\n\n let url = this.getLayer()\n .getSource()\n .getFeatureInfoUrl(\n params.coordinate,\n params.resolution,\n params.projection,\n {\n INFO_FORMAT:\n this.get(\"serverType\") === \"arcgis\" ||\n this.get(\"serverType\") === \"mapserver\"\n ? \"application/geojson\"\n : \"application/json\",\n feature_count: 100,\n }\n );\n\n if (url) {\n if (this.proxyUrl) {\n url = encodeURIComponent(url);\n }\n\n hfetch(this.proxyUrl + url)\n .then((response) => {\n response.json().then((data) => {\n var features = new GeoJSON().readFeatures(data);\n this.featureInformationCallback(features, this.getLayer());\n });\n })\n .catch((err) => {\n params.error(err);\n });\n }\n } catch (e) {\n params.error(e);\n }\n }\n\n /**\n * Get legend url.\n * @instance\n * @param {string} layerName\n * @return {object} legend\n */\n getLegendUrl(layerName) {\n var legend = Object.assign({}, this.legend);\n legend[0].Url = legend[0].Url.replace(/LAYER=.*/, \"LAYER=\" + layerName);\n return legend;\n }\n}\n\n/**\n * WmsLayer module.<br>\n * Use <code>require('layer/wmslayer')</code> for instantiation.\n * @module WMSLayer-module\n * @returns {WMSLayer}\n */\nexport default WMSLayer;\n","import View from \"ol/View\";\nimport TileLayer from \"ol/layer/Tile\";\nimport WMTS from \"ol/source/WMTS\";\nimport WMTSTileGrid from \"ol/tilegrid/WMTS\";\nimport LayerInfo from \"./LayerInfo.js\";\nimport { overrideLayerSourceParams } from \"utils/FetchWrapper\";\n\nvar wmtsLayerProperties = {\n url: \"\",\n projection: \"EPSG:3006\",\n layer: \"\",\n opacity: 1,\n matrixSet: \"3006\",\n style: \"default\",\n axisMode: \"natural\",\n origin: [-1200000, 8500000],\n resolutions: [4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0.5],\n matrixIds: [\n \"0\",\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"10\",\n \"11\",\n \"12\",\n ],\n attribution: \"\",\n};\n\nclass WMTSLayer {\n constructor(config, proxyUrl, map) {\n config = {\n ...wmtsLayerProperties,\n ...config,\n };\n this.proxyUrl = proxyUrl;\n this.map = map;\n this.resolutions = this.resolutions = config.resolutions.map((r) =>\n Number(r)\n );\n this.projection = config.projection;\n\n let source = {\n attributions: config.attribution,\n format: \"image/png\",\n wrapX: false,\n url: config.url,\n crossOrigin: config.crossOrigin,\n axisMode: config.axisMode,\n layer: config.layer,\n matrixSet: config.matrixSet,\n style: config.style,\n projection: this.projection,\n tileGrid: new WMTSTileGrid({\n origin: config.origin.map((o) => Number(o)),\n resolutions: this.resolutions,\n matrixIds: config.matrixIds,\n extent: config.extent,\n }),\n };\n\n overrideLayerSourceParams(source);\n\n const minZoom = config?.minZoom >= 0 ? config.minZoom : undefined;\n const maxZoom = config?.maxZoom >= 0 ? config.maxZoom : undefined;\n\n this.layer = new TileLayer({\n name: config.name,\n visible: config.visible,\n queryable: config.queryable,\n opacity: config.opacity,\n source: new WMTS(source),\n layerInfo: new LayerInfo(config),\n minZoom: minZoom,\n maxZoom: maxZoom,\n });\n this.updateMapViewResolutions();\n this.type = \"wmts\";\n }\n\n updateMapViewResolutions() {\n var view = this.map.getView();\n this.map.setView(\n new View({\n zoom: view.getZoom(),\n center: view.getCenter(),\n resolutions: this.resolutions,\n projection: this.projection,\n })\n );\n }\n}\n\nexport default WMTSLayer;\n","import VectorSource from \"ol/source/Vector\";\nimport VectorLayer from \"ol/layer/Vector\";\nimport GeoJSON from \"ol/format/GeoJSON\";\nimport GML2 from \"ol/format/GML2\";\nimport GML3 from \"ol/format/GML3\";\nimport WFS from \"ol/format/WFS\";\nimport { all as strategyAll, bbox as bboxStrategy } from \"ol/loadingstrategy\";\nimport { getPointResolution, transform } from \"ol/proj\";\n\nimport * as SLDReader from \"@nieuwlandgeo/sldreader\";\n\nimport LayerInfo from \"./LayerInfo.js\";\nimport { hfetch } from \"utils/FetchWrapper\";\n\nconst vectorLayerProperties = {\n url: \"\",\n params: {\n service: \"WFS\",\n version: \"1.1.0\",\n request: \"GetFeature\",\n typename: \"\",\n outputFormat: \"GML3\",\n srsname: \"\",\n bbox: \"\",\n },\n showLabels: true,\n};\n\nclass WFSVectorLayer {\n constructor(config, proxyUrl, map) {\n this.config = {\n ...vectorLayerProperties,\n ...config,\n };\n this.proxyUrl = proxyUrl;\n this.map = map;\n\n this.type = \"vector\"; // We're dealing with a vector layer\n\n this.allFeatures = [];\n\n // Read the three filter properties from config to allow filter on load\n this.filterAttribute = config.filterAttribute;\n this.filterComparer = config.filterComparer;\n this.filterValue = config.filterValue;\n\n this.vectorSource = new VectorSource({\n // Ensure we display copyright attributions\n attributions: config.attribution,\n // Loader function makes \"url\" and \"format\" parameters ignored as it\n // provides an own loading procedure. \"strategy\" is still respected, see below.\n loader: (extent, resolution, projection) => {\n this.loadData(this.createUrl(extent, projection.getCode()));\n },\n // The loading strategy to use. By default the BBox strategy is used,\n // loading features based on the view's extent and resolution.\n strategy:\n this.config?.loadingStrategy === \"all\" ? strategyAll : bboxStrategy,\n });\n\n // if (config.legend[0].url === \"\") {\n // this.generateLegend((imageData) => {\n // config.legend[0].url = imageData;\n // });\n // }\n\n this.layer = new VectorLayer({\n information: config.information,\n caption: config.caption,\n name: config.name,\n visible: config.visible,\n opacity: config.opacity,\n queryable: config.queryable,\n filterable: config.filterable,\n filterAttribute: config.filterAttribute,\n filterComparer: config.filterComparer,\n filterValue: config.filterValue,\n layerInfo: new LayerInfo(config),\n renderMode: \"image\",\n source: this.vectorSource,\n url: config.url,\n featureType: config.params.typename.split(\":\")[1],\n minZoom: config?.minZoom >= 0 ? config.minZoom : undefined,\n maxZoom: config?.maxZoom >= 0 ? config.maxZoom : undefined,\n timeSliderStart: config?.timeSliderStart,\n timeSliderEnd: config?.timeSliderEnd,\n });\n\n // Styling section starts here.\n // First read some values from config\n this.sldUrl = config?.sldUrl;\n this.sldText = config?.sldText;\n this.sldStyle = config?.sldStyle ?? \"Default Styler\";\n\n // Try fetching the URL, if specified, and style with the resulting SLD\n if (typeof this.sldUrl === \"string\" && this.sldUrl.trim().length > 0) {\n hfetch(this.sldUrl)\n .then((response) => response.text())\n .then((text) => this.applySldTextOnLayer(text));\n }\n // …else used supplied SLD text to style\n else if (\n typeof this.sldText === \"string\" &&\n this.sldText.trim().length > 10\n ) {\n this.applySldTextOnLayer(this.sldText);\n } // …or just fall back to OpenLayer's default styling if no SLD/SLD URL was specified.\n }\n\n applySldTextOnLayer = (text) => {\n const sldObject = SLDReader.Reader(text);\n const sldLayer = SLDReader.getLayer(sldObject);\n const style = SLDReader.getStyle(sldLayer, this.sldStyle);\n const featureTypeStyle = style.featuretypestyles[0];\n\n const viewProjection = this.map.getView().getProjection();\n const olFunction = SLDReader.createOlStyleFunction(featureTypeStyle, {\n // Use the convertResolution option to calculate a more accurate resolution.\n convertResolution: (viewResolution) => {\n const viewCenter = this.map.getView().getCenter();\n return getPointResolution(viewProjection, viewResolution, viewCenter);\n },\n // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback to\n // to update the vector layer when an image finishes loading.\n // If you do not do this, the image will only become visible after the next pan/zoom of the layer.\n imageLoadedCallback: () => {\n this.layer.changed();\n },\n });\n this.layer.setStyle(olFunction);\n };\n\n reprojectFeatures(features, from, to) {\n if (Array.isArray(features)) {\n features.forEach((feature) => {\n if (feature.getGeometry() && feature.getGeometry().getCoordinates) {\n let coords = feature.getGeometry().getCoordinates();\n try {\n switch (feature.getGeometry().getType()) {\n case \"Point\":\n feature\n .getGeometry()\n .setCoordinates(transform(coords, from, to));\n break;\n case \"LineString\":\n feature\n .getGeometry()\n .setCoordinates(\n coords.map((coord) => transform(coord, from, to))\n );\n break;\n case \"Polygon\":\n feature\n .getGeometry()\n .setCoordinates([\n coords[0].map((coord) => transform(coord, from, to)),\n ]);\n break;\n default:\n throw new Error(\"Unknown geometry type.\");\n }\n } catch (e) {\n console.error(\"Coordinate transformation error.\", e);\n }\n }\n });\n }\n }\n\n getAllFeatures(data) {\n let features = [];\n let parser = null;\n const to = this.map.getView().getProjection().getCode();\n const from = this.config.projection;\n const outputFormat = this.config.params.outputFormat;\n\n if (outputFormat.startsWith(\"GML\")) {\n // If output format starts with GML, create a GML parser.\n // For WFS version 1.0.0 the GML2 parser should be used,\n // else GML3.\n parser = new WFS({\n gmlFormat:\n this.config.params.version === \"1.0.0\" ? new GML2() : new GML3(),\n });\n }\n\n if (outputFormat === \"application/json\") {\n parser = new GeoJSON();\n }\n\n if (parser) {\n features = parser.readFeatures(data);\n }\n\n if (to !== from) {\n this.reprojectFeatures(features, from, to);\n }\n\n return features;\n }\n\n /**\n * @summary If filtering is activated, filter feature collection, f. Else return all features.\n *\n * @param {*} f Feature collection to be filtered.\n * @returns\n * @memberof WFSVectorLayer\n */\n getFilteredFeatures(f) {\n if (this.layer.get(\"filterAttribute\") && this.layer.get(\"filterValue\")) {\n return f.filter((feature) => this.filterMethod(feature));\n } else {\n return f;\n }\n }\n\n /**\n * @summary A predicate method (returns either true of false), used to determine\n * whether current feature should be included in the filtered result.\n *\n * @param {*} feature Feature to check.\n * @returns {boolean}\n * @memberof WFSVectorLayer\n */\n filterMethod(feature) {\n const filterAttribute = this.layer.get(\"filterAttribute\");\n const filterValue = this.layer.get(\"filterValue\");\n const filterComparer = this.layer.get(\"filterComparer\");\n\n switch (filterComparer) {\n case \"gt\":\n return (\n Number(feature.getProperties()[filterAttribute]) > Number(filterValue)\n );\n case \"lt\":\n return (\n Number(feature.getProperties()[filterAttribute]) < Number(filterValue)\n );\n case \"eq\":\n if (!Number.isNaN(Number(filterValue))) {\n return (\n Number(feature.getProperties()[filterAttribute]) ===\n Number(filterValue)\n );\n }\n return feature.getProperties()[filterAttribute] === filterValue;\n case \"not\":\n if (!Number.isNaN(Number(filterValue))) {\n return (\n Number(feature.getProperties()[filterAttribute]) !==\n Number(filterValue)\n );\n }\n return feature.getProperties()[filterAttribute] !== filterValue;\n default:\n return false;\n }\n }\n\n createUrl(extent = [], projection = \"\") {\n // Grab params needed for URL creation\n const props = this.config.params;\n\n // Get rid of bbox that comes from config\n delete props.bbox;\n\n // Turn params into URLSearchParams string\n const usp = new URLSearchParams(props).toString();\n\n // If extent doesn't contain Infinity values, append it to the URL\n const bbox =\n extent.length === 4 && extent.includes(Infinity) === false\n ? `&bbox=${extent.join(\",\")},${projection}`\n : \"\";\n\n const url = this.config.url + \"?\" + usp + bbox;\n return url;\n }\n\n loadData(url) {\n url = this.proxyUrl + url;\n\n hfetch(url).then((response) => {\n response.text().then((features) => {\n // Load all features (no filter active - only bbox limitation)\n this.allFeatures = this.getAllFeatures(features);\n\n // See if filtering is needed and populate the source with resulting features\n this.vectorSource.addFeatures(\n this.getFilteredFeatures(this.allFeatures)\n );\n });\n });\n }\n\n // getStyle(forcedPointRadius) {\n // if (forcedPointRadius) {\n // return createStyle.call(this, undefined, forcedPointRadius);\n // }\n // return this.style;\n // }\n\n // generateLegend(callback) {\n // var url = this.proxyUrl + this.createUrl();\n // fetch(url).then((response) => {\n // response.text().then((gmlText) => {\n // const parser = new GML2();\n // const features = parser.readFeatures(gmlText);\n // const canvas = document.createElement(\"canvas\");\n\n // const scale = 120;\n // const padding = 1 / 5;\n // const pointRadius = 15;\n\n // const vectorContext = toContext(canvas.getContext(\"2d\"), {\n // size: [scale, scale],\n // });\n // const style = this.getStyle(pointRadius)[0];\n // vectorContext.setStyle(style);\n\n // var featureType = \"Point\";\n // if (features.length > 0) {\n // featureType = features[0].getGeometry().getType();\n // }\n\n // switch (featureType) {\n // case \"Point\":\n // case \"MultiPoint\":\n // vectorContext.drawGeometry(new Point([scale / 2, scale / 2]));\n // break;\n // case \"Polygon\":\n // case \"MultiPolygon\":\n // vectorContext.drawGeometry(\n // new Polygon([\n // [\n // [scale * padding, scale * padding],\n // [scale * padding, scale - scale * padding],\n // [scale - scale * padding, scale - scale * padding],\n // [scale - scale * padding, scale * padding],\n // [scale * padding, scale * padding],\n // ],\n // ])\n // );\n // break;\n // case \"LineString\":\n // case \"MultiLineString\":\n // vectorContext.drawGeometry(\n // new LineString([\n // [scale * padding, scale - scale * padding],\n // [scale - scale * padding, scale * padding],\n // ])\n // );\n // break;\n // default:\n // break;\n // }\n // callback(canvas.toDataURL());\n // });\n // });\n // }\n}\n\nexport default WFSVectorLayer;\n","import Snap from \"ol/interaction/Snap\";\n\nexport default class SnapHelper {\n constructor(app) {\n this.map = app.map;\n this.globalObserver = app.globalObserver;\n\n this.snapInteractions = []; // Will hold snap interactions\n\n // Initiate a new set that will hold active plugins\n this.activePlugins = new Set();\n\n // Initiate a variable that keeps track of pending updates\n this.updatePending = false;\n\n // When layer visibility is changed, check if there was a\n // vector source. If so, refresh the snap interactions to\n // reflect the visibility change.\n this.globalObserver.on(\n \"core.layerVisibilityChanged\",\n this.#handleLayerVisibilityChanged\n );\n }\n /**\n * @summary Adds a given plugin to the set of plugins interested of\n * snap interaction. As long as this set isn't empty, Snap helper knows\n * that interactions should be added.\n *\n * @param {string} plugin\n * @memberof SnapHelper\n */\n add(plugin) {\n // If this is the first plugin that wants to activate Snap,\n // ensure that we add the interactions to map. Else, they've\n // already been added and there's no need to do it again.\n this.activePlugins.size === 0 && this.#addSnapToAllVectorSources();\n\n // Add the plugin to our stack\n this.activePlugins.add(plugin);\n }\n /**\n * @summary Does the opposite of add() by deleting a plugin from the Set.\n * When the set is empty, Snap helper knows that no one is interested in snapping\n * anyway, and it can remove all snap interactions (when the last plugin leaves the list).\n *\n * @param {string} plugin\n * @memberof SnapHelper\n */\n delete(plugin) {\n this.activePlugins.delete(plugin);\n\n // If there are no active plugins left, remove interactions\n this.activePlugins.size === 0 && this.#removeAllSnapInteractions();\n }\n /**\n * @summary Helper used to determine if a given source is ol.VectorSource.\n * @description Ideally, we would look into the prototype, to see if\n * constructor.name is \"VectorSource\". But, because Webpack uglifies the\n * class names, we can't do that. This is the best I came up with regarding\n * finding out whether the source appears to be a vector source or not: we\n * look for the getFeatures() method. It only exists on vector sources, so\n * it should be safe to use this way.\n *\n * @param {object} source\n * @returns {*} isVectorSource\n */\n #isVectorSource = (source) => {\n return typeof source[\"getFeatures\"] === \"function\";\n };\n\n /**\n * @summary Called when a layer's visibility is changed. Ensures that\n * snapping is always enabled for all visible vector sources.\n *\n * @param {*} e Event that contains the layer who's visibility has changed.\n */\n #handleLayerVisibilityChanged = (e) => {\n if (\n this.activePlugins.size === 0 || // Abort if no plugin is interested of snap interactions\n this.updatePending === true || // Abort if there already is a pending update\n this.#isVectorSource(e.target.getSource()) === false // Abort if event was triggered on a non-vector source\n )\n return;\n\n // Switch the pending flag to true, this will avoid multiple invokations\n this.updatePending = true;\n\n // After 250 ms…\n setTimeout(() => {\n // Reload sources\n this.#removeAllSnapInteractions();\n this.#addSnapToAllVectorSources();\n // Reset the flag\n this.updatePending = false;\n }, 250);\n };\n\n #addSnapToAllVectorSources = () => {\n const vectorSources = this.map\n .getLayers() // Get layers\n .getArray() // as arrays\n .filter((l) => l.getVisible()) // and only currently visible.\n .map((l) => l.getSource()) // Get each layer's source\n .filter(this.#isVectorSource); // but only if it is a VectorSource (which we'll know by checking for \"getFeatures\").\n\n // Add the snap interaction for each found source\n vectorSources.forEach((source) => {\n const snap = new Snap({\n source,\n });\n this.map.addInteraction(snap);\n\n // And save each interaction into a local stack (so we can remove them later)\n this.snapInteractions.push(snap);\n });\n };\n\n #removeAllSnapInteractions = () => {\n if (this.snapInteractions.length === 0) return;\n\n // Loop through the local stack of snap interactions\n for (const i of this.snapInteractions) {\n // And remove each one of them from the map\n this.map.removeInteraction(i);\n }\n\n // Important: purge the local stack!\n this.snapInteractions = [];\n };\n}\n","import React from \"react\";\nimport propTypes from \"prop-types\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport ArrowLeftIcon from \"@material-ui/icons/ArrowLeft\";\nimport ArrowRightIcon from \"@material-ui/icons/ArrowRight\";\nimport FeaturePropsParsing from \"./FeaturePropsParsing\";\n// import Diagram from \"../Diagram\";\n// import HajkTable from \"../Table\";\nimport {\n Table,\n TableContainer,\n CircularProgress,\n TableRow,\n TableCell,\n TableBody,\n Button,\n Typography,\n Grid,\n} from \"@material-ui/core\";\n\nconst styles = (theme) => ({\n toggler: {\n backgroundColor: theme.palette.primary.main,\n },\n infoContainer: {\n height: \"100%\",\n cursor: \"auto\",\n userSelect: \"text\",\n },\n typography: {\n textAlign: \"center\",\n },\n columnValue: {\n wordBreak: \"break-all\",\n },\n columnKey: {\n verticalAlign: \"top\",\n },\n featureInfoContainer: {\n flex: \"auto\",\n },\n featureInfo: {\n width: \"100%\",\n },\n togglerButtonRightContainer: {\n borderRight: `${theme.spacing(0.2)}px solid ${theme.palette.divider}`,\n },\n togglerButtonLeftContainer: {\n borderLeft: `${theme.spacing(0.2)}px solid ${theme.palette.divider}`,\n },\n});\n\nclass FeatureInfoContainer extends React.PureComponent {\n state = {\n selectedIndex: 0,\n };\n\n static propTypes = {\n classes: propTypes.object.isRequired,\n features: propTypes.array.isRequired,\n onDisplay: propTypes.func.isRequired,\n };\n\n constructor(props) {\n super(props);\n this.featurePropsParsing = new FeaturePropsParsing({\n globalObserver: props.globalObserver,\n options: props.options,\n });\n }\n\n componentDidMount() {\n this.updateFeatureInformation(0);\n }\n\n showFeatureInMap = () => {\n const { onDisplay, features } = this.props;\n onDisplay(features[this.state.selectedIndex]);\n };\n\n stepLeft = () => {\n if (this.state.selectedIndex - 1 > -1) {\n let newIndex = this.state.selectedIndex - 1;\n this.updateFeatureInformation(newIndex);\n }\n };\n\n stepRight = () => {\n const { features } = this.props;\n if (this.state.selectedIndex + 1 < features.length) {\n let newIndex = this.state.selectedIndex + 1;\n this.updateFeatureInformation(newIndex);\n }\n };\n\n getToggler = () => {\n const { features, classes } = this.props;\n return (\n <Grid\n alignItems=\"center\"\n justify=\"space-between\"\n className={classes.toggler}\n container\n >\n <Grid item className={classes.togglerButtonRightContainer}>\n <Button\n fullWidth\n disabled={this.state.selectedIndex - 1 < 0}\n onClick={this.stepLeft}\n aria-label=\"previous\"\n id=\"step-left\"\n >\n <ArrowLeftIcon color=\"secondary\" />\n </Button>\n </Grid>\n <Grid item>\n <Typography\n variant=\"button\"\n color=\"secondary\"\n className={classes.typography}\n >\n {this.state.selectedIndex + 1} av {features.length}\n </Typography>\n </Grid>\n <Grid item className={classes.togglerButtonLeftContainer}>\n <Button\n fullWidth\n disabled={this.state.selectedIndex + 1 >= features.length}\n onClick={this.stepRight}\n aria-label=\"next\"\n id=\"step-right\"\n >\n <ArrowRightIcon color=\"secondary\" />\n </Button>\n </Grid>\n </Grid>\n );\n };\n\n getFeaturesAsDefaultTable(data, caption) {\n const { classes } = this.props;\n // We can't use \"i\" for coloring every second row, as some rows\n // will be removed (Objects are not printed), so there's a need\n // for a separate counter of rows that actually get printed.\n let j = 0;\n const tableBody = Object.keys(data).map((key, i) => {\n if (typeof data[key] !== \"object\") {\n ++j;\n return (\n <TableRow key={i} selected={j % 2 === 0}>\n <TableCell className={classes.columnKey} variant=\"head\">\n {key}\n </TableCell>\n <TableCell className={classes.columnValue}>{data[key]}</TableCell>\n </TableRow>\n );\n } else {\n return null;\n }\n });\n\n return (\n <TableContainer component=\"div\">\n <Table size=\"small\" aria-label=\"Table with infoclick details\">\n <TableBody>{tableBody}</TableBody>\n </Table>\n </TableContainer>\n );\n }\n\n // shortcode(str) {\n // const codes = [];\n // let shortcodes = str.match(/\\[(.*?)\\]/g);\n // shortcodes = shortcodes === null ? [] : shortcodes;\n\n // if (shortcodes) {\n // shortcodes.forEach((code) => {\n // str = str.replace(code, \"\");\n // var params = code.replace(\"[\", \"\").replace(\"]\", \"\").split(\" \");\n // var c = {};\n\n // params.forEach((param, i) => {\n // if (i === 0) {\n // c.shortcode = param;\n // } else {\n // let parts = param.split(\"=\");\n // c[parts[0]] = param.replace(parts[0] + \"=\", \"\").replace(/\"/g, \"\");\n // }\n // });\n // codes.push(c);\n // });\n // return {\n // str: str,\n // codes: codes,\n // };\n // } else {\n // return;\n // }\n // }\n\n getMarkdownFromLocalInfoBox = (feature, layer, markdown) => {\n // Same goes for infobox, I'm shortening the code significantly using the optional chaining.\n // Features coming from search result have infobox set on Feature instead of Layer due to\n // different features sharing same vector layer.\n return (\n feature?.infobox ||\n feature.layer?.layersInfo?.[layer]?.infobox ||\n markdown\n );\n };\n\n getAGSCompatibleLayer = (feature) => {\n return Object.keys(feature.layer.layersInfo).find((id) => {\n const fid = feature.getId().split(\".\")[0];\n const layerId = id.split(\":\").length === 2 ? id.split(\":\")[1] : id;\n return fid === layerId;\n });\n };\n\n getFeatureProperties = (feature) => {\n let properties = feature.getProperties();\n properties = this.featurePropsParsing.extractPropertiesFromJson(properties);\n feature.setProperties(properties);\n return properties;\n };\n\n async updateFeatureInformation(newIndex) {\n let feature = this.props.features[newIndex];\n const layerInfo = feature.layer.get(\"layerInfo\");\n\n let markdown = layerInfo?.information,\n caption = layerInfo?.caption,\n layer,\n shortcodes = [];\n\n //Problem with geojson returned from AGS - Missing id on feature - how to handle?\n if (feature.layer.layersInfo && feature.getId()) {\n layer = this.getAGSCompatibleLayer(feature);\n }\n\n // Deal with layer groups that have a caption on sublayer. Layer groups will\n // have a 'layersInfo' (NB pluralis on layerSInfo), and if it exists,\n // let's overwrite the previously saved caption.\n // Below I'm using the new optional chaining operator (\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining),\n // which will return the new caption, if exists, or a falsy value. If falsy value is returned,\n // just fall back to the previous value of caption.\n caption = feature.layer?.layersInfo?.[layer]?.caption || caption;\n markdown = this.getMarkdownFromLocalInfoBox(feature, layer, markdown);\n\n // Disabled shortcodes for now as they mess with Markdown tags\n // for Links and Imgs that use \"[\" and \"]\".\n // if (markdown) {\n // let transformed = this.shortcode(markdown);\n // if (transformed) {\n // shortcodes = transformed.codes;\n // markdown = transformed.str;\n // }\n // }\n\n this.setState({ loading: true });\n\n let properties = this.getFeatureProperties(feature);\n const value = await this.getValue(markdown, properties, caption);\n\n this.setState(\n {\n value: value,\n loading: false,\n caption: caption,\n shortcodes: shortcodes,\n selectedIndex: newIndex,\n markdown: markdown,\n },\n () => {\n this.showFeatureInMap();\n }\n );\n }\n\n getValue = async (markdown, properties, caption) => {\n if (markdown) {\n return await this.featurePropsParsing\n .setMarkdownAndProperties({ markdown, properties })\n .mergeFeaturePropsWithMarkdown();\n } else {\n return this.getFeaturesAsDefaultTable(properties, caption);\n }\n };\n\n // renderShortcodes(shortcodes, feature) {\n // return shortcodes.map((shortcode, i) => {\n // switch (shortcode.shortcode) {\n // case \"diagram\":\n // return (\n // <Diagram key={i} source={shortcode.source} feature={feature} />\n // );\n // case \"table\":\n // return (\n // <HajkTable key={i} source={shortcode.source} feature={feature} />\n // );\n // default:\n // return null;\n // }\n // });\n // }\n\n isReadyToShowInfo = () => {\n const { caption, value, loading, shortcodes } = this.state;\n return caption && !loading && value && shortcodes;\n };\n\n renderFeatureInformation = () => {\n // const { caption, value, shortcodes, markdown } = this.state;\n const { caption, value } = this.state;\n const { classes } = this.props;\n\n return (\n <Grid className={classes.featureInfo} item>\n <Typography variant=\"button\" align=\"center\" component=\"h6\" gutterBottom>\n {caption}\n </Typography>\n {value}\n </Grid>\n );\n };\n\n render() {\n const { classes, features } = this.props;\n const featureInfoLoaded = this.isReadyToShowInfo();\n return (\n <Grid\n alignContent=\"flex-start\"\n className={classes.infoContainer}\n container\n spacing={1}\n >\n {features.length > 1 && (\n <Grid xs={12} item>\n {this.getToggler()}\n </Grid>\n )}\n <Grid\n justify=\"center\"\n alignContent={featureInfoLoaded ? \"flex-start\" : \"center\"}\n className={classes.featureInfoContainer}\n item\n container\n >\n {featureInfoLoaded ? (\n this.renderFeatureInformation()\n ) : (\n <CircularProgress />\n )}\n </Grid>\n </Grid>\n );\n }\n}\n\nexport default withStyles(styles)(FeatureInfoContainer);\n","import React from \"react\";\nimport { object, string } from \"prop-types\";\nimport { Button } from \"@material-ui/core\";\nimport { useSnackbar } from \"notistack\";\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n textButton: {\n color: theme.palette.primary.contrastText,\n marginRight: theme.spacing(1),\n },\n}));\n\nCookieNotice.propTypes = {\n defaultCookieNoticeMessage: string,\n defaultCookieNoticeUrl: string,\n globalObserver: object.isRequired,\n};\n\n/**\n * *\n * @export\n * @param {*} props\n * @returns React.Component\n */\nfunction CookieNotice({\n defaultCookieNoticeMessage = \"Vi använder cookies för att följa upp användandet och ge en bra upplevelse av kartan. Du kan blockera cookies i webbläsaren men då visas detta meddelande igen.\",\n defaultCookieNoticeUrl = \"https://pts.se/sv/bransch/regler/lagar/lag-om-elektronisk-kommunikation/kakor-cookies/\",\n globalObserver,\n}) {\n const classes = useStyles();\n const { enqueueSnackbar, closeSnackbar } = useSnackbar();\n\n const action = (key) => (\n <>\n <Button\n onClick={() => {\n window.open(defaultCookieNoticeUrl);\n }}\n variant=\"text\"\n className={classes.textButton}\n >\n {\"Mer information\"}\n </Button>\n <Button\n color=\"primary\"\n variant=\"contained\"\n onClick={() => {\n // Set a cookie that ensures that this message won't be shown again\n window.localStorage.setItem(\"cookieNoticeShown\", 1);\n closeSnackbar(key);\n }}\n >\n {\"Jag förstår\"}\n </Button>\n </>\n );\n\n // Display only if \"cookie\" hasn't been set yet\n parseInt(window.localStorage.getItem(\"cookieNoticeShown\")) !== 1 &&\n globalObserver.subscribe(\"core.appLoaded\", () => {\n enqueueSnackbar(defaultCookieNoticeMessage, {\n persist: true,\n anchorOrigin: {\n vertical: \"bottom\",\n horizontal: \"center\",\n },\n action: action,\n });\n });\n return null;\n}\n\n/**\n * The arePropsEqual() function is defined with two parameters:\n * prevProps and nextProps respectively.\n * The arePropsEqual() function returns true when the props are\n * compared to be equal, thereby preventing the component from\n * re-rendering, and returns false when the props are not equal.\n * @param {*} prevProps\n * @param {*} nextProps\n */\nfunction arePropsEqual(prevProps, nextProps) {\n // This ensures that CookieNotice only initiates once\n return true;\n}\n\nexport default React.memo(CookieNotice, arePropsEqual);\n","import React from \"react\";\nimport { Steps } from \"intro.js-react\";\nimport PropTypes from \"prop-types\";\n\nimport \"intro.js/introjs.css\";\nimport \"intro.js/themes/introjs-modern.css\";\n\n/**\n * @summary Renders a guide that introduces new users to features present in Hajk.\n * @description The introduction will only be rendered once. This is achieved by setting\n * a flag in the browser's local storage.\n *\n * @returns React.Component\n */\nclass Introduction extends React.PureComponent {\n state = {\n forceShow: false, // Used to force showing the Intro, overrides the LocalStorage value\n initialStep: 0,\n stepsEnabled: true,\n steps: [],\n };\n\n static propTypes = {\n experimentalIntroductionEnabled: PropTypes.bool.isRequired,\n experimentalIntroductionSteps: PropTypes.array,\n globalObserver: PropTypes.object.isRequired,\n };\n\n static defaultProps = {\n experimentalIntroductionEnabled: false,\n experimentalIntroductionSteps: [],\n globalObserver: {},\n };\n\n predefinedSteps = [\n {\n title: \"Välkommen till Hajk! 👋\",\n intro:\n \"Här kommer en kort guide som visar dig runt i applikationen. <br /><br />Häng med!\",\n },\n {\n title: \"Verktygspanel\",\n element: \"header > div:first-child\",\n intro: \"Med hjälp av knappen här uppe tar du fram verktygspanelen.\",\n },\n {\n title: \"Sökruta\",\n element: '[class*=\"searchContainer\"]',\n intro:\n \"Sökrutan hittar du här.<br /><br /> Med hjälp av sökverktyget hittar du enkelt till rätt ställe i kartan.\",\n },\n {\n title: \"Fler sökverktyg\",\n element: '[name=\"searchOptions\"]',\n intro: \"Under den här knappen hittar du fler avancerade sökalternativ.\",\n },\n {\n title: \"Kartkontroller\",\n element: \"#controls-column\",\n intro:\n \"Längst ut i den högra delen av skärmen finns olika kontroller som du använder för att navigera i kartan.\",\n },\n {\n title: \"Fönster\",\n element: '#windows-container > div[style*=\"display: block\"]', // My favorite selector. Selects the first visible Window, so if there's a plugin Window open, we can add intro text to it.\n intro:\n \"Varje verktyg ritar ut ett eget fönster. Du kan flytta på fönstret och ändra dess storlek genom att dra i fönstrets sidor.\",\n },\n {\n title: \"Widget-knapp\",\n element: \"#left-column > div > button\",\n intro:\n \"Det här är en Widget-knapp. Genom att klicka på den öppnar du det verktyget som knappen är kopplad till. <br><br>Det var det hela. Hoppas du kommer tycka om att använda Hajk!\",\n },\n ];\n\n constructor(props) {\n super(props);\n\n /**\n * When appLoaded is fired, let's filter through the provided 'steps'.\n * We must remove any steps that don't have corresponding DOM elements.\n * Otherwise, we would show intro steps even for non-existing elements,\n * which wouldn't be nice.\n */\n this.props.globalObserver.subscribe(\"core.appLoaded\", () => {\n // Allow a short wait so that everything renders first\n setTimeout(() => {\n // First check if we have any steps in our config\n const { experimentalIntroductionSteps } = this.props;\n // We must have at least 2 elements in the array in order to properly show intro guide\n const steps =\n experimentalIntroductionSteps.length >= 2\n ? experimentalIntroductionSteps\n : this.predefinedSteps;\n\n const filteredSteps = steps.filter((s) => {\n return (\n s.element === undefined ||\n document.querySelector(s?.element) !== null\n );\n });\n\n this.setState({ steps: filteredSteps });\n }, 100);\n });\n\n this.props.globalObserver.subscribe(\"core.showIntroduction\", () => {\n this.setState({\n initialStep: 0,\n stepsEnabled: true,\n forceShow: true,\n });\n });\n }\n\n disableSteps = () => {\n // Upon completion/closing, set a flag that won't show this guide again\n window.localStorage.setItem(\"introductionShown\", 1);\n };\n\n render() {\n const { experimentalIntroductionEnabled } = this.props;\n const { initialStep, steps, stepsEnabled } = this.state;\n\n return (\n // TODO: Remove check once the experimental flag is lifted. Remember to remove the unneeded prop from here and App.js too.\n experimentalIntroductionEnabled &&\n // Don't show unless we have 2 or more elements in array - too short guides are not meaningful!\n steps.length >= 2 &&\n // Show only once per browser, or override if forced by a user action.\n (parseInt(window.localStorage.getItem(\"introductionShown\")) !== 1 ||\n this.state.forceShow === true) && (\n <Steps\n enabled={stepsEnabled}\n steps={steps}\n initialStep={initialStep}\n onExit={this.disableSteps}\n options={{\n exitOnOverlayClick: false,\n nextLabel: \"Nästa\",\n prevLabel: \"Föregående\",\n doneLabel: \"Klart!\",\n }}\n />\n )\n );\n }\n}\n\nexport default Introduction;\n","import React, { useEffect } from \"react\";\nimport { detect } from \"detect-browser\";\n\nimport { useSnackbar } from \"notistack\";\n\nimport { IconButton } from \"@material-ui/core\";\nimport CloseIcon from \"@material-ui/icons/Close\";\n\n/**\n * You should have something like this in your appConfig.json in\n * order for this to work:\n * \n * \"announcements\": [\n {\n \"id\": 1, // Numeric. Must be a unique ID for this item in array of objects.\n \"text\": \"Message to show to the user. Keep it short.\", // String. Self-documenting. \n \"active\": true, // Boolean. Makes it possible to turn off messages completely without removing them.\n \"showOnlyOnce\": true, // Boolean. If true, a cookie will be saved on users browser and message will show only once.\n \"maps\": [\"jw\", \"map_1\"], // Array. Only specified maps will show message.\n \"timeout\": null, // null or Numeric. Snackbar will auto hide after specified amount of millisecond, or be persistent (if null).\n \"startTime\": \"2020-01-01\", // DateTime. Earliest timestamp for this to be visible. Must be a string parsable by Date.parse().\n \"stopTime\": \"2020-12-31\", // DateTime. Last timestamp when this will be visible.\n \"browsers\": [\"ie\"], // Array of browsers (see https://github.com/DamonOehlman/detect-browser for valid names)\n \"type\": \"info\" // String. See Notistack docs for allowed options, usually \"default\", \"info\", \"warning\", \"success\" and \"error\".\n }, {\n \"id\": 2, \n // ... and so on\n }, \n // ... and more objects here\n ]\n * \n */\n\nfunction Announcement({ announcements = [], currentMap }) {\n const { enqueueSnackbar, closeSnackbar } = useSnackbar();\n\n /**\n * Runs once. Filters the supplied announcements according to some conditions:\n * - should this be shown for current map?\n * - is it set to be activated?\n * - does it fit within the (optional) date/time limitations?\n * - is it set to only show up once, and if so, has it already been shown?\n *\n * All items that make it through all these tests are then sent to the\n * snackbar, which shows a nice message to the user.\n */\n useEffect(() => {\n // First, we define some helper filter functions.\n\n /**\n * Time filter. If an item has start/stop restrictions,\n * compare those to the current timestamp. Show only if the restrictions\n * are met.\n */\n const timeFilter = (a) => {\n const now = new Date().getTime();\n const startTime = Date.parse(a.startTime);\n const stopTime = Date.parse(a.stopTime);\n\n const validStartTime = !Number.isNaN(startTime);\n const validStopTime = !Number.isNaN(stopTime);\n\n if (validStartTime && validStopTime) {\n // If both start and stop are sat, now must be within\n return startTime < now && now < stopTime;\n } else if (validStartTime && !validStopTime) {\n // There's only a start time - show indefinitely if we're past it\n return startTime < now;\n } else if (!validStartTime && validStopTime) {\n // There's only a stop time, show if we haven't got there yet\n return now < stopTime;\n }\n\n // Finally, if none of the date strings parsed, it\n // means there are no time restrictions, let's show this.\n return true;\n };\n\n /**\n * See if ID of a given item exists in an array retrieved from local storage.\n * If the item is set to be shown only once, and it exists in the array already,\n * don't show it again. If it, on the other hand, is missing from the array,\n * show it _and_ add its ID to the array, so it won't show up again.\n */\n const localStorageFilter = (a) => {\n // If local storage flag is off, show this item.\n if (a.showOnlyOnce !== true) return true;\n\n // If we got this far, admin wants to use local storage.\n\n // First, see if we've already shown this item.\n const shownIds =\n window.localStorage.getItem(\"shownAnnouncementIds\") || \"\"; // Avoid null value - it can't be parsed to array easily\n const aShownIds = shownIds.split(\",\").filter(Boolean); // Create an array by splitting on commas; remove empty values by comparing to a Boolean\n if (aShownIds.includes(a.id.toString())) {\n // If ID is in array, item has already been shown\n return false;\n }\n\n // If we got this far, admin want's to show this item,\n // but only once - so let's return true, but also add\n // current id to the cookie array.\n aShownIds.push(a.id);\n const sShownIds = aShownIds.join();\n window.localStorage.setItem(\"shownAnnouncementIds\", sShownIds);\n return true;\n };\n\n /**\n * If \"maps\" property exists and current map exists in the \"maps\" array\n * or if \"maps\" is a string with value \"all\", show this notification.\n * Else, don't show it.\n */\n const mapFilter = (a) => {\n // If \"all\" is specified, no filtering is needed\n if (a?.maps === undefined || a.maps === \"all\") return true;\n\n // Else if an array is provided, check and see that current map exists in the array\n if (Array.isArray(a.maps)) return a.maps.includes(currentMap);\n\n // If anything else is provided, it is an invalid value. Just exit.\n return false;\n };\n\n /**\n * If \"browsers\" property exists and is an Array, return true only\n * if current browsers is included in the array.\n * If \"browsers\" is a string with value \"all\", or if it's undefined,\n * return true too.\n * For any other (invalid) value, return false.\n */\n const browserFilter = (a) => {\n const browsers = a?.browsers;\n if (browsers === undefined || browsers === \"all\") return true;\n if (Array.isArray(browsers)) return browsers.includes(detect().name);\n return false;\n };\n\n /**\n * Helper method: whatever is left in the announcements array after\n * all checks will be mapped to this render method.\n */\n const renderSnackbar = (f) => {\n if (!f?.text) return; // A text is required. If there's nothing to display, get out of here\n\n // Persistent snackbars will need an action that displays a close button.\n const action = (key) => {\n return (\n <IconButton\n size=\"small\"\n aria-label=\"close\"\n color=\"inherit\"\n onClick={() => closeSnackbar(key)}\n >\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n );\n };\n\n enqueueSnackbar(f?.text, {\n variant: f?.type || \"default\", // Allowed variants are \"default\", \"info\", \"warning\", \"success\" and \"error\"\n ...(Number.isFinite(f?.timeout) && { autoHideDuration: f?.timeout }), // If timeout is Numeric, auto hide\n ...(!Number.isFinite(f?.timeout) && { persist: true, action }), // If timeout isn't Numeric, snackbar is persistent\n });\n };\n\n // Now we're done defining helpers and can proceed with the actual filtration.\n // Let's oop through all announcements and do some checks to filter out those\n // that should be displayed.\n const filtered = announcements\n .filter((a) => mapFilter(a)) // Show only announcements for the current map\n .filter((a) => a.active === true) // Only active announcements\n .filter((a) => browserFilter(a)) // Show only for some browsers if admin said so\n .filter((a) => timeFilter(a)) // Respect possible date/time restrictions\n .filter((a) => localStorageFilter(a)); // Show only once if admin said so, by checking a local storage setting\n\n // Filtering is done, now let's invoke render for those\n // items that made it this far.\n filtered.forEach((f) => renderSnackbar(f));\n }, [announcements, currentMap, enqueueSnackbar, closeSnackbar]);\n\n // Finally, React's render _must_ return something…\n return null;\n}\n\n// Prevent unnecessary re-runs by explicitly comparing the relevant prop\nfunction arePropsEqual(prevProps, nextProps) {\n return prevProps.announcements.length === nextProps.announcements.length;\n}\n\nexport default React.memo(Announcement, arePropsEqual);\n","import React from \"react\";\nimport { array } from \"prop-types\";\n\nPluginWindows.propTypes = {\n plugins: array.isRequired,\n};\n\n/**\n * *\n * @export\n * @param {*} props\n * @returns React.Component\n */\nfunction PluginWindows({ plugins }) {\n return plugins.map((tool, i) => {\n return (\n <tool.component\n key={i}\n map={tool.map}\n app={tool.app}\n searchInterface={tool.searchInterface}\n options={tool.options}\n />\n );\n });\n}\n\n/**\n * The arePropsEqual() function is defined with two parameters:\n * prevProps and nextProps respectively.\n * The arePropsEqual() function returns true when the props are\n * compared to be equal, thereby preventing the component from\n * re-rendering, and returns false when the props are not equal.\n * @param {*} prevProps\n * @param {*} nextProps\n */\nfunction arePropsEqual(prevProps, nextProps) {\n return prevProps.plugins.length === nextProps.plugins.length;\n}\n\nexport default React.memo(PluginWindows, arePropsEqual);\n","import React from \"react\";\nimport cslx from \"clsx\";\nimport Grid from \"@material-ui/core/Grid\";\nimport ClearIcon from \"@material-ui/icons/Clear\";\nimport withWidth from \"@material-ui/core/withWidth\";\nimport Autocomplete from \"@material-ui/lab/Autocomplete\";\nimport SearchIcon from \"@material-ui/icons/Search\";\nimport RoomIcon from \"@material-ui/icons/Room\";\nimport CheckIcon from \"@material-ui/icons/Check\";\nimport DescriptionIcon from \"@material-ui/icons/Description\";\nimport ExpandLessIcon from \"@material-ui/icons/ExpandLess\";\nimport ExpandMoreIcon from \"@material-ui/icons/ExpandMore\";\nimport WarningIcon from \"@material-ui/icons/Warning\";\nimport SearchResultsContainer from \"./searchResults/SearchResultsContainer\";\nimport SearchTools from \"./SearchTools\";\nimport { withTheme, useTheme, withStyles } from \"@material-ui/core/styles\";\nimport { decodeCommas } from \"../../utils/StringCommaCoder\";\nimport {\n CircularProgress,\n IconButton,\n Paper,\n TextField,\n Typography,\n FormHelperText,\n useMediaQuery,\n Popper,\n Tooltip,\n} from \"@material-ui/core\";\n\nconst styles = (theme) => ({\n searchContainer: {\n width: 400,\n height: theme.spacing(6),\n },\n searchCollapsed: {\n left: -440,\n },\n\n autocompleteTypography: {\n maxWidth: \"100%\",\n },\n\n inputRoot: {\n height: theme.spacing(6),\n },\n originIconWrapper: {\n display: \"flex\",\n flexWrap: \"wrap\",\n paddingRight: theme.spacing(1),\n },\n});\n\n//Needed to make a CustomPopper with inline styling to be able to override width,\n//Popper.js didn't work as expected\nconst CustomPopper = (props) => {\n const theme = useTheme();\n const smallScreen = useMediaQuery(theme.breakpoints.down(\"xs\"));\n const style = smallScreen ? { width: \"100%\" } : { width: 400 };\n return (\n <Popper\n {...props}\n style={style}\n popperOptions={{\n modifiers: {\n computeStyle: { gpuAcceleration: false },\n preventOverflow: {\n enabled: smallScreen,\n boundariesElement: \"root\",\n },\n hide: { enabled: smallScreen },\n },\n }}\n placement=\"bottom-end\"\n />\n );\n};\n\nconst CustomPaper = (props) => {\n const theme = useTheme();\n const smallScreen = useMediaQuery(theme.breakpoints.down(\"xs\"));\n const style = smallScreen\n ? {\n margin: 0,\n borderTop: `${theme.spacing(0.2)}px solid ${theme.palette.divider}`,\n }\n : { margin: 0 };\n return <Paper {...props} style={style} />;\n};\n\nclass SearchBar extends React.PureComponent {\n state = {\n drawActive: false,\n panelCollapsed: false,\n moreOptionsId: undefined,\n moreOptionsOpen: false,\n selectSourcesOpen: false,\n };\n\n getOriginBasedIcon = (origin) => {\n const { classes } = this.props;\n let icon;\n switch (origin) {\n case \"WFS\":\n icon = <RoomIcon color=\"disabled\" />;\n break;\n case \"DOCUMENT\":\n icon = <DescriptionIcon color=\"disabled\" />;\n break;\n case \"USERSELECT\":\n icon = <CheckIcon color=\"disabled\" />;\n break;\n default:\n icon = <RoomIcon color=\"disabled\" />;\n }\n return <div className={classes.originIconWrapper}>{icon}</div>;\n };\n\n removeCommasAndSpaces = (string) => {\n return string.replace(/,/g, \"\").replace(/ /g, \"\");\n };\n\n //Can't use string.prototype.matchAll because of Edge (Polyfill not working atm)\n getMatches = (string, regex, index) => {\n var matches = [];\n var match = regex.exec(string);\n\n while (match != null && match[0] !== \"\") {\n matches.push(match);\n match = regex.exec(string);\n }\n return matches;\n };\n\n getAllStartingIndexForOccurencesInString = (toSearchFor, toSearchIn) => {\n let regexp = new RegExp(this.props.escapeRegExp(toSearchIn), \"gi\");\n let matches = this.getMatches(toSearchFor, regexp);\n let matchedIndexes = matches.map((match) => match.index);\n return matchedIndexes;\n };\n\n getHighlightedAutoCompleteEntryElement = (\n lastHighlightInformation,\n autocompleteEntry\n ) => {\n let { index, length } = lastHighlightInformation;\n return (\n <>\n <strong>{autocompleteEntry.slice(0, index + length)}</strong>\n {autocompleteEntry.slice(index + length)}\n </>\n );\n };\n\n //Highlights everything in autocomplete entry up until the last occurrence of a match in string.\n renderHighlightedAutocompleteEntry = (\n highlightInformation,\n autocompleteEntry\n ) => {\n const countOfHighlightInformation = highlightInformation.length;\n //We get lastHighlightInformation because we want to highlight everything up to last word that matches\n const lastHighlightInformation =\n highlightInformation[countOfHighlightInformation - 1];\n\n if (countOfHighlightInformation > 0) {\n return this.getHighlightedAutoCompleteEntryElement(\n lastHighlightInformation,\n autocompleteEntry\n );\n }\n };\n\n getHighlightedACE = (searchString, autocompleteEntry) => {\n const { getArrayWithSearchWords, classes } = this.props;\n const stringArraySS = getArrayWithSearchWords(searchString);\n\n let highlightInformation = stringArraySS\n .map((searchWord) => {\n return this.getAllStartingIndexForOccurencesInString(\n autocompleteEntry,\n searchWord\n ).map((index) => {\n return {\n index: index,\n length: searchWord.length,\n };\n });\n })\n .flat();\n\n return (\n <Typography noWrap={true} className={classes.autocompleteTypography}>\n {highlightInformation.length > 0\n ? this.renderHighlightedAutocompleteEntry(\n highlightInformation,\n autocompleteEntry\n )\n : autocompleteEntry}\n </Typography>\n );\n };\n\n /**\n * @summary Prepare a label to show as the placeholder in the Search bar\n * @returns {string} placeholder text\n */\n getPlaceholder = () => {\n const {\n options,\n searchActive,\n searchOptions: { searchInVisibleLayers },\n } = this.props;\n\n const labelPostfix = searchInVisibleLayers\n ? \" (endast i synliga lager)\"\n : \"\";\n\n return searchActive === \"selectSearch\" || searchActive === \"draw\"\n ? `Söker med objekt${labelPostfix}`\n : searchActive === \"extentSearch\"\n ? `Söker i området${labelPostfix}`\n : options.searchBarPlaceholder\n ? `${options.searchBarPlaceholder}${labelPostfix}`\n : `Sök${labelPostfix}`;\n };\n\n renderSearchResultList = () => {\n const {\n searchResults,\n app,\n map,\n localObserver,\n resultPanelCollapsed,\n toggleCollapseSearchResults,\n options,\n } = this.props;\n\n return (\n <SearchResultsContainer\n searchResults={searchResults}\n localObserver={localObserver}\n app={app}\n getOriginBasedIcon={this.getOriginBasedIcon}\n featureCollections={searchResults.featureCollections}\n map={map}\n panelCollapsed={resultPanelCollapsed}\n toggleCollapseSearchResults={toggleCollapseSearchResults}\n options={options}\n />\n );\n };\n\n renderAutoComplete = () => {\n const {\n autocompleteList,\n autoCompleteOpen,\n searchString,\n searchActive,\n classes,\n loading,\n handleOnAutocompleteInputChange,\n handleSearchInput,\n } = this.props;\n return (\n <Autocomplete\n id=\"searchInputField\"\n freeSolo\n size={\"small\"}\n classes={{\n inputRoot: classes.inputRoot,\n }}\n PopperComponent={CustomPopper}\n PaperComponent={CustomPaper}\n clearOnEscape\n disabled={\n searchActive === \"extentSearch\" ||\n searchActive === \"selectSearch\" ||\n searchActive === \"draw\"\n }\n autoComplete\n value={decodeCommas(searchString)}\n selectOnFocus\n blurOnSelect\n open={autoCompleteOpen}\n disableClearable\n onChange={handleSearchInput}\n onInputChange={handleOnAutocompleteInputChange}\n getOptionSelected={(option, value) =>\n option.autocompleteEntry === value.autocompleteEntry\n }\n renderOption={(option) => {\n if (searchString.length > 0) {\n return (\n <Grid container alignItems=\"center\">\n <Grid item xs={1}>\n {this.getOriginBasedIcon(option.origin)}\n </Grid>\n <Grid container item xs={11}>\n <Grid item xs={12}>\n {this.getHighlightedACE(\n searchString,\n decodeCommas(option.autocompleteEntry)\n )}\n </Grid>\n <Grid item xs={12}>\n <FormHelperText>{option.dataset}</FormHelperText>\n </Grid>\n </Grid>\n </Grid>\n );\n }\n }}\n getOptionLabel={(option) => {\n return option?.autocompleteEntry?.length > 0\n ? decodeCommas(option?.autocompleteEntry)\n : option;\n }}\n options={autocompleteList}\n loading={loading}\n renderInput={this.renderAutoCompleteInputField}\n />\n );\n };\n\n renderFailedWFSFetchWarning = (errorMessage) => {\n return (\n <Tooltip title={errorMessage}>\n <WarningIcon color=\"error\">\n <Typography variant=\"srOnly\">{errorMessage}</Typography>\n </WarningIcon>\n </Tooltip>\n );\n };\n\n renderAutoCompleteInputField = (params) => {\n const {\n searchString,\n loading,\n width,\n searchActive,\n map,\n app,\n handleOnClear,\n showSearchResults,\n toggleCollapseSearchResults,\n resultPanelCollapsed,\n handleSearchBarKeyPress,\n searchOptions,\n searchSources,\n updateSearchOptions,\n searchModel,\n handleOnClickOrKeyboardSearch,\n setSearchSources,\n failedWFSFetchMessage,\n } = this.props;\n const disableUnderline = width === \"xs\" ? { disableUnderline: true } : null;\n const showFailedWFSMessage =\n failedWFSFetchMessage.length > 0 && showSearchResults;\n const expandMessage = resultPanelCollapsed\n ? \"Visa sökresultat\"\n : \"Dölj sökresultat\";\n const placeholder = this.getPlaceholder();\n return (\n <TextField\n {...params}\n label={\n <Typography variant=\"srOnly\">Sök i webbplatsens innehåll</Typography>\n }\n variant={width === \"xs\" ? \"standard\" : \"outlined\"}\n placeholder={placeholder}\n onKeyPress={handleSearchBarKeyPress}\n InputLabelProps={{ shrink: true }}\n InputProps={{\n ...params.InputProps,\n ...disableUnderline,\n style: { margin: 0 },\n notched: width === \"xs\" ? null : false,\n endAdornment: (\n <>\n {loading ? <CircularProgress color=\"inherit\" size={20} /> : null}\n {params.InputProps.endAdornment}\n {showFailedWFSMessage &&\n this.renderFailedWFSFetchWarning(failedWFSFetchMessage)}\n {!showSearchResults ? (\n <Tooltip title=\"Utför sökning\">\n <IconButton\n size=\"small\"\n onClick={handleOnClickOrKeyboardSearch}\n >\n <Typography variant=\"srOnly\">Exekvera sökning</Typography>\n <SearchIcon />\n </IconButton>\n </Tooltip>\n ) : (\n <Tooltip title={expandMessage}>\n <IconButton\n onClick={(e) => {\n e.stopPropagation();\n toggleCollapseSearchResults();\n }}\n size=\"small\"\n >\n <Typography variant=\"srOnly\">{expandMessage}</Typography>\n {resultPanelCollapsed ? (\n <ExpandMoreIcon />\n ) : (\n <ExpandLessIcon />\n )}\n </IconButton>\n </Tooltip>\n )}\n {searchString.length > 0 ||\n showSearchResults ||\n searchActive !== \"\" ? (\n <Tooltip title=\"Rensa sökning\">\n <IconButton onClick={handleOnClear} size=\"small\">\n <Typography variant=\"srOnly\">Rensa sökning</Typography>\n <ClearIcon />\n </IconButton>\n </Tooltip>\n ) : (\n <SearchTools\n map={map}\n searchSources={searchSources}\n setSearchSources={setSearchSources}\n app={app}\n searchOptions={searchOptions}\n searchTools={this.props.searchTools}\n searchModel={searchModel}\n updateSearchOptions={updateSearchOptions}\n />\n )}\n </>\n ),\n }}\n />\n );\n };\n\n render() {\n const { classes, showSearchResults, width } = this.props;\n const { panelCollapsed } = this.state;\n\n return (\n <Grid\n className={cslx(classes.searchContainer, {\n [classes.searchCollapsed]: panelCollapsed,\n })}\n >\n <Grid item>\n <Paper elevation={width === \"xs\" ? 0 : 1}>\n {this.renderAutoComplete()}\n </Paper>\n </Grid>\n {showSearchResults && this.renderSearchResultList()}\n </Grid>\n );\n }\n}\n\nexport default withStyles(styles)(withTheme(withWidth()(SearchBar)));\n","import React from \"react\";\nimport Alert from \"@material-ui/lab/Alert\";\nimport SearchResultsList from \"./SearchResultsList\";\nimport Collapse from \"@material-ui/core/Collapse\";\nimport Breadcrumbs from \"@material-ui/core/Breadcrumbs\";\nimport Link from \"@material-ui/core/Link\";\nimport FilterListIcon from \"@material-ui/icons/FilterList\";\nimport SortIcon from \"@material-ui/icons/Sort\";\nimport MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport CloseIcon from \"@material-ui/icons/Close\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport ClearIcon from \"@material-ui/icons/Clear\";\nimport {\n Paper,\n Button,\n Grid,\n TextField,\n Typography,\n Tooltip,\n Badge,\n Menu,\n MenuItem,\n Grow,\n IconButton,\n} from \"@material-ui/core\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport SearchResultsDownloadMenu from \"./SearchResultsDownloadMenu\";\n\nconst styles = (theme) => ({\n hidden: {\n display: \"none\",\n },\n searchResultListWrapper: {\n [theme.breakpoints.down(\"xs\")]: {\n maxHeight: \"78vh\",\n },\n [theme.breakpoints.up(\"sm\")]: {\n maxHeight: \"82vh\",\n },\n },\n root: {\n maxHeight: \"80vh\",\n overflow: \"auto\",\n minWidth: 200,\n [theme.breakpoints.up(\"sm\")]: {\n maxWidth: 520,\n },\n [theme.breakpoints.down(\"xs\")]: {\n minWidth: \"100%\",\n maxWidth: \"100%\",\n position: \"absolute\",\n left: 0,\n borderTop: `${theme.spacing(0.2)}px solid ${theme.palette.divider}`,\n },\n },\n filterInputFieldContainer: {\n padding: theme.spacing(1),\n borderBottom: `${theme.spacing(0.1)}px solid ${theme.palette.divider}`,\n },\n headerContainer: {\n paddingRight: theme.spacing(1),\n paddingLeft: theme.spacing(1),\n },\n tallHeaderContainer: {\n minHeight: 42,\n paddingRight: theme.spacing(1),\n paddingLeft: theme.spacing(1),\n borderBottom: `${theme.spacing(0.1)}px solid ${theme.palette.divider}`,\n },\n headerTypography: {\n maxWidth: \"100%\",\n fontSize: 18,\n },\n headerButtons: {\n minWidth: 30,\n },\n breadCrumbLinks: {\n border: \"none\",\n cursor: \"pointer\",\n },\n});\n\nclass SearchResultsContainer extends React.PureComponent {\n state = {\n activeFeature: null,\n activeFeatureCollection: null,\n filteredFeatureCollections: null,\n filteredFeatures: null,\n sumOfResults: this.props.searchResults.featureCollections\n .map((fc) => fc.value.features.length ?? 0)\n .reduce((a, b) => a + b, 0),\n filterInputFieldOpen: false,\n featureCollectionFilter: \"\", // String used to filter featureCollections\n featureFilter: \"\", // String used to filter features\n sortingMenuAnchorEl: null,\n featureCollectionSortingStrategy: \"AtoZ\", // AtoZ representing alphabetical order\n featureSortingStrategy: \"AtoZ\",\n showTools: false,\n selectedFeatures: [],\n };\n\n // Used for setTimeout/clearTimeout, in order to delay filter update when user is typing\n filterInputTimer = null;\n lastFeatureFilter = \"\";\n lastFeatureCollectionFilter = \"\";\n\n // Amount of time before filter changes is committed\n delayBeforeFilterCommit = 300;\n\n searchResultTools = [\n {\n name: \"Filtrera\",\n type: \"filter\",\n render: () => this.renderFilterTool(),\n enabled: this.props.options.enableResultsFiltering ?? true,\n },\n {\n name: \"Sortera\",\n type: \"sort\",\n render: () => this.renderSortTool(),\n enabled: this.props.options.enableResultsSorting ?? true,\n },\n {\n name: \"Rensa\",\n type: \"clear\",\n render: () => this.renderClearTool(),\n enabled: this.props.options.enableResultsSelectionClearing ?? true,\n },\n {\n name: \"Ladda ner\",\n type: \"download\",\n render: () => this.renderDownloadTool(),\n enabled: this.props.options.enableResultsDownloading ?? true,\n },\n ];\n\n sortingStrategies = [\n {\n type: \"AtoZ\",\n name: \"alfabetisk stigande\",\n appliesTo: [\"featureCollections\", \"features\"],\n },\n {\n type: \"ZtoA\",\n name: \"alfabetisk fallande\",\n appliesTo: [\"featureCollections\", \"features\"],\n },\n {\n type: \"numHits\",\n name: \"antal träffar\",\n appliesTo: [\"featureCollections\"],\n },\n ];\n\n componentDidMount = () => {\n const { app } = this.props;\n app.globalObserver.subscribe(\n \"infoClick.searchResultLayerClick\",\n (features) => {\n const featureIds = features.map((feature) => {\n return feature.getId();\n });\n this.showFeatureDetails(featureIds);\n }\n );\n this.getPotentialSingleHit();\n };\n\n componentWillUnmount = () => {\n const { app } = this.props;\n app.globalObserver.unsubscribe(\"infoClick.searchResultLayerClick\");\n };\n\n showFeatureDetails = (featureIds) => {\n const { toggleCollapseSearchResults } = this.props;\n const featureId = featureIds[0]; // Do we want to handle stacked features?\n\n // If searchResultContainer is collapsed, open it.\n if (this.props.panelCollapsed) toggleCollapseSearchResults();\n\n // Get the featureCollection which the clicked feature belongs to\n const featureCollection = this.getFeatureCollectionFromFeatureId(featureId);\n\n // If the collection has onClickName set we won't show the details\n if (featureCollection.source.onClickName) {\n return;\n }\n\n // Get the clicked feature\n const feature = featureCollection.value.features.find(\n (feature) => feature.getId() === featureId\n );\n\n // If the feature has onClickName set we won't show the details\n if (feature.onClickName) {\n return;\n }\n\n this.handleActiveFeatureChange(feature, featureCollection, \"infoClick\");\n };\n\n getFeatureCollectionFromFeatureId = (featureId) => {\n const { featureCollections } = this.props;\n return featureCollections.find((featureCollection) => {\n return (\n featureCollection.value.features.findIndex(\n (feature) => feature.getId() === featureId\n ) > -1\n );\n });\n };\n\n getPotentialSingleHit = () => {\n const { featureCollections } = this.props;\n\n const activeFeatureCollection =\n featureCollections.length === 1 ? featureCollections[0] : undefined;\n const activeFeature = activeFeatureCollection\n ? activeFeatureCollection.value.features.length === 1\n ? activeFeatureCollection.value.features[0]\n : undefined\n : undefined;\n\n // Hack hack.. we shouldn't set active collection and feature if we have a onClickName\n // on the source\n const shouldSetActiveFeatureOrCollection = activeFeatureCollection?.source\n ?.onClickName\n ? false\n : true;\n\n if (shouldSetActiveFeatureOrCollection) {\n this.setState({\n activeFeatureCollection: activeFeatureCollection,\n activeFeature: activeFeature,\n });\n }\n };\n\n handleFilterTextFieldInputChange = (e) => {\n const filterInput = e.target.value;\n this.updateViewFilters(filterInput);\n\n clearTimeout(this.filterInputTimer);\n this.filterInputTimer = setTimeout(() => {\n this.handleFilterUpdate();\n }, this.delayBeforeFilterCommit);\n };\n\n addFeatureToSelected = (feature) => {\n const selectedFeatures = [...this.state.selectedFeatures];\n selectedFeatures.push(feature);\n this.setState({ selectedFeatures: selectedFeatures });\n this.updateMapView(selectedFeatures);\n };\n\n removeFeatureFromSelected = (feature) => {\n const { activeFeatureCollection } = this.state;\n const selectedFeatures = [...this.state.selectedFeatures];\n\n const featureIndex = this.getSelectedFeatureIndex(feature.getId());\n selectedFeatures.splice(featureIndex, 1);\n\n if (activeFeatureCollection?.origin === \"USERSELECT\") {\n this.setState({\n selectedFeatures: selectedFeatures,\n activeFeatureCollection:\n selectedFeatures.length === 0\n ? null\n : this.getSelectedCollection(selectedFeatures),\n });\n } else {\n this.setState({ selectedFeatures: selectedFeatures });\n }\n this.updateMapView(selectedFeatures);\n };\n\n updateMapView = (selectedFeatures) => {\n const { localObserver } = this.props;\n localObserver.publish(\"map.setSelectedStyle\", selectedFeatures);\n localObserver.publish(\"map.zoomToFeatures\", selectedFeatures);\n };\n\n getSelectedFeatureIndex = (featureId) => {\n return this.state.selectedFeatures.findIndex((featureInfo) => {\n return featureInfo.feature.getId() === featureId;\n });\n };\n\n appendSelectedFeaturesCollection = (featureCollections) => {\n const { selectedFeatures } = this.state;\n if (this.state.selectedFeatures.length === 0) {\n return featureCollections;\n }\n const updatedCollections = [...featureCollections];\n updatedCollections.filter((fc) => {\n return fc.origin !== \"USERSELECT\";\n });\n updatedCollections.unshift(this.getSelectedCollection(selectedFeatures));\n return updatedCollections;\n };\n\n getSelectedCollection = (selectedFeatures) => {\n const features = selectedFeatures.reduce(\n (features, featureInfo) => [...features, featureInfo.feature],\n []\n );\n return {\n origin: \"USERSELECT\",\n source: { id: \"userSelected\", caption: \"Markerade objekt\" },\n value: {\n type: \"featureCollection\",\n features: features,\n },\n };\n };\n\n updateViewFilters = (filterInput) => {\n // If we don't have a collection active, we know\n // that the filter is intended for the collections\n if (!this.state.activeFeatureCollection) {\n this.setState({\n featureCollectionFilter: filterInput,\n });\n } else {\n // If we DO have a collection active, we know that\n // the filter is intended for the features in the active\n // collection\n this.setState({\n featureFilter: filterInput,\n });\n }\n };\n\n clearViewFilters = () => {\n if (!this.state.activeFeatureCollection) {\n this.setState(\n {\n featureCollectionFilter: \"\",\n },\n () => {\n this.handleFilterUpdate();\n }\n );\n } else {\n this.setState(\n {\n featureFilter: \"\",\n },\n () => {\n this.handleFilterUpdate();\n }\n );\n }\n };\n\n renderFilterInputField = () => {\n const { classes } = this.props;\n const { activeFeatureCollection, featureFilter, featureCollectionFilter } =\n this.state;\n const showClearFilterButton =\n featureFilter.length > 0 || featureCollectionFilter.length > 0;\n return (\n <Grid item className={classes.filterInputFieldContainer} xs={12}>\n <Typography variant=\"srOnly\">\n Textfält för att filtrera resultatet\n </Typography>\n <TextField\n autoFocus\n onChange={this.handleFilterTextFieldInputChange}\n value={\n activeFeatureCollection ? featureFilter : featureCollectionFilter\n }\n fullWidth\n size=\"small\"\n variant=\"outlined\"\n label=\"Filtrera sökresultaten\"\n InputProps={{\n endAdornment: showClearFilterButton && (\n <Tooltip title=\"Rensa filtret\">\n <IconButton onClick={this.clearViewFilters} size=\"small\">\n <Typography variant=\"srOnly\">Rensa filtret</Typography>\n <ClearIcon />\n </IconButton>\n </Tooltip>\n ),\n }}\n ></TextField>\n </Grid>\n );\n };\n\n getFilteredFeatureCollections = () => {\n const { featureCollectionFilter, filteredFeatureCollections } = this.state;\n const { featureCollections } = this.props;\n // Do we have a filter value?\n if (this.lastFeatureCollectionFilter !== featureCollectionFilter) {\n // Filter all collections\n return featureCollections.filter((featureCollection) => {\n // Returning collections where the filter is included in caption\n return featureCollection?.source?.caption\n .toLowerCase()\n .includes(featureCollectionFilter.toLowerCase());\n });\n } else {\n // No filter update? Return all collections or last filtered.\n if (filteredFeatureCollections?.length > 0) {\n return filteredFeatureCollections;\n }\n return featureCollections;\n }\n };\n\n // Helper function that checks if the filter is active in the\n // current view.\n isFilterActive = () => {\n const { activeFeatureCollection, featureFilter, featureCollectionFilter } =\n this.state;\n // If we have an active featureCollection (meaning that we are\n // viewing _features_, and the featureFilter-value is set, the\n // filter is active.\n return activeFeatureCollection && featureFilter.length > 0\n ? true\n : // If we do not have an active featureCollection (meaning that\n // we are viewing _featureCollections_, and the featureCollection-\n // filter is set, the filter is active.\n !activeFeatureCollection && featureCollectionFilter.length > 0\n ? true\n : // Otherwise, the filter is not active.\n false;\n };\n\n getSortingStrategiesApplyingToView = (view) => {\n return this.sortingStrategies.filter((strategy) =>\n strategy.appliesTo.includes(view)\n );\n };\n\n handleSortingMenuItemClick = (type) => {\n const { activeFeatureCollection } = this.state;\n\n if (activeFeatureCollection) {\n this.setState({\n featureSortingStrategy: type,\n sortingMenuAnchorEl: null,\n });\n } else {\n this.setState({\n featureCollectionSortingStrategy: type,\n sortingMenuAnchorEl: null,\n });\n }\n };\n\n clearAllSelectedFeaturesInView = () => {\n const { localObserver } = this.props;\n const { activeFeatureCollection } = this.state;\n const sourceId = activeFeatureCollection?.source?.id;\n const onSelectedFeaturesView = sourceId === \"userSelected\";\n\n const selectedFeatures =\n !sourceId || onSelectedFeaturesView\n ? []\n : [...this.state.selectedFeatures].filter((featureInfo) => {\n return featureInfo.feature?.source.id !== sourceId;\n });\n this.setState({\n selectedFeatures: selectedFeatures,\n activeFeatureCollection: onSelectedFeaturesView\n ? null\n : activeFeatureCollection,\n });\n localObserver.publish(\"map.setSelectedStyle\", selectedFeatures);\n };\n\n renderSortingMenu = () => {\n const {\n featureCollectionSortingStrategy,\n featureSortingStrategy,\n sortingMenuAnchorEl,\n activeFeatureCollection,\n } = this.state;\n\n const currentSortingStrategies = this.getSortingStrategiesApplyingToView(\n activeFeatureCollection ? \"features\" : \"featureCollections\"\n );\n return (\n <Menu\n anchorEl={sortingMenuAnchorEl}\n open={Boolean(sortingMenuAnchorEl)}\n onClose={() => this.setState({ sortingMenuAnchorEl: null })}\n >\n {currentSortingStrategies.map((strategy, index) => {\n return (\n <MenuItem\n selected={\n strategy.type ===\n (activeFeatureCollection\n ? featureSortingStrategy\n : featureCollectionSortingStrategy)\n }\n onClick={() => this.handleSortingMenuItemClick(strategy.type)}\n key={index}\n value={strategy.type}\n >\n {`${strategy.name[0].toUpperCase()}${strategy.name.slice(1)}`}\n </MenuItem>\n );\n })}\n </Menu>\n );\n };\n\n renderFilterTool = () => {\n const { classes } = this.props;\n const filterActive = this.isFilterActive();\n const filterHelpText = filterActive\n ? \"Filtret är aktivt\"\n : \"Filtrera resultatet\";\n return (\n <Tooltip title={filterHelpText}>\n <Button\n className={classes.headerButtons}\n onClick={() =>\n this.setState({\n filterInputFieldOpen: !this.state.filterInputFieldOpen,\n })\n }\n >\n <Badge\n color=\"primary\"\n badgeContent=\" \"\n variant=\"dot\"\n invisible={!filterActive}\n >\n <FilterListIcon />\n </Badge>\n </Button>\n </Tooltip>\n );\n };\n\n renderSortTool = () => {\n const { classes } = this.props;\n const {\n activeFeatureCollection,\n featureCollectionSortingStrategy,\n featureSortingStrategy,\n } = this.state;\n\n const sortHelpText = `Sortera resultatet, sorterar nu enligt ${\n // Get current sorting strategy from the array of strategies\n this.sortingStrategies.find(\n // by finding...\n (strategy) =>\n // the strategy with the \"type\"-value...\n strategy.type ===\n // corresponding to either the current feature or featureCollection\n // sorting strategy (depending on if we have an active collection or not)\n (activeFeatureCollection\n ? featureSortingStrategy\n : featureCollectionSortingStrategy)\n ).name // And it is the name value of the strategy we want to show\n }`;\n\n return (\n <Tooltip title={sortHelpText}>\n <Button\n className={classes.headerButtons}\n onClick={(e) =>\n this.setState({ sortingMenuAnchorEl: e.currentTarget })\n }\n >\n <SortIcon />\n </Button>\n </Tooltip>\n );\n };\n\n renderClearTool = () => {\n const { classes } = this.props;\n return (\n <Tooltip title=\"Rensa alla selekterade objekt\">\n <Button\n className={classes.headerButtons}\n onClick={this.clearAllSelectedFeaturesInView}\n >\n <DeleteIcon />\n </Button>\n </Tooltip>\n );\n };\n\n renderDownloadTool = () => {\n const collectionsToDownload = this.getCollectionsToDownload();\n return (\n <SearchResultsDownloadMenu\n featureCollections={collectionsToDownload}\n localObserver={this.props.localObserver}\n />\n );\n };\n\n getCollectionsToDownload = () => {\n const {\n activeFeatureCollection,\n filteredFeatureCollections,\n featureFilter,\n } = this.state;\n const { featureCollections } = this.props;\n\n if (activeFeatureCollection) {\n if (activeFeatureCollection.source.id === \"userSelected\") {\n return [activeFeatureCollection];\n }\n if (featureFilter === \"\") {\n return [activeFeatureCollection];\n }\n const filteredFeatures = this.getFilteredFeatures([\n activeFeatureCollection,\n ]);\n const collectionToDownload = {\n ...activeFeatureCollection,\n value: { features: filteredFeatures },\n };\n return [collectionToDownload];\n }\n if (filteredFeatureCollections) {\n return filteredFeatureCollections;\n }\n\n return featureCollections;\n };\n\n allToolsDisabled = () => {\n return this.searchResultTools.filter((tool) => tool.enabled).length === 0;\n };\n\n renderSearchResultListTools = () => {\n const { classes } = this.props;\n if (this.allToolsDisabled()) {\n return null;\n } else {\n return (\n <Grid item container align=\"center\" justify=\"flex-end\">\n <Grow in={this.state.showTools} timeout={800}>\n <Grid\n item\n className={!this.state.showTools ? classes.hidden : null}\n >\n {this.searchResultTools.map((tool, index) => {\n return (\n tool.enabled && (\n <React.Fragment key={index}>{tool.render()}</React.Fragment>\n )\n );\n })}\n </Grid>\n </Grow>\n <Grid item>\n <Tooltip\n title={`${this.state.showTools ? \"Dölj\" : \"Visa\"} verktyg`}\n >\n <Button\n className={classes.headerButtons}\n onClick={() =>\n this.setState({\n showTools: !this.state.showTools,\n filterInputFieldOpen: false,\n })\n }\n >\n {this.state.showTools ? <CloseIcon /> : <MoreVertIcon />}\n </Button>\n </Tooltip>\n </Grid>\n </Grid>\n );\n }\n };\n\n setActiveFeature = (feature) => {\n const { activeFeatureCollection } = this.state;\n this.handleActiveFeatureChange(feature, activeFeatureCollection);\n };\n\n handleActiveFeatureChange = (nextFeature, nextCollection, initiator) => {\n const { localObserver } = this.props;\n const { activeFeature } = this.state;\n const selectedFeatures = [...this.state.selectedFeatures];\n const shouldZoomToFeature = initiator !== \"infoClick\";\n\n if (activeFeature) {\n const featureIndex = selectedFeatures.findIndex((featureInfo) => {\n return (\n featureInfo.feature.getId() === activeFeature.getId() &&\n featureInfo.initiator !== \"userSelect\"\n );\n });\n featureIndex !== -1 && selectedFeatures.splice(featureIndex, 1);\n localObserver.publish(\"map.setSelectedStyle\", selectedFeatures);\n }\n\n if (nextFeature) {\n const nextFeatureSelected = this.featureIsSelected(nextFeature);\n !nextFeatureSelected &&\n selectedFeatures.push(\n this.getNextFeatureInfo(nextFeature, nextCollection, initiator)\n );\n }\n this.setState(\n {\n selectedFeatures: selectedFeatures,\n activeFeatureCollection: nextCollection,\n activeFeature: nextFeature,\n filterInputFieldOpen: false,\n featureFilter: !nextCollection ? \"\" : this.state.featureFilter,\n },\n () => {\n !nextCollection && this.handleFilterUpdate();\n }\n );\n if (nextFeature) {\n if (shouldZoomToFeature) {\n localObserver.publish(\"map.zoomToFeature\", nextFeature);\n }\n localObserver.publish(\"map.setHighLightedStyle\", nextFeature);\n } else {\n localObserver.publish(\"map.setSelectedStyle\", selectedFeatures);\n }\n };\n\n featureIsSelected = (feature) => {\n const { selectedFeatures } = this.state;\n return selectedFeatures.some((featureInfo) => {\n return featureInfo.feature.getId() === feature.getId();\n });\n };\n\n getNextFeatureInfo = (nextFeature, nextCollection, initiator) => {\n if (!nextFeature.source) {\n nextFeature.source = nextCollection.source;\n }\n\n return {\n feature: nextFeature,\n sourceId: nextFeature.source ?? nextCollection.source.id,\n initiator: initiator,\n };\n };\n\n setActiveFeatureCollection = (featureCollection) => {\n this.setState(\n {\n activeFeatureCollection: featureCollection,\n filterInputFieldOpen: false,\n featureFilter: \"\",\n },\n () => {\n this.handleFilterUpdate();\n this.#showCorrespondingWMSLayers(featureCollection);\n }\n );\n };\n\n #showCorrespondingWMSLayers = (featureCollection) => {\n // Respect the setting from admin\n if (this.props.options.showCorrespondingWMSLayers !== true) return;\n\n const layer = this.#getLayerById(featureCollection.source.pid);\n\n if (layer.layerType === \"group\") {\n // Group layers will publish an event to LayerSwitcher that will take\n // care of the somewhat complicated toggling.\n\n // N.B. We don't want to hide any sublayers, only ensure that new ones are shown.\n // So the first step is to find out which sublayers are already visible.\n const alreadyVisibleSubLayers = layer\n .getSource()\n .getParams()\n [\"LAYERS\"].split(\",\")\n .filter((e) => e.length !== 0);\n\n // Next, prepare an array of the already visible layers, plus the new one.\n // Make sure NOT TO CHANGE THE ORDER of sublayers. Hence no push or spread,\n // only a filter on the admin-specified order that we have in the 'subLayers'\n // property.\n const subLayersToShow = layer.subLayers.filter((l) => {\n return (\n alreadyVisibleSubLayers.includes(l) ||\n l === featureCollection.source.id\n );\n });\n\n // Finally, let's publish the event so that LayerSwitcher can take care of the rest\n this.props.app.globalObserver.publish(\"layerswitcher.showLayer\", {\n layer,\n subLayersToShow,\n });\n } else if (!layer.getVisible()) {\n // \"Normal\" layers are easier, we can just toggle the visibility directly.\n // The already existing OL listener will update checkbox state on corresponding layer.\n layer.setVisible(true);\n }\n };\n\n #getLayerById = (layerId) => {\n return this.props.map\n .getLayers()\n .getArray()\n .find((layer) => {\n return layerId === layer.values_.name;\n });\n };\n\n handleFeatureCollectionClick = (featureCollection) => {\n const { app } = this.props;\n const onClickName = featureCollection?.source?.onClickName;\n if (onClickName) {\n app.globalObserver.publish(\n `search.featureCollectionClicked.${onClickName}`,\n featureCollection\n );\n } else {\n this.setActiveFeatureCollection(featureCollection);\n }\n };\n\n sortFeatureCollections = (featureCollections) => {\n const { featureCollectionSortingStrategy } = this.state;\n\n const featureCollectionsAtoZSorted = featureCollections.sort((a, b) =>\n a.source.caption.localeCompare(b.source.caption)\n );\n\n switch (featureCollectionSortingStrategy) {\n case \"numHits\":\n return featureCollections.sort((a, b) =>\n a.value.totalFeatures > b.value.totalFeatures ? -1 : 1\n );\n case \"ZtoA\":\n return featureCollectionsAtoZSorted.reverse();\n default:\n // AtoZ\n return featureCollectionsAtoZSorted;\n }\n };\n\n keyPressIsEnter = (event) => {\n return event.which === 13 || event.keyCode === 13;\n };\n\n getFilteredFeatures = (featureCollections) => {\n const { activeFeatureCollection, featureFilter } = this.state;\n return featureCollections\n .map((fc) => {\n if (activeFeatureCollection) {\n if (fc.source.id === activeFeatureCollection.source.id) {\n return fc.value.features.filter((f) => {\n return f.featureTitle\n .toLowerCase()\n .includes(featureFilter.toLowerCase());\n });\n }\n }\n return fc.value.features;\n })\n .flat();\n };\n\n handleFilterUpdate = () => {\n const { featureCollectionFilter, featureFilter } = this.state;\n const { localObserver, featureCollections } = this.props;\n\n if (\n this.lastFeatureFilter === featureFilter &&\n this.lastFeatureCollectionFilter === featureCollectionFilter\n ) {\n return;\n }\n\n const filteredFeatureCollections =\n this.getFilteredFeatureCollections(featureCollections);\n const filteredFeatures = this.getFilteredFeatures(\n filteredFeatureCollections\n );\n const currentFeatureIds = filteredFeatures.map((feature) => {\n return feature.getId();\n });\n\n this.setState({\n filteredFeatureCollections: filteredFeatureCollections,\n filteredFeatures: filteredFeatures,\n });\n\n this.lastFeatureFilter = featureFilter;\n this.lastFeatureCollectionFilter = featureCollectionFilter;\n\n localObserver.publish(\"map.updateFeaturesAfterFilterChange\", {\n features: filteredFeatures,\n featureIds: currentFeatureIds,\n });\n };\n\n renderBreadCrumbs = (featureCollectionTitle, featureTitle) => {\n const { classes } = this.props;\n const { activeFeatureCollection, activeFeature } = this.state;\n const shouldRenderFeatureCollectionDetails =\n activeFeatureCollection && !activeFeatureCollection.source.onClickName;\n const shouldRenderFeatureDetails =\n activeFeature && !activeFeature.onClickName;\n if (shouldRenderFeatureCollectionDetails) {\n return (\n <Breadcrumbs aria-label=\"breadcrumb\" separator=\"/\">\n <Tooltip title=\"Tillbaka till alla sökresultat\">\n <Link\n className={classes.breadCrumbLinks}\n tabIndex={0}\n color=\"textPrimary\"\n variant=\"caption\"\n onClick={(e) => {\n e.stopPropagation();\n this.handleActiveFeatureChange();\n }}\n onKeyDown={(event) => {\n if (this.keyPressIsEnter(event)) {\n this.handleActiveFeatureChange();\n }\n }}\n onChange={this.handleActiveFeatureChange}\n >\n Sökresultat\n </Link>\n </Tooltip>\n <Tooltip title={featureCollectionTitle}>\n <Link\n className={classes.breadCrumbLinks}\n tabIndex={0}\n color=\"textPrimary\"\n variant=\"caption\"\n onClick={(e) => {\n e.stopPropagation();\n this.setActiveFeature(undefined);\n }}\n onKeyDown={(event) => {\n if (this.keyPressIsEnter(event)) {\n this.setActiveFeature(undefined);\n }\n }}\n >\n {featureCollectionTitle}\n </Link>\n </Tooltip>\n {shouldRenderFeatureDetails && (\n <Tooltip title={featureTitle}>\n <Link\n tabIndex={0}\n className={classes.breadCrumbLinks}\n color=\"textPrimary\"\n variant=\"caption\"\n >\n {featureTitle}\n </Link>\n </Tooltip>\n )}\n </Breadcrumbs>\n );\n } else {\n return null;\n }\n };\n\n renderHeaderInfoBar = (featureCollectionTitle) => {\n const { activeFeatureCollection } = this.state;\n const { classes } = this.props;\n return (\n <Grid\n container\n item\n justify=\"space-between\"\n alignItems=\"center\"\n wrap=\"nowrap\"\n xs={12}\n >\n <Grid\n container\n item\n wrap=\"nowrap\"\n alignItems=\"center\"\n xs={this.state.showTools ? 5 : 11}\n >\n <Tooltip\n title={\n activeFeatureCollection ? featureCollectionTitle : \"Sökresultat\"\n }\n >\n <Typography\n variant=\"button\"\n component=\"div\"\n noWrap\n className={classes.headerTypography}\n >\n {`${\n activeFeatureCollection ? featureCollectionTitle : \"Sökresultat\"\n }`}\n </Typography>\n </Tooltip>\n </Grid>\n <Grid\n container\n item\n justify=\"flex-end\"\n xs={this.state.showTools ? 7 : 1}\n >\n {this.renderSearchResultListTools()}\n </Grid>\n </Grid>\n );\n };\n\n renderSearchResultsHeader = () => {\n const { classes } = this.props;\n const { activeFeatureCollection, activeFeature } = this.state;\n\n const featureCollectionTitle = activeFeatureCollection\n ? activeFeatureCollection.source.caption\n : \"\";\n const featureTitle = activeFeature ? activeFeature.featureTitle : \"\";\n const shouldRenderHeaderInfoBar =\n !activeFeature || activeFeature?.onClickName;\n\n return (\n <Grid\n className={\n shouldRenderHeaderInfoBar\n ? classes.tallHeaderContainer\n : classes.headerContainer\n }\n container\n item\n xs={12}\n >\n <Grid item xs={12}>\n {this.renderBreadCrumbs(featureCollectionTitle, featureTitle)}\n </Grid>\n {shouldRenderHeaderInfoBar &&\n this.renderHeaderInfoBar(featureCollectionTitle, featureTitle)}\n </Grid>\n );\n };\n\n render() {\n const {\n classes,\n app,\n getOriginBasedIcon,\n localObserver,\n panelCollapsed,\n options,\n } = this.props;\n const {\n sumOfResults,\n activeFeatureCollection,\n activeFeature,\n filterInputFieldOpen,\n featureFilter,\n featureCollectionSortingStrategy,\n featureSortingStrategy,\n } = this.state;\n\n const featureCollections =\n // Do we have an active (selected) featureCollection?\n activeFeatureCollection\n ? // Return a array containing only that collection\n [activeFeatureCollection]\n : // Otherwise we return all collections passing the filter\n this.getFilteredFeatureCollections(this.props.featureCollections);\n\n const sortedFeatureCollections =\n this.sortFeatureCollections(featureCollections);\n\n const shouldRenderSelectedCollection =\n options.enableSelectedFeaturesCollection ?? true;\n\n const collectionsToRender = activeFeatureCollection\n ? [activeFeatureCollection]\n : shouldRenderSelectedCollection\n ? this.appendSelectedFeaturesCollection(sortedFeatureCollections)\n : sortedFeatureCollections;\n\n return (\n <Collapse in={!panelCollapsed}>\n {sumOfResults === 0 ? (\n <Paper className={classes.root}>\n <Alert severity=\"warning\">Sökningen gav inget resultat.</Alert>\n </Paper>\n ) : (\n <Paper className={classes.root}>\n <Grid container className={classes.searchResultListWrapper}>\n {this.renderSearchResultsHeader()}\n {filterInputFieldOpen && this.renderFilterInputField()}\n {this.renderSortingMenu()}\n <Grid item xs={12}>\n <SearchResultsList\n localObserver={localObserver}\n getOriginBasedIcon={getOriginBasedIcon}\n featureCollections={collectionsToRender}\n app={app}\n handleFeatureCollectionClick={\n this.handleFeatureCollectionClick\n }\n setActiveFeature={this.setActiveFeature}\n activeFeatureCollection={activeFeatureCollection}\n activeFeature={activeFeature}\n featureFilter={featureFilter}\n featureCollectionSortingStrategy={\n featureCollectionSortingStrategy\n }\n featureSortingStrategy={featureSortingStrategy}\n enableFeaturePreview={options.enableFeaturePreview ?? true}\n enableFeatureToggler={options.enableFeatureToggler ?? true}\n addFeatureToSelected={this.addFeatureToSelected}\n removeFeatureFromSelected={this.removeFeatureFromSelected}\n selectedFeatures={this.state.selectedFeatures}\n shouldRenderSelectedCollection={\n shouldRenderSelectedCollection\n }\n options={options}\n />\n </Grid>\n </Grid>\n </Paper>\n )}\n </Collapse>\n );\n }\n}\n\nexport default withStyles(styles)(SearchResultsContainer);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { withWidth, List, ListItem } from \"@material-ui/core\";\nimport SearchResultsDataset from \"./SearchResultsDataset\";\nimport SearchResultsDatasetSummary from \"./SearchResultsDatasetSummary\";\n\nconst styles = () => ({\n searchResultList: {\n padding: 0,\n width: \"100%\",\n transition: \"none\",\n },\n searchResultListItem: {\n width: \"100%\",\n display: \"flex\",\n padding: 0,\n transition: \"none\",\n },\n});\n\nclass SearchResultsList extends React.PureComponent {\n componentDidMount = () => {\n const { activeFeature } = this.props;\n //If the search results in exactly one hit (meaning that activeFeature is set on first render),\n // we activate it right a way.\n if (activeFeature) {\n this.handleSingleSearchResult();\n }\n };\n\n handleSingleSearchResult = () => {\n const {\n app,\n activeFeature,\n activeFeatureCollection,\n localObserver,\n addFeatureToSelected,\n } = this.props;\n\n if (activeFeature.onClickName) {\n app.globalObserver.publish(\n `search.featureClicked.${activeFeature.onClickName}`,\n activeFeature\n );\n } else {\n const source = activeFeatureCollection?.source;\n\n activeFeature.source = source;\n addFeatureToSelected({\n feature: activeFeature,\n sourceId: source?.id,\n initiator: \"showDetails\",\n });\n if (this.props.width === \"xs\" || this.props.width === \"sm\") {\n localObserver.publish(\"minimizeSearchResultList\");\n }\n localObserver.publish(\"map.addAndHighlightFeatureInSearchResultLayer\", {\n feature: activeFeature,\n });\n }\n };\n\n handleOnFeatureClick = (feature) => {\n const { app, setActiveFeature } = this.props;\n if (feature.onClickName) {\n app.globalObserver.publish(\n `search.featureClicked.${feature.onClickName}`,\n feature\n );\n } else {\n setActiveFeature(feature);\n }\n };\n\n handleOnFeatureKeyPress = (event, feature) => {\n if (event.which === 13 || event.keyCode === 13) {\n this.handleOnFeatureClick(feature);\n }\n };\n\n renderSearchResultDatasetSummary = (featureCollection) => {\n const { getOriginBasedIcon } = this.props;\n return (\n <SearchResultsDatasetSummary\n featureCollection={featureCollection}\n getOriginBasedIcon={getOriginBasedIcon}\n maxResultsPerDataset={this.props.options.maxResultsPerDataset ?? 100}\n showResultsLimitReachedWarning={\n this.props.options.showResultsLimitReachedWarning ?? true\n }\n />\n );\n };\n\n renderSearchResultDataset = (featureCollection) => {\n const {\n getOriginBasedIcon,\n app,\n activeFeatureCollection,\n activeFeature,\n setActiveFeature,\n handleFeatureCollectionClick,\n featureFilter,\n featureSortingStrategy,\n enableFeaturePreview,\n localObserver,\n enableFeatureToggler,\n selectedFeatures,\n addFeatureToSelected,\n removeFeatureFromSelected,\n shouldRenderSelectedCollection,\n } = this.props;\n return (\n <SearchResultsDataset\n app={app}\n featureCollection={featureCollection}\n getOriginBasedIcon={getOriginBasedIcon}\n selectedFeatures={selectedFeatures}\n activeFeatureCollection={activeFeatureCollection}\n activeFeature={activeFeature}\n handleFeatureCollectionClick={handleFeatureCollectionClick}\n setActiveFeature={setActiveFeature}\n handleOnFeatureClick={this.handleOnFeatureClick}\n handleOnFeatureKeyPress={this.handleOnFeatureKeyPress}\n featureFilter={featureFilter}\n featureSortingStrategy={featureSortingStrategy}\n enableFeaturePreview={enableFeaturePreview}\n localObserver={localObserver}\n enableFeatureToggler={enableFeatureToggler}\n addFeatureToSelected={addFeatureToSelected}\n removeFeatureFromSelected={removeFeatureFromSelected}\n shouldRenderSelectedCollection={shouldRenderSelectedCollection}\n />\n );\n };\n\n renderSearchResultList = () => {\n const { featureCollections, classes, handleFeatureCollectionClick } =\n this.props;\n return (\n <List className={classes.searchResultList}>\n {featureCollections.map((featureCollection) => (\n <ListItem\n disableTouchRipple\n key={featureCollection.source.id}\n className={classes.searchResultListItem}\n id={`search-result-dataset-${featureCollection.source.id}`}\n aria-controls={`search-result-dataset-details-${featureCollection.source.id}`}\n onClick={() => handleFeatureCollectionClick(featureCollection)}\n button\n divider\n >\n {this.renderSearchResultDatasetSummary(featureCollection)}\n </ListItem>\n ))}\n </List>\n );\n };\n\n render() {\n const { activeFeatureCollection } = this.props;\n\n return activeFeatureCollection\n ? this.renderSearchResultDataset(activeFeatureCollection)\n : this.renderSearchResultList();\n }\n}\n\nexport default withStyles(styles)(withWidth()(SearchResultsList));\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { isMobile } from \"../../../utils/IsMobile\";\nimport { List, ListItem } from \"@material-ui/core\";\nimport SearchResultsDatasetFeature from \"./SearchResultsDatasetFeature\";\nimport SearchResultsDatasetFeatureDetails from \"./SearchResultsDatasetFeatureDetails\";\nimport SearchResultsPreview from \"./SearchResultsPreview\";\n\nconst styles = () => ({\n featureList: {\n padding: 0,\n width: \"100%\",\n transition: \"none\",\n },\n featureListItem: {\n width: \"100%\",\n display: \"flex\",\n padding: 0,\n transition: \"none\",\n },\n});\n\nclass SearchResultsDataset extends React.Component {\n //Some sources does not return numberMatched and numberReturned, falling back on features.length\n state = {\n previewFeature: null, // Feature to show in preview\n previewAnchorEl: null, // The element which the preview popper will anchor to\n };\n\n delayBeforeShowingPreview = 800; //Delay before showing preview popper in ms\n previewTimer = null; // Timer to keep track of when delay has passed\n\n shouldComponentUpdate = (prevProps) => {\n const { featureFilter, featureCollection } = this.props;\n const prevFeatureFilter = prevProps.featureFilter;\n const numFeatures = featureCollection.value.features.length;\n const prevNumFeatures = prevProps.featureCollection.value.features.length;\n if (\n featureFilter !== prevFeatureFilter ||\n numFeatures !== prevNumFeatures\n ) {\n clearTimeout(this.previewTimer);\n this.setState({ previewAnchorEl: undefined, previewFeature: undefined });\n return false;\n }\n return true;\n };\n\n componentWillUnmount = () => {\n clearTimeout(this.previewTimer);\n };\n\n setPreviewFeature = (e, feature) => {\n const target = e.currentTarget;\n clearTimeout(this.previewTimer);\n this.previewTimer = setTimeout(() => {\n this.setState({\n previewAnchorEl: target,\n previewFeature: feature,\n });\n }, this.delayBeforeShowingPreview);\n };\n\n resetPreview = () => {\n clearTimeout(this.previewTimer);\n if (this.state.previewFeature)\n this.setState({\n previewAnchorEl: undefined,\n previewFeature: undefined,\n });\n };\n\n getFilteredFeatures = () => {\n const { featureFilter } = this.props;\n const featureCollection = { ...this.props.featureCollection };\n // If user has a value in the filter input...\n if (featureFilter.length > 0) {\n // Filter all features in the collection\n const filteredFeatures = featureCollection.value.features.filter(\n (feature) => {\n // Returning the features having a title including\n // the filter string\n return feature.featureTitle\n .toLowerCase()\n .includes(featureFilter.toLowerCase());\n }\n );\n return filteredFeatures ?? [];\n }\n // Filter length is zero? Return all features\n return featureCollection.value.features ?? [];\n };\n\n getSortedFeatures = (features) => {\n const { featureSortingStrategy } = this.props;\n\n const featuresAtoZSorted = features.sort((a, b) =>\n a.featureTitle.localeCompare(b.featureTitle, undefined, {\n numeric: true, // Ensure that 1 < 2 < 10\n })\n );\n\n switch (featureSortingStrategy) {\n case \"ZtoA\":\n return featuresAtoZSorted.reverse();\n default:\n // AtoZ\n return featuresAtoZSorted;\n }\n };\n\n renderFeatureDetails = (features) => {\n const {\n featureCollection,\n app,\n activeFeatureCollection,\n activeFeature,\n localObserver,\n setActiveFeature,\n enableFeatureToggler,\n } = this.props;\n return (\n <SearchResultsDatasetFeatureDetails\n feature={activeFeature}\n features={features}\n setActiveFeature={setActiveFeature}\n featureCollection={featureCollection}\n app={app}\n source={activeFeatureCollection.source}\n localObserver={localObserver}\n enableFeatureToggler={enableFeatureToggler}\n />\n );\n };\n\n renderFeatureList = (features) => {\n const {\n featureCollection,\n classes,\n app,\n selectedFeatures,\n activeFeature,\n handleOnFeatureClick,\n handleOnFeatureKeyPress,\n getOriginBasedIcon,\n addFeatureToSelected,\n removeFeatureFromSelected,\n shouldRenderSelectedCollection,\n } = this.props;\n\n const sortedFeatures = this.getSortedFeatures(features);\n return (\n <>\n <List\n className={classes.featureList}\n id={`search-result-dataset-details-${featureCollection.source.id}`}\n >\n {sortedFeatures.map((f) => {\n return (\n <ListItem\n disableTouchRipple\n className={classes.featureListItem}\n key={f.getId()}\n divider\n button\n onClick={() => {\n this.resetPreview();\n handleOnFeatureClick(f);\n }}\n onKeyDown={(event) => handleOnFeatureKeyPress(event, f)}\n onMouseEnter={\n !isMobile ? (e) => this.setPreviewFeature(e, f) : null\n }\n onMouseLeave={!isMobile ? this.resetPreview : null}\n >\n <SearchResultsDatasetFeature\n feature={f}\n app={app}\n source={featureCollection.source}\n origin={featureCollection.origin}\n visibleInMap={\n selectedFeatures.findIndex(\n (item) => item.feature.getId() === f.getId()\n ) > -1\n }\n addFeatureToSelected={addFeatureToSelected}\n removeFeatureFromSelected={removeFeatureFromSelected}\n activeFeature={activeFeature}\n getOriginBasedIcon={getOriginBasedIcon}\n shouldRenderSelectedCollection={\n shouldRenderSelectedCollection\n }\n />\n </ListItem>\n );\n })}\n </List>\n {this.renderSearchResultPreview()}\n </>\n );\n };\n\n renderDatasetDetails = () => {\n const { activeFeature } = this.props;\n\n // If the user has selected a feature, we should show its details\n // if the feature does not have a onClickName. If it does, the details\n // will be taken care of somewhere else.\n const shouldRenderFeatureDetails =\n activeFeature && !activeFeature.onClickName;\n\n const features = this.getFilteredFeatures();\n\n return shouldRenderFeatureDetails\n ? this.renderFeatureDetails(features)\n : this.renderFeatureList(features);\n };\n\n renderSearchResultPreview = () => {\n const { previewFeature, previewAnchorEl } = this.state;\n const { activeFeatureCollection, enableFeaturePreview } = this.props;\n const shouldShowPreview =\n enableFeaturePreview && !isMobile && !previewFeature?.onClickName\n ? true\n : false;\n\n if (shouldShowPreview) {\n return (\n <SearchResultsPreview\n previewFeature={previewFeature}\n activeFeatureCollection={activeFeatureCollection}\n app={this.props.app}\n anchorEl={previewAnchorEl}\n />\n );\n } else {\n return null;\n }\n };\n\n render() {\n return this.renderDatasetDetails();\n }\n}\n\nexport default withStyles(styles)(SearchResultsDataset);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { Checkbox, Typography, Tooltip, Grid } from \"@material-ui/core\";\nimport StarIcon from \"@material-ui/icons/Star\";\nimport StarBorderIcon from \"@material-ui/icons/StarBorder\";\n\nconst styles = (theme) => ({\n root: {\n minHeight: 42,\n width: \"100%\",\n },\n originIconWrapper: {\n paddingLeft: theme.spacing(1),\n },\n typography: {\n maxWidth: \"100%\",\n },\n});\n\nclass SearchResultsDatasetFeature extends React.PureComponent {\n renderShowInMapCheckbox = () => {\n const { visibleInMap } = this.props;\n const helpText = !visibleInMap ? \"Lägg till i urval\" : \"Ta bort från urval\";\n\n return (\n <Grid item align=\"center\">\n <Tooltip title={helpText}>\n <Checkbox\n color=\"default\"\n checked={visibleInMap}\n onClick={(e) => e.stopPropagation()}\n onChange={this.handleCheckboxToggle}\n icon={<StarBorderIcon />}\n checkedIcon={<StarIcon />}\n />\n </Tooltip>\n </Grid>\n );\n };\n\n handleCheckboxToggle = () => {\n const {\n feature,\n source,\n visibleInMap,\n addFeatureToSelected,\n removeFeatureFromSelected,\n } = this.props;\n if (visibleInMap) {\n removeFeatureFromSelected(feature);\n } else {\n feature.source = source;\n addFeatureToSelected({\n feature: feature,\n sourceId: source?.id,\n initiator: \"userSelect\",\n });\n }\n };\n\n renderOriginBasedIcon = () => {\n const { getOriginBasedIcon, origin, classes } = this.props;\n return (\n <Grid className={classes.originIconWrapper}>\n {getOriginBasedIcon(origin)}\n </Grid>\n );\n };\n\n render() {\n const { feature, classes, shouldRenderSelectedCollection } = this.props;\n const shouldRenderCheckbox =\n feature.getGeometry() && shouldRenderSelectedCollection;\n if (feature.featureTitle.length > 0) {\n return (\n <Grid container alignItems=\"center\" className={classes.root}>\n {shouldRenderCheckbox\n ? this.renderShowInMapCheckbox()\n : this.renderOriginBasedIcon()}\n <Grid item xs={9}>\n <Typography noWrap align=\"left\" className={classes.typography}>\n {feature.featureTitle}\n </Typography>\n </Grid>\n <Grid item xs={1}></Grid>\n </Grid>\n );\n } else {\n return null;\n }\n }\n}\nexport default withStyles(styles)(SearchResultsDatasetFeature);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { Grid, Popover, Typography, fade } from \"@material-ui/core\";\nimport SearchResultsDatasetFeatureDetails from \"./SearchResultsDatasetFeatureDetails\";\n\nconst styles = (theme) => ({\n datasetContainer: {\n boxShadow: \"none\",\n overflow: \"hidden\",\n },\n divider: {\n backgroundColor: theme.palette.divider,\n width: \"100%\",\n },\n datasetDetailsContainer: {\n padding: 0,\n },\n hover: {\n cursor: \"pointer\",\n \"&:hover\": {\n backgroundColor: theme.palette.action.hover,\n },\n },\n preview: {\n pointerEvents: \"none\",\n },\n previewPaper: {\n width: 400,\n maxHeight: 200,\n overflow: \"hidden\",\n background: fade(theme.palette.background.paper, 0.8),\n },\n previewHeaderContainer: {\n paddingTop: theme.spacing(0.8),\n },\n previewContentContainer: {\n borderTop: `${theme.spacing(0.2)}px solid ${theme.palette.divider}`,\n },\n});\n\nclass SearchResultsPreview extends React.PureComponent {\n renderFeaturePreview = () => {\n const { classes, activeFeatureCollection, previewFeature, anchorEl, app } =\n this.props;\n\n return (\n <Popover\n id=\"mouse-over-popover\"\n open={anchorEl ? true : false}\n anchorEl={anchorEl}\n classes={{\n root: classes.preview,\n paper: classes.previewPaper,\n }}\n anchorOrigin={{\n vertical: \"center\",\n horizontal: \"left\",\n }}\n transformOrigin={{\n vertical: \"top\",\n horizontal: \"right\",\n }}\n disableRestoreFocus\n >\n <Grid container>\n <Grid\n item\n align=\"center\"\n className={classes.previewHeaderContainer}\n xs={12}\n >\n <Typography variant=\"button\">Förhandsvisning</Typography>\n </Grid>\n <Grid item className={classes.previewContentContainer} xs={12}>\n <SearchResultsDatasetFeatureDetails\n feature={previewFeature}\n app={app}\n source={activeFeatureCollection.source}\n />\n </Grid>\n </Grid>\n </Popover>\n );\n };\n\n render() {\n const { previewFeature } = this.props;\n return previewFeature ? this.renderFeaturePreview() : null;\n }\n}\n\nexport default withStyles(styles)(SearchResultsPreview);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { Typography, Chip, Tooltip, Grid } from \"@material-ui/core\";\n\nconst styles = (theme) => ({\n summaryContainer: {\n minHeight: 42,\n paddingRight: theme.spacing(1),\n paddingLeft: theme.spacing(1),\n },\n typography: {\n maxWidth: \"100%\",\n },\n warningChip: {\n color: theme.palette.warning.contrastText,\n backgroundColor:\n theme.palette.type === \"dark\"\n ? theme.palette.warning.dark\n : theme.palette.warning.light,\n },\n});\n\nclass SearchResultsDatasetSummary extends React.PureComponent {\n //Some sources does not return numberMatched and numberReturned, falling back on features.length\n state = {\n numberOfResultsToDisplay:\n this.props.featureCollection.value.features.length,\n };\n\n shouldDisplayWarning = () => {\n const { numberOfResultsToDisplay } = this.state;\n const {\n maxResultsPerDataset,\n featureCollection,\n showResultsLimitReachedWarning,\n } = this.props;\n const { numberMatched, numberReturned } = featureCollection.value;\n\n if (!showResultsLimitReachedWarning) {\n return false;\n }\n\n if (numberReturned < numberMatched) {\n return true;\n }\n\n return maxResultsPerDataset <= numberOfResultsToDisplay;\n };\n\n renderDatasetSummary = () => {\n const { numberOfResultsToDisplay } = this.state;\n const { featureCollection, getOriginBasedIcon, classes } = this.props;\n\n const displayWarning = this.shouldDisplayWarning();\n const toolTipTitle = displayWarning\n ? `Maximalt antal sökträffar har uppnåtts. Förfina sökningen för att säkerställa att viktig information inte missas.`\n : `Visar ${numberOfResultsToDisplay} resultat`;\n\n return (\n <>\n <Grid\n alignItems=\"center\"\n container\n className={classes.summaryContainer}\n >\n <Grid item xs={1}>\n {getOriginBasedIcon(featureCollection.origin)}\n </Grid>\n <Grid item xs={9}>\n <Typography\n noWrap\n variant=\"button\"\n component=\"div\" // The noWrap does not work on variant=\"button\" without changing component\n className={classes.typography}\n >\n {featureCollection.source.caption}\n </Typography>\n </Grid>\n <Grid container item justify=\"flex-end\" xs={2}>\n <Tooltip title={toolTipTitle}>\n <Chip\n size=\"small\"\n color=\"default\"\n className={displayWarning ? classes.warningChip : null}\n label={`${numberOfResultsToDisplay}${\n displayWarning ? \"+\" : \"\"\n }`}\n />\n </Tooltip>\n </Grid>\n </Grid>\n </>\n );\n };\n\n render() {\n const { numberOfResultsToDisplay } = this.state;\n return parseInt(numberOfResultsToDisplay) > 0\n ? this.renderDatasetSummary()\n : null;\n }\n}\n\nexport default withStyles(styles)(SearchResultsDatasetSummary);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { Button, Tooltip, Menu, MenuItem, Grid } from \"@material-ui/core\";\nimport GetAppIcon from \"@material-ui/icons/GetApp\";\nimport DescriptionIcon from \"@material-ui/icons/Description\";\nimport PublicIcon from \"@material-ui/icons/Public\";\n\nconst styles = (theme) => ({\n menuTogglerButton: {\n minWidth: 30,\n },\n menuItemIcon: {\n paddingRight: theme.spacing(1),\n },\n});\n\nclass SearchResultsDownloadMenu extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.state = {\n anchorEl: null,\n };\n\n this.downloadOptions = [\n {\n name: \"Ladda ner till Excel\",\n icon: <DescriptionIcon />,\n type: \"Excel\",\n enabled: true,\n onClick: this.handleXLSXDownloadClick,\n },\n {\n name: \"Ladda ner till KML\",\n icon: <PublicIcon />,\n type: \"kml\",\n enabled: true,\n onClick: this.handleKMLDownloadClick,\n },\n ];\n }\n\n handleXLSXDownloadClick = () => {\n const { localObserver, featureCollections, featureId } = this.props;\n localObserver.publish(\"downloadMenu.exportXLSXClick\", {\n featureCollections: featureCollections,\n featureId: featureId,\n });\n this.setState({ anchorEl: null });\n };\n\n handleKMLDownloadClick = () => {\n const { localObserver, featureCollections } = this.props;\n localObserver.publish(\"downloadMenu.exportKMLClick\", featureCollections);\n this.setState({ anchorEl: null });\n };\n\n renderMenuTogglerButton = () => {\n const { classes } = this.props;\n return (\n <Tooltip title=\"Ladda ner objekten\">\n <Button\n className={classes.menuTogglerButton}\n onClick={(e) =>\n this.setState({\n anchorEl: e.currentTarget,\n })\n }\n >\n <GetAppIcon />\n </Button>\n </Tooltip>\n );\n };\n\n renderDownloadMenu = () => {\n const { classes } = this.props;\n const { anchorEl } = this.state;\n const enabledDownloadOptions = this.downloadOptions.filter((option) => {\n return option.enabled;\n });\n return (\n <Menu\n anchorEl={anchorEl}\n open={Boolean(anchorEl)}\n onClose={() => this.setState({ anchorEl: null })}\n >\n {enabledDownloadOptions.map((downloadOption, index) => {\n return (\n <MenuItem key={index} onClick={downloadOption.onClick}>\n <Grid container>\n <Grid item className={classes.menuItemIcon}>\n {downloadOption.icon}\n </Grid>\n <Grid item>{downloadOption.name}</Grid>\n </Grid>\n </MenuItem>\n );\n })}\n </Menu>\n );\n };\n\n render() {\n const { classes } = this.props;\n return (\n <>\n <Tooltip title=\"Ladda ner objekten\">\n <Button\n className={classes.menuTogglerButton}\n onClick={(e) =>\n this.setState({\n anchorEl: e.currentTarget,\n })\n }\n >\n <GetAppIcon />\n </Button>\n </Tooltip>\n {this.renderDownloadMenu()}\n </>\n );\n }\n}\n\nexport default withStyles(styles)(SearchResultsDownloadMenu);\n","import React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport {\n ListItemIcon,\n Menu,\n MenuItem,\n Paper,\n Tooltip,\n Typography,\n} from \"@material-ui/core\";\n\nimport Dialog from \"../Dialog.js\";\nimport SearchSettings from \"./SearchSettings\";\n\nconst styles = (theme) => ({});\n\nclass SearchTools extends React.PureComponent {\n state = {\n anchorEl: undefined,\n settingsDialog: false,\n };\n\n constructor(props) {\n super(props);\n this.map = props.map;\n }\n\n handleMenuItemClick = (event, index, option) => {\n const type = option.type;\n if (type === \"SETTINGS\") {\n this.setState({ settingsDialog: true });\n } else {\n this.props.app.globalObserver.publish(option[\"onClickEventName\"], option);\n }\n this.setState({ anchorEl: undefined });\n };\n\n getEnabledTools = () => {\n const { searchTools } = this.props;\n return searchTools.filter((tool) => tool.enabled ?? true);\n };\n\n renderSettingsDialog = () => {\n const { settingsDialog } = this.state;\n const {\n searchOptions,\n searchSources,\n updateSearchOptions,\n searchModel,\n setSearchSources,\n } = this.props;\n if (settingsDialog) {\n return createPortal(\n <Dialog\n options={{\n text: (\n <SearchSettings\n searchOptions={searchOptions}\n searchSources={searchSources}\n updateSearchOptions={updateSearchOptions}\n setSearchSources={setSearchSources}\n searchModel={searchModel}\n />\n ),\n headerText: \"Sökinställningar\",\n buttonText: \"OK\",\n }}\n open={settingsDialog}\n onClose={() => {\n this.setState({\n settingsDialog: false,\n });\n }}\n ></Dialog>,\n document.getElementById(\"windows-container\")\n );\n } else {\n return null;\n }\n };\n\n render() {\n const { anchorEl } = this.state;\n const enabledTools = this.getEnabledTools();\n return (\n <>\n {this.renderSettingsDialog()}\n <Tooltip title=\"Fler sökverktyg och inställningar\">\n <IconButton\n aria-haspopup=\"true\"\n aria-controls=\"lock-menu\"\n name=\"searchOptions\"\n size=\"small\"\n onClick={(e) =>\n this.setState({\n anchorEl: e.currentTarget,\n })\n }\n >\n <Typography variant=\"srOnly\">\n Öppna dialog med fler inställningar\n </Typography>\n <MoreVertIcon />\n </IconButton>\n </Tooltip>\n <Paper>\n <Menu\n id=\"lock-menu\"\n autoFocus={false}\n anchorEl={anchorEl}\n getContentAnchorEl={null}\n anchorOrigin={{ vertical: \"bottom\", horizontal: \"right\" }}\n transformOrigin={{ vertical: \"top\", horizontal: \"center\" }}\n keepMounted\n open={Boolean(anchorEl)}\n onClose={() =>\n this.setState({\n anchorEl: undefined,\n })\n }\n >\n {enabledTools.map((option, index) => (\n <Tooltip key={index} title={option.toolTipTitle ?? \"\"}>\n <MenuItem\n onClick={(event) =>\n this.handleMenuItemClick(event, index, option)\n }\n >\n {option.icon ? (\n <ListItemIcon>{option.icon}</ListItemIcon>\n ) : null}\n <Typography variant=\"srOnly\" noWrap>\n {option.name}\n </Typography>\n <Typography variant=\"inherit\" noWrap>\n {option.name}\n </Typography>\n </MenuItem>\n </Tooltip>\n ))}\n </Menu>\n </Paper>\n </>\n );\n }\n}\n\nexport default withStyles(styles)(SearchTools);\n","import React from \"react\";\n\nimport { withStyles } from \"@material-ui/core/styles\";\nimport {\n Tooltip,\n Grid,\n Switch,\n FormGroup,\n FormLabel,\n FormControl,\n FormControlLabel,\n Select,\n Chip,\n MenuItem,\n Input,\n} from \"@material-ui/core\";\n\nconst styles = (theme) => ({\n chips: {\n display: \"flex\",\n flexWrap: \"wrap\",\n },\n chip: {\n margin: 2,\n },\n});\n\nclass SearchSettings extends React.PureComponent {\n state = {\n showSearchSourcesFilter: this.props.searchSources.length > 0 ? true : false,\n };\n\n localUpdateSearchOptions = (name, value) => {\n const { searchOptions } = this.props;\n // Send the new values up to the Search component's state\n this.props.updateSearchOptions({ ...searchOptions, [name]: value });\n };\n\n render() {\n const { classes, searchOptions, searchSources, searchModel } = this.props;\n return (\n <Grid container spacing={2} direction=\"column\">\n <Grid item xs>\n <FormControl component=\"fieldset\">\n <FormLabel component=\"legend\">Generella sökinställningar</FormLabel>\n <FormGroup>\n <Tooltip title=\"Slå på för att välja vilka datakällor som sökningen kommer göras i. Om reglaget är i off-läget kommer sökningen att ske i alla tillgänliga sökkällor.\">\n <FormControlLabel\n label=\"Begränsa sökkällor\"\n control={\n <Switch\n checked={this.state.showSearchSourcesFilter}\n onChange={(e) => {\n // Pull out the new value\n const showSearchSourcesFilter = e.target.checked;\n\n // Set state to reflect in Switch's UI\n this.setState({\n showSearchSourcesFilter,\n });\n\n // Now, if user has turned off this setting, ensure\n // that we also clean all search sources\n if (showSearchSourcesFilter === false)\n this.props.setSearchSources([]);\n }}\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n {this.state.showSearchSourcesFilter && (\n <Grid container spacing={2}>\n <Grid item xs>\n <Select\n fullWidth\n labelId=\"demo-mutiple-chip-label\"\n multiple\n value={searchSources}\n onChange={(event) =>\n this.props.setSearchSources(event.target.value)\n }\n input={<Input id=\"select-multiple-chip\" />}\n renderValue={(selected) => (\n <div className={classes.chips}>\n {selected.map((option) => (\n <Chip\n key={option.id}\n label={option.caption}\n className={classes.chip}\n />\n ))}\n </div>\n )}\n >\n {searchModel.getSources().map((source) => (\n <MenuItem\n key={source.id}\n value={source}\n // style={getStyles(name, personName, theme)}\n >\n {source.caption}\n </MenuItem>\n ))}\n </Select>\n </Grid>\n </Grid>\n )}\n </FormGroup>\n <FormGroup>\n <Tooltip title=\"Om aktivt kommer sökningen att ske i lager som är inställda för sökning av systemadministratören och som är synliga.\">\n <FormControlLabel\n label=\"Sök endast i synliga lager\"\n control={\n <Switch\n checked={searchOptions.searchInVisibleLayers}\n onChange={() => {\n this.localUpdateSearchOptions(\n \"searchInVisibleLayers\",\n !searchOptions.searchInVisibleLayers\n );\n }}\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n </FormGroup>\n </FormControl>\n </Grid>\n\n <Grid item xs>\n <FormControl component=\"fieldset\">\n <FormLabel component=\"legend\">\n Inställningar för textsökning\n </FormLabel>\n <FormGroup>\n <Tooltip title=\"Om aktivt kommer en sökning på 'väg' även ge träffar på exempelvis 'storväg'.\">\n <FormControlLabel\n label=\"Wildcard före\"\n control={\n <Switch\n checked={searchOptions.wildcardAtStart}\n onChange={() =>\n this.localUpdateSearchOptions(\n \"wildcardAtStart\",\n !searchOptions.wildcardAtStart\n )\n }\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n <Tooltip title=\"Om aktivt kommer en sökning på 'väg' även ge träffar på exempelvis 'vägen'.\">\n <FormControlLabel\n label=\"Wildcard efter\"\n control={\n <Switch\n checked={searchOptions.wildcardAtEnd}\n onChange={() =>\n this.localUpdateSearchOptions(\n \"wildcardAtEnd\",\n !searchOptions.wildcardAtEnd\n )\n }\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n <Tooltip title=\"Om aktivt kommer en sökning på 'a' inte ge träffar på 'A'. Inaktivera för att söka oberoende av gemener/versaler.\">\n <FormControlLabel\n label=\"Skiftlägeskänslighet\"\n control={\n <Switch\n checked={searchOptions.matchCase}\n onChange={() =>\n this.localUpdateSearchOptions(\n \"matchCase\",\n !searchOptions.matchCase\n )\n }\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n </FormGroup>\n </FormControl>\n </Grid>\n\n <Grid item xs>\n <FormControl component=\"fieldset\">\n <FormLabel component=\"legend\">Spatiala sökinställningar</FormLabel>\n <FormGroup>\n <Tooltip title=\"Om aktivt kommer hela objektet (exempelvis en fastigheten) behöva rymmas inom sökområdet för att komma med i resultatet. Om inaktivt räcker det att endast en liten del av objektet ryms inom, eller nuddar vid, sökområdet.\">\n <FormControlLabel\n label=\"Kräv att hela objektet ryms inom sökområde\"\n control={\n <Switch\n checked={searchOptions.activeSpatialFilter === \"within\"}\n onChange={() =>\n this.localUpdateSearchOptions(\n \"activeSpatialFilter\",\n searchOptions.activeSpatialFilter === \"intersects\"\n ? \"within\"\n : \"intersects\"\n )\n }\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n </FormGroup>\n </FormControl>\n </Grid>\n\n <Grid item xs>\n <FormControl component=\"fieldset\">\n <FormLabel component=\"legend\">Visning av resultat</FormLabel>\n <FormGroup>\n <Tooltip title=\"Om aktivt kommer en etikett att visas i kartan intill det markerade sökresultatet\">\n <FormControlLabel\n label=\"Visa textetikett i kartan\"\n control={\n <Switch\n checked={searchOptions.enableLabelOnHighlight}\n onChange={() =>\n this.localUpdateSearchOptions(\n \"enableLabelOnHighlight\",\n !searchOptions.enableLabelOnHighlight\n )\n }\n color=\"primary\"\n />\n }\n />\n </Tooltip>\n </FormGroup>\n </FormControl>\n </Grid>\n </Grid>\n );\n }\n}\n\nexport default withStyles(styles)(SearchSettings);\n","import Draw from \"ol/interaction/Draw\";\nimport { Stroke, Style, Circle, Fill } from \"ol/style\";\nimport { Vector as VectorLayer } from \"ol/layer\";\nimport VectorSource from \"ol/source/Vector\";\nimport { extend, createEmpty, isEmpty } from \"ol/extent\";\nimport Feature from \"ol/Feature\";\nimport FeatureStyle from \"./utils/FeatureStyle\";\nimport { fromExtent } from \"ol/geom/Polygon\";\nimport TileLayer from \"ol/layer/Tile\";\nimport ImageLayer from \"ol/layer/Image\";\nimport { handleClick } from \"../../models/Click\";\nimport { deepMerge } from \"utils/DeepMerge\";\nimport { isValidLayerId } from \"../../utils/Validator\";\n\nclass MapViewModel {\n constructor(settings) {\n this.map = settings.map;\n this.app = settings.app;\n this.options = settings.options;\n this.drawStyleSettings = this.getDrawStyleSettings();\n this.featureStyle = new FeatureStyle(settings.options);\n this.localObserver = settings.localObserver;\n this.initMapLayers();\n this.bindSubscriptions();\n }\n\n ctrlKeyPressed = false;\n\n // An object holding the last highlightInformation.\n // We use this to restore highlight after filter changes.\n lastFeaturesInfo = [];\n\n refreshFeatureStyle = (options) => {\n this.featureStyle = new FeatureStyle(deepMerge(this.options, options));\n // Make sure to set the new style on the results layer. This way\n // we'll get correct labels (if user wants to show them).\n this.resultsLayer.setStyle(this.featureStyle.getDefaultSearchResultStyle);\n };\n\n getDrawStyleSettings = () => {\n const strokeColor = this.options.drawStrokeColor ?? \"rgba(74,74,74,0.5)\";\n const fillColor = this.options.drawFillColor ?? \"rgba(255,255,255,0.07)\";\n\n return { strokeColor: strokeColor, fillColor: fillColor };\n };\n\n getNewVectorSource = () => {\n return new VectorSource({ wrapX: false });\n };\n\n getNewVectorLayer = (source, style) => {\n return new VectorLayer({\n source: source,\n style: style,\n });\n };\n\n getVisibleLayers = () => {\n return this.map\n .getLayers()\n .getArray()\n .filter((layer) => {\n return (\n (layer instanceof TileLayer || layer instanceof ImageLayer) &&\n layer.layersInfo !== undefined &&\n // We consider a layer to be visible only if…\n layer.getVisible() && // …it's visible…\n layer.getSource().getParams()[\"LAYERS\"] &&\n layer.getProperties().name &&\n isValidLayerId(layer.getProperties().name) // …has a specified name property…\n );\n })\n .map((layer) => layer.getSource().getParams()[\"LAYERS\"])\n .join(\",\")\n .split(\",\");\n };\n\n getVisibleSearchLayers = () => {\n const searchSources = this.options.sources;\n const visibleLayers = this.getVisibleLayers();\n const visibleSearchLayers = searchSources.filter((s) => {\n return visibleLayers.find((l_id) => l_id === s.id);\n });\n return visibleSearchLayers;\n };\n\n initMapLayers = () => {\n this.resultSource = this.getNewVectorSource();\n this.resultsLayer = this.getNewVectorLayer(\n this.resultSource,\n this.options.showResultFeaturesInMap ?? true\n ? this.featureStyle.getDefaultSearchResultStyle\n : null\n );\n this.resultsLayer.set(\"type\", \"searchResultLayer\");\n this.drawSource = this.getNewVectorSource();\n this.drawLayer = this.getNewVectorLayer(\n this.drawSource,\n this.getDrawStyle()\n );\n this.map.addLayer(this.drawLayer);\n this.map.addLayer(this.resultsLayer);\n };\n\n bindSubscriptions = () => {\n // Local subscriptions\n this.localObserver.subscribe(\"clearMapView\", this.clearMap);\n this.localObserver.subscribe(\"map.zoomToFeatures\", this.zoomToFeatures);\n this.localObserver.subscribe(\n \"map.addFeaturesToResultsLayer\",\n this.addFeaturesToResultsLayer\n );\n this.localObserver.subscribe(\"map.setSelectedStyle\", this.setSelectedStyle);\n this.localObserver.subscribe(\n \"map.addAndHighlightFeatureInSearchResultLayer\",\n this.addAndHighlightFeatureInSearchResultLayer\n );\n this.localObserver.subscribe(\n \"map.updateFeaturesAfterFilterChange\",\n this.updateFeaturesAfterFilterChange\n );\n this.localObserver.subscribe(\n \"map.setHighLightedStyle\",\n this.setHighLightedStyle\n );\n this.localObserver.subscribe(\"map.zoomToFeature\", this.zoomToFeature);\n // Global subscriptions\n this.app.globalObserver.subscribe(\n \"search.spatialSearchActivated\",\n (options) => {\n if (options.type === \"Extent\") {\n this.searchInCurrentExtent();\n } else if (options.type === \"Select\") {\n this.enableSelectFeaturesSearch();\n } else {\n this.toggleDraw(true, options.type);\n }\n\n // At this stage, the Search input field could be in focus. On\n // mobile devices the on-screen keyboard will show up. We don't\n // need it here (as these search options are purely click/touch-based)\n // so we ensure that it's hidden by blurring the focus.\n document.activeElement.blur();\n }\n );\n };\n\n updateFeaturesAfterFilterChange = (featureInfo) => {\n const { features, featureIds } = featureInfo;\n this.resultSource.forEachFeature((feature) => {\n if (featureIds.indexOf(feature.getId()) === -1) {\n this.resultSource.removeFeature(feature);\n }\n });\n features.forEach((feature) => {\n if (!this.resultSource.getFeatureById(feature.getId())) {\n this.resultSource.addFeature(feature);\n }\n });\n this.setSelectedStyle(this.lastFeaturesInfo);\n this.zoomToFeatures(this.lastFeaturesInfo);\n };\n\n fitMapToSearchResult = () => {\n const currentExtent = this.resultSource.getExtent();\n if (currentExtent.map(Number.isFinite).includes(false) === false) {\n this.fitMapToExtent(currentExtent);\n }\n };\n\n fitMapToExtent = (extent) => {\n this.map.getView().fit(extent, {\n size: this.map.getSize(),\n padding: [20, 20, 20, 20],\n maxZoom: 7,\n });\n };\n\n addFeaturesToResultsLayer = (features) => {\n this.resultSource.clear();\n this.resultSource.addFeatures(features);\n\n if (this.options.showResultFeaturesInMap) {\n this.fitMapToSearchResult();\n }\n };\n\n resetStyleForFeaturesInResultSource = () => {\n this.resultSource.getFeatures().map((f) => f.setStyle(null));\n };\n\n drawSourceHasFeatures = () => {\n return this.drawSource.getFeatures().length > 0;\n };\n\n getDrawStyle = () => {\n return new Style({\n stroke: new Stroke({\n color: this.drawStyleSettings.strokeColor,\n width: 4,\n }),\n fill: new Fill({\n color: this.drawStyleSettings.fillColor,\n }),\n image: new Circle({\n radius: 6,\n stroke: new Stroke({\n color: this.drawStyleSettings.strokeColor,\n width: 2,\n }),\n }),\n });\n };\n\n setHighLightedStyle = (feature) => {\n if (!feature) {\n return;\n }\n const mapFeature = this.getFeatureFromResultSourceById(feature.getId());\n return mapFeature?.setStyle(\n this.featureStyle.getFeatureStyle(mapFeature, \"highlight\")\n );\n };\n\n zoomToFeature = (feature) => {\n if (!feature) {\n return;\n }\n const extent = createEmpty();\n const mapFeature = this.getFeatureFromResultSourceById(feature.getId());\n extend(extent, mapFeature?.getGeometry().getExtent());\n const extentToZoomTo = isEmpty(extent)\n ? this.resultSource.getExtent()\n : extent;\n this.fitMapToExtent(extentToZoomTo);\n };\n\n setSelectedStyle = (featuresInfo) => {\n this.lastFeaturesInfo = featuresInfo;\n this.resetStyleForFeaturesInResultSource();\n featuresInfo.map((featureInfo) => {\n const feature = this.getFeatureFromResultSourceById(\n featureInfo.feature.getId()\n );\n return feature?.setStyle(\n this.featureStyle.getFeatureStyle(feature, \"selection\")\n );\n });\n };\n\n addAndHighlightFeatureInSearchResultLayer = (featureInfo) => {\n const feature = featureInfo.feature;\n feature.setStyle(this.featureStyle.getFeatureStyle(feature, \"highlight\"));\n this.resultSource.addFeature(feature);\n this.fitMapToSearchResult();\n };\n\n getFeatureFromResultSourceById = (fid) => {\n return this.resultSource.getFeatureById(fid);\n };\n\n zoomToFeatures = (featuresInfo) => {\n let extent = createEmpty();\n\n //BoundingExtent-function gave wrong coordinates for some\n featuresInfo.forEach((featureInfo) => {\n const feature = this.getFeatureFromResultSourceById(\n featureInfo.feature.getId()\n );\n if (feature) {\n extend(\n extent,\n this.getFeatureFromResultSourceById(featureInfo.feature.getId())\n .getGeometry()\n .getExtent()\n );\n }\n });\n const extentToZoomTo = isEmpty(extent)\n ? this.resultSource.getExtent()\n : extent;\n\n this.fitMapToExtent(extentToZoomTo);\n };\n\n clearMap = () => {\n if (this.drawSource) {\n this.drawSource.clear();\n }\n if (this.resultSource) {\n this.resultSource.clear();\n }\n this.removeDrawInteraction();\n this.removeSelectListeners();\n this.lastFeaturesInfo = [];\n };\n\n removeDrawInteraction = () => {\n if (this.draw) {\n this.map.removeInteraction(this.draw);\n }\n };\n\n toggleDraw = (active, type, freehand = false) => {\n this.localObserver.publish(\"on-draw-start\", type);\n if (active) {\n this.draw = new Draw({\n source: this.drawSource,\n type: type,\n freehand: type === \"Circle\" ? true : freehand,\n stopClick: true,\n style: this.getDrawStyle(),\n });\n\n this.map.clickLock.add(\"search\");\n this.map.addInteraction(this.draw);\n this.drawSource.clear();\n this.drawSource.on(\"addfeature\", this.handleDrawFeatureAdded);\n } else {\n this.map.removeInteraction(this.draw);\n this.map.clickLock.delete(\"search\");\n\n this.drawSource.clear();\n }\n };\n\n handleDrawFeatureAdded = (e) => {\n // OpenLayers seems to have a problem stopping the clicks if\n // the draw interaction is removed too early. This fix is not pretty,\n // but it gets the job done. It seems to be enough to remove the draw\n // interaction after one cpu-cycle.\n // If this is not added, the user will get a zoom-event when closing\n // a polygon drawing.\n setTimeout(() => {\n this.map.removeInteraction(this.draw);\n this.map.clickLock.delete(\"search\");\n }, 1);\n this.localObserver.publish(\"on-draw-end\", e.feature);\n };\n\n searchInCurrentExtent = () => {\n try {\n const currentExtent = this.map\n .getView()\n .calculateExtent(this.map.getSize());\n\n if (!this.extentIsFinite(currentExtent)) {\n throw new Error(\"Current extent could not be calculated correctly.\");\n }\n const feature = new Feature(fromExtent(currentExtent));\n this.drawSource.addFeature(feature);\n this.localObserver.publish(\"search-within-extent\", [feature]);\n } catch (error) {\n this.handleSearchInCurrentExtentError(error);\n }\n };\n\n extentIsFinite = (extent) => {\n return extent.map(Number.isFinite).includes(false) === false;\n };\n\n handleSearchInCurrentExtentError = (error) => {\n this.localObserver.publish(\"extent-search-failed\");\n console.warn(\"Extent-search-failed: \", error);\n };\n\n enableSelectFeaturesSearch = () => {\n this.drawSource.un(\"addfeature\", this.handleDrawFeatureAdded);\n this.ctrlKeyPressed = false;\n this.localObserver.publish(\"on-select-search-start\");\n this.addSelectListeners();\n };\n\n addSelectListeners = () => {\n this.map.clickLock.add(\"search\");\n this.map.on(\"singleclick\", this.handleSelectFeatureClick);\n document.addEventListener(\"keydown\", this.handleKeyDown);\n document.addEventListener(\"keyup\", this.handleKeyUp);\n };\n\n removeSelectListeners = () => {\n this.map.clickLock.delete(\"search\");\n this.map.un(\"singleclick\", this.handleSelectFeatureClick);\n document.removeEventListener(\"keydown\", this.handleKeyDown);\n document.removeEventListener(\"keyup\", this.handleKeyUp);\n };\n\n handleSelectFeatureClick = (event) => {\n handleClick(event, event.map, (response) => {\n const features = response.features;\n if (features.length === 0) {\n return;\n }\n this.drawSource.addFeatures(response.features);\n if (!this.ctrlKeyPressed) {\n const allFeatures = this.drawSource.getFeatures();\n this.localObserver.publish(\"on-search-selection-done\", allFeatures);\n this.removeSelectListeners();\n }\n });\n };\n\n handleKeyDown = (event) => {\n const { keyCode } = event;\n if (keyCode === 17 && !this.ctrlKeyPressed) {\n this.ctrlKeyPressed = true;\n }\n };\n\n handleKeyUp = (event) => {\n const { keyCode } = event;\n if (keyCode === 17) {\n this.ctrlKeyPressed = false;\n if (this.drawSourceHasFeatures()) {\n const features = this.drawSource.getFeatures();\n this.localObserver.publish(\"on-search-selection-done\", features);\n this.removeSelectListeners();\n }\n }\n };\n}\n\nexport default MapViewModel;\n","import FeatureStyle from \"./FeatureStyle\";\nimport { createXML } from \"../../../utils/KMLWriter\";\nimport { saveAs } from \"file-saver\";\n\nimport { Circle as CircleStyle, Icon } from \"ol/style.js\";\nimport { fromCircle } from \"ol/geom/Polygon.js\";\nimport { Circle } from \"ol/geom.js\";\n\nexport default class KmlExport {\n #featureStyle;\n\n constructor(settings) {\n this.#featureStyle = new FeatureStyle(settings.options);\n this.localObserver = settings.localObserver;\n this.map = settings.map;\n this.bindSubscriptions();\n }\n\n bindSubscriptions = () => {\n this.localObserver.subscribe(\"downloadMenu.exportKMLClick\", this.export);\n };\n\n // Exposed method that:\n // - Expects an object as follows:\n // - {featureCollections: [collections], feature: feature}\n // - If feature is undefined, it exports all features in all collections\n // - Otherwise, it exports the supplied feature. (The collection is needed\n // to create the labels.\n export = (featureCollections) => {\n const exportFeatures = this.#getStyledFeatures(featureCollections);\n this.#exportFeatures(exportFeatures);\n };\n\n #getStyledFeatures = (featureCollections) => {\n return featureCollections\n .map((featureCollection) => {\n return featureCollection.value.features.map((feature) => {\n // Loop all Feature Collections, and loop each Feature\n // within in order to extract a new, correctly styled\n // OL Feature that will be used by the KML writer.\n return this.#getStyledFeature(feature);\n });\n })\n .flat();\n };\n\n #getStyledFeature = (feature) => {\n // Don't modify existing features\n const gjFeature = feature.clone();\n\n // .clone() doesn't take care of our custom properties,\n // so we must add them manually.\n gjFeature.featureTitle = feature.featureTitle;\n gjFeature.shortFeatureTitle = feature.shortFeatureTitle;\n\n // Reset the current style before applying new one\n gjFeature.setStyle();\n gjFeature.setStyle(\n this.#featureStyle.getFeatureStyle(gjFeature, \"selection\")\n );\n return gjFeature;\n };\n\n #exportFeatures = (features) => {\n try {\n new Blob();\n } catch {\n console.info(\"KML export not supported on current platform.\");\n return;\n }\n\n const transformed = [];\n\n features.forEach((feature) => {\n let circleRadius = false;\n if (feature.getGeometry() instanceof Circle) {\n const geom = fromCircle(feature.getGeometry(), 96);\n feature.setGeometry(geom);\n circleRadius = feature.getGeometry().getRadius();\n }\n feature\n .getGeometry()\n .transform(this.map.getView().getProjection(), \"EPSG:4326\");\n\n if (feature.getStyle()[1]) {\n feature.setProperties({\n style: JSON.stringify(\n this.#extractStyle(\n feature.getStyle()[1] || feature.getStyle()[0],\n circleRadius\n )\n ),\n geometryType:\n feature.getGeometryName() === \"geometry\"\n ? feature.getProperties().geometryType\n : feature.getGeometryName(),\n });\n }\n\n transformed.push(feature);\n });\n\n if (features.length > 0) {\n const postData = createXML(transformed, \"Sökexport\");\n saveAs(\n new Blob([postData], {\n type: \"application/vnd.google-earth.kml+xml;charset=utf-8\",\n }),\n `Hajk - ${new Date().toLocaleString()}.kml`\n );\n }\n };\n\n #extractStyle = (style, circleRadius) => {\n const styleObj = {};\n\n styleObj.text = style?.getText()?.getText() ?? \"\";\n styleObj.image =\n styleObj.getImage() instanceof Icon ? style.getImage().getSrc() : \"\";\n styleObj.pointRadius =\n style.getImage() instanceof CircleStyle\n ? style.getImage().getRadius()\n : \"\";\n if (circleRadius) {\n styleObj.radius = circleRadius;\n }\n styleObj.pointColor =\n style.getImage() instanceof CircleStyle\n ? style.getImage().getFill().getColor()\n : \"\";\n styleObj.fillColor = style.getFill().getColor();\n styleObj.strokeColor = style.getStroke().getColor();\n styleObj.strokeWidth = style.getStroke().getWidth();\n styleObj.strokeDash = style.getStroke().getLineDash();\n return styleObj;\n };\n}\n","import XLSX from \"xlsx\";\n\nexport default class XLSXExport {\n constructor(settings) {\n this.localObserver = settings.localObserver;\n this.bindSubscriptions();\n }\n\n bindSubscriptions = () => {\n this.localObserver.subscribe(\"downloadMenu.exportXLSXClick\", this.export);\n };\n\n export = (exportItems) => {\n try {\n const { featureCollections } = exportItems;\n const workBook = XLSX.utils.book_new();\n const fileName = this.#getFileName(featureCollections);\n\n if (\n featureCollections?.length === 1 &&\n featureCollections[0].origin === \"USERSELECT\"\n ) {\n return this.#createUserSelectedExport(featureCollections[0], fileName);\n }\n\n featureCollections.forEach((fc) => {\n const sheet = this.#createXLSXSheet(fc);\n if (sheet) {\n const sheetName = this.#getSheetName(fc);\n XLSX.utils.book_append_sheet(workBook, sheet, sheetName);\n }\n });\n\n return XLSX.writeFile(workBook, fileName);\n } catch (error) {\n console.warn(\"Failed to export xlsx...\", error);\n }\n };\n\n #getFileName = (featureCollections) => {\n return featureCollections?.length === 1\n ? `${this.#getSheetName(\n featureCollections[0]\n )}-${new Date().toLocaleString()}.xlsx`\n : `Sökexport-${new Date().toLocaleString()}.xlsx`;\n };\n\n #createUserSelectedExport = (featureCollection, fileName) => {\n try {\n const workBook = XLSX.utils.book_new();\n const groupedFeatures = this.#getGroupedFeatures(featureCollection);\n\n Object.keys(groupedFeatures).forEach((key) => {\n const sheetName = key.slice(0, 30);\n const exportArray = this.#getUserSelectedExportArray(\n groupedFeatures[key]\n );\n const sheet = XLSX.utils.aoa_to_sheet(exportArray);\n XLSX.utils.book_append_sheet(workBook, sheet, sheetName);\n });\n\n return XLSX.writeFile(workBook, fileName);\n } catch (error) {\n console.warn(\"Failed to export user selected xlsx...\", error);\n }\n };\n\n #getGroupedFeatures = (featureCollection) => {\n return featureCollection.value.features.reduce((result, f) => {\n (result[f.source.caption] ?? (result[f.source.caption] = [])).push(f);\n return result;\n }, {});\n };\n\n #getUserSelectedExportArray = (features) => {\n const exportArray = [];\n // Keys from first feature. We assume that all features in the collections has the same keys.\n const keys = Object.keys(features[0].getProperties());\n exportArray.push(keys);\n features.forEach((feature) => {\n exportArray.push(Object.values(feature.getProperties()));\n });\n return exportArray;\n };\n\n #createXLSXSheet = (featureCollection) => {\n if (featureCollection?.value?.features?.length > 0) {\n // Destruct the features for readability\n const { features } = featureCollection.value;\n // Initialize a set which will keep track of _all_ the keys that exist on the\n // features. (Except for the key corresponding to the geometry).\n const keys = new Set();\n // Initialize an array that will contain the keys and all values. (This array\n // will be the result from this function). Example:\n // [key1, key2, key3, val_0_0, val_0_1, val_0_2, val_1_0, val_1_1, val_1_2]\n const exportArray = [];\n // We have to make sure that we get all the keys. To ensure this, we must loop\n // over all the features, and make sure that each key is in the set. If it is not\n // we should add it! (As long as it's not the geometry-key).\n features.forEach((feature) => {\n // Get the geometry name (since we don't want to add the geometry\n // property key). (We don't want the geometry in the export).\n const geometryName = feature.getGeometryName();\n // Then we'll get all the value keys (all keys except for the geometry-key).\n const featureValueKeys = feature\n .getKeys()\n .filter((key) => key !== geometryName);\n // Then we'll loop over the keys and add them to the set of keys if it is missing.\n featureValueKeys.forEach((key) => {\n keys.add(key);\n });\n });\n\n // We want the keys at the beginning (top) of the export, so lets\n // push them to the exportArray first.\n exportArray.push([...keys]);\n\n // When we got the keys, we can extract the corresponding values\n // from each feature.\n features.forEach((feature) => {\n // First we have to get all the properties\n const featureProperties = feature.getProperties();\n // Then we initiate a values array\n const values = [];\n // Then we push the value for each key to the value\n // array. Remember that some values might be nullish,\n // but they are still important, otherwise the fields in the\n // xlsx export might get a messed up order.\n for (const key of keys) {\n // If the value is missing, we replace it with an empty string.\n const value = featureProperties[key] ?? \"\";\n // Then push we push it to the array.\n values.push(value);\n }\n // Then we push the array of values to the export array!\n exportArray.push(values);\n });\n\n return XLSX.utils.aoa_to_sheet(exportArray);\n } else {\n return null;\n }\n };\n\n #getSheetName = (featureCollection) => {\n const sheetName = featureCollection?.source?.caption ?? \"Namn saknas\";\n // XLSX does not support names longer than 30 chars.\n return sheetName.slice(0, 30);\n };\n}\n","import React from \"react\";\nimport { easeOut } from \"ol/easing\";\nimport { Button, Paper } from \"@material-ui/core\";\nimport AddIcon from \"@material-ui/icons/Add\";\nimport RemoveIcon from \"@material-ui/icons/Remove\";\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n display: \"flex\",\n flexDirection: \"column\",\n },\n button: {\n minWidth: \"unset\",\n },\n}));\n\nconst ZoomControl = React.memo((props) => {\n const classes = useStyles();\n\n function zoomByDelta(delta) {\n if (!props.map) return;\n const view = props.map.getView();\n\n if (!view) return;\n const currentZoom = view.getZoom();\n\n if (currentZoom !== undefined) {\n const newZoom = currentZoom + delta;\n\n // TODO: Duration could be an option from map config, allowing admin to disable zoom animation\n const duration = 200;\n if (duration > 0) {\n if (view.getAnimating()) {\n view.cancelAnimations();\n }\n view.animate({\n zoom: newZoom,\n duration: duration,\n easing: easeOut,\n });\n } else {\n view.setZoom(newZoom);\n }\n }\n }\n\n return (\n props.map !== undefined && (\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Zooma in\"\n className={classes.button}\n onClick={() => {\n zoomByDelta(1);\n }}\n >\n <AddIcon />\n </Button>\n <Button\n aria-label=\"Zooma ut\"\n className={classes.button}\n onClick={() => {\n zoomByDelta(-1);\n }}\n >\n <RemoveIcon />\n </Button>\n </Paper>\n )\n );\n});\n\nexport default ZoomControl;\n","import React from \"react\";\nimport { Avatar, Button, Paper, Tooltip } from \"@material-ui/core\";\n\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n avatar: {\n width: 25,\n height: 25,\n fontSize: \"0.8rem\",\n backgroundColor: theme.palette.text.primary,\n },\n}));\n\n/**\n * @summary Transform a full name to initials, e.g. \"John Smith\" to \"JS\"\n *\n * @param {string} displayName\n * @returns {string} The initials from supplied string\n */\nconst getInitialsFromDisplayName = (displayName) => {\n return displayName\n .split(\" \")\n .map((name) => name[0])\n .join(\"\")\n .toUpperCase();\n};\n\n/**\n * @summary Compose a tooltip string by joining some user detail values\n *\n * @param {object} userDetails\n * @returns {string} Tooltip string value\n */\nconst getTooltipString = (userDetails) => {\n // Let's combine the details to an array\n const userDetailsArrays = [userDetails.displayName, userDetails.description];\n // Then we'll get rid of empty values, and create a string by joining the non-empty\n // values.\n return userDetailsArrays.filter((v) => v !== undefined).join(\", \");\n};\n\n/**\n * @summary A button that contains user's initials inside an Avatar component\n *\n * @param {object} props\n * @returns {object} React\n */\nconst User = React.memo(({ userDetails }) => {\n const classes = useStyles();\n\n return (\n (userDetails && (\n <Tooltip title={getTooltipString(userDetails)}>\n <Paper className={classes.paper}>\n <Button\n aria-label={userDetails.displayName}\n className={classes.button}\n >\n <Avatar alt={userDetails.displayName} className={classes.avatar}>\n {getInitialsFromDisplayName(userDetails.displayName)}\n </Avatar>\n </Button>\n </Paper>\n </Tooltip>\n )) ||\n null\n );\n});\n\nexport default User;\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { easeOut } from \"ol/easing\";\nimport { Button, Paper, Tooltip } from \"@material-ui/core\";\nimport NavigationIcon from \"@material-ui/icons/Navigation\";\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n}));\n\nconst RotateControl = React.memo((props) => {\n const classes = useStyles();\n const view = useRef();\n const [rotation, setRotation] = useState(view.current?.getRotation() || 0);\n\n useEffect(() => {\n // No reason to go on if there's no map yet\n if (!props.map) return;\n\n // Put the View object into our ref\n view.current = props.map.getView();\n\n // Subscribe to View's rotation change event. When this happens,\n // we want to read the new rotation and put in state.\n view.current.on(\"change:rotation\", subscribeToRotation);\n return () => {\n // Callback in useEffect is the place where we can cleanup\n // previous code. In this case, we unsubscribe the from the\n // event (so we don't get multiple listeners should this get\n // called more times).\n view.current.un(\"change:rotation\", subscribeToRotation);\n };\n }, [props]);\n\n // Use when (un)subscribing View's change rotation event\n function subscribeToRotation() {\n setRotation(view.current.getRotation());\n }\n\n // onClick handler that resets the map (north at top)\n function rotateNorth() {\n // TODO: This could be an option in admin\n const duration = 400;\n\n if (!view.current) return;\n\n if (rotation !== undefined) {\n // If 'duration' will be an option, we must see if user wants to animate or not\n if (duration > 0) {\n view.current.animate({\n rotation: 0,\n duration: duration,\n easing: easeOut,\n });\n } else {\n view.current.setRotation(0);\n }\n }\n }\n\n return (\n (props.map && rotation !== 0 && (\n <Tooltip title=\"Återställ rotation\">\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Återställ rotation\"\n className={classes.button}\n onClick={rotateNorth}\n >\n <NavigationIcon style={{ transform: `rotate(${rotation}rad)` }} />\n </Button>\n </Paper>\n </Tooltip>\n )) ||\n null\n );\n});\n\nexport default RotateControl;\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { ScaleLine } from \"ol/control\";\nimport { Paper, Tooltip } from \"@material-ui/core\";\n\nconst styles = (theme) => {\n return {\n scaleLine: {\n \"& .ol-scale-line\": {\n position: \"static\",\n right: \"inherit\",\n bottom: \"inherit\",\n padding: \"3px\",\n background: theme.palette.background.paper,\n boxShadow: theme.shadows[4],\n borderRadius: theme.shape.borderRadius,\n },\n \"& .ol-scale-line-inner\": {\n cursor: \"default\",\n borderColor: theme.palette.text.primary,\n color: theme.palette.text.primary,\n fontSize: \"0.7em\",\n lineHeight: \"1.5em\",\n },\n },\n scaleBadge: {\n padding: \"0 4px\",\n color: theme.palette.text.primary,\n fontSize: \"0.7em\",\n lineHeight: \"25px\",\n borderRadius: theme.shape.borderRadius,\n cursor: \"default\",\n },\n };\n};\n\nclass ScaleLineControl extends React.PureComponent {\n state = {\n scale: 0,\n };\n\n constructor(props) {\n super(props);\n this.ref = React.createRef();\n }\n\n componentDidUpdate() {\n // Important condition, to ensure that we don't add new ScaleLine and Binds each time value changes\n if (this.props.map && this.ref.current.children.length === 0) {\n // Set initial value of scale\n this.setState({\n scale: this.formatScale(this.getScale()),\n });\n\n // Add ScaleLine\n const scaleLineControl = new ScaleLine({\n target: this.ref.current,\n });\n this.props.map.addControl(scaleLineControl);\n\n // Add custom scale bar with numbers (e.g. 1:1000)\n // Bind change event to update current scale\n this.props.map.getView().on(\"change:resolution\", () => {\n this.setState({\n scale: this.formatScale(this.getScale()),\n });\n });\n }\n }\n\n /**\n * Get current map sclae\n * @instance\n * @return {number} map scale\n */\n getScale() {\n const dpi = 25.4 / 0.28,\n mpu = this.props.map.getView().getProjection().getMetersPerUnit(),\n inchesPerMeter = 39.37,\n res = this.props.map.getView().getResolution();\n\n return res * mpu * inchesPerMeter * dpi;\n }\n\n /**\n * Format scale\n * @instance\n * @param {number} scale\n * @return {string} formatted\n */\n formatScale(scale) {\n return Math.round(scale)\n .toString()\n .replace(/\\B(?=(\\d{3})+(?!\\d))/g, \" \");\n }\n\n renderScaleBadge() {\n const { classes } = this.props;\n return (\n <Tooltip title=\"Nuvarande skala\">\n <Paper elevation={4} className={classes.scaleBadge}>\n 1:{this.state.scale}\n </Paper>\n </Tooltip>\n );\n }\n\n render() {\n const { classes } = this.props;\n return (\n <>\n <div ref={this.ref} className={classes.scaleLine} />\n {this.renderScaleBadge()}\n </>\n );\n }\n}\n\nexport default withStyles(styles)(ScaleLineControl);\n","import React from \"react\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport { Attribution } from \"ol/control\";\n\nconst styles = (theme) => {\n return {\n attributions: {\n \"& .ol-control\": {\n position: \"static\",\n maxWidth: \"none\",\n },\n \"& .ol-attribution\": {\n background: theme.palette.background.paper,\n boxShadow: theme.shadows[4],\n borderRadius: theme.shape.borderRadius,\n height: \"25px\",\n overflow: \"auto\",\n whiteSpace: \"nowrap\",\n [theme.breakpoints.down(\"xs\")]: {\n maxWidth: \"100px\",\n },\n },\n \"& .ol-attribution ul\": {\n color: \"unset\",\n textShadow: \"unset\",\n },\n \"& button\": {\n cursor: \"pointer\",\n boxShadow: \"none\",\n outline: \"none\",\n },\n },\n };\n};\n\nclass AttributionControl extends React.PureComponent {\n constructor(props) {\n super(props);\n this.ref = React.createRef();\n }\n\n componentDidUpdate() {\n // Go on only if map exists AND we haven't done this yet.\n // Without the children.length part, we'd do this all the\n // time as we're inside componentDidUpdate.\n if (this.props.map && this.ref.current.children.length === 0) {\n const attributionControl = new Attribution({\n target: this.ref.current,\n tipLabel: \"Visa/dölj copyrightinformation för kartdata\",\n label: \"©\",\n });\n this.props.map.addControl(attributionControl);\n }\n }\n\n render() {\n const { classes } = this.props;\n return <div ref={this.ref} className={classes.attributions} />;\n }\n}\n\nexport default withStyles(styles)(AttributionControl);\n","import React from \"react\";\nimport { Button, Paper, Tooltip } from \"@material-ui/core\";\nimport VisibilityOffIcon from \"@material-ui/icons/VisibilityOff\";\n\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n}));\n\n/**\n * @summary Hides all visible layers\n *\n * @param {object} props\n * @returns {object} React\n */\nconst MapCleaner = React.memo((props) => {\n const classes = useStyles();\n\n return (\n props.appModel.config.mapConfig.map.mapcleaner && (\n <Tooltip title=\"Dölj alla aktiva lager\">\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Rensa kartan\"\n className={classes.button}\n onClick={(e) => {\n props.appModel.clear();\n }}\n >\n <VisibilityOffIcon />\n </Button>\n </Paper>\n </Tooltip>\n )\n );\n});\n\nexport default MapCleaner;\n","import React from \"react\";\nimport { Button, Paper, Tooltip } from \"@material-ui/core\";\nimport HomeIcon from \"@material-ui/icons/Home\";\n\nimport { withStyles } from \"@material-ui/core/styles\";\n\nconst styles = (theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n});\n\n/**\n * @summary Resets map to initial zoom level, centrum coordinate and active layers.\n *\n * @param {object} props\n * @returns {object} React\n */\nclass MapResetter extends React.PureComponent {\n // TODO: Also reset layers to default visibility!\n handleClick = (e) => {\n const { map } = this.props;\n if (map !== undefined) {\n const view = map.getView();\n const { zoom, center } = this.props.mapConfig.map;\n view.animate({ zoom, center });\n }\n };\n\n render() {\n const { classes } = this.props;\n\n return (\n <Tooltip title=\"Återställ kartan till startläget\">\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Återställ kartan till startläget\"\n className={classes.button}\n onClick={this.handleClick}\n >\n <HomeIcon />\n </Button>\n </Paper>\n </Tooltip>\n );\n }\n}\n\nexport default withStyles(styles)(MapResetter);\n","import React from \"react\";\nimport { Button, Menu, MenuItem, Paper, Tooltip } from \"@material-ui/core\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport SwitchCameraIcon from \"@material-ui/icons/SwitchCamera\";\nimport { hfetch } from \"utils/FetchWrapper\";\n\nconst styles = (theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n});\n\nclass MapSwitcher extends React.PureComponent {\n // Will hold map configs\n maps = [];\n\n state = {\n anchorEl: null,\n selectedIndex: null,\n };\n\n constructor(props) {\n super(props);\n this.appModel = this.props.appModel;\n this.map = this.props.appModel.getMap();\n }\n\n handleLoading(maps) {\n let { activeMap } = this.appModel.config;\n // Save fetched map configs to global variable\n this.maps = maps;\n\n // Set selectedIndex to currently selected map\n let selectedIndex = this.maps.findIndex((map) => {\n return map.mapConfigurationName === activeMap;\n });\n this.setState({ selectedIndex });\n }\n\n componentDidMount() {\n let { proxy, mapserviceBase } = this.appModel.config.appConfig;\n\n // If user specific maps is provided by the new API, the key will\n // already exist in config and there's no need to fetch again.\n // However, if it's undefined, it looks like we're using the old API\n // and MapSwitcher must do the fetch by itself.\n if (this.appModel.config.userSpecificMaps !== undefined) {\n this.handleLoading(this.appModel.config.userSpecificMaps);\n } else {\n hfetch(`${proxy}${mapserviceBase}/config/userspecificmaps`)\n .then((resp) => resp.json())\n .then((maps) => this.handleLoading(maps))\n .catch((err) => {\n throw new Error(err);\n });\n }\n }\n\n renderMenuItems = () => {\n let menuItems = [];\n this.maps.forEach((item, index) => {\n menuItems.push(\n <MenuItem\n key={index}\n // disabled={index === this.state.selectedIndex}\n selected={index === this.state.selectedIndex}\n onClick={(event) => this.handleMenuItemClick(event, index)}\n >\n {item.mapConfigurationTitle}\n </MenuItem>\n );\n });\n return menuItems;\n };\n\n // Show dropdown menu, anchored to the element clicked\n handleClick = (event) => {\n this.setState({ anchorEl: event.currentTarget });\n };\n\n handleMenuItemClick = (event, index) => {\n const selectedMap = this.maps[index].mapConfigurationName;\n const x = this.map.getView().getCenter()[0];\n const y = this.map.getView().getCenter()[1];\n const z = this.map.getView().getZoom();\n // TODO: A better solution then redirecting is needed. It requires more\n // work in the App component, so that changing the value of this.appModel.config.activeMap\n // would dynamically reload configuration as needed.\n // But for now, simple redirection will do.\n window.location.assign(\n `${window.location.origin}${window.location.pathname}?m=${selectedMap}&x=${x}&y=${y}&z=${z}`\n );\n\n // Not used as we change window.location. But in a better solution, we wouldn't reload the app,\n // and then code below would be needed to hide the dropdown menu.\n // this.setState({ anchorEl: null, selectedIndex: index });\n };\n\n handleClose = () => {\n this.setState({ anchorEl: null });\n };\n\n render() {\n const { anchorEl } = this.state;\n const { classes } = this.props;\n const open = Boolean(anchorEl);\n\n const title =\n this.props.appModel.config.mapConfig.map.title || \"Karta utan titel\";\n\n return (\n // Render only if config says so\n this.props.appModel.config.mapConfig.map.mapselector && (\n <>\n <Tooltip title={`Nuvarande karta: ${title}`}>\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Byt karta\"\n aria-owns={open ? \"render-props-menu\" : undefined}\n aria-haspopup=\"true\"\n className={classes.button}\n onClick={this.handleClick}\n >\n <SwitchCameraIcon />\n </Button>\n </Paper>\n </Tooltip>\n <Menu\n id=\"render-props-menu\"\n anchorEl={anchorEl}\n open={open}\n onClose={this.handleClose}\n >\n {this.renderMenuItems()}\n </Menu>\n </>\n )\n );\n }\n}\n\nexport default withStyles(styles)(MapSwitcher);\n","import React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport propTypes from \"prop-types\";\n\nimport { Button, Paper, Tooltip } from \"@material-ui/core\";\nimport InfoIcon from \"@material-ui/icons/Info\";\n\nimport Dialog from \"../components/Dialog.js\";\n\nconst styles = (theme) => {\n return {\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n };\n};\n\nclass Information extends React.PureComponent {\n static propTypes = {\n classes: propTypes.object.isRequired,\n options: propTypes.object.isRequired,\n };\n\n constructor(props) {\n super(props);\n this.type = \"Information\"; // Special case - plugins that don't use BaseWindowPlugin must specify .type here\n this.options = props.options;\n this.title = this.options.title || \"Om kartan\";\n this.state = {\n dialogOpen: false,\n };\n }\n\n componentDidMount() {\n let dialogOpen = this.options.visibleAtStart;\n\n if (this.options.visibleAtStart === true) {\n if (\n this.options.showInfoOnce === true &&\n parseInt(\n window.localStorage.getItem(\"pluginInformationMessageShown\")\n ) === 1\n ) {\n dialogOpen = false;\n } else {\n if (this.options.showInfoOnce === true) {\n window.localStorage.setItem(\"pluginInformationMessageShown\", 1);\n }\n dialogOpen = true;\n }\n } else {\n dialogOpen = false;\n }\n\n this.setState({\n dialogOpen,\n });\n }\n\n onClose = () => {\n this.setState({\n dialogOpen: false,\n });\n };\n\n handleOnClick = () => {\n this.setState({\n dialogOpen: true,\n });\n };\n\n renderDialog() {\n const { headerText, text, buttonText } = this.props.options;\n\n return createPortal(\n <Dialog\n options={{ headerText, text, buttonText }}\n open={this.state.dialogOpen}\n onClose={this.onClose}\n />,\n document.getElementById(\"windows-container\")\n );\n }\n\n render() {\n const { classes } = this.props;\n return (\n <>\n {this.renderDialog()}\n <Tooltip title={this.title}>\n <Paper className={classes.paper}>\n <Button\n aria-label={this.title}\n className={classes.button}\n onClick={this.handleOnClick}\n >\n <InfoIcon />\n </Button>\n </Paper>\n </Tooltip>\n </>\n );\n }\n}\n\nexport default withStyles(styles)(Information);\n","import React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { withStyles } from \"@material-ui/core/styles\";\nimport propTypes from \"prop-types\";\n\nimport { Button, Paper, Tooltip, Menu, MenuItem } from \"@material-ui/core\";\nimport FolderSpecial from \"@material-ui/icons/FolderSpecial\";\n\nimport Dialog from \"../components/Dialog.js\";\n\nconst styles = (theme) => {\n return {\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n };\n};\n\nclass Preset extends React.PureComponent {\n static propTypes = {\n classes: propTypes.object.isRequired,\n appModel: propTypes.object.isRequired,\n };\n\n state = {\n anchorEl: null,\n dialogOpen: false,\n };\n\n constructor(props) {\n super(props);\n this.type = \"Preset\"; // Special case - plugins that don't use BaseWindowPlugin must specify .type here\n this.config = props.appModel.config.mapConfig.tools.find(\n (t) => t.type === \"preset\"\n );\n\n this.appModel = props.appModel;\n this.globalObserver = props.appModel.globalObserver;\n\n // If config wasn't found, it means that Preset is not configured. Quit.\n if (this.config === undefined) return;\n\n // Else, if we're still here, go on.\n this.options = this.config.options;\n this.map = props.appModel.getMap();\n this.title = this.options.title || \"Snabbval\";\n\n this.location = null;\n this.zoom = null;\n this.layers = null;\n }\n\n // Show dropdown menu, anchored to the element clicked\n handleClick = (event) => {\n this.setState({ anchorEl: event.currentTarget });\n };\n\n handleClose = () => {\n this.setState({ anchorEl: null });\n };\n\n // A map-link must contain an x-, y-, and z-position to be valid. This function\n // checks wether that is true or not.\n isValidMapLink = (mapLink) => {\n return (\n mapLink.includes(\"x=\") && mapLink.includes(\"y=\") && mapLink.includes(\"z=\")\n );\n };\n\n // Extracts map-information from the provided link and returns the\n // information as an object.\n getMapInfoFromMapLink = (mapLink) => {\n const queryParams = new URLSearchParams(mapLink);\n const x = queryParams.get(\"x\");\n const y = queryParams.get(\"y\");\n const z = queryParams.get(\"z\");\n const l = queryParams.get(\"l\");\n\n const location = [x, y];\n const zoom = z;\n return { location, zoom, layers: l };\n };\n\n handleItemClick = (event, item) => {\n const url = item.presetUrl.toLowerCase();\n // Let's make sure that the provided url is a valid map-link\n if (this.isValidMapLink(url)) {\n this.handleClose(); // Ensure that popup menu is closed\n const { location, zoom, layers } = this.getMapInfoFromMapLink(url);\n this.location = location;\n this.zoom = zoom;\n this.layers = layers;\n\n // If the link contains layers we open the dialog where the user can choose to\n // proceed.\n if (layers) {\n this.openDialog();\n } // If the link does not contain layers, we can simply fly to the new location\n // without toggling layers and so on.\n else {\n this.flyTo(this.map.getView(), this.location, this.zoom);\n }\n } // If the provided url is not a valid map-link, warn the user.\n else {\n this.props.enqueueSnackbar(\n \"Länken till platsen är tyvärr felaktig. Kontakta administratören av karttjänsten för att åtgärda felet.\",\n {\n variant: \"warning\",\n }\n );\n console.error(\n \"Fel i verktyget Snabbval. Länken til : \\n\" +\n item.name +\n \"\\n\" +\n item.presetUrl +\n \"\\när tyvärr felaktig. Någon av följande parametrar saknas: &x=, &y=, &z= eller innehåller fel.\"\n );\n }\n };\n\n renderMenuItems = () => {\n const menuItems = [];\n this.options.presetList.forEach((item, index) => {\n menuItems.push(\n <MenuItem\n key={index}\n onClick={(event) => this.handleItemClick(event, item)}\n >\n {item.name}\n </MenuItem>\n );\n });\n return menuItems;\n };\n\n flyTo(view, location, zoom) {\n const duration = 1500;\n view.animate({\n center: location,\n zoom: zoom,\n duration: duration,\n });\n }\n\n openDialog = () => {\n this.setState({\n dialogOpen: true,\n });\n };\n\n closeDialog = () => {\n const visibleLayers = this.layers.split(\",\");\n this.setState({\n dialogOpen: false,\n });\n this.toggleMapLayers(visibleLayers);\n this.flyTo(this.map.getView(), this.location, this.zoom);\n };\n\n abortDialog = () => {\n this.setState({\n dialogOpen: false,\n });\n };\n\n layerShouldBeVisible = (layer, visibleLayers) => {\n return visibleLayers.some(\n (layerId) => layerId === layer.getProperties()[\"name\"]\n );\n };\n\n toggleMapLayers = (visibleLayers) => {\n const layerSwitcherLayers = this.map\n .getLayers()\n .getArray()\n .filter((layer) => layer.get(\"layerInfo\"));\n\n for (const l of layerSwitcherLayers) {\n if (this.layerShouldBeVisible(l, visibleLayers)) {\n this.globalObserver.publish(\"layerswitcher.showLayer\", l);\n l.setVisible(true);\n } else {\n this.globalObserver.publish(\"layerswitcher.hideLayer\", l);\n l.setVisible(false);\n }\n }\n };\n\n renderDialog() {\n if (this.state.dialogOpen) {\n return createPortal(\n <Dialog\n options={{\n text: \"Alla tända lager i kartan kommer nu att släckas. Snabbvalets fördefinierade lager tänds istället.\",\n headerText: \"Visa snabbval\",\n buttonText: \"OK\",\n abortText: \"Avbryt\",\n }}\n open={this.state.dialogOpen}\n onClose={this.closeDialog}\n onAbort={this.abortDialog}\n />,\n document.getElementById(\"windows-container\")\n );\n } else {\n return null;\n }\n }\n\n render() {\n // If config for Control isn't found, or if the config doesn't contain any presets, quit.\n if (\n this.config === undefined ||\n (this.config.hasOwnProperty(\"options\") &&\n this.config.options.presetList.length < 1)\n ) {\n return null;\n } else {\n const { anchorEl } = this.state;\n const { classes } = this.props;\n const open = Boolean(anchorEl);\n return (\n <>\n <Tooltip title={this.title}>\n <Paper className={classes.paper}>\n <Button\n aria-label={this.title}\n className={classes.button}\n onClick={this.handleClick}\n >\n <FolderSpecial />\n </Button>\n </Paper>\n </Tooltip>\n <Menu\n id=\"render-props-menu\"\n anchorEl={anchorEl}\n open={open}\n onClose={this.handleClose}\n >\n {this.renderMenuItems()}\n </Menu>\n {this.renderDialog()}\n </>\n );\n }\n }\n}\n\nexport default withStyles(styles)(Preset);\n","import React, { useEffect, useState } from \"react\";\n\nimport { makeStyles } from \"@material-ui/core/styles\";\n\nimport ToggleButton from \"@material-ui/lab/ToggleButton\";\nimport ToggleButtonGroup from \"@material-ui/lab/ToggleButtonGroup\";\n\nimport CloseIcon from \"@material-ui/icons/Close\";\nimport { Paper, Hidden } from \"@material-ui/core\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n marginRight: theme.spacing(1),\n [theme.breakpoints.down(\"xs\")]: {\n boxShadow: \"none\",\n },\n },\n button: {\n border: 0,\n color:\n theme.palette.type === \"dark\"\n ? theme.palette.common.white\n : theme.palette.action.active,\n },\n icon: {\n [theme.breakpoints.up(\"md\")]: {\n marginRight: theme.spacing(1),\n },\n },\n grouped: {\n [theme.breakpoints.down(\"xs\")]: {\n border: \"none\",\n },\n },\n}));\n\nfunction DrawerToggleButtons({\n drawerButtons,\n globalObserver,\n initialActiveButton,\n}) {\n const classes = useStyles();\n\n //Set initial active button state based on the initially active drawer, received from App.js\n //This will either be a drawer button name such as \"plugins\" or null, depending on whether there\n //is an active drawer when the map starts (set either from the cookie or config).\n const [activeButton, setActiveButton] = useState(initialActiveButton);\n\n // Sort by the (optional) @order property prior rendering\n // Sort using minus (-) causes the correct behavior, as this will\n // first implicitly convert the value to number.\n // If we'd compare using less than (<), that would sort our values\n // as UTF-16 strings, so we could get something like: 1, 1000, 2,\n // instead of 1, 2, 1000 which is desired in this case.\n drawerButtons = drawerButtons.sort((a, b) => a?.order - b?.order);\n\n // Subscribe only once, important that it's done inside useEffect!\n useEffect(() => {\n globalObserver.subscribe(\"core.unsetActiveButton\", () => {\n setActiveButton(null);\n });\n }, [globalObserver]);\n\n const handleClickOnToggleButton = (e, v) => {\n setActiveButton(v);\n\n if (v === null) {\n window.localStorage.removeItem(\"activeDrawerContent\");\n } else {\n window.localStorage.setItem(\"activeDrawerContent\", v);\n }\n\n // Let the outside world know that a button has been pressed.\n // App will handle changing context. v=null is valid too.\n globalObserver.publish(\"core.drawerContentChanged\", v);\n };\n\n const renderToggleButton = ({ ButtonIcon, value, caption }) => {\n // Currently active toggle button should have a \"Close\" icon\n const icon =\n value === activeButton ? (\n <CloseIcon className={classes.icon} />\n ) : (\n <ButtonIcon className={classes.icon} />\n );\n\n // Caption should be hidden on small screens\n return (\n <ToggleButton\n id={value}\n key={value}\n value={value}\n className={classes.button}\n >\n {icon}\n <Hidden smDown>{caption}</Hidden>\n </ToggleButton>\n );\n };\n\n return (\n drawerButtons.length > 0 && (\n <Paper className={classes.root}>\n <ToggleButtonGroup\n value={activeButton}\n exclusive\n onChange={handleClickOnToggleButton}\n aria-label=\"Drawer content\"\n classes={{ grouped: classes.grouped }}\n >\n {drawerButtons.map((b) => renderToggleButton(b))}\n </ToggleButtonGroup>\n </Paper>\n )\n );\n}\n\nfunction arePropsEqual(prevProps, nextProps) {\n // Only re-render if drawerButtons have changed since last render\n return prevProps.drawerButtons.length === nextProps.drawerButtons.length;\n}\n\nexport default React.memo(DrawerToggleButtons, arePropsEqual);\n","import React from \"react\";\nimport { Button, Paper, Tooltip } from \"@material-ui/core\";\nimport Brightness4Icon from \"@material-ui/icons/Brightness4\";\n\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n marginBottom: theme.spacing(1),\n },\n button: {\n minWidth: \"unset\",\n },\n}));\n\n/**\n * @summary Hides all visible layers\n *\n * @param {object} props\n * @returns {object} React\n */\nconst ThemeToggler = React.memo((props) => {\n const classes = useStyles();\n\n return (\n (props.showThemeToggler && (\n <Tooltip title=\"Växla mellan mörkt och ljust färgtema\">\n <Paper className={classes.paper}>\n <Button\n aria-label=\"Växla färgtema\"\n className={classes.button}\n onClick={(e) => {\n props.toggleMUITheme();\n }}\n >\n <Brightness4Icon />\n </Button>\n </Paper>\n </Tooltip>\n )) ||\n null\n );\n});\n\nexport default ThemeToggler;\n","const reportWebVitals = (onPerfEntry) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import(\"web-vitals\").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","// IE 11 starts here.\n// If you don't need IE 11, comment out those lines line.\n// Also, change 'browserslist' in package.json to exclude ie11.\nimport \"react-app-polyfill/ie11\";\nimport \"react-app-polyfill/stable\";\nimport \"abortcontroller-polyfill/dist/polyfill-patch-fetch\";\nimport \"allsettled-polyfill\";\n// IE 11 ends here.\n\n// iOS 12 and other older touch devices need this polyfill to\n// support OpenLayers map interactions through Pointer Events API.\n// See: https://github.com/hajkmap/Hajk/issues/606\nimport \"elm-pep\";\n\n// Since we don't want to download roboto from the Google CDN,\n// we use fontSource and import all subsets that MUI relies on here.\nimport \"@fontsource/roboto/300.css\";\nimport \"@fontsource/roboto/400.css\";\nimport \"@fontsource/roboto/500.css\";\nimport \"@fontsource/roboto/700.css\";\n\n// We want to support open-sans locally as well (If someone sets open-sans\n// in the customTheme.json, we still want to avoid requests to outside CDN)\nimport \"@fontsource/open-sans\";\n\n// The documentHandler imports icons in a dynamic way. To avoid requests against\n// an outside CDN, we make sure to install the required font for the icons as well.\nimport \"@fontsource/material-icons\";\n\nimport \"ol/ol.css\";\nimport \"./custom-ol.css\";\n\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport buildConfig from \"./buildConfig.json\";\nimport ErrorIcon from \"@material-ui/icons/Error\";\nimport HajkThemeProvider from \"./components/HajkThemeProvider\";\nimport reportWebVitals from \"./reportWebVitals\";\nimport { initHFetch, hfetch, initFetchWrapper } from \"utils/FetchWrapper\";\nimport LocalStorageHelper from \"utils/LocalStorageHelper\";\n\ninitHFetch();\n\nlet networkErrorMessage =\n \"Nätverksfel. Prova att ladda om applikationen genom att trycka på F5 på ditt tangentbord.\";\nlet parseErrorMessage =\n \"Fel när applikationen skulle läsas in. Detta beror troligtvis på ett konfigurationsfel. Försök igen senare.\";\n\nconst renderError = (message, err) => {\n console.error(err);\n ReactDOM.render(\n <div className=\"start-error\">\n <div>\n <ErrorIcon />\n </div>\n <div>{message}</div>\n </div>,\n document.getElementById(\"root\")\n );\n};\n\n/**\n * Entry point to Hajk.\n * We start with a fetching appConfig.json, that is expected\n * to be located in the same directory as index.js.\n *\n * appConfig.json includes URL to the backend application (called MapService),\n * as well as the default preferred map configuration's file name.\n */\nhfetch(\"appConfig.json\", { cacheBuster: true })\n .then((appConfigResponse) => {\n appConfigResponse.json().then((appConfig) => {\n // Update hfetch with loaded config.\n initFetchWrapper(appConfig);\n // See if we have site-specific error messages\n if (appConfig.networkErrorMessage)\n networkErrorMessage = appConfig.networkErrorMessage;\n if (appConfig.parseErrorMessage)\n parseErrorMessage = appConfig.parseErrorMessage;\n\n // Grab URL params using the new URL API, save for later\n const urlParams = new URL(window.location).searchParams;\n\n // If m param is supplied, try loading a map with that name\n // or else, fall back to default from appConfig.json\n let activeMap = urlParams.has(\"m\")\n ? urlParams.get(\"m\")\n : appConfig.defaultMap;\n\n // Check if mapserviceBase is set in appConfig. If it is not, we will\n // fall back on the simple map and layer configurations found in /public.\n const useMapService =\n appConfig.mapserviceBase && appConfig.mapserviceBase.trim().length > 0;\n\n const useNewApi = appConfig.experimentalNewApi === true;\n\n // Declare fetchMapConfig() that we'll use later on.\n //\n // The name of map config to fetch comes from appConfig.json's \"defaultMap\"\n // parameter, but it can be overridden by the \"m\" URL param.\n //\n // This can lead to a number of problems when users specify non-existing\n // map configs or if a map config's name has been changed.\n //\n // To avoid this, we first try to fetch the user-specified file,\n // but if that fails, we fall back to the hard-coded \"defaultMap\".\n const fetchMapConfig = async () => {\n // If the optional, experimental, consolidated loading process is active,\n // change the API from v1 to v2:\n const mapserviceBase =\n useNewApi === true\n ? appConfig.mapserviceBase.replace(\"v1\", \"v2\")\n : appConfig.mapserviceBase;\n\n // This saves us some keystrokes later on…\n const configUrl = `${appConfig.proxy}${mapserviceBase}/config`;\n try {\n // Try to fetch user-specified config. Return it if OK.\n return await hfetch(`${configUrl}/${activeMap}`);\n } catch {\n // If the previous attempt fails reset \"activeMap\" to hard-coded value…\n activeMap = appConfig.defaultMap;\n // …and fetch again.\n return await hfetch(`${configUrl}/${activeMap}`);\n }\n };\n\n if (useNewApi === true) {\n Promise.all([\n fetchMapConfig(),\n hfetch(\"customTheme.json\", { cacheBuster: true }),\n ])\n .then(([mapConfigResponse, customThemeResponse]) => {\n Promise.all([mapConfigResponse.json(), customThemeResponse.json()])\n .then(([mapConfig, customTheme]) => {\n const config = {\n activeMap: useMapService ? activeMap : \"simpleMapConfig\", // If we are not utilizing mapService, we know that the active map must be \"simpleMapConfig\".\n appConfig: appConfig,\n layersConfig: mapConfig.layersConfig,\n mapConfig: mapConfig.mapConfig,\n userDetails: mapConfig.userDetails,\n userSpecificMaps: mapConfig.userSpecificMaps,\n urlParams,\n };\n\n // At this stage, we know for sure what activeMap is, so we can initiate the LocalStorageHelper\n LocalStorageHelper.setKeyName(config.activeMap);\n\n // Invoke React's renderer. Render Theme. Theme will render App.\n ReactDOM.render(\n <HajkThemeProvider\n activeTools={buildConfig.activeTools}\n config={config}\n customTheme={customTheme}\n />,\n document.getElementById(\"root\")\n );\n })\n .catch((err) => renderError(parseErrorMessage, err));\n })\n .catch((err) => renderError(networkErrorMessage, err));\n } else {\n // Next, we do 3 necessary requests to get the map, layers, and customTheme configurations.\n Promise.all([\n // Get the layers configuration from mapService (if mapService is not active, we fall back on the local\n // \"simpleLayerConfig\" configuration file\n useMapService\n ? hfetch(\n `${appConfig.proxy}${appConfig.mapserviceBase}/config/layers`\n )\n : hfetch(\"simpleLayersConfig.json\", { cacheBuster: true }),\n // Get the specific, requested map configuration (if mapService is not active, we fall back on the local\n // \"simpleMapConfig\" configuration file).\n useMapService\n ? fetchMapConfig()\n : hfetch(\"simpleMapConfig.json\", { cacheBuster: true }),\n // Additionally, we fetch a custom theme that allows site admins to override\n // the default MUI theme without re-compiling the application.\n hfetch(\"customTheme.json\", { cacheBuster: true }),\n ])\n .then(\n ([\n layersConfigResponse,\n mapConfigResponse,\n customThemeResponse,\n ]) => {\n Promise.all([\n layersConfigResponse.json(),\n mapConfigResponse.json(),\n customThemeResponse.json(),\n ])\n .then(([layersConfig, mapConfig, customTheme]) => {\n // The fetched files are decoded to Objects and placed in\n // another object, @name config.\n const config = {\n activeMap: useMapService ? activeMap : \"simpleMapConfig\", // If we are not utilizing mapService, we know that the active map must be \"simpleMapConfig\".\n appConfig: appConfig,\n layersConfig: layersConfig,\n mapConfig: mapConfig,\n urlParams,\n };\n\n // At this stage, we know for sure what activeMap is, so we can initiate the LocalStorageHelper\n LocalStorageHelper.setKeyName(config.activeMap);\n\n // Make sure that the current user is allowed to display the current map\n const layerSwitcherConfig = config.mapConfig.tools.find(\n (tool) => tool.type === \"layerswitcher\"\n );\n if (layerSwitcherConfig === undefined) {\n throw new Error(\n \"noLayerSwitcher: \" +\n (config.appConfig.noLayerSwitcherMessage === undefined\n ? \"This map has no layerSwitcher indicating that you are not allowed to use this map!\"\n : config.appConfig.noLayerSwitcherMessage)\n );\n }\n\n // Invoke React's renderer. Render Theme. Theme will render App.\n ReactDOM.render(\n <HajkThemeProvider\n activeTools={buildConfig.activeTools}\n config={config}\n customTheme={customTheme}\n />,\n document.getElementById(\"root\")\n );\n })\n .catch((err) => {\n console.error(\"Parse error: \", err.message);\n let errMsg = parseErrorMessage;\n if (err.message.startsWith(\"noLayerSwitcher:\")) {\n errMsg = err.message.substr(err.message.indexOf(\":\") + 2);\n }\n renderError(errMsg, err);\n });\n }\n )\n .catch((err) => {\n renderError(networkErrorMessage, err);\n });\n }\n });\n })\n .catch((err) => {\n renderError(networkErrorMessage, err);\n });\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n","// We need som default options before we\n// get the real default options from appConfig\nlet config = {\n hfetch: {\n defaultOptions: { credentials: \"same-origin\" },\n },\n};\n\n// From appConfig it looks approx like this.\n// \"hfetch\": {\n// \"defaultOptions\": {\n// \"credentials\": \"same-origin\"\n// },\n// \"useOptionOverrides\": true,\n// \"optionOverrides\": {\n// \"*www.cachebuster.com*\": {\n// \"cacheBuster\": true\n// },\n// \"*wms-utv.varberg.se*\": {\n// \"credentials\": \"include\"\n// },\n// \"*www.requires-credentials.com*\": {\n// \"credentials\": \"include\"\n// }\n// }\n// }\n\nconst cacheBusterParamName = \"cacheBuster\";\n\nclass FetchWrapper {\n // Had to disable.... eslint does not like my regex for som reason.\n // eslint-disable-next-line no-useless-escape\n urlRegex = /([.*+?^=!:${}()|\\[\\]\\/\\\\])/g;\n\n constructor(options = {}, config = {}) {\n this.isJqueryAjax = options.isJqueryAjax === true;\n this.config = config;\n this.url = \"\";\n this.options = {};\n\n // Hash is used for cacheBuster function.\n this.hash = process?.env?.REACT_APP_GIT_HASH || null;\n this.useCacheBuster =\n process?.env?.REACT_APP_USE_CACHE_BUSTER === \"true\" || false;\n }\n\n matchesUrlPart(url, ruleWithWildCard) {\n // Works with *, example:\n // monk* matches monkey\n // *nk* matches monkey\n // *key matches monkey\n\n const escapeRegex = (url) => url.replace(this.urlRegex, \"\\\\$1\");\n return new RegExp(\n \"^\" + ruleWithWildCard.split(\"*\").map(escapeRegex).join(\".*\") + \"$\"\n ).test(url);\n }\n\n applyOptionOverrides() {\n if (!this.partKeys) {\n this.partKeys = Object.keys(this.config.hfetch.optionOverrides || {});\n this.partKeys.sort((a, b) => b.length - a.length);\n }\n\n const key = this.partKeys.find((key) => {\n return this.matchesUrlPart(this.url, key);\n });\n\n if (key) {\n // We've found a match!\n let overrides = this.config.hfetch.optionOverrides[key] || {};\n this.options = Object.assign(this.options, overrides);\n }\n }\n\n translateToJqueryAjaxOptions() {\n // translate credentials to work with $.ajax(), old admin UI.\n // Will be used in admin later.\n if (this.options.credentials && this.options.credentials === \"include\") {\n this.options.xhrFields = { withCredentials: true };\n delete this.options.credentials; // clean up.\n }\n }\n\n overrideOptions() {\n this.options = Object.assign(\n { ...this.config.hfetch.defaultOptions },\n this.options\n );\n\n if (this.config.hfetch.useOptionOverrides) {\n this.applyOptionOverrides();\n }\n\n if (this.isJqueryAjax) {\n // handle $.ajax() specific things.\n // Will be used in admin later.\n this.translateToJqueryAjaxOptions();\n }\n\n if (this.useCacheBuster === true) {\n // cacheBuster will force browser to reload the file.\n // In this case it's using git commit hash.\n // So every new Hajk version that's build will force reload.\n\n if (\n this.options.cacheBuster === true ||\n (this.mapserviceBaseUri &&\n this.url.indexOf(this.mapserviceBaseUri) === 0)\n ) {\n let cacheBuster = `${\n this.url.indexOf(\"?\") === -1 ? \"?\" : \"&\"\n }${cacheBusterParamName}=${this.hash}`;\n this.url = `${this.url}${cacheBuster}`;\n }\n }\n }\n\n updateConfig(config) {\n this.config = config;\n this.mapserviceBase = this.config.mapserviceBase || \"\";\n this.proxy = this.config.proxy || \"\";\n this.mapserviceBaseUri = `${this.proxy}${this.mapserviceBase}`;\n }\n\n reset() {\n this.options = {};\n this.url = \"\";\n }\n}\n\nlet fetchWrapper = null;\nlet originalFetch = null;\n\nfunction initFetchWrapper(appConfig) {\n config = Object.assign(config, appConfig);\n if (fetchWrapper) {\n fetchWrapper.updateConfig(config);\n }\n if (jqueryAjaxWrapper) {\n jqueryAjaxWrapper.updateConfig(config);\n }\n}\n\nfunction initHFetch() {\n if (fetchWrapper) {\n throw new Error(\"You should only initiate wrapFetch once\");\n }\n fetchWrapper = new FetchWrapper({}, config);\n originalFetch = fetch;\n\n return hfetch;\n}\n\nfunction overrideLayerSourceParams(source) {\n let fw = fetchWrapper;\n fw.reset();\n fw.url = source.url;\n fw.options = { ...source };\n if (fw.config.hfetch.useOptionOverrides) {\n fw.applyOptionOverrides();\n }\n if (fw.options?.credentials === \"include\") {\n if (source.crossOrigin) {\n // handle crossOrigin in tile images etc\n source.crossOrigin = \"use-credentials\";\n }\n }\n}\n\nfunction hfetch(...args) {\n let fw = fetchWrapper;\n fw.reset();\n\n fw.options = args[1] || {};\n\n // Handle all types that the original fetch accepts. The next 2 comment are from fetch documentation.\n // \"A string or any other object with a stringifier — including a URL object — that provides the URL of the resource you want to fetch.\"\n // \"A Request object.\"\n\n if (typeof args[0] === \"string\") {\n fw.url = args[0];\n } else if (args[0] instanceof URL) {\n fw.url = args[0].href;\n } else if (args[0] instanceof Request) {\n // The Request object is deconstructed then reconstructed by original fetch. Not perfect...\n fw.url = args[0].url;\n fw.options = args[0];\n } else {\n fw.url = args[0].toString();\n }\n\n fw.overrideOptions();\n //console.log(\"hfetch\", fw.url, fw.options);\n return originalFetch(fw.url, fw.options);\n}\n\nlet jqueryAjaxWrapper = null;\nlet originalJqueryAjax = null;\n\nfunction wrapJqueryAjax(jqueryObject) {\n if (jqueryAjaxWrapper) {\n throw new Error(\"You should only initiate wrapJqueryAjax once\");\n }\n jqueryAjaxWrapper = new FetchWrapper({ isJqueryAjax: true }, config);\n originalJqueryAjax = jqueryObject.ajax;\n jqueryObject.ajax = xJqueryAjax;\n}\n\nfunction xJqueryAjax(...args) {\n let jw = jqueryAjaxWrapper;\n jw.reset();\n jw.url = args[0];\n\n if (args.length === 1) {\n // Assume $.ajax(object with url)\n jw.options = Object.assign({}, args[0]);\n jw.overrideOptions();\n return originalJqueryAjax(jw.options);\n } else if (args.length === 2) {\n // Assume $.ajax(url, options)\n jw.options = args[1];\n jw.overrideOptions();\n return originalJqueryAjax(jw.url, jw.options);\n }\n}\n\nexport {\n initFetchWrapper,\n initHFetch,\n hfetch,\n wrapJqueryAjax,\n overrideLayerSourceParams,\n};\n","var map = {\n\t\"./components/Alert.js\": [\n\t\t420\n\t],\n\t\"./components/Announcement/Announcement.js\": [\n\t\t484\n\t],\n\t\"./components/App.js\": [\n\t\t470\n\t],\n\t\"./components/Card.js\": [\n\t\t1157,\n\t\t98\n\t],\n\t\"./components/CookieNotice.js\": [\n\t\t482\n\t],\n\t\"./components/Diagram.js\": [\n\t\t1318,\n\t\t3,\n\t\t33,\n\t\t145\n\t],\n\t\"./components/Dialog.js\": [\n\t\t220\n\t],\n\t\"./components/Drawer/DrawerToggleButtons.js\": [\n\t\t510\n\t],\n\t\"./components/FeatureInfo/FeatureInfoContainer.js\": [\n\t\t481\n\t],\n\t\"./components/FeatureInfo/FeaturePropsFilters.js\": [\n\t\t418\n\t],\n\t\"./components/FeatureInfo/FeaturePropsParsing.js\": [\n\t\t313\n\t],\n\t\"./components/HajkThemeProvider.js\": [\n\t\t375\n\t],\n\t\"./components/Introduction.js\": [\n\t\t483\n\t],\n\t\"./components/PanelHeader.js\": [\n\t\t447\n\t],\n\t\"./components/PluginControlButton.js\": [\n\t\t1158,\n\t\t146\n\t],\n\t\"./components/PluginWindows.js\": [\n\t\t485\n\t],\n\t\"./components/PopPanel.js\": [\n\t\t1319,\n\t\t147\n\t],\n\t\"./components/Search/MapViewModel.js\": [\n\t\t496\n\t],\n\t\"./components/Search/Search.js\": [\n\t\t467\n\t],\n\t\"./components/Search/SearchBar.js\": [\n\t\t486\n\t],\n\t\"./components/Search/SearchSettings.js\": [\n\t\t495\n\t],\n\t\"./components/Search/SearchTools.js\": [\n\t\t494\n\t],\n\t\"./components/Search/searchResults/SearchResultsContainer.js\": [\n\t\t487\n\t],\n\t\"./components/Search/searchResults/SearchResultsDataset.js\": [\n\t\t489\n\t],\n\t\"./components/Search/searchResults/SearchResultsDatasetFeature.js\": [\n\t\t490\n\t],\n\t\"./components/Search/searchResults/SearchResultsDatasetFeatureDetails.js\": [\n\t\t314\n\t],\n\t\"./components/Search/searchResults/SearchResultsDatasetSummary.js\": [\n\t\t492\n\t],\n\t\"./components/Search/searchResults/SearchResultsDownloadMenu.js\": [\n\t\t493\n\t],\n\t\"./components/Search/searchResults/SearchResultsList.js\": [\n\t\t488\n\t],\n\t\"./components/Search/searchResults/SearchResultsPreview.js\": [\n\t\t491\n\t],\n\t\"./components/Search/utils/FeatureStyle.js\": [\n\t\t269\n\t],\n\t\"./components/Search/utils/KmlExport.js\": [\n\t\t497\n\t],\n\t\"./components/Search/utils/XLSXExport.js\": [\n\t\t498\n\t],\n\t\"./components/SrShortcuts/SrShortcuts.js\": [\n\t\t471\n\t],\n\t\"./components/Table.js\": [\n\t\t1320,\n\t\t148\n\t],\n\t\"./components/Window.js\": [\n\t\t410\n\t],\n\t\"./controls/Attribution.js\": [\n\t\t504\n\t],\n\t\"./controls/Information.js\": [\n\t\t508\n\t],\n\t\"./controls/MapCleaner.js\": [\n\t\t505\n\t],\n\t\"./controls/MapResetter.js\": [\n\t\t506\n\t],\n\t\"./controls/MapSwitcher.js\": [\n\t\t507\n\t],\n\t\"./controls/PresetLinks.js\": [\n\t\t509\n\t],\n\t\"./controls/Rotate.js\": [\n\t\t501\n\t],\n\t\"./controls/ScaleLine.js\": [\n\t\t502\n\t],\n\t\"./controls/ThemeToggler.js\": [\n\t\t511\n\t],\n\t\"./controls/User.js\": [\n\t\t500\n\t],\n\t\"./controls/Zoom.js\": [\n\t\t499\n\t],\n\t\"./index.js\": [\n\t\t558\n\t],\n\t\"./models/AppModel.js\": [\n\t\t472\n\t],\n\t\"./models/Click.js\": [\n\t\t299\n\t],\n\t\"./models/Drag.js\": [\n\t\t1321,\n\t\t149\n\t],\n\t\"./models/DrawModel.js\": [\n\t\t1322,\n\t\t118\n\t],\n\t\"./models/Error.js\": [\n\t\t1323,\n\t\t150\n\t],\n\t\"./models/KmlModel.js\": [\n\t\t1324,\n\t\t7,\n\t\t151\n\t],\n\t\"./models/Plugin.js\": [\n\t\t474\n\t],\n\t\"./models/SearchModel.js\": [\n\t\t473\n\t],\n\t\"./models/SnapHelper.js\": [\n\t\t480\n\t],\n\t\"./models/layers/LayerInfo.js\": [\n\t\t230\n\t],\n\t\"./models/layers/VectorLayer.js\": [\n\t\t479\n\t],\n\t\"./models/layers/WMSLayer.js\": [\n\t\t477\n\t],\n\t\"./models/layers/WMTSLayer.js\": [\n\t\t478\n\t],\n\t\"./plugins/Anchor/Anchor.js\": [\n\t\t1325,\n\t\t43\n\t],\n\t\"./plugins/Anchor/AnchorModel.js\": [\n\t\t1245,\n\t\t152\n\t],\n\t\"./plugins/Anchor/AnchorView.js\": [\n\t\t1244,\n\t\t82\n\t],\n\t\"./plugins/BaseWindowPlugin.js\": [\n\t\t1159,\n\t\t74\n\t],\n\t\"./plugins/Bookmarks/Bookmarks.js\": [\n\t\t1326,\n\t\t44\n\t],\n\t\"./plugins/Bookmarks/BookmarksModel.js\": [\n\t\t1246,\n\t\t153\n\t],\n\t\"./plugins/Bookmarks/BookmarksView.js\": [\n\t\t1247,\n\t\t99\n\t],\n\t\"./plugins/Buffer/Buffer.js\": [\n\t\t1327,\n\t\t6,\n\t\t53,\n\t\t79\n\t],\n\t\"./plugins/Buffer/BufferModel.js\": [\n\t\t1249,\n\t\t6,\n\t\t154\n\t],\n\t\"./plugins/Buffer/BufferView.js\": [\n\t\t1248,\n\t\t75\n\t],\n\t\"./plugins/Collector/Collector.js\": [\n\t\t1328,\n\t\t0,\n\t\t45,\n\t\t23,\n\t\t88\n\t],\n\t\"./plugins/Collector/CollectorModel.js\": [\n\t\t1251,\n\t\t119\n\t],\n\t\"./plugins/Collector/CollectorView.js\": [\n\t\t1311,\n\t\t0,\n\t\t23,\n\t\t72\n\t],\n\t\"./plugins/Collector/components/CollectorForm.js\": [\n\t\t1250,\n\t\t0,\n\t\t51\n\t],\n\t\"./plugins/Collector/components/Page.js\": [\n\t\t1200,\n\t\t0,\n\t\t54\n\t],\n\t\"./plugins/Collector/components/Toolbar.js\": [\n\t\t1184,\n\t\t0,\n\t\t100\n\t],\n\t\"./plugins/Coordinates/Coordinates.js\": [\n\t\t1329,\n\t\t12,\n\t\t46\n\t],\n\t\"./plugins/Coordinates/CoordinatesModel.js\": [\n\t\t1253,\n\t\t155\n\t],\n\t\"./plugins/Coordinates/CoordinatesTransformRow.js\": [\n\t\t1202,\n\t\t12,\n\t\t156\n\t],\n\t\"./plugins/Coordinates/CoordinatesView.js\": [\n\t\t1252,\n\t\t12,\n\t\t120\n\t],\n\t\"./plugins/DocumentHandler/DocumentHandler.js\": [\n\t\t1330,\n\t\t8,\n\t\t18,\n\t\t15,\n\t\t24,\n\t\t69\n\t],\n\t\"./plugins/DocumentHandler/DocumentHandlerModel.js\": [\n\t\t1257,\n\t\t55\n\t],\n\t\"./plugins/DocumentHandler/MapViewModel.js\": [\n\t\t1260,\n\t\t157\n\t],\n\t\"./plugins/DocumentHandler/documentSearch/DocumentSearchModel.js\": [\n\t\t1208,\n\t\t101\n\t],\n\t\"./plugins/DocumentHandler/documentSearch/MatchSearch.js\": [\n\t\t1187,\n\t\t158\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/Contents.js\": [\n\t\t1204,\n\t\t110\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/DocumentViewer.js\": [\n\t\t1254,\n\t\t8,\n\t\t76\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/DocumentWindowBase.js\": [\n\t\t1312,\n\t\t8,\n\t\t18,\n\t\t15\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/ImagePopupModal.js\": [\n\t\t1185,\n\t\t159\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/Progress.js\": [\n\t\t1256,\n\t\t160\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/ScrollToTop.js\": [\n\t\t1205,\n\t\t121\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/TableOfContents.js\": [\n\t\t1203,\n\t\t122\n\t],\n\t\"./plugins/DocumentHandler/documentWindow/TextArea.js\": [\n\t\t1186,\n\t\t161\n\t],\n\t\"./plugins/DocumentHandler/panelMenu/PanelList.js\": [\n\t\t1209,\n\t\t26\n\t],\n\t\"./plugins/DocumentHandler/panelMenu/PanelMenuContainerView.js\": [\n\t\t1313,\n\t\t8,\n\t\t24,\n\t\t163\n\t],\n\t\"./plugins/DocumentHandler/panelMenu/PanelMenuListItem.js\": [\n\t\t1238,\n\t\t26\n\t],\n\t\"./plugins/DocumentHandler/panelMenu/panelMenuUtils.js\": [\n\t\t1259,\n\t\t162\n\t],\n\t\"./plugins/DocumentHandler/printMenu/PrintList.js\": [\n\t\t1181,\n\t\t25\n\t],\n\t\"./plugins/DocumentHandler/printMenu/PrintListItem.js\": [\n\t\t1175,\n\t\t123\n\t],\n\t\"./plugins/DocumentHandler/printMenu/PrintSubList.js\": [\n\t\t1197,\n\t\t25\n\t],\n\t\"./plugins/DocumentHandler/printMenu/PrintWindow.js\": [\n\t\t1255,\n\t\t60\n\t],\n\t\"./plugins/DocumentHandler/printMenu/TableOfContents.js\": [\n\t\t1206,\n\t\t124\n\t],\n\t\"./plugins/DocumentHandler/utils/ContentComponentFactory.js\": [\n\t\t1198,\n\t\t102\n\t],\n\t\"./plugins/DocumentHandler/utils/helpers.js\": [\n\t\t1165,\n\t\t164\n\t],\n\t\"./plugins/DocumentHandler/utils/htmlToMaterialUiParser.js\": [\n\t\t1207,\n\t\t126\n\t],\n\t\"./plugins/DocumentHandler/utils/stateConverter.js\": [\n\t\t1258,\n\t\t125\n\t],\n\t\"./plugins/Draw/Draw.js\": [\n\t\t1331,\n\t\t0,\n\t\t3,\n\t\t5,\n\t\t7,\n\t\t39\n\t],\n\t\"./plugins/Draw/DrawModel.js\": [\n\t\t1262,\n\t\t7,\n\t\t11,\n\t\t127\n\t],\n\t\"./plugins/Draw/DrawView.js\": [\n\t\t1261,\n\t\t0,\n\t\t3,\n\t\t5,\n\t\t83\n\t],\n\t\"./plugins/Draw/components/Symbology.js\": [\n\t\t1210,\n\t\t3,\n\t\t5,\n\t\t165\n\t],\n\t\"./plugins/Dummy/Dummy.js\": [\n\t\t1332,\n\t\t49\n\t],\n\t\"./plugins/Dummy/DummyModel.js\": [\n\t\t1263,\n\t\t166\n\t],\n\t\"./plugins/Dummy/DummyView.js\": [\n\t\t1264,\n\t\t128\n\t],\n\t\"./plugins/Edit/Edit.js\": [\n\t\t1333,\n\t\t0,\n\t\t11,\n\t\t19,\n\t\t97,\n\t\t66\n\t],\n\t\"./plugins/Edit/EditModel.js\": [\n\t\t1266,\n\t\t11,\n\t\t129\n\t],\n\t\"./plugins/Edit/EditView.js\": [\n\t\t1265,\n\t\t0,\n\t\t19,\n\t\t111\n\t],\n\t\"./plugins/Edit/components/AttributeEditor.js\": [\n\t\t1212,\n\t\t167\n\t],\n\t\"./plugins/Edit/components/Toolbar.js\": [\n\t\t1211,\n\t\t0,\n\t\t84\n\t],\n\t\"./plugins/Export/Export.js\": [\n\t\t1334,\n\t\t59,\n\t\t80\n\t],\n\t\"./plugins/Export/ExportModel.js\": [\n\t\t1268,\n\t\t112\n\t],\n\t\"./plugins/Export/components/ExportPdfSettings.js\": [\n\t\t1267,\n\t\t103\n\t],\n\t\"./plugins/Fir/Fir.js\": [\n\t\t1335,\n\t\t1,\n\t\t2,\n\t\t6,\n\t\t7,\n\t\t34\n\t],\n\t\"./plugins/Fir/FirExportEdpView.js\": [\n\t\t1189,\n\t\t85\n\t],\n\t\"./plugins/Fir/FirExportPropertyListView.js\": [\n\t\t1190,\n\t\t86\n\t],\n\t\"./plugins/Fir/FirExportResidentListView.js\": [\n\t\t1191,\n\t\t77\n\t],\n\t\"./plugins/Fir/FirExportView.js\": [\n\t\t1214,\n\t\t56\n\t],\n\t\"./plugins/Fir/FirIcons.js\": [\n\t\t1162,\n\t\t168\n\t],\n\t\"./plugins/Fir/FirImport.js\": [\n\t\t1272,\n\t\t7,\n\t\t169\n\t],\n\t\"./plugins/Fir/FirLayerController.js\": [\n\t\t1271,\n\t\t6,\n\t\t113\n\t],\n\t\"./plugins/Fir/FirModel.js\": [\n\t\t1269,\n\t\t170\n\t],\n\t\"./plugins/Fir/FirSearchNeighborView.js\": [\n\t\t1215,\n\t\t1,\n\t\t6,\n\t\t58\n\t],\n\t\"./plugins/Fir/FirSearchResultItemView.js\": [\n\t\t1192,\n\t\t171\n\t],\n\t\"./plugins/Fir/FirSearchResultsView.js\": [\n\t\t1216,\n\t\t21,\n\t\t130\n\t],\n\t\"./plugins/Fir/FirSearchView.js\": [\n\t\t1213,\n\t\t57\n\t],\n\t\"./plugins/Fir/FirStyles.js\": [\n\t\t1199,\n\t\t172\n\t],\n\t\"./plugins/Fir/FirToolbarView.js\": [\n\t\t1188,\n\t\t89\n\t],\n\t\"./plugins/Fir/FirView.js\": [\n\t\t1270,\n\t\t1,\n\t\t2,\n\t\t6,\n\t\t21,\n\t\t41\n\t],\n\t\"./plugins/Fir/FirWfsService.js\": [\n\t\t1237,\n\t\t173\n\t],\n\t\"./plugins/Fme/Fme.js\": [\n\t\t1336,\n\t\t0,\n\t\t50\n\t],\n\t\"./plugins/Fme/FmeModel.js\": [\n\t\t1273,\n\t\t180\n\t],\n\t\"./plugins/Fme/FmeView.js\": [\n\t\t1274,\n\t\t0,\n\t\t181\n\t],\n\t\"./plugins/FmeServer/FmeServer.js\": [\n\t\t1337,\n\t\t1,\n\t\t22,\n\t\t87,\n\t\t20,\n\t\t81\n\t],\n\t\"./plugins/FmeServer/FmeServerView.js\": [\n\t\t1314,\n\t\t1,\n\t\t22,\n\t\t20\n\t],\n\t\"./plugins/FmeServer/components/DrawToolbox.js\": [\n\t\t1275,\n\t\t131\n\t],\n\t\"./plugins/FmeServer/components/InformationWrapper.js\": [\n\t\t1177,\n\t\t174\n\t],\n\t\"./plugins/FmeServer/components/ListBoxSelector.js\": [\n\t\t1217,\n\t\t175\n\t],\n\t\"./plugins/FmeServer/components/OrderPanel.js\": [\n\t\t1276,\n\t\t104\n\t],\n\t\"./plugins/FmeServer/components/ProductParameters.js\": [\n\t\t1277,\n\t\t1,\n\t\t90\n\t],\n\t\"./plugins/FmeServer/constants/index.js\": [\n\t\t1176,\n\t\t176\n\t],\n\t\"./plugins/FmeServer/hooks/useInterval.js\": [\n\t\t1279,\n\t\t177\n\t],\n\t\"./plugins/FmeServer/hooks/useProductParameters.js\": [\n\t\t1278,\n\t\t178\n\t],\n\t\"./plugins/FmeServer/models/FmeServerModel.js\": [\n\t\t1280,\n\t\t179\n\t],\n\t\"./plugins/FmeServer/models/MapViewModel.js\": [\n\t\t1281,\n\t\t132\n\t],\n\t\"./plugins/GeosuiteExport/GeosuiteExport.js\": [\n\t\t1338,\n\t\t16,\n\t\t27,\n\t\t28,\n\t\t67\n\t],\n\t\"./plugins/GeosuiteExport/GeosuiteExportModel.js\": [\n\t\t1315,\n\t\t28\n\t],\n\t\"./plugins/GeosuiteExport/GeosuiteExportView.js\": [\n\t\t1316,\n\t\t16,\n\t\t27\n\t],\n\t\"./plugins/GeosuiteExport/components/LinkItem.js\": [\n\t\t1283,\n\t\t182\n\t],\n\t\"./plugins/GeosuiteExport/components/ProductList.js\": [\n\t\t1282,\n\t\t114\n\t],\n\t\"./plugins/Informative/Informative.js\": [\n\t\t1339,\n\t\t40\n\t],\n\t\"./plugins/Informative/InformativeModel.js\": [\n\t\t1285,\n\t\t183\n\t],\n\t\"./plugins/Informative/InformativeView.js\": [\n\t\t1284,\n\t\t61\n\t],\n\t\"./plugins/Informative/components/BreadCrumbs.js\": [\n\t\t1218,\n\t\t184\n\t],\n\t\"./plugins/LayerSwitcher/LayerSwitcher.js\": [\n\t\t1340,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t10,\n\t\t35\n\t],\n\t\"./plugins/LayerSwitcher/LayerSwitcherModel.js\": [\n\t\t1287,\n\t\t185\n\t],\n\t\"./plugins/LayerSwitcher/LayerSwitcherView.js\": [\n\t\t1286,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t10,\n\t\t37\n\t],\n\t\"./plugins/LayerSwitcher/components/BackgroundSwitcher.js\": [\n\t\t1227,\n\t\t1,\n\t\t9,\n\t\t91\n\t],\n\t\"./plugins/LayerSwitcher/components/BreadCrumb.js\": [\n\t\t1193,\n\t\t105\n\t],\n\t\"./plugins/LayerSwitcher/components/BreadCrumbs.js\": [\n\t\t1220,\n\t\t0,\n\t\t10,\n\t\t133\n\t],\n\t\"./plugins/LayerSwitcher/components/CQLFilter.js\": [\n\t\t1179,\n\t\t115\n\t],\n\t\"./plugins/LayerSwitcher/components/DownloadLink.js\": [\n\t\t1171,\n\t\t134\n\t],\n\t\"./plugins/LayerSwitcher/components/LayerGroup.js\": [\n\t\t1219,\n\t\t1,\n\t\t9,\n\t\t62\n\t],\n\t\"./plugins/LayerSwitcher/components/LayerGroupItem.js\": [\n\t\t1182,\n\t\t1,\n\t\t9,\n\t\t144\n\t],\n\t\"./plugins/LayerSwitcher/components/LayerItem.js\": [\n\t\t1174,\n\t\t1,\n\t\t9,\n\t\t106\n\t],\n\t\"./plugins/LayerSwitcher/components/LayerSettings.js\": [\n\t\t1170,\n\t\t1,\n\t\t92\n\t],\n\t\"./plugins/LayerSwitcher/components/VectorFilter.js\": [\n\t\t1178,\n\t\t186\n\t],\n\t\"./plugins/Location/CustomControlButtonView.js\": [\n\t\t1288,\n\t\t107\n\t],\n\t\"./plugins/Location/Location.js\": [\n\t\t1341,\n\t\t65,\n\t\t73\n\t],\n\t\"./plugins/Location/LocationModel.js\": [\n\t\t1289,\n\t\t135\n\t],\n\t\"./plugins/Location/LocationView.js\": [\n\t\t1290,\n\t\t136\n\t],\n\t\"./plugins/Measure/Measure.js\": [\n\t\t1342,\n\t\t96,\n\t\t68\n\t],\n\t\"./plugins/Measure/MeasureModel.js\": [\n\t\t1292,\n\t\t137\n\t],\n\t\"./plugins/Measure/MeasureView.js\": [\n\t\t1291,\n\t\t187\n\t],\n\t\"./plugins/Print/AdvancedOptions.js\": [\n\t\t1221,\n\t\t3,\n\t\t5,\n\t\t116\n\t],\n\t\"./plugins/Print/GeneralOptions.js\": [\n\t\t1222,\n\t\t188\n\t],\n\t\"./plugins/Print/Print.js\": [\n\t\t1343,\n\t\t2,\n\t\t3,\n\t\t5,\n\t\t14,\n\t\t36\n\t],\n\t\"./plugins/Print/PrintDialog.js\": [\n\t\t1223,\n\t\t138\n\t],\n\t\"./plugins/Print/PrintModel.js\": [\n\t\t1293,\n\t\t14,\n\t\t78\n\t],\n\t\"./plugins/Print/PrintView.js\": [\n\t\t1294,\n\t\t2,\n\t\t3,\n\t\t5,\n\t\t70\n\t],\n\t\"./plugins/Routing/Routing.js\": [\n\t\t1344,\n\t\t17,\n\t\t47\n\t],\n\t\"./plugins/Routing/RoutingModel.js\": [\n\t\t1305,\n\t\t139\n\t],\n\t\"./plugins/Routing/RoutingView.js\": [\n\t\t1295,\n\t\t17,\n\t\t189\n\t],\n\t\"./plugins/StreetView/StreetView.js\": [\n\t\t1345,\n\t\t48\n\t],\n\t\"./plugins/StreetView/StreetViewModel.js\": [\n\t\t1297,\n\t\t140\n\t],\n\t\"./plugins/StreetView/StreetViewView.js\": [\n\t\t1296,\n\t\t190\n\t],\n\t\"./plugins/Suggest/Suggest.js\": [\n\t\t1346,\n\t\t108\n\t],\n\t\"./plugins/TimeSlider/TimeSlider.js\": [\n\t\t1347,\n\t\t1,\n\t\t42\n\t],\n\t\"./plugins/TimeSlider/TimeSliderView.js\": [\n\t\t1298,\n\t\t1,\n\t\t71\n\t],\n\t\"./plugins/TimeSlider/components/TimeSliderSettings.js\": [\n\t\t1224,\n\t\t117\n\t],\n\t\"./plugins/vtsearch/MapViewModel.js\": [\n\t\t1299,\n\t\t191\n\t],\n\t\"./plugins/vtsearch/SearchModel.js\": [\n\t\t1300,\n\t\t192\n\t],\n\t\"./plugins/vtsearch/SearchResultList/AdvancedAttributeTable.js\": [\n\t\t1194,\n\t\t4,\n\t\t109\n\t],\n\t\"./plugins/vtsearch/SearchResultList/AttributeTable.js\": [\n\t\t1172,\n\t\t4,\n\t\t141\n\t],\n\t\"./plugins/vtsearch/SearchResultList/PanelToolbox.js\": [\n\t\t1225,\n\t\t142\n\t],\n\t\"./plugins/vtsearch/SearchResultList/SearchResultListContainer.js\": [\n\t\t1301,\n\t\t2,\n\t\t4,\n\t\t63\n\t],\n\t\"./plugins/vtsearch/SearchResultList/SummaryTable.js\": [\n\t\t1180,\n\t\t4,\n\t\t143\n\t],\n\t\"./plugins/vtsearch/SearchResultList/TabPanel.js\": [\n\t\t1226,\n\t\t4,\n\t\t93\n\t],\n\t\"./plugins/vtsearch/SearchResultList/VirtualizedTable.js\": [\n\t\t1166,\n\t\t4,\n\t\t193\n\t],\n\t\"./plugins/vtsearch/SearchViews/Journeys.js\": [\n\t\t1302,\n\t\t13,\n\t\t94\n\t],\n\t\"./plugins/vtsearch/SearchViews/Lines.js\": [\n\t\t1303,\n\t\t95\n\t],\n\t\"./plugins/vtsearch/SearchViews/Stops.js\": [\n\t\t1304,\n\t\t64\n\t],\n\t\"./plugins/vtsearch/vtsearch.js\": [\n\t\t1348,\n\t\t2,\n\t\t4,\n\t\t13,\n\t\t52,\n\t\t38\n\t],\n\t\"./reportWebVitals.js\": [\n\t\t512\n\t],\n\t\"./utils/ArraySort.js\": [\n\t\t1349,\n\t\t194\n\t],\n\t\"./utils/ConfigMapper.js\": [\n\t\t475\n\t],\n\t\"./utils/CoordinateSystemLoader.js\": [\n\t\t476\n\t],\n\t\"./utils/DeepMerge.js\": [\n\t\t260\n\t],\n\t\"./utils/Delay.js\": [\n\t\t414\n\t],\n\t\"./utils/FetchWrapper.js\": [\n\t\t65\n\t],\n\t\"./utils/IsMobile.js\": [\n\t\t98\n\t],\n\t\"./utils/KMLWriter.js\": [\n\t\t421\n\t],\n\t\"./utils/LocalStorageHelper.js\": [\n\t\t234\n\t],\n\t\"./utils/StringCommaCoder.js\": [\n\t\t147\n\t],\n\t\"./utils/Validator.js\": [\n\t\t416\n\t]\n};\nfunction webpackAsyncContext(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\treturn Promise.resolve().then(function() {\n\t\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\t\te.code = 'MODULE_NOT_FOUND';\n\t\t\tthrow e;\n\t\t});\n\t}\n\n\tvar ids = map[req], id = ids[0];\n\treturn Promise.all(ids.slice(1).map(__webpack_require__.e)).then(function() {\n\t\treturn __webpack_require__(id);\n\t});\n}\nwebpackAsyncContext.keys = function webpackAsyncContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackAsyncContext.id = 966;\nmodule.exports = webpackAsyncContext;","/**\n * TODO:\n * This is obsolete and will be removed once we refactor methods that\n * make use of getIsMobile() and isMobile().\n */\nexport const isMobile = getIsMobile();\n\nexport function getIsMobile() {\n return window.innerWidth < 600;\n}\n"],"sourceRoot":""}