forked from MapComplete/MapComplete
		
	Add filters
This commit is contained in:
		
							parent
							
								
									965faca0e5
								
							
						
					
					
						commit
						42a6b37ca6
					
				
					 13 changed files with 287 additions and 219 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -18,3 +18,4 @@ missing_translations.txt
 | 
				
			||||||
Svg.ts
 | 
					Svg.ts
 | 
				
			||||||
data/
 | 
					data/
 | 
				
			||||||
Folder.DotSettings.user
 | 
					Folder.DotSettings.user
 | 
				
			||||||
 | 
					index_*.ts
 | 
				
			||||||
| 
						 | 
					@ -223,6 +223,9 @@ export default class MapState extends UserRelatedState {
 | 
				
			||||||
    private initGpsLocation() {
 | 
					    private initGpsLocation() {
 | 
				
			||||||
        // Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
 | 
					        // Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
 | 
				
			||||||
        let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location")[0]
 | 
					        let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location")[0]
 | 
				
			||||||
 | 
					        if(gpsLayerDef === undefined){
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0));
 | 
					        this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +238,7 @@ export default class MapState extends UserRelatedState {
 | 
				
			||||||
        features.ping()
 | 
					        features.ping()
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        let i = 0
 | 
					        let i = 0
 | 
				
			||||||
        this.currentUserLocation.features.addCallbackAndRunD(([location]) => {
 | 
					        this.currentUserLocation?.features?.addCallbackAndRunD(([location]) => {
 | 
				
			||||||
            if (location === undefined) {
 | 
					            if (location === undefined) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -266,7 +269,9 @@ export default class MapState extends UserRelatedState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0]
 | 
					        let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0]
 | 
				
			||||||
 | 
					        if(gpsLayerDef !== undefined){
 | 
				
			||||||
            this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features);
 | 
					            this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const asLine = features.map(allPoints => {
 | 
					        const asLine = features.map(allPoints => {
 | 
				
			||||||
| 
						 | 
					@ -294,8 +299,10 @@ export default class MapState extends UserRelatedState {
 | 
				
			||||||
            }]
 | 
					            }]
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0]
 | 
					        let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0]
 | 
				
			||||||
 | 
					        if(gpsLineLayerDef !== undefined){
 | 
				
			||||||
            this.historicalUserLocationsTrack = new SimpleFeatureSource(gpsLineLayerDef, Tiles.tile_index(0, 0, 0), asLine);
 | 
					            this.historicalUserLocationsTrack = new SimpleFeatureSource(gpsLineLayerDef, Tiles.tile_index(0, 0, 0), asLine);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private initHomeLocation() {
 | 
					    private initHomeLocation() {
 | 
				
			||||||
        const empty = []
 | 
					        const empty = []
 | 
				
			||||||
| 
						 | 
					@ -331,7 +338,9 @@ export default class MapState extends UserRelatedState {
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const flayer = this.filteredLayers.data.filter(l => l.layerDef.id === "home_location")[0]
 | 
					        const flayer = this.filteredLayers.data.filter(l => l.layerDef.id === "home_location")[0]
 | 
				
			||||||
 | 
					        if (flayer !== undefined) {
 | 
				
			||||||
            this.homeLocation = new SimpleFeatureSource(flayer, Tiles.tile_index(0, 0, 0), feature)
 | 
					            this.homeLocation = new SimpleFeatureSource(flayer, Tiles.tile_index(0, 0, 0), feature)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,9 +56,6 @@ export class TagUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /***
 | 
					    /***
 | 
				
			||||||
     * Creates a hash {key --> [values : string | Regex ]}, with all the values present in the tagsfilter
 | 
					     * Creates a hash {key --> [values : string | Regex ]}, with all the values present in the tagsfilter
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param tagsFilters
 | 
					 | 
				
			||||||
     * @constructor
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    static SplitKeys(tagsFilters: TagsFilter[], allowRegex = false) {
 | 
					    static SplitKeys(tagsFilters: TagsFilter[], allowRegex = false) {
 | 
				
			||||||
        const keyValues = {} // Map string -> string[]
 | 
					        const keyValues = {} // Map string -> string[]
 | 
				
			||||||
| 
						 | 
					@ -189,16 +186,26 @@ export class TagUtils {
 | 
				
			||||||
                if (tag.indexOf(operator) >= 0) {
 | 
					                if (tag.indexOf(operator) >= 0) {
 | 
				
			||||||
                    const split = Utils.SplitFirst(tag, operator);
 | 
					                    const split = Utils.SplitFirst(tag, operator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    const val = Number(split[1].trim())
 | 
					                    let val = Number(split[1].trim())
 | 
				
			||||||
                    if (isNaN(val)) {
 | 
					                    if (isNaN(val)) {
 | 
				
			||||||
                        throw `Error: not a valid value for a comparison: ${split[1]}, make sure it is a number and nothing more (at ${context})`
 | 
					                        val = new Date(split[1].trim()).getTime()
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    const f = (value: string | undefined) => {
 | 
					                    const f = (value: string | undefined) => {
 | 
				
			||||||
                        const b = Number(value?.replace(/[^\d.]/g, ''))
 | 
					                        console.log("Comparing ",value,operator,val)
 | 
				
			||||||
                        if (isNaN(b)) {
 | 
					                        if(value === undefined){
 | 
				
			||||||
                            return false;
 | 
					                            return false;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        let b = Number(value?.trim() )
 | 
				
			||||||
 | 
					                        if (isNaN(b)) {
 | 
				
			||||||
 | 
					                            if(value.endsWith(" UTC")) {
 | 
				
			||||||
 | 
					                                value = value.replace(" UTC", "+00")
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            b = new Date(value).getTime()
 | 
				
			||||||
 | 
					                            if(isNaN(b)){
 | 
				
			||||||
 | 
					                                return false
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        return comparator(b, val)
 | 
					                        return comparator(b, val)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    return new ComparingTag(split[0], f, operator + val)
 | 
					                    return new ComparingTag(split[0], f, operator + val)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,12 +42,11 @@ export default class FilterConfig {
 | 
				
			||||||
                `${ctx}.question`
 | 
					                `${ctx}.question`
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            let osmTags = undefined;
 | 
					            let osmTags = undefined;
 | 
				
			||||||
            if (option.osmTags !== undefined) {
 | 
					            if ((option.fields?.length ?? 0) == 0 && option.osmTags !== undefined) {
 | 
				
			||||||
                osmTags = TagUtils.Tag(
 | 
					                osmTags = TagUtils.Tag(
 | 
				
			||||||
                    option.osmTags,
 | 
					                    option.osmTags,
 | 
				
			||||||
                    `${ctx}.osmTags`
 | 
					                    `${ctx}.osmTags`
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (question === undefined) {
 | 
					            if (question === undefined) {
 | 
				
			||||||
                throw `Invalid filter: no question given at ${ctx}`
 | 
					                throw `Invalid filter: no question given at ${ctx}`
 | 
				
			||||||
| 
						 | 
					@ -67,10 +66,6 @@ export default class FilterConfig {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (fields.length > 0) {
 | 
					 | 
				
			||||||
                // erase the tags, they aren't needed
 | 
					 | 
				
			||||||
                osmTags = undefined
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return {question: question, osmTags: osmTags, fields, originalTagsSpec: option.osmTags};
 | 
					            return {question: question, osmTags: osmTags, fields, originalTagsSpec: option.osmTags};
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
| 
						 | 
					@ -92,6 +87,7 @@ export default class FilterConfig {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return "" + state.state
 | 
					            return "" + state.state
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const defaultValue = this.options.length > 1 ? "0" : ""
 | 
					        const defaultValue = this.options.length > 1 ? "0" : ""
 | 
				
			||||||
        const qp = QueryParameters.GetQueryParameter("filter-" + this.id, defaultValue, "State of filter " + this.id)
 | 
					        const qp = QueryParameters.GetQueryParameter("filter-" + this.id, defaultValue, "State of filter " + this.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,8 +131,9 @@ export default class FilterConfig {
 | 
				
			||||||
                            return v
 | 
					                            return v
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					                    const parsed = TagUtils.Tag(rewrittenTags)
 | 
				
			||||||
                    return <FilterState>{
 | 
					                    return <FilterState>{
 | 
				
			||||||
                        currentFilter: TagUtils.Tag(rewrittenTags),
 | 
					                        currentFilter: parsed,
 | 
				
			||||||
                        state: str
 | 
					                        state: str
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } catch (e) {
 | 
					                } catch (e) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,6 @@ import Title from "../../UI/Base/Title";
 | 
				
			||||||
import List from "../../UI/Base/List";
 | 
					import List from "../../UI/Base/List";
 | 
				
			||||||
import Link from "../../UI/Base/Link";
 | 
					import Link from "../../UI/Base/Link";
 | 
				
			||||||
import {Utils} from "../../Utils";
 | 
					import {Utils} from "../../Utils";
 | 
				
			||||||
import {tag} from "@turf/turf";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class LayerConfig extends WithContextLoader {
 | 
					export default class LayerConfig extends WithContextLoader {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ export default class SimpleDatePicker extends InputElement<string> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    IsValid(t: string): boolean {
 | 
					    IsValid(t: string): boolean {
 | 
				
			||||||
        return false;
 | 
					        return !isNaN(new Date(t).getTime());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected InnerConstructElement(): HTMLElement {
 | 
					    protected InnerConstructElement(): HTMLElement {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,8 +206,7 @@ export default class ValidatedTextField {
 | 
				
			||||||
            "date",
 | 
					            "date",
 | 
				
			||||||
            "A date",
 | 
					            "A date",
 | 
				
			||||||
            (str) => {
 | 
					            (str) => {
 | 
				
			||||||
                const time = Date.parse(str);
 | 
					                return !isNaN(new Date(str).getTime());
 | 
				
			||||||
                return !isNaN(time);
 | 
					 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            (str) => {
 | 
					            (str) => {
 | 
				
			||||||
                const d = new Date(str);
 | 
					                const d = new Date(str);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										206
									
								
								assets/layers/note/note.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								assets/layers/note/note.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,206 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "id": "note",
 | 
				
			||||||
 | 
					  "name": {
 | 
				
			||||||
 | 
					    "en": "OpenStreetMap notes"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "description": "This layer shows notes on OpenStreetMap.",
 | 
				
			||||||
 | 
					  "source": {
 | 
				
			||||||
 | 
					    "osmTags": "id~*",
 | 
				
			||||||
 | 
					    "geoJson": "https://api.openstreetmap.org/api/0.6/notes.json?closed=7&bbox={x_min},{y_min},{x_max},{y_max}",
 | 
				
			||||||
 | 
					    "geoJsonZoomLevel": 12,
 | 
				
			||||||
 | 
					    "maxCacheAge": 0
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "minzoom": 10,
 | 
				
			||||||
 | 
					  "title": {
 | 
				
			||||||
 | 
					    "render": {
 | 
				
			||||||
 | 
					      "en": "Note"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "mappings": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "if": "closed_at~*",
 | 
				
			||||||
 | 
					        "then": {
 | 
				
			||||||
 | 
					          "en": "Closed note"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "calculatedTags": [
 | 
				
			||||||
 | 
					    "_first_comment:=feat.get('comments')[0].text.toLowerCase()",
 | 
				
			||||||
 | 
					    "_opened_by_anonymous_user:=feat.get('comments')[0].user === undefined",
 | 
				
			||||||
 | 
					    "_first_user:=feat.get('comments')[0].user",
 | 
				
			||||||
 | 
					    "_first_user_lc:=feat.get('comments')[0].user?.toLowerCase()",
 | 
				
			||||||
 | 
					    "_first_user_id:=feat.get('comments')[0].uid"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "titleIcons": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "render": "<a href='https://openstreetmap.org/note/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'></a>"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "tagRenderings": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "conversation",
 | 
				
			||||||
 | 
					      "render": "{visualize_note_comments()}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "add_image",
 | 
				
			||||||
 | 
					      "render": "{add_image_to_note()}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "comment",
 | 
				
			||||||
 | 
					      "render": "{add_note_comment()}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "report-contributor",
 | 
				
			||||||
 | 
					      "render": {
 | 
				
			||||||
 | 
					        "en": "<a href='https://www.openstreetmap.org/reports/new?reportable_id={_first_user_id}&reportable_type=User' target='_blank' class='subtle'>Report {_first_user} as spam</a>"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "condition": "_opened_by_anonymous_user=false"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "report-note",
 | 
				
			||||||
 | 
					      "render": {
 | 
				
			||||||
 | 
					        "en": "<a href='https://www.openstreetmap.org/reports/new?reportable_id={id}&reportable_type=Note' target='_blank'>Report this note as spam or inappropriate</a>"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "mapRendering": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "location": [
 | 
				
			||||||
 | 
					        "point",
 | 
				
			||||||
 | 
					        "centroid"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "icon": {
 | 
				
			||||||
 | 
					        "render": "./assets/svg/note.svg",
 | 
				
			||||||
 | 
					        "mappings": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "if": "closed_at~*",
 | 
				
			||||||
 | 
					            "then": "./assets/svg/resolved.svg"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "iconSize": "40,40,bottom"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "filter": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "search",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "_first_comment~.*{search}.*",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Should mention {search} in the first comment"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "not",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "_first_comment!~.*{search}.*",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Should <b>not</b> mention {search} in the first comment"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "opened_by",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "_first_user_lc~.*{search}.*",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Opened by {search}"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "not_opened_by",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "_first_user_lc!~.*{search}.*",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "<b>Not</b> opened by {search}"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "opened_before",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "date_created<{search}",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search",
 | 
				
			||||||
 | 
					              "type": "date"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Opened before {search}"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "opened_after",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "date_created>{search}",
 | 
				
			||||||
 | 
					          "fields": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "name": "search",
 | 
				
			||||||
 | 
					              "type": "date"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Opened after {search}"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "anonymous",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "_opened_by_anonymous_user=true",
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Opened by anonymous user"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "id": "is_open",
 | 
				
			||||||
 | 
					      "options": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "osmTags": "closed_at=",
 | 
				
			||||||
 | 
					          "question": {
 | 
				
			||||||
 | 
					            "en": "Only show open notes"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,166 +14,6 @@
 | 
				
			||||||
  "clustering": false,
 | 
					  "clustering": false,
 | 
				
			||||||
  "enableDownload": true,
 | 
					  "enableDownload": true,
 | 
				
			||||||
  "layers": [
 | 
					  "layers": [
 | 
				
			||||||
    {
 | 
					    "note"
 | 
				
			||||||
      "id": "notes",
 | 
					 | 
				
			||||||
      "name": {
 | 
					 | 
				
			||||||
        "en": "OpenStreetMap notes"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "description": "This layer shows notes on OpenStreetMap.",
 | 
					 | 
				
			||||||
      "source": {
 | 
					 | 
				
			||||||
        "osmTags": "id~*",
 | 
					 | 
				
			||||||
        "geoJson": "https://api.openstreetmap.org/api/0.6/notes.json?closed=7&bbox={x_min},{y_min},{x_max},{y_max}",
 | 
					 | 
				
			||||||
        "geoJsonZoomLevel": 12,
 | 
					 | 
				
			||||||
        "maxCacheAge": 0
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "minzoom": 8,
 | 
					 | 
				
			||||||
      "title": {
 | 
					 | 
				
			||||||
        "render": {
 | 
					 | 
				
			||||||
          "en": "Note"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "mappings": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "if": "closed_at~*",
 | 
					 | 
				
			||||||
            "then": {
 | 
					 | 
				
			||||||
              "en": "Closed note"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "calculatedTags": [
 | 
					 | 
				
			||||||
        "_first_comment:=feat.get('comments')[0].text.toLowerCase()",
 | 
					 | 
				
			||||||
        "_opened_by_anonymous_user:=feat.get('comments')[0].user === undefined",
 | 
					 | 
				
			||||||
        "_first_user:=feat.get('comments')[0].user",
 | 
					 | 
				
			||||||
        "_first_user_lc:=feat.get('comments')[0].user?.toLowerCase()",
 | 
					 | 
				
			||||||
        "_first_user_id:=feat.get('comments')[0].uid"
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      "titleIcons": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "render": "<a href='https://openstreetmap.org/note/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'></a>"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      "tagRenderings": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "conversation",
 | 
					 | 
				
			||||||
          "render": "{visualize_note_comments()}"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "add_image",
 | 
					 | 
				
			||||||
          "render": "{add_image_to_note()}"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "comment",
 | 
					 | 
				
			||||||
          "render": "{add_note_comment()}"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "report-contributor",
 | 
					 | 
				
			||||||
          "render": {
 | 
					 | 
				
			||||||
            "en": "<a href='https://www.openstreetmap.org/reports/new?reportable_id={_first_user_id}&reportable_type=User' target='_blank' class='subtle'>Report {_first_user} as spam</a>"
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "condition": "_opened_by_anonymous_user=false"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "report-note",
 | 
					 | 
				
			||||||
          "render": {
 | 
					 | 
				
			||||||
            "en": "<a href='https://www.openstreetmap.org/reports/new?reportable_id={id}&reportable_type=Note' target='_blank'>Report this note as spam or inappropriate</a>"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      "mapRendering": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "location": [
 | 
					 | 
				
			||||||
            "point",
 | 
					 | 
				
			||||||
            "centroid"
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
          "icon": {
 | 
					 | 
				
			||||||
            "render": "./assets/svg/note.svg",
 | 
					 | 
				
			||||||
            "mappings": [
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                "if": "closed_at~*",
 | 
					 | 
				
			||||||
                "then": "./assets/svg/resolved.svg"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "iconSize": "40,40,bottom"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      "filter": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "search",
 | 
					 | 
				
			||||||
          "options": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "osmTags": "_first_comment~.*{search}.*",
 | 
					 | 
				
			||||||
              "fields": [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  "name": "search"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              ],
 | 
					 | 
				
			||||||
              "question": {
 | 
					 | 
				
			||||||
                "en": "Should mention {search} in the first comment"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "not",
 | 
					 | 
				
			||||||
          "options": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "osmTags": "_first_comment!~.*{search}.*",
 | 
					 | 
				
			||||||
              "fields": [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  "name": "search"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              ],
 | 
					 | 
				
			||||||
              "question": {
 | 
					 | 
				
			||||||
                "en": "Should <b>not</b> mention {search} in the first comment"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "opened_by",
 | 
					 | 
				
			||||||
          "options": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "osmTags": "_first_user_lc~.*{search}.*",
 | 
					 | 
				
			||||||
              "fields": [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  "name": "search"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              ],
 | 
					 | 
				
			||||||
              "question": {
 | 
					 | 
				
			||||||
                "en": "Opened by {search}"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "not_opened_by",
 | 
					 | 
				
			||||||
          "options": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "osmTags": "_first_user_lc!~.*{search}.*",
 | 
					 | 
				
			||||||
              "fields": [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  "name": "search"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              ],
 | 
					 | 
				
			||||||
              "question": {
 | 
					 | 
				
			||||||
                "en": "<b>Not</b> opened by {search}"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "id": "anonymous",
 | 
					 | 
				
			||||||
          "options": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "osmTags": "_opened_by_anonymous_user=true",
 | 
					 | 
				
			||||||
              "question": {
 | 
					 | 
				
			||||||
                "en": "Opened by anonymous user"
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,12 +8,16 @@ rm -rf .cache
 | 
				
			||||||
mkdir dist 2> /dev/null
 | 
					mkdir dist 2> /dev/null
 | 
				
			||||||
mkdir dist/assets 2> /dev/null
 | 
					mkdir dist/assets 2> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
npm run generate
 | 
					# This script ends every line with '&&' to chain everything. A failure will thus stop the build
 | 
				
			||||||
npm run test
 | 
					 | 
				
			||||||
npm run generate:editor-layer-index 
 | 
					npm run generate:editor-layer-index 
 | 
				
			||||||
npm run generate:translations
 | 
					npm run generate &&
 | 
				
			||||||
 | 
					npm run test &&
 | 
				
			||||||
npm run generate:layouts
 | 
					npm run generate:layouts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ $? -ne 0]; then;
 | 
				
			||||||
 | 
					    echo "ERROR"
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy the layer files, as these might contain assets (e.g. svgs)
 | 
					# Copy the layer files, as these might contain assets (e.g. svgs)
 | 
				
			||||||
cp -r assets/layers/ dist/assets/layers/
 | 
					cp -r assets/layers/ dist/assets/layers/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,8 @@
 | 
				
			||||||
import T from "./TestHelper";
 | 
					import T from "./TestHelper";
 | 
				
			||||||
import {Utils} from "../Utils";
 | 
					import {Utils} from "../Utils";
 | 
				
			||||||
import ReplaceGeometryAction from "../Logic/Osm/Actions/ReplaceGeometryAction";
 | 
					import ReplaceGeometryAction from "../Logic/Osm/Actions/ReplaceGeometryAction";
 | 
				
			||||||
import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline";
 | 
					 | 
				
			||||||
import {Tag} from "../Logic/Tags/Tag";
 | 
					 | 
				
			||||||
import MapState from "../Logic/State/MapState";
 | 
					 | 
				
			||||||
import * as grb from "../assets/themes/grb_import/grb.json"
 | 
					import * as grb from "../assets/themes/grb_import/grb.json"
 | 
				
			||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
 | 
					import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
 | 
				
			||||||
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
 | 
					 | 
				
			||||||
import State from "../State";
 | 
					import State from "../State";
 | 
				
			||||||
import {BBox} from "../Logic/BBox";
 | 
					import {BBox} from "../Logic/BBox";
 | 
				
			||||||
import Minimap from "../UI/Base/Minimap";
 | 
					import Minimap from "../UI/Base/Minimap";
 | 
				
			||||||
| 
						 | 
					@ -33,7 +29,11 @@ export default class ReplaceGeometrySpec extends T {
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "layers": [
 | 
					        "layers": [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                "builtin": "type_node",
 | 
					                "id": "type_node",
 | 
				
			||||||
 | 
					                source:{
 | 
				
			||||||
 | 
					                    osmTags:"type=node"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                mapRendering: null,
 | 
				
			||||||
                "override": {
 | 
					                "override": {
 | 
				
			||||||
                    "calculatedTags": [
 | 
					                    "calculatedTags": [
 | 
				
			||||||
                        "_is_part_of_building=feat.get('parent_ways')?.some(p => p.building !== undefined && p.building !== '') ?? false",
 | 
					                        "_is_part_of_building=feat.get('parent_ways')?.some(p => p.building !== undefined && p.building !== '') ?? false",
 | 
				
			||||||
| 
						 | 
					@ -266,7 +266,6 @@ export default class ReplaceGeometrySpec extends T {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
             "address",
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                "id": "grb",
 | 
					                "id": "grb",
 | 
				
			||||||
                "description": "Geometry which comes from GRB with tools to import them",
 | 
					                "description": "Geometry which comes from GRB with tools to import them",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -516,7 +516,14 @@ export default class TagSpec extends T {
 | 
				
			||||||
                    const filter = TagUtils.Tag("_key~*")
 | 
					                    const filter = TagUtils.Tag("_key~*")
 | 
				
			||||||
                    T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
 | 
					                    T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ]]);
 | 
					            ],
 | 
				
			||||||
 | 
					        ["test date comparison",() => {
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            const filter = TagUtils.Tag("date_created<2022-01-07")
 | 
				
			||||||
 | 
					            T.isFalse(filter.matchesProperties({"date_created":"2022-01-08"}), "Date comparison: expected a match")
 | 
				
			||||||
 | 
					            T.isTrue(filter.matchesProperties({"date_created":"2022-01-01"}), "Date comparison: didn't expect a match")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }]]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue