adb-shared 6.2.0-beta → 6.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,11 +8,13 @@ import * as i1$2 from '@angular/common/http';
8
8
  import { provideHttpClient, withInterceptorsFromDi, HttpHeaders, HTTP_INTERCEPTORS } from '@angular/common/http';
9
9
  import * as i1 from '@angular/router';
10
10
  import { NavigationEnd, RouterModule, NavigationStart } from '@angular/router';
11
- import { Subscription, Subject, of, BehaviorSubject, catchError, throwError, map as map$1, tap } from 'rxjs';
12
- import { endOfDay, addYears, startOfDay, subYears, getMonth, subMonths, addMonths, isSameYear, endOfMonth, startOfMonth, eachWeekOfInterval, getISOWeek, addDays, eachDayOfInterval, getHours, getMinutes, isSameDay, isWithinInterval, isSameMonth, isValid, parseISO, addSeconds, format } from 'date-fns';
13
- import * as i1$4 from '@angular/forms';
14
- import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule } from '@angular/forms';
11
+ import { Subscription, Subject, of, BehaviorSubject, catchError, throwError, map as map$1, tap, combineLatest, debounceTime as debounceTime$1, shareReplay } from 'rxjs';
12
+ import { endOfDay, addYears, startOfDay, subYears, getMonth, subMonths, addMonths, isSameYear, endOfMonth, startOfMonth, eachWeekOfInterval, getISOWeek, addDays, eachDayOfInterval, getHours, getMinutes, isSameDay, isWithinInterval, isSameMonth, isValid, parseISO, addSeconds, format, subDays, startOfYear, endOfYear } from 'date-fns';
13
+ import * as i4 from '@angular/forms';
14
+ import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, FormControl, FormGroup, FormArray, Validators, ReactiveFormsModule } from '@angular/forms';
15
15
  import { delay, debounceTime, switchMap, map, catchError as catchError$1 } from 'rxjs/operators';
16
+ import * as Leaflet from 'leaflet';
17
+ import 'leaflet-draw';
16
18
 
17
19
  class EnvironmentService {
18
20
  constructor(environment) {
@@ -1869,7 +1871,7 @@ class AdbRichEditorComponent {
1869
1871
  /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AdbRichEditorComponent, isStandalone: false, selector: "adb-rich-editor", inputs: { hasTaxon: "hasTaxon", hasReference: "hasReference", rows: "rows" }, providers: [{
1870
1872
  provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((() => AdbRichEditorComponent)),
1871
1873
  multi: true
1872
- }], ngImport: i0, template: "<div>\r\n <div class=\"d-flex justify-content-end gap-3 mb-1\">\r\n <button class=\"btn btn-secondary\" (click)=\"onItalicClick()\" title=\"Italic\" aria-label=\"Italic\" type=\"button\"><span class=\"fas fa-italic\"></span></button>\r\n <button class=\"btn btn-secondary\" (click)=\"onBoldClick()\" title=\"Italic\" aria-label=\"strong\" type=\"button\"><span class=\"fas fa-bold\"></span></button>\r\n @if (hasTaxon) {\r\n <button class=\"btn btn-secondary\" (click)=\"onTaxonClick()\" title=\"Taxon\" aria-label=\"Taxon\" type=\"button\"><span class=\"fas fa-bug\"></span></button>\r\n }\r\n @if (hasReference) {\r\n <button class=\"btn btn-secondary\" (click)=\"onReferenceClick()\" title=\"Reference\" aria-label=\"Reference\" type=\"button\"><span class=\"fas fa-asterisk\"></span></button>\r\n }\r\n </div>\r\n <textarea class=\"form-control\" [(ngModel)]=\"text\" (ngModelChange)=\"onTextChange()\" [rows]=\"rows\" (dblclick)=\"onDoubleClick()\"></textarea>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
1874
+ }], ngImport: i0, template: "<div>\r\n <div class=\"d-flex justify-content-end gap-3 mb-1\">\r\n <button class=\"btn btn-secondary\" (click)=\"onItalicClick()\" title=\"Italic\" aria-label=\"Italic\" type=\"button\"><span class=\"fas fa-italic\"></span></button>\r\n <button class=\"btn btn-secondary\" (click)=\"onBoldClick()\" title=\"Italic\" aria-label=\"strong\" type=\"button\"><span class=\"fas fa-bold\"></span></button>\r\n @if (hasTaxon) {\r\n <button class=\"btn btn-secondary\" (click)=\"onTaxonClick()\" title=\"Taxon\" aria-label=\"Taxon\" type=\"button\"><span class=\"fas fa-bug\"></span></button>\r\n }\r\n @if (hasReference) {\r\n <button class=\"btn btn-secondary\" (click)=\"onReferenceClick()\" title=\"Reference\" aria-label=\"Reference\" type=\"button\"><span class=\"fas fa-asterisk\"></span></button>\r\n }\r\n </div>\r\n <textarea class=\"form-control\" [(ngModel)]=\"text\" (ngModelChange)=\"onTextChange()\" [rows]=\"rows\" (dblclick)=\"onDoubleClick()\"></textarea>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
1873
1875
  }
1874
1876
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbRichEditorComponent, decorators: [{
1875
1877
  type: Component,
@@ -2467,7 +2469,7 @@ class GenericPickerComponent {
2467
2469
  this.subs.unsubscribe();
2468
2470
  }
2469
2471
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: GenericPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2470
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: GenericPickerComponent, isStandalone: false, selector: "adb-generic-picker", inputs: { search: "search", displayFn: "displayFn", loadById: "loadById", disabled: "disabled", placeholder: "placeholder", initialValue: "initialValue" }, outputs: { selectItemChange: "selectItemChange", focus: "focus" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: ["itemTemplate"], descendants: true }], ngImport: i0, template: "<div (adbClickOutside)=\"resetPopup()\">\r\n <div class=\"input-group\">\r\n <input [(ngModel)]=\"searchQuery\" class=\"form-control\" role=\"combobox\" aria-autocomplete=\"list\" [attr.aria-expanded]=\"showPop\" aria-controls=\"picker-listbox\" [disabled]=\"disabled\" autocomplete=\"off\" (keyup.arrowdown)=\"onArrowDown()\"\r\n (keyup.arrowup)=\"onArrowUp()\" (keydown.enter)=\"onEnter($event)\" (keydown.escape)=\"resetPopup()\" (keydown.tab)=\"resetPopup()\" (ngModelChange)=\"onModelChange()\" (focus)=\"focus.emit($event)\" [placeholder]=\"placeholder\" />\r\n @if (searchQuery && !showPop) {\r\n <div>\r\n <button type=\"button\" (click)=\"resetModel()\" class=\"btn btn-secondary border border-start-0\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@let items = items$ | async;\r\n@if (showPop) {\r\n<div class=\"pop\">\r\n <div class=\"pop-body\">\r\n <div [class.loading]=\"loading\">\r\n @if (error) {\r\n <div class=\"alert alert-danger mb-0\">\r\n Serverfel\r\n </div>\r\n }\r\n @else {\r\n <ul class=\"list-group list-group-flush\" role=\"listbox\" id=\"picker-listbox\">\r\n @for (item of items; track item; let i = $index) {\r\n <li role=\"option\" class=\"list-group-item list-group-item-action pointer\" [class.active]=\"i === rowIndex\" (click)=\"$event.preventDefault(); $event.stopPropagation(); selectItem(item)\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, searchQuery: searchQuery }\"></ng-container>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n}", dependencies: [{ kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[adbClickOutside]", outputs: ["adbClickOutside"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }] }); }
2472
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: GenericPickerComponent, isStandalone: false, selector: "adb-generic-picker", inputs: { search: "search", displayFn: "displayFn", loadById: "loadById", disabled: "disabled", placeholder: "placeholder", initialValue: "initialValue" }, outputs: { selectItemChange: "selectItemChange", focus: "focus" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: ["itemTemplate"], descendants: true }], ngImport: i0, template: "<div (adbClickOutside)=\"resetPopup()\">\r\n <div class=\"input-group\">\r\n <input [(ngModel)]=\"searchQuery\" class=\"form-control\" role=\"combobox\" aria-autocomplete=\"list\" [attr.aria-expanded]=\"showPop\" aria-controls=\"picker-listbox\" [disabled]=\"disabled\" autocomplete=\"off\" (keyup.arrowdown)=\"onArrowDown()\"\r\n (keyup.arrowup)=\"onArrowUp()\" (keydown.enter)=\"onEnter($event)\" (keydown.escape)=\"resetPopup()\" (keydown.tab)=\"resetPopup()\" (ngModelChange)=\"onModelChange()\" (focus)=\"focus.emit($event)\" [placeholder]=\"placeholder\" />\r\n @if (searchQuery && !showPop) {\r\n <div>\r\n <button type=\"button\" (click)=\"resetModel()\" class=\"btn btn-secondary border border-start-0\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@let items = items$ | async;\r\n@if (showPop) {\r\n<div class=\"pop\">\r\n <div class=\"pop-body\">\r\n <div [class.loading]=\"loading\">\r\n @if (error) {\r\n <div class=\"alert alert-danger mb-0\">\r\n Serverfel\r\n </div>\r\n }\r\n @else {\r\n <ul class=\"list-group list-group-flush\" role=\"listbox\" id=\"picker-listbox\">\r\n @for (item of items; track item; let i = $index) {\r\n <li role=\"option\" class=\"list-group-item list-group-item-action pointer\" [class.active]=\"i === rowIndex\" (click)=\"$event.preventDefault(); $event.stopPropagation(); selectItem(item)\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, searchQuery: searchQuery }\"></ng-container>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n}", dependencies: [{ kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[adbClickOutside]", outputs: ["adbClickOutside"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }] }); }
2471
2473
  }
2472
2474
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: GenericPickerComponent, decorators: [{
2473
2475
  type: Component,
@@ -2751,6 +2753,870 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
2751
2753
  }]
2752
2754
  }] });
2753
2755
 
2756
+ class AdbMapUtils {
2757
+ static { this.OverlayMaps = {
2758
+ 'Altitude': new Leaflet.TileLayer.WMS("https://maps.sgu.se/lmv/hojdmodell/v1.1?SERVICE=WMS", { layers: "terrangskuggning", format: "image/png", transparent: true, opacity: 0.3, maxZoom: 16, version: "1.3.0" }),
2759
+ 'Fjällkarta': new Leaflet.TileLayer.WMS('api/maps/mountain', {
2760
+ minZoom: 6,
2761
+ maxZoom: 18,
2762
+ maxNativeZoom: 14,
2763
+ attribution: '© <a href="https://www.lantmateriet.se/">Fjällkart</a>',
2764
+ wms: true
2765
+ }),
2766
+ 'Kommuner': new Leaflet.TileLayer.WMS('https://sosgeo.artdata.slu.se/geoserver/GeoRegion/wms?', {
2767
+ layers: 'GeoRegion:Municipality',
2768
+ version: '1.1.0',
2769
+ transparent: true,
2770
+ format: 'image/png'
2771
+ }),
2772
+ 'Län': new Leaflet.TileLayer.WMS('https://sosgeo.artdata.slu.se/geoserver/GeoRegion/wms?', {
2773
+ layers: 'GeoRegion:County',
2774
+ version: '1.1.0',
2775
+ transparent: true,
2776
+ format: 'image/png'
2777
+ }),
2778
+ 'Ortnamn': new Leaflet.TileLayer.WMS("https://maps.sgu.se/lmv/topowebb-skikt/v1.1?SERVICE=WMS", {
2779
+ layers: "text",
2780
+ format: "image/png",
2781
+ transparent: true,
2782
+ version: "1.3.0",
2783
+ }),
2784
+ 'Ekonomisk zon': new Leaflet.TileLayer.WMS("https://sosgeo.artdata.slu.se/geoserver/it.geosolutions/wms?", {
2785
+ layers: "it.geosolutions:Ekonomiska_zonens_yttre_avgränsningslinjer_linje",
2786
+ format: "image/png",
2787
+ transparent: true,
2788
+ version: "1.1.0"
2789
+ })
2790
+ }; }
2791
+ static { this.Providers = [
2792
+ {
2793
+ name: 'Open Streetmap',
2794
+ id: 3,
2795
+ url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
2796
+ minZoom: 0,
2797
+ maxZoom: 18,
2798
+ params: {
2799
+ maxNativeZoom: 18,
2800
+ attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
2801
+ },
2802
+ wms: false
2803
+ },
2804
+ {
2805
+ name: 'Sveriges gränser',
2806
+ id: 7,
2807
+ url: 'https://sosgeo.artdata.slu.se/geoserver/GeoRegion/wms',
2808
+ minZoom: 6,
2809
+ maxZoom: 18,
2810
+ params: {
2811
+ maxNativeZoom: 14,
2812
+ attribution: '© <a href="https://www.lantmateriet.se/">Sveriges gränser</a>',
2813
+ layers: 'GeoRegion:County', styles: 'municipality_name_yellow'
2814
+ },
2815
+ wms: true
2816
+ }
2817
+ ]; }
2818
+ }
2819
+
2820
+ class AdbBaseMap {
2821
+ constructor(options = {}) {
2822
+ // protected static PRIMARY = '#007681';
2823
+ this.subscriptions = new Subscription();
2824
+ this.map = Leaflet.map;
2825
+ this.INITIAL_CENTER_LAT = 62;
2826
+ this.INITIAL_CENTER_LNG = 17;
2827
+ this.mapReadySubject = new BehaviorSubject(false);
2828
+ this.mapReady$ = this.mapReadySubject.asObservable();
2829
+ this.mapMoveSubject = new BehaviorSubject(null);
2830
+ this.mapMove$ = this.mapMoveSubject.asObservable();
2831
+ this.hasProviders = options?.providers ?? true;
2832
+ this.hasZoom = options?.zoom ?? true;
2833
+ this.hasScrollZoom = options?.scrollZoom ?? true;
2834
+ }
2835
+ getId() {
2836
+ return '' + Math.floor(Math.random() * Date.now());
2837
+ }
2838
+ ngAfterViewInit() {
2839
+ this.map = Leaflet.map(this.mapId, {
2840
+ zoomAnimation: false,
2841
+ fadeAnimation: false,
2842
+ markerZoomAnimation: false,
2843
+ inertia: false,
2844
+ scrollWheelZoom: this.hasZoom,
2845
+ minZoom: -1,
2846
+ zoomControl: this.hasScrollZoom,
2847
+ dragging: this.hasZoom,
2848
+ fullscreenControl: true,
2849
+ fullscreenControlOptions: {
2850
+ position: 'topleft'
2851
+ }
2852
+ });
2853
+ if (this.hasZoom) {
2854
+ this.map.on('moveend', () => {
2855
+ this.mapMoveSubject.next();
2856
+ });
2857
+ }
2858
+ window.addEventListener('resize', () => {
2859
+ this.map.invalidateSize();
2860
+ });
2861
+ Leaflet.control.scale().addTo(this.map);
2862
+ if (this.hasProviders) {
2863
+ this.addMapLayers();
2864
+ }
2865
+ this.map.whenReady(() => {
2866
+ setTimeout(() => {
2867
+ this.mapReadySubject.next(true);
2868
+ });
2869
+ });
2870
+ this.map.setView([62, 17], 5);
2871
+ }
2872
+ addMapLayers() {
2873
+ let backgroundMaps = {};
2874
+ for (const value of Object.values(AdbMapUtils.Providers)) {
2875
+ backgroundMaps[value.name] = value.wms ?
2876
+ Leaflet.tileLayer.wms(value.url, value.params) :
2877
+ Leaflet.tileLayer(value.url, value.params);
2878
+ }
2879
+ this.map.addLayer(backgroundMaps['Open Streetmap']);
2880
+ Leaflet.control.layers(backgroundMaps, AdbMapUtils.OverlayMaps).addTo(this.map);
2881
+ }
2882
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbBaseMap, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
2883
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: AdbBaseMap, isStandalone: true, ngImport: i0 }); }
2884
+ }
2885
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbBaseMap, decorators: [{
2886
+ type: Directive
2887
+ }], ctorParameters: () => [{ type: undefined }] });
2888
+
2889
+ class PolygonDrawerInput extends AdbBaseMap {
2890
+ ngOnInit() {
2891
+ this.mapId = this.getId();
2892
+ this.subscriptions.add(this.mapReady$.subscribe(ready => {
2893
+ if (ready) {
2894
+ Leaflet.drawLocal.draw.handlers.rectangle.tooltip = {};
2895
+ Leaflet.drawLocal.draw.handlers.simpleshape.tooltip = {};
2896
+ Leaflet.drawLocal.draw.handlers.polygon.tooltip = {};
2897
+ Leaflet.drawLocal.draw.toolbar.undo.title = '';
2898
+ Leaflet.drawLocal.draw.toolbar.finish.title = '';
2899
+ Leaflet.drawLocal.draw.toolbar.actions.title = '';
2900
+ if (this.geoJson?.type === 'Feature') {
2901
+ this.shapeLayer = Leaflet.geoJson(this.geoJson);
2902
+ this.shapeLayer.interactive = false;
2903
+ this.map.addLayer(this.shapeLayer);
2904
+ this.map.fitBounds(this.shapeLayer.getBounds());
2905
+ }
2906
+ else {
2907
+ this.map.setView([this.INITIAL_CENTER_LAT, this.INITIAL_CENTER_LNG], 5);
2908
+ }
2909
+ this.map.on('draw:created', event => {
2910
+ if (event.layerType === 'polygon') {
2911
+ this.polygonDraw = false;
2912
+ this.shapeLayer = Leaflet.geoJson(event.layer.toGeoJSON());
2913
+ this.shapeLayer.interactive = false;
2914
+ this.map.addLayer(this.shapeLayer);
2915
+ this.map.fitBounds(this.shapeLayer.getBounds());
2916
+ this.onChange(event.layer.toGeoJSON());
2917
+ }
2918
+ });
2919
+ }
2920
+ }));
2921
+ }
2922
+ constructor() {
2923
+ super(null);
2924
+ //ControlValueAccessor starts
2925
+ this.onChange = () => { };
2926
+ this.onTouched = () => { };
2927
+ }
2928
+ onDrawPolygon() {
2929
+ this.polygonDraw = true;
2930
+ this.drawLayer = new Leaflet.Draw.Polygon(this.map, { allowIntersection: false });
2931
+ this.drawLayer.enable();
2932
+ }
2933
+ onDeleteShape() {
2934
+ if (this.drawLayer) {
2935
+ this.map.removeLayer(this.drawLayer);
2936
+ }
2937
+ if (this.shapeLayer) {
2938
+ this.map.removeLayer(this.shapeLayer);
2939
+ }
2940
+ this.shapeLayer = null;
2941
+ this.polygonDraw = false;
2942
+ this.onChange(null);
2943
+ this.drawLayer = null;
2944
+ this.map.setView([62, 17], 5);
2945
+ }
2946
+ onUndoStep() {
2947
+ this.drawLayer.deleteLastVertex();
2948
+ }
2949
+ onMapMoveEnd() {
2950
+ }
2951
+ writeValue(geoJson) {
2952
+ this.geoJson = geoJson;
2953
+ }
2954
+ registerOnChange(fn) {
2955
+ this.onChange = fn;
2956
+ }
2957
+ registerOnTouched(fn) {
2958
+ this.onTouched = fn;
2959
+ }
2960
+ setDisabledState(isDisabled) {
2961
+ }
2962
+ ngOnDestroy() {
2963
+ this.subscriptions.unsubscribe();
2964
+ }
2965
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PolygonDrawerInput, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2966
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: PolygonDrawerInput, isStandalone: false, selector: "adb-polygon-drawer", providers: [
2967
+ {
2968
+ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((() => PolygonDrawerInput)),
2969
+ multi: true
2970
+ }
2971
+ ], usesInheritance: true, ngImport: i0, template: "<div class=\"mb-1 d-flex gap-1 flex-wrap align-items-start\">\r\n <button class=\"btn btn-secondary\" type=\"button\" [disabled]=\"shapeLayer||drawLayer\" (click)=\"onDrawPolygon()\" title=\"Polygon\">\r\n <span class=\"fas fa-draw-polygon\"></span> {{'OBSERVATION.DRAW'|translate}}\r\n </button>\r\n @if (shapeLayer||drawLayer) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDeleteShape()\" title=\"Ta bort\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n }\r\n @if (polygonDraw) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onUndoStep()\" title=\"\u00C5ngra\">\r\n <span class=\"fas fa-undo\"></span>\r\n </button>\r\n }\r\n</div>\r\n<div [id]=\"mapId\" class=\"border\" style=\"height:20rem\"></div>", dependencies: [{ kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] }); }
2972
+ }
2973
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PolygonDrawerInput, decorators: [{
2974
+ type: Component,
2975
+ args: [{ selector: 'adb-polygon-drawer', standalone: false, providers: [
2976
+ {
2977
+ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((() => PolygonDrawerInput)),
2978
+ multi: true
2979
+ }
2980
+ ], template: "<div class=\"mb-1 d-flex gap-1 flex-wrap align-items-start\">\r\n <button class=\"btn btn-secondary\" type=\"button\" [disabled]=\"shapeLayer||drawLayer\" (click)=\"onDrawPolygon()\" title=\"Polygon\">\r\n <span class=\"fas fa-draw-polygon\"></span> {{'OBSERVATION.DRAW'|translate}}\r\n </button>\r\n @if (shapeLayer||drawLayer) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDeleteShape()\" title=\"Ta bort\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n }\r\n @if (polygonDraw) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onUndoStep()\" title=\"\u00C5ngra\">\r\n <span class=\"fas fa-undo\"></span>\r\n </button>\r\n }\r\n</div>\r\n<div [id]=\"mapId\" class=\"border\" style=\"height:20rem\"></div>" }]
2981
+ }], ctorParameters: () => [] });
2982
+
2983
+ var AdbMapFilterType;
2984
+ (function (AdbMapFilterType) {
2985
+ AdbMapFilterType["Taxon"] = "taxon";
2986
+ AdbMapFilterType["Area"] = "area";
2987
+ AdbMapFilterType["Time"] = "time";
2988
+ AdbMapFilterType["RedList"] = "redlist";
2989
+ AdbMapFilterType["RiskList"] = "risklist";
2990
+ AdbMapFilterType["TaxaLists"] = "taxonLists";
2991
+ AdbMapFilterType["Datasources"] = "datasources";
2992
+ })(AdbMapFilterType || (AdbMapFilterType = {}));
2993
+ class VisibleFilters {
2994
+ }
2995
+ const ADB_MAP_CONFIG = new InjectionToken('ADB_MAP_CONFIG');
2996
+ class AdbMapConfigService {
2997
+ constructor(config) {
2998
+ this.log = config.log ?? false;
2999
+ this.artfaktaTaxonLists = config.artfaktaTaxonLists ?? 'https://artfakta.se/metadata/listor';
3000
+ this.taxaListsApi = config.api + '/taxalists';
3001
+ this.aportalenObservations = config.artportalen + '/observation';
3002
+ this.filters = {
3003
+ showTaxon: this.hasFilter(AdbMapFilterType.Taxon, config.filters),
3004
+ showTime: this.hasFilter(AdbMapFilterType.Time, config.filters),
3005
+ showArea: this.hasFilter(AdbMapFilterType.Area, config.filters),
3006
+ showRedList: this.hasFilter(AdbMapFilterType.RedList, config.filters),
3007
+ showRiskList: this.hasFilter(AdbMapFilterType.RiskList, config.filters),
3008
+ showTaxaLists: this.hasFilter(AdbMapFilterType.TaxaLists, config.filters),
3009
+ showDatasets: this.hasFilter(AdbMapFilterType.Datasources, config.filters),
3010
+ };
3011
+ }
3012
+ hasFilter(f, filters) {
3013
+ return filters?.includes(f) ?? true;
3014
+ }
3015
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapConfigService, deps: [{ token: ADB_MAP_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
3016
+ /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapConfigService }); }
3017
+ }
3018
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapConfigService, decorators: [{
3019
+ type: Injectable
3020
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3021
+ type: Inject,
3022
+ args: [ADB_MAP_CONFIG]
3023
+ }] }] });
3024
+
3025
+ class TreeviewComponent {
3026
+ constructor() {
3027
+ this.nodes = [];
3028
+ this.selectedIds = [];
3029
+ this.onChange = () => { };
3030
+ this.onTouched = () => { };
3031
+ }
3032
+ writeValue(ids) {
3033
+ this.selectedIds = ids ?? [];
3034
+ this.applySelection(this.nodes);
3035
+ }
3036
+ registerOnChange(fn) {
3037
+ this.onChange = fn;
3038
+ }
3039
+ registerOnTouched(fn) {
3040
+ this.onTouched = fn;
3041
+ }
3042
+ setDisabledState(isDisabled) {
3043
+ this.setReadOnly(this.nodes, isDisabled);
3044
+ }
3045
+ onLeafToggle(node) {
3046
+ if (node._readOnly)
3047
+ return;
3048
+ node._selected = !node._selected;
3049
+ this.selectedIds = TreeviewComponent.collectSelectedLeafIds(this.nodes);
3050
+ this.onChange(this.selectedIds);
3051
+ this.onTouched();
3052
+ }
3053
+ applySelection(nodes) {
3054
+ for (const node of nodes) {
3055
+ if (node.children?.length) {
3056
+ this.applySelection(node.children);
3057
+ }
3058
+ else {
3059
+ node._selected = this.selectedIds.includes(node.id);
3060
+ }
3061
+ }
3062
+ }
3063
+ setReadOnly(nodes, readOnly) {
3064
+ for (const node of nodes) {
3065
+ node._readOnly = readOnly;
3066
+ if (node.children?.length) {
3067
+ this.setReadOnly(node.children, readOnly);
3068
+ }
3069
+ }
3070
+ }
3071
+ static collectSelectedLeafIds(nodes) {
3072
+ const ids = [];
3073
+ for (const node of nodes) {
3074
+ if (node.children?.length) {
3075
+ ids.push(...this.collectSelectedLeafIds(node.children));
3076
+ }
3077
+ else if (node._selected) {
3078
+ ids.push(node.id);
3079
+ }
3080
+ }
3081
+ return ids;
3082
+ }
3083
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TreeviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3084
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: TreeviewComponent, isStandalone: false, selector: "app-treeview", inputs: { nodes: "nodes" }, providers: [
3085
+ {
3086
+ provide: NG_VALUE_ACCESSOR,
3087
+ useExisting: forwardRef((() => TreeviewComponent)),
3088
+ multi: true
3089
+ }
3090
+ ], ngImport: i0, template: "<ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: nodes }\">\r\n</ng-container>\r\n<ng-template #nodeTpl let-nodes>\r\n @for (node of nodes; track node) {\r\n <div class=\"ms-3\">\r\n @if(!node.children || node.children.length === 0){\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <input id=\"{{node.id}}\" type=\"checkbox\" class=\"form-check-input m-0\" [checked]=\"node._selected\" [disabled]=\"node._readOnly\" (change)=\"onLeafToggle(node)\" />\r\n <label for=\"{{node.id}}\">{{ node.name }}</label>\r\n </div>\r\n }\r\n @else {\r\n {{ node.name }}\r\n <div>\r\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: node.children }\">\r\n </ng-container>\r\n </div>\r\n }\r\n </div>\r\n}\r\n</ng-template>", dependencies: [{ kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
3091
+ }
3092
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TreeviewComponent, decorators: [{
3093
+ type: Component,
3094
+ args: [{ selector: 'app-treeview', standalone: false, providers: [
3095
+ {
3096
+ provide: NG_VALUE_ACCESSOR,
3097
+ useExisting: forwardRef((() => TreeviewComponent)),
3098
+ multi: true
3099
+ }
3100
+ ], template: "<ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: nodes }\">\r\n</ng-container>\r\n<ng-template #nodeTpl let-nodes>\r\n @for (node of nodes; track node) {\r\n <div class=\"ms-3\">\r\n @if(!node.children || node.children.length === 0){\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <input id=\"{{node.id}}\" type=\"checkbox\" class=\"form-check-input m-0\" [checked]=\"node._selected\" [disabled]=\"node._readOnly\" (change)=\"onLeafToggle(node)\" />\r\n <label for=\"{{node.id}}\">{{ node.name }}</label>\r\n </div>\r\n }\r\n @else {\r\n {{ node.name }}\r\n <div>\r\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: node.children }\">\r\n </ng-container>\r\n </div>\r\n }\r\n </div>\r\n}\r\n</ng-template>" }]
3101
+ }], propDecorators: { nodes: [{
3102
+ type: Input
3103
+ }] } });
3104
+
3105
+ class MapUtils {
3106
+ static { this.redlistMapper = {
3107
+ "228": 24,
3108
+ "229": 25,
3109
+ "230": 26,
3110
+ "231": 27,
3111
+ "232": 28,
3112
+ "233": 29
3113
+ }; }
3114
+ static { this.redListMapper2 = {
3115
+ 'VU': '228',
3116
+ 'EN': '229',
3117
+ 'CR': '230',
3118
+ 'RE': '231',
3119
+ 'DD': '232',
3120
+ 'NT': '233'
3121
+ }; }
3122
+ static { this.riskListMapper = {
3123
+ "39": 19,
3124
+ "40": 20,
3125
+ "41": 21,
3126
+ "42": 22,
3127
+ "43": 23
3128
+ }; }
3129
+ static { this.listMapper = {
3130
+ '8': 8,
3131
+ '34': 1,
3132
+ '35': 4,
3133
+ '36': 3,
3134
+ '44': 13,
3135
+ "46": 15,
3136
+ '282': 2
3137
+ }; }
3138
+ static { this.euRegulation = 5; }
3139
+ static createObservationsBody(queryParams) {
3140
+ const body = {};
3141
+ if (queryParams.startAt) {
3142
+ body.date = {};
3143
+ body.date.startDate = queryParams.startAt;
3144
+ if (queryParams.endAt) {
3145
+ body.date.endDate = queryParams.endAt;
3146
+ }
3147
+ }
3148
+ const taxonId = queryParams?.taxonId;
3149
+ if (taxonId) {
3150
+ body.taxon = { Ids: [+taxonId] };
3151
+ body.taxon.includeUnderlyingTaxa = true;
3152
+ }
3153
+ MapUtils.handleLists(queryParams, body);
3154
+ body.geographics = {};
3155
+ if (queryParams.bbox) {
3156
+ const boundArray = JSON.parse(queryParams.bbox);
3157
+ body.geographics.boundingBox = {
3158
+ bottomRight: {
3159
+ latitude: boundArray[0],
3160
+ longitude: boundArray[3]
3161
+ },
3162
+ topLeft: {
3163
+ latitude: boundArray[2],
3164
+ longitude: boundArray[1]
3165
+ }
3166
+ };
3167
+ }
3168
+ if (queryParams.area) {
3169
+ const areas = Array.isArray(queryParams.area)
3170
+ ? queryParams.area
3171
+ : queryParams.area ? [queryParams.area] : [];
3172
+ const parsedAreas = areas.map(a => {
3173
+ const [areaType, ...rest] = a.split('-');
3174
+ const featureId = rest.join('-');
3175
+ return areaType && featureId ? { areaType, featureId } : null;
3176
+ }).filter(v => v !== null);
3177
+ body.geographics.areas = parsedAreas;
3178
+ }
3179
+ if (queryParams.geo) {
3180
+ body.geographics.geometries = [{ type: 'Polygon', coordinates: [JSON.parse(queryParams.geo)] }];
3181
+ }
3182
+ const noted = queryParams.noted === 'true';
3183
+ if (queryParams.ds) {
3184
+ const providers = Array.isArray(queryParams.ds) ? queryParams.ds.map(m => +m) : [+queryParams.ds];
3185
+ body.dataProvider = { ids: providers };
3186
+ }
3187
+ const presets = {
3188
+ occurrenceStatus: noted ? 'Present' : 'BothPresentAndAbsent',
3189
+ verificationStatus: "BothVerifiedAndNotVerified",
3190
+ notRecoveredFilter: 'DontIncludeNotRecovered',
3191
+ determinationFilter: 'NotUnsureDetermination',
3192
+ protectionFilter: "Public",
3193
+ diffusionStatuses: ['NotDiffused', 'DiffusedBySystem', 'DiffusedByProvider'],
3194
+ extendedFilter: {
3195
+ 'notPresentFilter': 'DontIncludeNotPresent'
3196
+ }
3197
+ };
3198
+ if (queryParams.activities) {
3199
+ const stringArray = JSON.parse(queryParams.activities);
3200
+ presets.extendedFilter.activityIds = stringArray?.map(Number);
3201
+ }
3202
+ return { ...presets, ...body };
3203
+ }
3204
+ static handleLists(queryParams, body) {
3205
+ let listIds = [];
3206
+ if (queryParams.rc) { //RISK CLASS
3207
+ const risk = queryParams.rc ? (Array.isArray(queryParams.rc) ? queryParams.rc : [queryParams.rc]) : [];
3208
+ listIds = risk.map(t => MapUtils.riskListMapper[t]);
3209
+ }
3210
+ if (queryParams.rlc) { //REDLIST
3211
+ let redLists = queryParams.rlc ? (Array.isArray(queryParams.rlc) ? queryParams.rlc : [queryParams.rlc]) : [];
3212
+ redLists = redLists.map(t => MapUtils.redlistMapper[t]);
3213
+ listIds.push(...redLists);
3214
+ }
3215
+ if (queryParams.tl || queryParams.eu) { //OTHER LISTS
3216
+ let taxonLists = queryParams.tl ? (Array.isArray(queryParams.tl) ? queryParams.tl : [queryParams.tl]) : [];
3217
+ taxonLists = taxonLists.map(t => MapUtils.listMapper[t]);
3218
+ if (queryParams.eu) {
3219
+ taxonLists.push(MapUtils.euRegulation);
3220
+ }
3221
+ listIds.push(...taxonLists);
3222
+ }
3223
+ body.taxon ??= {};
3224
+ body.taxon.taxonListIds = listIds;
3225
+ }
3226
+ }
3227
+
3228
+ class AdbObsMapComponent extends AdbBaseMap {
3229
+ constructor(activatedRoute, config, router, http) {
3230
+ super({ zoom: true, scrollZoom: true });
3231
+ this.activatedRoute = activatedRoute;
3232
+ this.config = config;
3233
+ this.router = router;
3234
+ this.http = http;
3235
+ this.aportalenObservations = this.config.aportalenObservations;
3236
+ }
3237
+ ngOnInit() {
3238
+ this.mapId = this.getId();
3239
+ const combined$ = combineLatest([this.mapReady$, this.activatedRoute.paramMap, this.activatedRoute.queryParams])
3240
+ .pipe(map(results => ({ ready: results[0], urlParams: results[1], qParams: results[2] })), debounceTime(0));
3241
+ this.subscriptions.add(combined$.subscribe(result => {
3242
+ if (result.ready) {
3243
+ this.hasBox = result.qParams.bbox ? true : false;
3244
+ const qps = { ...result.qParams };
3245
+ if (result.urlParams.has('taxonId')) {
3246
+ qps.taxonId = result.urlParams.get('taxonId');
3247
+ }
3248
+ this.loadFeature(qps);
3249
+ }
3250
+ }));
3251
+ }
3252
+ ngOnDestroy() {
3253
+ this.subscriptions.unsubscribe();
3254
+ }
3255
+ loadFeature(qParams) {
3256
+ this.loading = true;
3257
+ this.error = null;
3258
+ const body = MapUtils.createObservationsBody(qParams);
3259
+ //TODO: will be const url = this.config.api + '/observationmap/observation-features';
3260
+ const url = 'https://sos-search-st.wt.artdata.slu.se/Observations/Internal/AdaptiveSearch';
3261
+ // this.subscriptions.add(this.http.post<GeoJson>(url, body, { observe: 'response', params: { includeFilterAreasInResult: true, observationsLimit: 0 } }).subscribe({
3262
+ this.subscriptions.add(this.http.post(url, body, { observe: 'response', params: { includeFilterAreasInResult: true, observationsLimit: 0 } }).subscribe({
3263
+ next: (response) => {
3264
+ const geo = response.body;
3265
+ geo.properties = { count: response.headers.get('X-Observations-TotalCount') };
3266
+ this.buildMap(geo);
3267
+ }, error: err => {
3268
+ this.error = err;
3269
+ this.loading = false;
3270
+ }
3271
+ }));
3272
+ }
3273
+ buildMap(geojson) {
3274
+ if (this.siteLayer) {
3275
+ this.map.removeLayer(this.siteLayer);
3276
+ }
3277
+ this.count = geojson?.properties?.count;
3278
+ this.siteLayer = Leaflet.geoJson(geojson, {
3279
+ style: (feature) => {
3280
+ return {
3281
+ className: `svg ${this.getPolygonClassName(feature.properties)}`, // Leaflet applies this class to the SVG path
3282
+ weight: 1,
3283
+ fillOpacity: 0.8,
3284
+ };
3285
+ },
3286
+ pointToLayer: (feature, latlng) => {
3287
+ const marker = Leaflet.marker(latlng, {
3288
+ icon: Leaflet.divIcon({
3289
+ className: '',
3290
+ html: '<div class="adb-map-marker"></div>',
3291
+ iconAnchor: [3, 3]
3292
+ })
3293
+ });
3294
+ if (feature.properties && feature.properties['Occurrence.OccurrenceId']) {
3295
+ marker.on('click', () => {
3296
+ window.location.href = this.aportalenObservations + '/' + feature.properties['Occurrence.OccurrenceId'];
3297
+ });
3298
+ }
3299
+ return marker;
3300
+ }, onEachFeature: (feature, layer) => {
3301
+ if (feature.geometry.type === "Polygon" ||
3302
+ feature.geometry.type === "MultiPolygon") {
3303
+ if (feature.properties.ObservationsCount > 0) {
3304
+ layer.on('click', () => {
3305
+ const boundBox = JSON.stringify(this.getMapBoundsToBbox(layer.getBounds()));
3306
+ this.router.navigate([], { queryParams: { bbox: boundBox }, queryParamsHandling: 'merge' });
3307
+ });
3308
+ layer.on('mouseover', () => {
3309
+ layer.setStyle({ className: 'svg cursor-pointer' });
3310
+ });
3311
+ layer.on('mouseout', () => {
3312
+ layer.setStyle({ className: 'svg' });
3313
+ });
3314
+ }
3315
+ if (feature.properties.FeatureType) { //area
3316
+ layer.setStyle({ interactive: false });
3317
+ }
3318
+ }
3319
+ }
3320
+ });
3321
+ const circleLayer = Leaflet.featureGroup();
3322
+ circleLayer.addTo(this.siteLayer);
3323
+ this.map.addLayer(this.siteLayer);
3324
+ if (geojson.bbox) {
3325
+ const [minLon, minLat, maxLon, maxLat] = geojson.bbox;
3326
+ const bounds = Leaflet.latLngBounds([[minLat, minLon], [maxLat, maxLon]]);
3327
+ if (bounds.isValid()) {
3328
+ // Safari sometimes needs extra time after layer adds
3329
+ setTimeout(() => {
3330
+ this.map.invalidateSize({ animate: false });
3331
+ this.map.fitBounds(bounds);
3332
+ this.loading = false;
3333
+ }, 50); // 30–50ms works best in Safari
3334
+ }
3335
+ }
3336
+ else {
3337
+ this.loading = false;
3338
+ }
3339
+ }
3340
+ getPolygonClassName(props) {
3341
+ if (props.FeatureType) {
3342
+ return 'map-area';
3343
+ }
3344
+ if (props.ObservationsCount < 10)
3345
+ return 'map-heat-low';
3346
+ if (props.ObservationsCount < 500)
3347
+ return 'map-heat-small';
3348
+ return 'map-heat-high';
3349
+ }
3350
+ getMapBoundsToBbox(bounds) {
3351
+ return [bounds.getNorthWest().lat, bounds.getNorthWest().lng, bounds.getSouthEast().lat, bounds.getSouthEast().lng];
3352
+ }
3353
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbObsMapComponent, deps: [{ token: i1.ActivatedRoute }, { token: AdbMapConfigService }, { token: i1.Router }, { token: i1$2.HttpClient }], target: i0.ɵɵFactoryTarget.Component }); }
3354
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AdbObsMapComponent, isStandalone: false, selector: "adb-obs-map", usesInheritance: true, ngImport: i0, template: "@if(hasBox&&!loading){\r\n <div class=\"mb-1 d-flex justify-content-between flex-wrap\">\r\n <a [routerLink]=\"[]\" [queryParams]=\"{bbox:null,z:null}\" queryParamsHandling=\"merge\" class=\"d-flex gap-1 align-items-baseline\">\r\n <span class=\"fas fa-chevron-left\"></span>\r\n Tillbaka upp\r\n </a>\r\n </div>\r\n}\r\n@if(error){\r\n <div class=\"alert alert-danger\">\r\n {{'ERROR.SERVER_ERROR'|translate}}\r\n </div>\r\n}\r\n<div [class.loading]=\"loading\">\r\n <div [style.visibility]=\"loading ? 'hidden':'visible'\" [id]=\"mapId\" class=\"mb-1 map-container\"></div>\r\n</div>\r\n<div class=\"mb-1 d-flex gap-3 justify-content-between flex-wrap\">\r\n @if (count > 5000) {\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-low\"></div>\r\n &lt;10\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-medium\"></div>\r\n 10 - 500\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-high\"></div>\r\n &gt;500\r\n </div>\r\n }\r\n @if (!loading&&count) {\r\n <div class=\"ms-auto\">\r\n {{count|adbSpacing}} {{'OBSERVATION.OBSERVATIONS'|translate}}\r\n </div>\r\n }\r\n</div>", dependencies: [{ kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: NumberSpacingPipe, name: "adbSpacing" }] }); }
3355
+ }
3356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbObsMapComponent, decorators: [{
3357
+ type: Component,
3358
+ args: [{ selector: 'adb-obs-map', standalone: false, template: "@if(hasBox&&!loading){\r\n <div class=\"mb-1 d-flex justify-content-between flex-wrap\">\r\n <a [routerLink]=\"[]\" [queryParams]=\"{bbox:null,z:null}\" queryParamsHandling=\"merge\" class=\"d-flex gap-1 align-items-baseline\">\r\n <span class=\"fas fa-chevron-left\"></span>\r\n Tillbaka upp\r\n </a>\r\n </div>\r\n}\r\n@if(error){\r\n <div class=\"alert alert-danger\">\r\n {{'ERROR.SERVER_ERROR'|translate}}\r\n </div>\r\n}\r\n<div [class.loading]=\"loading\">\r\n <div [style.visibility]=\"loading ? 'hidden':'visible'\" [id]=\"mapId\" class=\"mb-1 map-container\"></div>\r\n</div>\r\n<div class=\"mb-1 d-flex gap-3 justify-content-between flex-wrap\">\r\n @if (count > 5000) {\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-low\"></div>\r\n &lt;10\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-medium\"></div>\r\n 10 - 500\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-high\"></div>\r\n &gt;500\r\n </div>\r\n }\r\n @if (!loading&&count) {\r\n <div class=\"ms-auto\">\r\n {{count|adbSpacing}} {{'OBSERVATION.OBSERVATIONS'|translate}}\r\n </div>\r\n }\r\n</div>" }]
3359
+ }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: AdbMapConfigService }, { type: i1.Router }, { type: i1$2.HttpClient }] });
3360
+
3361
+ class AdbMapFilters {
3362
+ static { this.AlienSpecies = 35; }
3363
+ static { this.Risklist = 38; }
3364
+ static { this.Redlist = 227; }
3365
+ static { this.datasets = ['1', '3', '5', '6', '4', '8']; }
3366
+ constructor(cdr, config, http, router, activatedRoute) {
3367
+ this.cdr = cdr;
3368
+ this.config = config;
3369
+ this.http = http;
3370
+ this.router = router;
3371
+ this.activatedRoute = activatedRoute;
3372
+ this.inline = false;
3373
+ this.artfakta = this.config.artfaktaTaxonLists;
3374
+ this.subscriptions = new Subscription();
3375
+ this.thisYear = new Date();
3376
+ this.lastYear = addYears(new Date(), -1);
3377
+ this.dateConfig = { minDate: null, maxDate: subDays(new Date(), 1) };
3378
+ this.filters = config.filters;
3379
+ }
3380
+ ngOnInit() {
3381
+ const lists$ = this.getLists();
3382
+ const combined$ = combineLatest([this.activatedRoute.paramMap, this.activatedRoute.queryParamMap, lists$])
3383
+ .pipe(map$1(results => ({ params: results[0], qParams: results[1], lists: results[2] })), debounceTime$1(0));
3384
+ this.subscriptions.add(combined$.subscribe(result => {
3385
+ this.form = this.createForm(result.params, result.qParams, result.lists);
3386
+ this.cdr.markForCheck();
3387
+ }));
3388
+ }
3389
+ removeArea(index) {
3390
+ this.form.get('areas').removeAt(index);
3391
+ this.form.markAsDirty();
3392
+ }
3393
+ addArea() {
3394
+ const areas = this.form.get('areas');
3395
+ areas.push(new FormControl(null));
3396
+ this.form.updateValueAndValidity();
3397
+ this.form.markAsDirty();
3398
+ }
3399
+ onSubmit() {
3400
+ const data = this.form.value;
3401
+ let params = {};
3402
+ params.p = data.period ?? null;
3403
+ if (data.period === '1') {
3404
+ params.startAt = startOfYear(this.thisYear).toISOString();
3405
+ params.endAt = null;
3406
+ }
3407
+ else if (data.period === '2') {
3408
+ params.startAt = startOfYear(this.lastYear).toISOString();
3409
+ params.endAt = endOfYear(this.lastYear).toISOString();
3410
+ }
3411
+ else if (data.period === '3') {
3412
+ params.startAt = null;
3413
+ params.endAt = null;
3414
+ }
3415
+ else if (data.period === '4') {
3416
+ params.startAt = startOfYear(addYears(new Date(), -5)).toISOString();
3417
+ params.endAt = null;
3418
+ }
3419
+ else if (data.period === '5') {
3420
+ params.startAt = startOfYear(addYears(new Date(), -25)).toISOString();
3421
+ params.endAt = null;
3422
+ }
3423
+ else if (data.period === '6') {
3424
+ params.startAt = startOfDay(data.startAt).toISOString();
3425
+ params.endAt = endOfDay(data.endAt).toISOString();
3426
+ }
3427
+ if (this.hasOwnArea && data.geo) {
3428
+ params.geo = JSON.stringify(data.geo.geometry?.coordinates[0]);
3429
+ }
3430
+ const cleaned = data.areas?.filter(v => v != null && v !== '');
3431
+ if (cleaned.length > 0) {
3432
+ params.area = cleaned;
3433
+ }
3434
+ if (this.activatedRoute.snapshot.paramMap.has('taxonId')) {
3435
+ params.taxonId = this.activatedRoute.snapshot.paramMap.get('taxonId');
3436
+ }
3437
+ else {
3438
+ params.taxonId = data.taxonId ?? null;
3439
+ }
3440
+ if (data.rlc?.length > 0) {
3441
+ const selected = data.rlc.filter(f => f.selected).map(m => m.id);
3442
+ params.rlc = selected.length ? selected : null;
3443
+ }
3444
+ if (data.rc?.length > 0) {
3445
+ const selected = data.rc.filter(f => f.selected).map(m => m.id);
3446
+ params.rc = selected.length ? selected : null;
3447
+ }
3448
+ if (data.tl?.length > 0) {
3449
+ params.tl = data.tl;
3450
+ }
3451
+ if (data.ds?.length > 0) {
3452
+ const selected = data.ds.filter(f => f.selected).map(m => m.id);
3453
+ params.ds = selected.length ? selected : null;
3454
+ }
3455
+ this.router.navigate([], { queryParams: params, relativeTo: this.activatedRoute });
3456
+ }
3457
+ createForm(params, qMap, lists) {
3458
+ this.hasTaxonInUrlParameter = params.has('taxonId');
3459
+ this.hasOwnArea = qMap.has('geo');
3460
+ const areas = qMap.getAll('area').filter(a => a != null && a.trim() !== '' && a.includes('-'));
3461
+ const form = new FormGroup({
3462
+ period: new FormControl(qMap.has('p') ? qMap.get('p') : '3'),
3463
+ areas: new FormArray((Array.isArray(areas) && areas.length ? areas : [null]).map(a => new FormControl(a))),
3464
+ geo: new FormControl(qMap.has('geo') ? {
3465
+ type: 'Feature',
3466
+ geometry: { type: 'Polygon', coordinates: [JSON.parse(qMap.get('geo'))] }
3467
+ } : null)
3468
+ });
3469
+ this.areasArray = form.get('areas');
3470
+ this.periodCount = qMap.has('p') && qMap.get('p') !== '3' ? 1 : 0;
3471
+ this.areaCount = areas?.length;
3472
+ if (!this.hasTaxonInUrlParameter) {
3473
+ form.addControl('taxonId', new FormControl(qMap.get('taxonId') ?? null));
3474
+ let selectedRedLists = qMap.has('rlc') ? (Array.isArray(qMap.getAll('rlc')) ? qMap.getAll('rlc') : [qMap.get('rlc')]) : null;
3475
+ this.redListCount = selectedRedLists?.length;
3476
+ form.addControl('rlc', new FormArray(lists.redlist.map(redlistCat => new FormGroup({
3477
+ id: new FormControl(redlistCat.id),
3478
+ selected: new FormControl(selectedRedLists?.includes('' + redlistCat.id))
3479
+ }))));
3480
+ this.rlcControls = form.get('rlc').controls;
3481
+ let selectedRisks = qMap.has('rc') ? (Array.isArray(qMap.getAll('rc')) ? qMap.getAll('rc') : [qMap.get('rc')]) : null;
3482
+ this.riskListCount = selectedRisks?.length;
3483
+ form.addControl('rc', new FormArray(lists.riskList.map(risklistCat => new FormGroup({
3484
+ id: new FormControl(risklistCat.id),
3485
+ selected: new FormControl(selectedRisks?.includes('' + risklistCat.id))
3486
+ }))));
3487
+ this.rcControls = form.get('rc').controls;
3488
+ const selectedTaxonList = qMap.has('tl') ? qMap.getAll('tl').map(val => Number(val)).filter(val => !isNaN(val)) : null;
3489
+ this.taxaLists = lists.others;
3490
+ this.taxonListCount = selectedTaxonList?.length;
3491
+ form.addControl('tl', new FormControl(selectedTaxonList));
3492
+ let datasets = qMap.has('ds') ? (Array.isArray(qMap.getAll('ds')) ? qMap.getAll('ds') : [qMap.get('ds')]) : null;
3493
+ this.dataSetCount = datasets?.length;
3494
+ form.addControl('ds', new FormArray(AdbMapFilters.datasets.map(id => new FormGroup({
3495
+ id: new FormControl(id),
3496
+ selected: new FormControl(datasets?.includes(id))
3497
+ }))));
3498
+ this.dsControls = form.get('ds').controls;
3499
+ }
3500
+ this.updateCustomDate(form, qMap.get('p'), qMap);
3501
+ this.subscriptions.add(form.get('period').valueChanges.subscribe(period => {
3502
+ this.updateCustomDate(form, period, qMap);
3503
+ }));
3504
+ return form;
3505
+ }
3506
+ updateCustomDate(form, period, qMap) {
3507
+ if (period === '6') {
3508
+ form.addControl('startAt', new FormControl(qMap.has('startAt') ? parseISO(qMap.get('startAt')) : null, Validators.required));
3509
+ form.addControl('endAt', new FormControl(qMap.has('endAt') ? parseISO(qMap.get('endAt')) : null, Validators.required));
3510
+ }
3511
+ else {
3512
+ form.removeControl('startAt');
3513
+ form.removeControl('endAt');
3514
+ }
3515
+ }
3516
+ ;
3517
+ getLists() {
3518
+ return this.http.get(this.config.taxaListsApi).pipe(map$1(lists => {
3519
+ const alienSpecies = lists.find(f => f.id === AdbMapFilters.AlienSpecies);
3520
+ const redlist = lists.find(f => f.id === AdbMapFilters.Redlist);
3521
+ return {
3522
+ others: lists.filter(f => f.id !== AdbMapFilters.AlienSpecies && f.id !== AdbMapFilters.Redlist),
3523
+ redlist: redlist?.children,
3524
+ riskList: alienSpecies?.children?.find(c => c.id === AdbMapFilters.Risklist)?.children
3525
+ };
3526
+ }), catchError(err => {
3527
+ this.listsError = err;
3528
+ return of({
3529
+ others: [],
3530
+ redlist: [],
3531
+ riskList: []
3532
+ });
3533
+ }), shareReplay(1));
3534
+ }
3535
+ ngOnDestroy() {
3536
+ this.subscriptions.unsubscribe();
3537
+ }
3538
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapFilters, deps: [{ token: i0.ChangeDetectorRef }, { token: AdbMapConfigService }, { token: i1$2.HttpClient }, { token: i1.Router }, { token: i1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
3539
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AdbMapFilters, isStandalone: false, selector: "adb-map-filters", inputs: { inline: "inline" }, ngImport: i0, template: "@if(form){\r\n<form [formGroup]=\"form\" class=\"form mb-3\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <adb-filter-section titleResource=\"TAXON.SPECIES\" [expanded]=\"true\">\r\n @if(filters.showTaxon&&!hasTaxonInUrlParameter){\r\n <div class=\"mb-3\">\r\n <label for=\"species\">{{'TAXON.SPECIES_SINGULAR'|translate}}</label>\r\n <adb-taxon-picker formControlName=\"taxonId\" id=\"species\"></adb-taxon-picker>\r\n </div>\r\n }\r\n </adb-filter-section>\r\n @if(filters.showTime){\r\n <adb-filter-section [count]=\"periodCount\" titleResource=\"OBSERVATION.PERIOD\">\r\n <div class=\"mb-1\">\r\n <select class=\"form-select\" formControlName=\"period\" id=\"period\">\r\n <option value=\"1\">{{thisYear|date:'yyyy'}}</option>\r\n <option value=\"2\">{{lastYear|date:'yyyy'}}</option>\r\n <option value=\"3\">{{'OBSERVATION.ALL_YEAR'|translate}}</option>\r\n <option value=\"4\">{{'OBSERVATION.LAST_5_YEAR'|translate}}</option>\r\n <option value=\"5\">{{'OBSERVATION.LAST_25_YEAR'|translate}}</option>\r\n <option value=\"6\">{{'OBSERVATION.CUSTOMIZED'|translate}}</option>\r\n </select>\r\n </div>\r\n @if (form.value?.period==='6') {\r\n <div class=\"mb-2\">\r\n <label for=\"startAt\">{{'FROM' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"startAt\" formControlName=\"startAt\" [settings]=\"dateConfig\">\r\n </div>\r\n <div class=\"mb-2\">\r\n <label for=\"endAt\">{{'TO' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"endAt\" formControlName=\"endAt\" [settings]=\"dateConfig\">\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showArea){\r\n <adb-filter-section [count]=\"areaCount\" titleResource=\"GEOGRAPHY\" [lazy]=\"true\">\r\n <ng-template>\r\n <div role=\"tablist\" aria-label=\"{{'AREA'|translate}}\" class=\"d-flex gap-2 justify-content-end\">\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"!hasOwnArea\" (click)=\"hasOwnArea=false\" role=\"tab\" id=\"tab-select\" aria-selected=\"{{!hasOwnArea}}\" aria-controls=\"panel-select\">\r\n {{'CHOOSE'|translate}}\r\n </button>\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"hasOwnArea\"(click)=\"hasOwnArea=true\" role=\"tab\" id=\"tab-draw\" aria-selected=\"false\" aria-controls=\"panel-draw\">\r\n {{'OWN_AREA'|translate}}\r\n </button>\r\n </div>\r\n <div class=\"mb-2\">\r\n @if(hasOwnArea){\r\n <div class=\"pt-1\" role=\"tabpanel\" id=\"area-draw\" aria-labelledby=\"tab-draw\">\r\n <div>\r\n <adb-polygon-drawer formControlName=\"geo\"></adb-polygon-drawer>\r\n </div>\r\n </div>\r\n }@else{\r\n <div role=\"tabpanel\" id=\"area-select\" aria-labelledby=\"tab-select\">\r\n <div formArrayName=\"areas\">\r\n <div class=\"d-flex align-items-end mb-1\">\r\n <label>{{'AREAS'|translate}}</label>\r\n <button class=\"ms-auto text-dark btn btn-sm btn-secondary\" attr.aria-label=\"{{'OBSERVATION.ADD_AREA'|translate}}\" title=\"{{'OBSERVATION.ADD_AREA'|translate}}\" type=\"button\" (click)=\"addArea()\">\r\n <span class=\"fas fa-plus\"></span>\r\n </button>\r\n </div>\r\n @for (ctrl of areasArray.controls; track ctrl; let i = $index; let last = $last) {\r\n <div class=\"d-flex mb-2\">\r\n <adb-area-picker id=\"area-{{i}}\" [formControlName]=\"i\"></adb-area-picker>\r\n @if(areasArray.length>1){\r\n <button class=\"btn btn-secondary ms-1\" attr.aria-label=\"{{'DELETE'|translate}}\" title=\"{{'DELETE'|translate}}\" type=\"button\" (click)=\"removeArea(i)\">\r\n <span class=\"fas fa-trash\"></span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </adb-filter-section>\r\n }\r\n @if(form.get('taxonId')){\r\n @if(filters.showRedList){\r\n <adb-filter-section [count]=\"redListCount\" titleResource=\"REDLIST.REDLIST_2025\">\r\n @if (form.get('rlc')) {\r\n <div formArrayName=\"rlc\">\r\n @for (item of rlcControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'rlc-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'rlc-' + item.value.id\" class=\"form-check-label\">{{ 'REDLIST_CATEGORIES_LIST_ID.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showRiskList){\r\n <adb-filter-section [count]=\"riskListCount\" titleResource=\"ALIEN.ALIEN_SPECIES_SHORT\">\r\n @if(form.get('rc')){\r\n <div formArrayName=\"rc\">\r\n @for ( item of rcControls; track item.id; let i = $index ) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'rc-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'rc-' + item.value.id\" class=\"form-check-label\">{{ 'RISKLIST_CATEGORIES.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showTaxaLists){\r\n <adb-filter-section [count]=\"taxonListCount\" titleResource=\"LISTS.NATURE_CONSERVATION_LISTS\">\r\n <div class=\"mb-3\">\r\n <app-treeview formControlName=\"tl\" [nodes]=\"taxaLists\"></app-treeview>\r\n </div>\r\n {{'LISTS.READ_MORE'|translate}}\r\n <a [href]=\"artfakta\">{{'LISTS.LIST_CONTENT'|translate}}</a>\r\n </adb-filter-section>\r\n }\r\n @if(filters.showDatasets){\r\n <adb-filter-section [count]=\"dataSetCount\" titleResource=\"DATASET.DATASETS\">\r\n @if (form.get('ds')) {\r\n <div formArrayName=\"ds\">\r\n @for (item of dsControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'ds-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'ds-' + item.value.id\" class=\"form-check-label\">{{ 'PROVIDERS.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n }\r\n </div>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n @if (inline) {\r\n <a class=\"btn btn-secondary\" [routerLink]=\"[]\">\r\n {{'CANCEL'|translate}}\r\n </a>\r\n }\r\n <button type=\"submit\" class=\"btn btn-primary\" [disabled]=\"form.invalid||form.pristine\">{{'FILTER'|translate}}</button>\r\n </div>\r\n</form>\r\n}\r\n", dependencies: [{ kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i4.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i4.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: AdbDatePickerDirective, selector: "input[adbDatepicker]", inputs: ["format", "toLeft", "settings"], outputs: ["adbBlur"] }, { kind: "component", type: FilterSectionComponent, selector: "adb-filter-section", inputs: ["titleResource", "helpResource", "count", "expanded", "lazy"] }, { kind: "component", type: AdbAreaPickerComponent, selector: "adb-area-picker", inputs: ["placeholder", "useObject", "prefill"] }, { kind: "component", type: AdbTaxonPickerComponent, selector: "adb-taxon-picker", inputs: ["placeholder", "useObject", "prefill"] }, { kind: "component", type: PolygonDrawerInput, selector: "adb-polygon-drawer" }, { kind: "component", type: TreeviewComponent, selector: "app-treeview", inputs: ["nodes"] }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] }); }
3540
+ }
3541
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapFilters, decorators: [{
3542
+ type: Component,
3543
+ args: [{ selector: 'adb-map-filters', standalone: false, template: "@if(form){\r\n<form [formGroup]=\"form\" class=\"form mb-3\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <adb-filter-section titleResource=\"TAXON.SPECIES\" [expanded]=\"true\">\r\n @if(filters.showTaxon&&!hasTaxonInUrlParameter){\r\n <div class=\"mb-3\">\r\n <label for=\"species\">{{'TAXON.SPECIES_SINGULAR'|translate}}</label>\r\n <adb-taxon-picker formControlName=\"taxonId\" id=\"species\"></adb-taxon-picker>\r\n </div>\r\n }\r\n </adb-filter-section>\r\n @if(filters.showTime){\r\n <adb-filter-section [count]=\"periodCount\" titleResource=\"OBSERVATION.PERIOD\">\r\n <div class=\"mb-1\">\r\n <select class=\"form-select\" formControlName=\"period\" id=\"period\">\r\n <option value=\"1\">{{thisYear|date:'yyyy'}}</option>\r\n <option value=\"2\">{{lastYear|date:'yyyy'}}</option>\r\n <option value=\"3\">{{'OBSERVATION.ALL_YEAR'|translate}}</option>\r\n <option value=\"4\">{{'OBSERVATION.LAST_5_YEAR'|translate}}</option>\r\n <option value=\"5\">{{'OBSERVATION.LAST_25_YEAR'|translate}}</option>\r\n <option value=\"6\">{{'OBSERVATION.CUSTOMIZED'|translate}}</option>\r\n </select>\r\n </div>\r\n @if (form.value?.period==='6') {\r\n <div class=\"mb-2\">\r\n <label for=\"startAt\">{{'FROM' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"startAt\" formControlName=\"startAt\" [settings]=\"dateConfig\">\r\n </div>\r\n <div class=\"mb-2\">\r\n <label for=\"endAt\">{{'TO' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"endAt\" formControlName=\"endAt\" [settings]=\"dateConfig\">\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showArea){\r\n <adb-filter-section [count]=\"areaCount\" titleResource=\"GEOGRAPHY\" [lazy]=\"true\">\r\n <ng-template>\r\n <div role=\"tablist\" aria-label=\"{{'AREA'|translate}}\" class=\"d-flex gap-2 justify-content-end\">\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"!hasOwnArea\" (click)=\"hasOwnArea=false\" role=\"tab\" id=\"tab-select\" aria-selected=\"{{!hasOwnArea}}\" aria-controls=\"panel-select\">\r\n {{'CHOOSE'|translate}}\r\n </button>\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"hasOwnArea\"(click)=\"hasOwnArea=true\" role=\"tab\" id=\"tab-draw\" aria-selected=\"false\" aria-controls=\"panel-draw\">\r\n {{'OWN_AREA'|translate}}\r\n </button>\r\n </div>\r\n <div class=\"mb-2\">\r\n @if(hasOwnArea){\r\n <div class=\"pt-1\" role=\"tabpanel\" id=\"area-draw\" aria-labelledby=\"tab-draw\">\r\n <div>\r\n <adb-polygon-drawer formControlName=\"geo\"></adb-polygon-drawer>\r\n </div>\r\n </div>\r\n }@else{\r\n <div role=\"tabpanel\" id=\"area-select\" aria-labelledby=\"tab-select\">\r\n <div formArrayName=\"areas\">\r\n <div class=\"d-flex align-items-end mb-1\">\r\n <label>{{'AREAS'|translate}}</label>\r\n <button class=\"ms-auto text-dark btn btn-sm btn-secondary\" attr.aria-label=\"{{'OBSERVATION.ADD_AREA'|translate}}\" title=\"{{'OBSERVATION.ADD_AREA'|translate}}\" type=\"button\" (click)=\"addArea()\">\r\n <span class=\"fas fa-plus\"></span>\r\n </button>\r\n </div>\r\n @for (ctrl of areasArray.controls; track ctrl; let i = $index; let last = $last) {\r\n <div class=\"d-flex mb-2\">\r\n <adb-area-picker id=\"area-{{i}}\" [formControlName]=\"i\"></adb-area-picker>\r\n @if(areasArray.length>1){\r\n <button class=\"btn btn-secondary ms-1\" attr.aria-label=\"{{'DELETE'|translate}}\" title=\"{{'DELETE'|translate}}\" type=\"button\" (click)=\"removeArea(i)\">\r\n <span class=\"fas fa-trash\"></span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </adb-filter-section>\r\n }\r\n @if(form.get('taxonId')){\r\n @if(filters.showRedList){\r\n <adb-filter-section [count]=\"redListCount\" titleResource=\"REDLIST.REDLIST_2025\">\r\n @if (form.get('rlc')) {\r\n <div formArrayName=\"rlc\">\r\n @for (item of rlcControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'rlc-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'rlc-' + item.value.id\" class=\"form-check-label\">{{ 'REDLIST_CATEGORIES_LIST_ID.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showRiskList){\r\n <adb-filter-section [count]=\"riskListCount\" titleResource=\"ALIEN.ALIEN_SPECIES_SHORT\">\r\n @if(form.get('rc')){\r\n <div formArrayName=\"rc\">\r\n @for ( item of rcControls; track item.id; let i = $index ) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'rc-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'rc-' + item.value.id\" class=\"form-check-label\">{{ 'RISKLIST_CATEGORIES.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showTaxaLists){\r\n <adb-filter-section [count]=\"taxonListCount\" titleResource=\"LISTS.NATURE_CONSERVATION_LISTS\">\r\n <div class=\"mb-3\">\r\n <app-treeview formControlName=\"tl\" [nodes]=\"taxaLists\"></app-treeview>\r\n </div>\r\n {{'LISTS.READ_MORE'|translate}}\r\n <a [href]=\"artfakta\">{{'LISTS.LIST_CONTENT'|translate}}</a>\r\n </adb-filter-section>\r\n }\r\n @if(filters.showDatasets){\r\n <adb-filter-section [count]=\"dataSetCount\" titleResource=\"DATASET.DATASETS\">\r\n @if (form.get('ds')) {\r\n <div formArrayName=\"ds\">\r\n @for (item of dsControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'ds-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'ds-' + item.value.id\" class=\"form-check-label\">{{ 'PROVIDERS.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n }\r\n </div>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n @if (inline) {\r\n <a class=\"btn btn-secondary\" [routerLink]=\"[]\">\r\n {{'CANCEL'|translate}}\r\n </a>\r\n }\r\n <button type=\"submit\" class=\"btn btn-primary\" [disabled]=\"form.invalid||form.pristine\">{{'FILTER'|translate}}</button>\r\n </div>\r\n</form>\r\n}\r\n" }]
3544
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: AdbMapConfigService }, { type: i1$2.HttpClient }, { type: i1.Router }, { type: i1.ActivatedRoute }], propDecorators: { inline: [{
3545
+ type: Input
3546
+ }] } });
3547
+
3548
+ class AdbMapModule {
3549
+ static forRoot(config) {
3550
+ return {
3551
+ ngModule: AdbMapModule,
3552
+ providers: [
3553
+ {
3554
+ provide: ADB_MAP_CONFIG,
3555
+ useValue: config
3556
+ }
3557
+ ]
3558
+ };
3559
+ }
3560
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3561
+ /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: AdbMapModule, declarations: [AdbObsMapComponent,
3562
+ PolygonDrawerInput,
3563
+ AdbMapFilters,
3564
+ TreeviewComponent], imports: [CommonModule,
3565
+ FormsModule,
3566
+ RouterModule,
3567
+ ReactiveFormsModule,
3568
+ AdbDatePickerModule, i1$1.TranslateModule, AdbPipesModule,
3569
+ AdbFilterSectionModule,
3570
+ AdbPickerModule], exports: [AdbObsMapComponent,
3571
+ PolygonDrawerInput,
3572
+ AdbMapFilters] }); }
3573
+ /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapModule, providers: [
3574
+ AdbMapConfigService
3575
+ ], imports: [CommonModule,
3576
+ FormsModule,
3577
+ RouterModule,
3578
+ ReactiveFormsModule,
3579
+ AdbDatePickerModule,
3580
+ TranslateModule.forChild(),
3581
+ AdbPipesModule,
3582
+ AdbFilterSectionModule,
3583
+ AdbPickerModule] }); }
3584
+ }
3585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AdbMapModule, decorators: [{
3586
+ type: NgModule,
3587
+ args: [{
3588
+ imports: [
3589
+ CommonModule,
3590
+ FormsModule,
3591
+ RouterModule,
3592
+ ReactiveFormsModule,
3593
+ AdbDatePickerModule,
3594
+ TranslateModule.forChild(),
3595
+ AdbPipesModule,
3596
+ AdbFilterSectionModule,
3597
+ AdbPickerModule
3598
+ ],
3599
+ declarations: [
3600
+ AdbObsMapComponent,
3601
+ PolygonDrawerInput,
3602
+ AdbMapFilters,
3603
+ TreeviewComponent,
3604
+ // Stats,
3605
+ // AdbGeojsonPolygonDirective
3606
+ ],
3607
+ exports: [
3608
+ AdbObsMapComponent,
3609
+ PolygonDrawerInput,
3610
+ AdbMapFilters,
3611
+ // Stats,
3612
+ // AdbGeojsonPolygonDirective
3613
+ ],
3614
+ providers: [
3615
+ AdbMapConfigService
3616
+ ]
3617
+ }]
3618
+ }] });
3619
+
2754
3620
  /*
2755
3621
  * Public API Surface of artdata-shared
2756
3622
  */
@@ -2759,5 +3625,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
2759
3625
  * Generated bundle index. Do not edit.
2760
3626
  */
2761
3627
 
2762
- export { ADB_PICKER_CONFIG, ADB_USER_SERVICE_CONFIG, AdbAreaPickerComponent, AdbButtonsModule, AdbConfirmModal, AdbDatePickerComponent, AdbDatePickerDirective, AdbDatePickerModule, AdbDirectivesModule, AdbDropdown2Directive, AdbDropdownDirective, AdbDropdownModule, AdbFilterSectionModule, AdbHelpButtonComponent, AdbModalModule, AdbModalService, AdbPagersModule, AdbPickerConfigService, AdbPickerModule, AdbPipesModule, AdbRichEditorComponent, AdbRichEditorModule, AdbTaxonPickerComponent, AdbToast, AdbToastModule, AdbToastService, AdbUserInterceptor, AdbUserModule, AdbUserService, ArtportalenFooterComponent, ArtportalenNavComponent, ArtportalenNavModule, AuthCallbackComponent, ClickOutsideDirective, DEFAULT_ADB_USER_SERVICE_CONFIG, EmptyValuePipe, EnvironmentService, FileUploadDirective, FilterSectionComponent, FocusDirective, GenericPickerComponent, HighlightHtmlPipe, HighlightPipe, ImageLoaderDirective, InfiniteScrollComponent, LocaleDatePipe, NumberSpacingPipe, PagerComponent, PagerInlineComponent, RedListBadgeClassDirective, RichTextComponent, RiskClassDirective, RouterLinkActiveFragmentDirective, ToastType, UserModuleConstants };
3628
+ export { ADB_MAP_CONFIG, ADB_PICKER_CONFIG, ADB_USER_SERVICE_CONFIG, AdbAreaPickerComponent, AdbBaseMap, AdbButtonsModule, AdbConfirmModal, AdbDatePickerComponent, AdbDatePickerDirective, AdbDatePickerModule, AdbDirectivesModule, AdbDropdown2Directive, AdbDropdownDirective, AdbDropdownModule, AdbFilterSectionModule, AdbHelpButtonComponent, AdbMapConfigService, AdbMapFilterType, AdbMapFilters, AdbMapModule, AdbModalModule, AdbModalService, AdbObsMapComponent, AdbPagersModule, AdbPickerConfigService, AdbPickerModule, AdbPipesModule, AdbRichEditorComponent, AdbRichEditorModule, AdbTaxonPickerComponent, AdbToast, AdbToastModule, AdbToastService, AdbUserInterceptor, AdbUserModule, AdbUserService, ArtportalenFooterComponent, ArtportalenNavComponent, ArtportalenNavModule, AuthCallbackComponent, ClickOutsideDirective, DEFAULT_ADB_USER_SERVICE_CONFIG, EmptyValuePipe, EnvironmentService, FileUploadDirective, FilterSectionComponent, FocusDirective, GenericPickerComponent, HighlightHtmlPipe, HighlightPipe, ImageLoaderDirective, InfiniteScrollComponent, LocaleDatePipe, NumberSpacingPipe, PagerComponent, PagerInlineComponent, PolygonDrawerInput, RedListBadgeClassDirective, RichTextComponent, RiskClassDirective, RouterLinkActiveFragmentDirective, ToastType, UserModuleConstants, VisibleFilters };
2763
3629
  //# sourceMappingURL=adb-shared.mjs.map