From 120832f2417fbb02167c2bf1747f0a90fe00faa5 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 00:41:53 +0200 Subject: [PATCH 01/10] Move tags into subdirectory --- Customizations/JSON/FromJSON.ts | 11 +++++------ Customizations/JSON/LayerConfig.ts | 4 ++-- Customizations/JSON/LayerConfigJson.ts | 1 - Customizations/JSON/SourceConfig.ts | 2 +- Customizations/JSON/TagRenderingConfig.ts | 6 +++--- Logic/Osm/Changes.ts | 6 +++--- Logic/{ => Tags}/And.ts | 0 Logic/{ => Tags}/Or.ts | 0 Logic/{ => Tags}/RegexTag.ts | 0 Logic/{ => Tags}/Tag.ts | 2 +- Logic/{ => Tags}/TagUtils.ts | 2 +- Logic/{ => Tags}/TagsFilter.ts | 0 UI/Image/DeleteImage.ts | 2 +- UI/Image/ImageUploadFlow.ts | 2 +- UI/Popup/EditableTagRendering.ts | 1 - UI/Popup/TagRenderingAnswer.ts | 2 +- UI/Popup/TagRenderingQuestion.ts | 8 ++++---- test/Tag.spec.ts | 4 ++-- 18 files changed, 25 insertions(+), 28 deletions(-) rename Logic/{ => Tags}/And.ts (100%) rename Logic/{ => Tags}/Or.ts (100%) rename Logic/{ => Tags}/RegexTag.ts (100%) rename Logic/{ => Tags}/Tag.ts (98%) rename Logic/{ => Tags}/TagUtils.ts (99%) rename Logic/{ => Tags}/TagsFilter.ts (100%) diff --git a/Customizations/JSON/FromJSON.ts b/Customizations/JSON/FromJSON.ts index 402a91a..b583cca 100644 --- a/Customizations/JSON/FromJSON.ts +++ b/Customizations/JSON/FromJSON.ts @@ -1,11 +1,10 @@ import {AndOrTagConfigJson} from "./TagConfigJson"; -import {Or} from "../../Logic/Or"; - import {Utils} from "../../Utils"; -import {TagsFilter} from "../../Logic/TagsFilter"; -import {RegexTag} from "../../Logic/RegexTag"; -import {Tag} from "../../Logic/Tag"; -import {And} from "../../Logic/And"; +import {RegexTag} from "../../Logic/Tags/RegexTag"; +import {Or} from "../../Logic/Tags/Or"; +import {And} from "../../Logic/Tags/And"; +import {Tag} from "../../Logic/Tags/Tag"; +import {TagsFilter} from "../../Logic/Tags/TagsFilter"; export class FromJSON { diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index 0756591..e83a59a 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -15,8 +15,8 @@ import {FixedUiElement} from "../../UI/Base/FixedUiElement"; import {UIElement} from "../../UI/UIElement"; import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation"; import SourceConfig from "./SourceConfig"; -import {TagsFilter} from "../../Logic/TagsFilter"; -import {Tag} from "../../Logic/Tag"; +import {TagsFilter} from "../../Logic/Tags/TagsFilter"; +import {Tag} from "../../Logic/Tags/Tag"; export default class LayerConfig { diff --git a/Customizations/JSON/LayerConfigJson.ts b/Customizations/JSON/LayerConfigJson.ts index 335c265..630699e 100644 --- a/Customizations/JSON/LayerConfigJson.ts +++ b/Customizations/JSON/LayerConfigJson.ts @@ -1,6 +1,5 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; import {AndOrTagConfigJson} from "./TagConfigJson"; -import TagRenderingConfig from "./TagRenderingConfig"; /** * Configuration for a single layer diff --git a/Customizations/JSON/SourceConfig.ts b/Customizations/JSON/SourceConfig.ts index 80f4cb7..f354ed3 100644 --- a/Customizations/JSON/SourceConfig.ts +++ b/Customizations/JSON/SourceConfig.ts @@ -1,4 +1,4 @@ -import {TagsFilter} from "../../Logic/TagsFilter"; +import {TagsFilter} from "../../Logic/Tags/TagsFilter"; export default class SourceConfig { diff --git a/Customizations/JSON/TagRenderingConfig.ts b/Customizations/JSON/TagRenderingConfig.ts index ca2cea7..d634afc 100644 --- a/Customizations/JSON/TagRenderingConfig.ts +++ b/Customizations/JSON/TagRenderingConfig.ts @@ -4,9 +4,9 @@ import {FromJSON} from "./FromJSON"; import ValidatedTextField from "../../UI/Input/ValidatedTextField"; import {Translation} from "../../UI/i18n/Translation"; import {Utils} from "../../Utils"; -import {TagsFilter} from "../../Logic/TagsFilter"; -import {And} from "../../Logic/And"; -import {TagUtils} from "../../Logic/TagUtils"; +import {TagUtils} from "../../Logic/Tags/TagUtils"; +import {And} from "../../Logic/Tags/And"; +import {TagsFilter} from "../../Logic/Tags/TagsFilter"; /*** * The parsed version of TagRenderingConfigJSON diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index b661629..a42ffb2 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -4,9 +4,9 @@ import {Utils} from "../../Utils"; import {UIEventSource} from "../UIEventSource"; import Constants from "../../Models/Constants"; import FeatureSource from "../FeatureSource/FeatureSource"; -import {TagsFilter} from "../TagsFilter"; -import {Tag} from "../Tag"; -import {And} from "../And"; +import {TagsFilter} from "../Tags/TagsFilter"; +import {Tag} from "../Tags/Tag"; +import {And} from "../Tags/And"; /** * Handles all changes made to OSM. diff --git a/Logic/And.ts b/Logic/Tags/And.ts similarity index 100% rename from Logic/And.ts rename to Logic/Tags/And.ts diff --git a/Logic/Or.ts b/Logic/Tags/Or.ts similarity index 100% rename from Logic/Or.ts rename to Logic/Tags/Or.ts diff --git a/Logic/RegexTag.ts b/Logic/Tags/RegexTag.ts similarity index 100% rename from Logic/RegexTag.ts rename to Logic/Tags/RegexTag.ts diff --git a/Logic/Tag.ts b/Logic/Tags/Tag.ts similarity index 98% rename from Logic/Tag.ts rename to Logic/Tags/Tag.ts index 3519d7e..d97c1dd 100644 --- a/Logic/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -1,4 +1,4 @@ -import {Utils} from "../Utils"; +import {Utils} from "../../Utils"; import {RegexTag} from "./RegexTag"; import {TagsFilter} from "./TagsFilter"; import {TagUtils} from "./TagUtils"; diff --git a/Logic/TagUtils.ts b/Logic/Tags/TagUtils.ts similarity index 99% rename from Logic/TagUtils.ts rename to Logic/Tags/TagUtils.ts index 15c8901..6fb73f2 100644 --- a/Logic/TagUtils.ts +++ b/Logic/Tags/TagUtils.ts @@ -1,7 +1,7 @@ import {Tag} from "./Tag"; import {TagsFilter} from "./TagsFilter"; import {And} from "./And"; -import {Utils} from "../Utils"; +import {Utils} from "../../Utils"; export class TagUtils { static ApplyTemplate(template: string, tags: any): string { diff --git a/Logic/TagsFilter.ts b/Logic/Tags/TagsFilter.ts similarity index 100% rename from Logic/TagsFilter.ts rename to Logic/Tags/TagsFilter.ts diff --git a/UI/Image/DeleteImage.ts b/UI/Image/DeleteImage.ts index 0c86c4e..2211fb0 100644 --- a/UI/Image/DeleteImage.ts +++ b/UI/Image/DeleteImage.ts @@ -5,7 +5,7 @@ import CheckBox from "../Input/CheckBox"; import Combine from "../Base/Combine"; import State from "../../State"; import Svg from "../../Svg"; -import {Tag} from "../../Logic/Tag"; +import {Tag} from "../../Logic/Tags/Tag"; export default class DeleteImage extends UIElement { diff --git a/UI/Image/ImageUploadFlow.ts b/UI/Image/ImageUploadFlow.ts index 9c43010..e6a710a 100644 --- a/UI/Image/ImageUploadFlow.ts +++ b/UI/Image/ImageUploadFlow.ts @@ -8,7 +8,7 @@ import {Imgur} from "../../Logic/Web/Imgur"; import {DropDown} from "../Input/DropDown"; import Translations from "../i18n/Translations"; import Svg from "../../Svg"; -import {Tag} from "../../Logic/Tag"; +import {Tag} from "../../Logic/Tags/Tag"; export class ImageUploadFlow extends UIElement { private readonly _licensePicker: UIElement; diff --git a/UI/Popup/EditableTagRendering.ts b/UI/Popup/EditableTagRendering.ts index cd8411d..c4733d8 100644 --- a/UI/Popup/EditableTagRendering.ts +++ b/UI/Popup/EditableTagRendering.ts @@ -7,7 +7,6 @@ import Combine from "../Base/Combine"; import TagRenderingAnswer from "./TagRenderingAnswer"; import State from "../../State"; import Svg from "../../Svg"; -import {TagUtils} from "../../Logic/TagUtils"; export default class EditableTagRendering extends UIElement { private readonly _tags: UIEventSource; diff --git a/UI/Popup/TagRenderingAnswer.ts b/UI/Popup/TagRenderingAnswer.ts index 3bf9e42..863f0c0 100644 --- a/UI/Popup/TagRenderingAnswer.ts +++ b/UI/Popup/TagRenderingAnswer.ts @@ -5,7 +5,7 @@ import {Utils} from "../../Utils"; import Combine from "../Base/Combine"; import {SubstitutedTranslation} from "../SubstitutedTranslation"; import {Translation} from "../i18n/Translation"; -import {TagUtils} from "../../Logic/TagUtils"; +import {TagUtils} from "../../Logic/Tags/TagUtils"; /*** * Displays the correct value for a known tagrendering diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index e34aeb5..ac6da33 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -18,10 +18,10 @@ import {FixedUiElement} from "../Base/FixedUiElement"; import {Translation} from "../i18n/Translation"; import Constants from "../../Models/Constants"; import {SubstitutedTranslation} from "../SubstitutedTranslation"; -import {TagsFilter} from "../../Logic/TagsFilter"; -import {Tag} from "../../Logic/Tag"; -import {And} from "../../Logic/And"; -import {TagUtils} from "../../Logic/TagUtils"; +import {TagsFilter} from "../../Logic/Tags/TagsFilter"; +import {Tag} from "../../Logic/Tags/Tag"; +import {And} from "../../Logic/Tags/And"; +import {TagUtils} from "../../Logic/Tags/TagUtils"; /** * Shows the question element. diff --git a/test/Tag.spec.ts b/test/Tag.spec.ts index 3171328..8b3dab2 100644 --- a/test/Tag.spec.ts +++ b/test/Tag.spec.ts @@ -12,8 +12,8 @@ import {Translation} from "../UI/i18n/Translation"; import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours"; import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput"; import {SubstitutedTranslation} from "../UI/SubstitutedTranslation"; -import {Tag} from "../Logic/Tag"; -import {And} from "../Logic/And"; +import {Tag} from "../Logic/Tags/Tag"; +import {And} from "../Logic/Tags/And"; new T("Tags", [ From cd1171e678127bf4a22fdee26bbf443ed0cd33c9 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 01:20:06 +0200 Subject: [PATCH 02/10] Add substituting tag, remove some old code --- Customizations/JSON/FromJSON.ts | 15 ++++++--- Docs/Tags_format.md | 29 ++++++++++++++++ Folder.DotSettings.user | 5 ++- Logic/Tags/And.ts | 8 ----- Logic/Tags/Or.ts | 8 ----- Logic/Tags/SubstitutingTag.ts | 59 +++++++++++++++++++++++++++++++++ Logic/Tags/TagsFilter.ts | 11 +----- test/Tag.spec.ts | 8 +++++ 8 files changed, 112 insertions(+), 31 deletions(-) create mode 100644 Logic/Tags/SubstitutingTag.ts diff --git a/Customizations/JSON/FromJSON.ts b/Customizations/JSON/FromJSON.ts index b583cca..ce48951 100644 --- a/Customizations/JSON/FromJSON.ts +++ b/Customizations/JSON/FromJSON.ts @@ -5,6 +5,7 @@ import {Or} from "../../Logic/Tags/Or"; import {And} from "../../Logic/Tags/And"; import {Tag} from "../../Logic/Tags/Tag"; import {TagsFilter} from "../../Logic/Tags/TagsFilter"; +import SubstitutingTag from "../../Logic/Tags/SubstitutingTag"; export class FromJSON { @@ -12,18 +13,19 @@ export class FromJSON { const tag = Utils.SplitFirst(json, "="); return new Tag(tag[0], tag[1]); } + public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter { - try{ + try { return this.TagUnsafe(json, context); - }catch(e){ - console.error("Could not parse tag", json,"in context",context,"due to ", e) + } catch (e) { + console.error("Could not parse tag", json, "in context", context, "due to ", e) throw e; } } private static TagUnsafe(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter { - if (json === undefined) { + if (json === undefined) { throw `Error while parsing a tag: 'json' is undefined in ${context}. Make sure all the tags are defined and at least one tag is present in a complex expression` } if (typeof (json) == "string") { @@ -49,6 +51,11 @@ export class FromJSON { new RegExp("^" + split[1] + "$") ); } + if(tag.indexOf(":=") >= 0){ + const split = Utils.SplitFirst(tag, ":="); + return new SubstitutingTag(split[0], split[1]); + } + if (tag.indexOf("!=") >= 0) { const split = Utils.SplitFirst(tag, "!="); if (split[1] === "*") { diff --git a/Docs/Tags_format.md b/Docs/Tags_format.md index 4ea7c9c..f6968f6 100644 --- a/Docs/Tags_format.md +++ b/Docs/Tags_format.md @@ -35,3 +35,32 @@ Regex equals A tag can also be tested against a regex with `key~regex`. Note that this regex __must match__ the entire value. If the value is allowed to appear anywhere as substring, use `key~.*regex.*` Equivalently, `key!~regex` can be used if you _don't_ want to match the regex in order to appear. + + +Using other tags as variables +----------------------------- + +**This is an advanced feature - use with caution** + +Some tags are automatically set or calculated - see [CalculatedTags](CalculatedTags.md) for an entire overview. +If one wants to apply such a value as tag, use a substituting-tag such, for example`survey:date:={_date:now}`. Note that the separator between key and value here is `:=`. +The text between `{` and `}` is interpreted as a key, and the respective value is substituted into the string. + +One can also append, e.g. `key:={some_key} fixed text {some_other_key}`. + +An assigning tag _cannot_ be used to query OpenStreetMap/Overpass. + +If using a key or variable which might not be defined, add a condition in the mapping to hide the option. +This is because, if `some_other_key` is not defined, one might actually upload the literal text `key={some_other_key}` to OSM - which we do not want. + +To mitigate this, use: + +``` +"mappings": [ +{ + "if":"key:={some_other_key}" + "then": "...", + "hideInAnswer": "some_other_key=" +} +] +``` \ No newline at end of file diff --git a/Folder.DotSettings.user b/Folder.DotSettings.user index e9e707c..1732b9a 100644 --- a/Folder.DotSettings.user +++ b/Folder.DotSettings.user @@ -1,2 +1,5 @@  - ShowAndRun \ No newline at end of file + ShowAndRun + <SessionState ContinuousTestingMode="0" IsActive="True" Name="Session" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <Nothing /> +</SessionState> \ No newline at end of file diff --git a/Logic/Tags/And.ts b/Logic/Tags/And.ts index 9ca6e27..209ad50 100644 --- a/Logic/Tags/And.ts +++ b/Logic/Tags/And.ts @@ -46,14 +46,6 @@ export class And extends TagsFilter { return allChoices; } - substituteValues(tags: any): TagsFilter { - const newChoices = []; - for (const c of this.and) { - newChoices.push(c.substituteValues(tags)); - } - return new And(newChoices); - } - asHumanString(linkToWiki: boolean, shorten: boolean) { return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&"); } diff --git a/Logic/Tags/Or.ts b/Logic/Tags/Or.ts index c05e2d1..1510b37 100644 --- a/Logic/Tags/Or.ts +++ b/Logic/Tags/Or.ts @@ -30,14 +30,6 @@ export class Or extends TagsFilter { return choices; } - substituteValues(tags: any): TagsFilter { - const newChoices = []; - for (const c of this.or) { - newChoices.push(c.substituteValues(tags)); - } - return new Or(newChoices); - } - asHumanString(linkToWiki: boolean, shorten: boolean) { return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|"); } diff --git a/Logic/Tags/SubstitutingTag.ts b/Logic/Tags/SubstitutingTag.ts new file mode 100644 index 0000000..9aecf2e --- /dev/null +++ b/Logic/Tags/SubstitutingTag.ts @@ -0,0 +1,59 @@ +import {TagsFilter} from "./TagsFilter"; + +/** + * The substituting-tag uses the tags of a feature a variables and replaces them. + * + * e.g. key:={other_key}_{ref} will match an object that has at least 'key'. + * If {other_key} is _not_ defined, it will not be substituted. + * + * The 'key' is always fixed and should not contain substitutions. + * This cannot be used to query features + */ +export default class SubstitutingTag implements TagsFilter { + private readonly _key: string; + private readonly _value: string; + + constructor(key: string, value: string) { + this._key = key; + this._value = value; + } + + private static substituteString(template: string, dict: any) { + for (const k in dict) { + template = template.replace(new RegExp("\\{" + k + "\\}", 'g'), dict[k]) + } + return template; + } + + asHumanString(linkToWiki: boolean, shorten: boolean) { + return this._key + ":=" + this._value; + } + + asOverpass(): string[] { + throw "A variable with substitution can not be used to query overpass" + } + + isEquivalent(other: TagsFilter): boolean { + if (!(other instanceof SubstitutingTag)) { + return false; + } + return other._key === this._key && other._value === this._value; + } + + isUsableAsAnswer(): boolean { + return true; + } + + matchesProperties(properties: any): boolean { + const value = properties[this._key]; + if (value === undefined || value === "") { + return false; + } + const expectedValue = SubstitutingTag.substituteString(this._value, properties); + return value === expectedValue; + } + + usedKeys(): string[] { + return [this._key]; + } +} \ No newline at end of file diff --git a/Logic/Tags/TagsFilter.ts b/Logic/Tags/TagsFilter.ts index 3283986..0f91c74 100644 --- a/Logic/Tags/TagsFilter.ts +++ b/Logic/Tags/TagsFilter.ts @@ -2,8 +2,6 @@ export abstract class TagsFilter { abstract asOverpass(): string[] - abstract substituteValues(tags: any): TagsFilter; - abstract isUsableAsAnswer(): boolean; abstract isEquivalent(other: TagsFilter): boolean; @@ -13,12 +11,5 @@ export abstract class TagsFilter { abstract asHumanString(linkToWiki: boolean, shorten: boolean); abstract usedKeys(): string[]; - - public matches(tags: { k: string, v: string }[]) { - const properties = {}; - for (const kv of tags) { - properties[kv.k] = kv.v; - } - return this.matchesProperties(properties); - } + } \ No newline at end of file diff --git a/test/Tag.spec.ts b/test/Tag.spec.ts index 8b3dab2..5fa3263 100644 --- a/test/Tag.spec.ts +++ b/test/Tag.spec.ts @@ -78,6 +78,14 @@ new T("Tags", [ equal(nameStartsWith.matchesProperties({"name": "speelbos Sint-Anna"}), true) equal(nameStartsWith.matchesProperties({"name": "Sint-Anna"}), false) equal(nameStartsWith.matchesProperties({"name": ""}), false) + + + const assign = FromJSON.Tag("survey:date:={_date:now}") + equal(assign.matchesProperties({"survey:date":"2021-03-29", "_date:now":"2021-03-29"}), true); + equal(assign.matchesProperties({"survey:date":"2021-03-29", "_date:now":"2021-01-01"}), false); + equal(assign.matchesProperties({"survey:date":"2021-03-29"}), false); + equal(assign.matchesProperties({"_date:now":"2021-03-29"}), false); + equal(assign.matchesProperties({"some_key":"2021-03-29"}), false); })], ["Is equivalent test", (() => { From bec1998a6d1470acf8a9a0b88ef2f02bd1700b53 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 02:04:42 +0200 Subject: [PATCH 03/10] Fix incorrect imports due to refactoring --- Logic/Actors/UpdateFromOverpass.ts | 4 +- Logic/ExtraFunction.ts | 63 ++++++++++++++++++++++++++---- Logic/SimpleMetaTagger.ts | 6 +-- UI/BigComponents/SimpleAddUI.ts | 4 +- UI/Popup/FeatureInfoBox.ts | 3 +- 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/Logic/Actors/UpdateFromOverpass.ts b/Logic/Actors/UpdateFromOverpass.ts index d7b470a..c75239a 100644 --- a/Logic/Actors/UpdateFromOverpass.ts +++ b/Logic/Actors/UpdateFromOverpass.ts @@ -1,12 +1,12 @@ import {UIEventSource} from "../UIEventSource"; import Loc from "../../Models/Loc"; -import {Or} from "../Or"; +import {Or} from "../Tags/Or"; import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; import {Overpass} from "../Osm/Overpass"; import Bounds from "../../Models/Bounds"; import FeatureSource from "../FeatureSource/FeatureSource"; import {Utils} from "../../Utils"; -import {TagsFilter} from "../TagsFilter"; +import {TagsFilter} from "../Tags/TagsFilter"; export default class UpdateFromOverpass implements FeatureSource { diff --git a/Logic/ExtraFunction.ts b/Logic/ExtraFunction.ts index 432a549..e286d1d 100644 --- a/Logic/ExtraFunction.ts +++ b/Logic/ExtraFunction.ts @@ -61,13 +61,60 @@ Some advanced functions are available on feat as well: "Calculates the distance between the feature and a specified point", ["longitude", "latitude"], (featuresPerLayer, feature) => { - return (lon, lat) => { - // Feature._lon and ._lat is conveniently place by one of the other metatags - return GeoOperations.distanceBetween([lon, lat], [feature._lon, feature._lat]); + return (arg0, lat) => { + if(typeof arg0 === "number"){ + const lon = arg0 + // Feature._lon and ._lat is conveniently place by one of the other metatags + return GeoOperations.distanceBetween([lon, lat], [feature._lon, feature._lat]); + }else{ + // arg0 is probably a feature + return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0),[feature._lon, feature._lat]) + } + } } ) - private static readonly allFuncs: ExtraFunction[] = [ExtraFunction.DistanceToFunc, ExtraFunction.OverlapFunc]; + + private static ClosestObjectFunc = new ExtraFunction( + "closest", + "Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered.", + ["list of features"], + (featuresPerLayer, feature) => { + return (features) => { + if (typeof features === "string") { + features = featuresPerLayer.get(features) + } + let closestFeature = undefined; + let closestDistance = undefined; + for (const otherFeature of features) { + if(otherFeature == feature){ + continue; // We ignore self + } + let distance = undefined; + if (otherFeature._lon !== undefined && otherFeature._lat !== undefined) { + distance = GeoOperations.distanceBetween([otherFeature._lon, otherFeature._lat], [feature._lon, feature._lat]); + } else { + distance = GeoOperations.distanceBetween( + GeoOperations.centerpointCoordinates(otherFeature), + [feature._lon, feature._lat] + ) + } + if(distance === undefined){ + throw "Undefined distance!" + } + if(closestFeature === undefined || distance < closestDistance){ + console.log("Distance between ", feature.properties.id, "and", otherFeature.properties.id, "is", distance) + closestFeature = otherFeature + closestDistance = distance; + } + } + return closestFeature; + } + } + ) + + + private static readonly allFuncs: ExtraFunction[] = [ExtraFunction.DistanceToFunc, ExtraFunction.OverlapFunc, ExtraFunction.ClosestObjectFunc]; private readonly _name: string; private readonly _args: string[]; private readonly _doc: string; @@ -91,10 +138,10 @@ Some advanced functions are available on feat as well: return new Combine([ ExtraFunction.intro, "
    ", - ...ExtraFunction.allFuncs.map(func => - new Combine([ - "
  • ", func._name, "
  • " - ]) + ...ExtraFunction.allFuncs.map(func => + new Combine([ + "
  • ", func._name, "
  • " + ]) ), "
", ...ExtraFunction.allFuncs.map(func => diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index 4609939..ae77b7b 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -1,8 +1,8 @@ import {GeoOperations} from "./GeoOperations"; import State from "../State"; -import {And} from "./And"; -import {Tag} from "./Tag"; -import {Or} from "./Or"; +import {And} from "./Tags/And"; +import {Tag} from "./Tags/Tag"; +import {Or} from "./Tags/Or"; import {Utils} from "../Utils"; import opening_hours from "opening_hours"; import {UIElement} from "../UI/UIElement"; diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 716f8fe..7530837 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -12,8 +12,8 @@ import {FixedUiElement} from "../Base/FixedUiElement"; import Translations from "../i18n/Translations"; import Constants from "../../Models/Constants"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; -import {Tag} from "../../Logic/Tag"; -import {TagUtils} from "../../Logic/TagUtils"; +import {Tag} from "../../Logic/Tags/Tag"; +import {TagUtils} from "../../Logic/Tags/TagUtils"; export default class SimpleAddUI extends UIElement { private readonly _loginButton: UIElement; diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 20c2e28..7cea701 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -8,8 +8,7 @@ import TagRenderingAnswer from "./TagRenderingAnswer"; import State from "../../State"; import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; -import {Utils} from "../../Utils"; -import {Tag} from "../../Logic/Tag"; +import {Tag} from "../../Logic/Tags/Tag"; export default class FeatureInfoBox extends ScrollableFullScreen { From fa5b92e6e115f4443cc8149f52763e33a7d75ef7 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 02:05:11 +0200 Subject: [PATCH 04/10] Add link to nearby drinking water points with some fancy calculated tag magic --- Logic/GeoOperations.ts | 4 +--- Models/Constants.ts | 2 +- assets/layers/drinking_water/drinking_water.json | 9 +++++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts index e239951..a687dee 100644 --- a/Logic/GeoOperations.ts +++ b/Logic/GeoOperations.ts @@ -16,9 +16,7 @@ export class GeoOperations { } static centerpointCoordinates(feature: any){ - const coordinates = turf.center(feature).geometry.coordinates; - coordinates.reverse(); - return coordinates; + return turf.center(feature).geometry.coordinates; } /** diff --git a/Models/Constants.ts b/Models/Constants.ts index 44371d6..ef3f8eb 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.6.3"; + public static vNumber = "0.6.4"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index b59d754..5a057db 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -41,6 +41,10 @@ ] } }, + "calculatedTags": [ + "_closest_other_drinking_water_id=feat.closest('drinking_water').id", + "_closest_other_drinking_water_distance=Math.floor(feat.distanceTo(feat.closest('drinking_water')) * 1000)" + ], "minzoom": 13, "wayHandling": 1, "presets": [ @@ -122,6 +126,11 @@ } } ] + }, + { + "render":{ + "en": "The closest other drinking water fountain is {_closest_other_drinking_water_distance} meter" + } } ] } \ No newline at end of file From 15a6794e59b0be33fbb6df69f9a80c61a7bf1f19 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 02:31:08 +0200 Subject: [PATCH 05/10] Move 'asChanges' into tagsFilter; add 'survey:date' option with automatic date to benches --- Logic/Osm/Changes.ts | 38 ++++++------------------------ Logic/Tags/And.ts | 12 ++++++++-- Logic/Tags/Or.ts | 8 +++++-- Logic/Tags/RegexTag.ts | 8 +++---- Logic/Tags/SubstitutingTag.ts | 14 ++++++++--- Logic/Tags/Tag.ts | 4 ++++ Logic/Tags/TagsFilter.ts | 8 ++++++- UI/BigComponents/SimpleAddUI.ts | 4 ++-- UI/Popup/TagRenderingQuestion.ts | 4 ++-- assets/layers/benches/benches.json | 18 ++++++++++++++ 10 files changed, 71 insertions(+), 47 deletions(-) diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index a42ffb2..caf0afe 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -6,7 +6,6 @@ import Constants from "../../Models/Constants"; import FeatureSource from "../FeatureSource/FeatureSource"; import {TagsFilter} from "../Tags/TagsFilter"; import {Tag} from "../Tags/Tag"; -import {And} from "../Tags/And"; /** * Handles all changes made to OSM. @@ -29,7 +28,9 @@ export class Changes implements FeatureSource{ /** * Adds a change to the pending changes */ - private static checkChange(key: string, value: string): { k: string, v: string } { + private static checkChange(kv: {k: string, v: string}): { k: string, v: string } { + const key = kv.k; + const value = kv.v; if (key === undefined || key === null) { console.log("Invalid key"); return undefined; @@ -43,22 +44,19 @@ export class Changes implements FeatureSource{ console.warn("Tag starts with or ends with a space - trimming anyway") } - key = key.trim(); - value = value.trim(); - - return {k: key, v: value}; + return {k: key.trim(), v: value.trim()}; } addTag(elementId: string, tagsFilter: TagsFilter, tags?: UIEventSource) { - const changes = this.tagToChange(tagsFilter); + const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId); + const elementTags = eventSource.data; + const changes = tagsFilter.asChange(elementTags).map(Changes.checkChange) if (changes.length == 0) { return; } - const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId); - const elementTags = eventSource.data; for (const change of changes) { if (elementTags[change.k] !== change.v) { elementTags[change.k] = change.v; @@ -132,28 +130,6 @@ export class Changes implements FeatureSource{ return geojson; } - private tagToChange(tagsFilter: TagsFilter) { - let changes: { k: string, v: string }[] = []; - - if (tagsFilter instanceof Tag) { - const tag = tagsFilter as Tag; - if (typeof tag.value !== "string") { - throw "Invalid value" - } - return [Changes.checkChange(tag.key, tag.value)]; - } - - if (tagsFilter instanceof And) { - const and = tagsFilter as And; - for (const tag of and.and) { - changes = changes.concat(this.tagToChange(tag)); - } - return changes; - } - console.log("Unsupported tagsfilter element to addTag", tagsFilter); - throw "Unsupported tagsFilter element"; - } - private uploadChangesWithLatestVersions( knownElements, newElements: OsmObject[], pending: { elementId: string; key: string; value: string }[]) { // Here, inside the continuation, we know that all 'neededIds' are loaded in 'knownElements', which maps the ids onto the elements diff --git a/Logic/Tags/And.ts b/Logic/Tags/And.ts index 209ad50..ef5789d 100644 --- a/Logic/Tags/And.ts +++ b/Logic/Tags/And.ts @@ -46,8 +46,8 @@ export class And extends TagsFilter { return allChoices; } - asHumanString(linkToWiki: boolean, shorten: boolean) { - return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&"); + asHumanString(linkToWiki: boolean, shorten: boolean, properties) { + return this.and.map(t => t.asHumanString(linkToWiki, shorten, properties)).join("&"); } isUsableAsAnswer(): boolean { @@ -108,4 +108,12 @@ export class And extends TagsFilter { usedKeys(): string[] { return [].concat(...this.and.map(subkeys => subkeys.usedKeys())); } + + asChange(properties: any): { k: string; v: string }[] { + const result = [] + for (const tagsFilter of this.and) { + result.push(...tagsFilter.asChange(properties)) + } + return result; + } } \ No newline at end of file diff --git a/Logic/Tags/Or.ts b/Logic/Tags/Or.ts index 1510b37..40cee60 100644 --- a/Logic/Tags/Or.ts +++ b/Logic/Tags/Or.ts @@ -30,8 +30,8 @@ export class Or extends TagsFilter { return choices; } - asHumanString(linkToWiki: boolean, shorten: boolean) { - return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|"); + asHumanString(linkToWiki: boolean, shorten: boolean, properties) { + return this.or.map(t => t.asHumanString(linkToWiki, shorten, properties)).join("|"); } isUsableAsAnswer(): boolean { @@ -59,6 +59,10 @@ export class Or extends TagsFilter { usedKeys(): string[] { return [].concat(...this.or.map(subkeys => subkeys.usedKeys())); } + + asChange(properties: any): { k: string; v: string }[] { + throw "Can not convert an 'or' into a changeset" + } } diff --git a/Logic/Tags/RegexTag.ts b/Logic/Tags/RegexTag.ts index 35fdaa4..7c680b8 100644 --- a/Logic/Tags/RegexTag.ts +++ b/Logic/Tags/RegexTag.ts @@ -55,10 +55,6 @@ export class RegexTag extends TagsFilter { return this.invert; } - substituteValues(tags: any): TagsFilter { - return this; - } - asHumanString() { if (typeof this.key === "string") { return `${this.key}${this.invert ? "!" : ""}~${RegexTag.source(this.value)}`; @@ -82,4 +78,8 @@ export class RegexTag extends TagsFilter { } throw "Key cannot be determined as it is a regex" } + + asChange(properties: any): { k: string; v: string }[] { + throw "Cannot convert a regex-tag into a change"; + } } \ No newline at end of file diff --git a/Logic/Tags/SubstitutingTag.ts b/Logic/Tags/SubstitutingTag.ts index 9aecf2e..58591d5 100644 --- a/Logic/Tags/SubstitutingTag.ts +++ b/Logic/Tags/SubstitutingTag.ts @@ -18,15 +18,15 @@ export default class SubstitutingTag implements TagsFilter { this._value = value; } - private static substituteString(template: string, dict: any) { + private static substituteString(template: string, dict: any): string { for (const k in dict) { template = template.replace(new RegExp("\\{" + k + "\\}", 'g'), dict[k]) } return template; } - asHumanString(linkToWiki: boolean, shorten: boolean) { - return this._key + ":=" + this._value; + asHumanString(linkToWiki: boolean, shorten: boolean, properties) { + return this._key + "=" + SubstitutingTag.substituteString(this._value, properties); } asOverpass(): string[] { @@ -56,4 +56,12 @@ export default class SubstitutingTag implements TagsFilter { usedKeys(): string[] { return [this._key]; } + + asChange(properties: any): { k: string; v: string }[] { + const v = SubstitutingTag.substituteString(this._value, properties); + if (v.match(/{.*}/) !== null) { + throw "Could not calculate all the substitutions: still have " + v + } + return [{k: this._key, v: v}]; + } } \ No newline at end of file diff --git a/Logic/Tags/Tag.ts b/Logic/Tags/Tag.ts index d97c1dd..a3a4650 100644 --- a/Logic/Tags/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -81,4 +81,8 @@ export class Tag extends TagsFilter { usedKeys(): string[] { return [this.key]; } + + asChange(properties: any): { k: string; v: string }[] { + return [{k: this.key, v: this.value}]; + } } \ No newline at end of file diff --git a/Logic/Tags/TagsFilter.ts b/Logic/Tags/TagsFilter.ts index 0f91c74..5400aa8 100644 --- a/Logic/Tags/TagsFilter.ts +++ b/Logic/Tags/TagsFilter.ts @@ -8,8 +8,14 @@ export abstract class TagsFilter { abstract matchesProperties(properties: any): boolean; - abstract asHumanString(linkToWiki: boolean, shorten: boolean); + abstract asHumanString(linkToWiki: boolean, shorten: boolean, properties: any); abstract usedKeys(): string[]; + + /** + * Converts the tagsFilter into a list of key-values that should be uploaded to OSM. + * Throws an error if not applicable + */ + abstract asChange(properties:any): {k: string, v:string}[] } \ No newline at end of file diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 7530837..0574d9d 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -158,7 +158,7 @@ export default class SimpleAddUI extends UIElement { let tagInfo = ""; const csCount = State.state.osmConnection.userDetails.data.csCount; if (csCount > Constants.userJourney.tagsVisibleAt) { - tagInfo = this._confirmPreset.data.tags.map(t => t.asHumanString(csCount > Constants.userJourney.tagsVisibleAndWikiLinked, true)).join("&"); + tagInfo = this._confirmPreset.data.tags.map(t => t.asHumanString(csCount > Constants.userJourney.tagsVisibleAndWikiLinked, true, {})).join("&"); tagInfo = `
More information about the preset: ${tagInfo}` } @@ -186,7 +186,7 @@ export default class SimpleAddUI extends UIElement { const csCount = State.state.osmConnection.userDetails.data.csCount; let tagInfo = undefined; if (csCount > Constants.userJourney.tagsVisibleAt) { - const presets = preset.tags.map(t => new Combine ([t.asHumanString(false, true), " "]).SetClass("subtle break-words") ) + const presets = preset.tags.map(t => new Combine ([t.asHumanString(false, true, {}), " "]).SetClass("subtle break-words") ) tagInfo = new Combine(presets) } const button: UIElement = diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index ac6da33..751e2b7 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -86,10 +86,10 @@ export default class TagRenderingQuestion extends UIElement { return Translations.t.general.noTagsSelected.SetClass("subtle").Render(); } if (csCount < Constants.userJourney.tagsVisibleAndWikiLinked) { - const tagsStr = tags.asHumanString(false, true); + const tagsStr = tags.asHumanString(false, true, self._tags.data); return new FixedUiElement(tagsStr).SetClass("subtle").Render(); } - return tags.asHumanString(true, true); + return tags.asHumanString(true, true, self._tags.data); } ) ).SetClass("block") diff --git a/assets/layers/benches/benches.json b/assets/layers/benches/benches.json index 7eb2c4e..b1ac1c2 100644 --- a/assets/layers/benches/benches.json +++ b/assets/layers/benches/benches.json @@ -227,6 +227,24 @@ } } ] + }, + { + "question":{ + "en": "When was this bench last surveyed?" + }, + "render": { + "en": "This bench was last surveyed on {survey:date}" + }, + "freeform": { + "key": "survey:date", + "type": "date" + }, + "mappings": [ + { + "if": "survey:date:={_now:date}", + "then": "Surveyed today!" + } + ] } ], "hideUnderlayingFeaturesMinPercentage": 0, From 4342b38e9d902492f7cd6fb746fade060c746434 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 02:53:06 +0200 Subject: [PATCH 06/10] Formatting and small cleanups --- Customizations/JSON/LayerConfig.ts | 2 +- Customizations/JSON/LayerConfigJson.ts | 60 ++++++++++--------- Folder.DotSettings.user | 2 +- Logic/ExtraFunction.ts | 1 - Logic/FeatureSource/GeoJsonSource.ts | 1 - UI/Popup/TagRenderingQuestion.ts | 3 +- UI/ShowDataLayer.ts | 4 +- .../themes/drinking_water/drinking_water.json | 4 +- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index e83a59a..7d85a61 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -81,7 +81,7 @@ export default class LayerConfig { this.source = new SourceConfig({ osmTags: osmTags, - geojsonSource: json.source["geoJsonSource"], + geojsonSource: json.source["geoJson"], overpassScript: json.source["overpassScript"], }); } else { diff --git a/Customizations/JSON/LayerConfigJson.ts b/Customizations/JSON/LayerConfigJson.ts index 630699e..b21bb3f 100644 --- a/Customizations/JSON/LayerConfigJson.ts +++ b/Customizations/JSON/LayerConfigJson.ts @@ -10,7 +10,7 @@ export interface LayerConfigJson { * This should be a simple, lowercase, human readable string that is used to identify the layer. */ id: string; - + /** * The name of this layer * Used in the layer control panel and the 'Personal theme' @@ -27,22 +27,24 @@ export interface LayerConfigJson { /** * This determines where the data for the layer is fetched. * There are some options: - * + * * source: {osmTags: "key=value"} will fetch all objects with given tags from OSM. Currently, this will create a query to overpass and fetch the data - in the future this might fetch from the OSM API * source: {geoJsonSource: "https://my.source.net/some-geo-data.geojson"} to fetch a geojson from a third party source - * - * source: {overpassScript: ""} when you want to do special things. _This should be really rare_. + * + * source: {overpassScript: ""} when you want to do special things. _This should be really rare_. * This means that the data will be pulled from overpass with this script, and will ignore the osmTags for the query * However, for the rest of the pipeline, the OsmTags will _still_ be used. This is important to enable layers etc... - * - * + * + * * NOTE: the previous format was 'overpassTags: AndOrTagCOnfigJson | string', which is interpreted as a shorthand for source: {osmTags: "key=value"} * While still supported, this is considered deprecated */ - source: {osmTags: AndOrTagConfigJson | string} | {geoJsonSource: string} | {overpassScript: string} + source: { osmTags: AndOrTagConfigJson | string } | + { osmTags: AndOrTagConfigJson | string, geoJson: string } | + { osmTags: AndOrTagConfigJson | string, overpassScript: string } /** - * + * * A list of extra tags to calculate, specified as "keyToAssignTo=javascript-expression". * There are a few extra functions available. Refer to Docs/CalculatedTags.md for more information * The functions will be run in order, e.g. @@ -50,12 +52,12 @@ export interface LayerConfigJson { * "_max_overlap_m2=Math.max(...feat.overlapsWith("someOtherLayer").map(o => o.overlap)) * "_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area * ] - * + * */ - calculatedTags? : string[]; + calculatedTags?: string[]; /** - * If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers. + * If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers. * Works well together with 'passAllFeatures', to add decoration */ doNotDownload?: boolean; @@ -64,7 +66,7 @@ export interface LayerConfigJson { * This tagrendering should either be 'yes' or 'no'. If 'no' is returned, then the feature will be hidden from view. * This is useful to hide certain features from view. Important: hiding features does not work dynamically, but is only calculated when the data is first renders. * This implies that it is not possible to hide a feature after a tagging change - * + * * The default value is 'yes' */ isShown?: TagRenderingConfigJson; @@ -81,7 +83,7 @@ export interface LayerConfigJson { * Default: 100 (thus: always visible */ maxzoom?: number; - + /** * The title shown in a popup for elements of this layer. */ @@ -97,7 +99,7 @@ export interface LayerConfigJson { /** * The icon for an element. * Note that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets. - * + * * The result of the icon is rendered as follows: * the resulting string is interpreted as a _list_ of items, seperated by ";". The bottommost layer is the first layer. * As a result, on could use a generic pin, then overlay it with a specific icon. @@ -111,13 +113,13 @@ export interface LayerConfigJson { * The 'badge'-toggle changes their behaviour. * If badge is set, it will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout. * If badges is false, it'll be a simple overlay - * + * * Note: strings are interpreted as icons, so layering and substituting is supported */ - iconOverlays?: {if: string | AndOrTagConfigJson, then: string | TagRenderingConfigJson, badge?: boolean}[] + iconOverlays?: { if: string | AndOrTagConfigJson, then: string | TagRenderingConfigJson, badge?: boolean }[] /** - * A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ... + * A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ... * Default is '40,40,center' */ iconSize?: string | TagRenderingConfigJson; @@ -156,18 +158,18 @@ export interface LayerConfigJson { * If set, this layer will pass all the features it receives onto the next layer. * This is ideal for decoration, e.g. directionss on cameras */ - passAllFeatures?:boolean - + passAllFeatures?: boolean + /** * Presets for this layer. * A preset shows up when clicking the map on a without data (or when right-clicking/long-pressing); * it will prompt the user to add a new point. - * + * * The most important aspect are the tags, which define which tags the new point will have; * The title is shown in the dialog, along with the first sentence of the description. - * + * * Upon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples. - * + * * Note: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that! * NB: if no presets are defined, the popup to add new points doesn't show up at all */ @@ -183,7 +185,7 @@ export interface LayerConfigJson { /** * The _first sentence_ of the description is shown on the button of the `add` menu. * The full description is shown in the confirmation dialog. - * + * * (The first sentence is until the first '.'-character in the description) */ description?: string | any, @@ -192,16 +194,16 @@ export interface LayerConfigJson { /** * All the tag renderings. * A tag rendering is a block that either shows the known value or asks a question. - * + * * Refer to the class `TagRenderingConfigJson` to see the possibilities. - * + * * Note that we can also use a string here - where the string refers to a tagrenering defined in `assets/questions/questions.json`, * where a few very general questions are defined e.g. website, phone number, ... - * + * * A special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox. - * + * */ tagRenderings?: (string | TagRenderingConfigJson) [] - - + + } \ No newline at end of file diff --git a/Folder.DotSettings.user b/Folder.DotSettings.user index 1732b9a..e8c3e8e 100644 --- a/Folder.DotSettings.user +++ b/Folder.DotSettings.user @@ -1,5 +1,5 @@  - ShowAndRun + DoNotShowAndRun <SessionState ContinuousTestingMode="0" IsActive="True" Name="Session" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Nothing /> </SessionState> \ No newline at end of file diff --git a/Logic/ExtraFunction.ts b/Logic/ExtraFunction.ts index e286d1d..1689e67 100644 --- a/Logic/ExtraFunction.ts +++ b/Logic/ExtraFunction.ts @@ -103,7 +103,6 @@ Some advanced functions are available on feat as well: throw "Undefined distance!" } if(closestFeature === undefined || distance < closestDistance){ - console.log("Distance between ", feature.properties.id, "and", otherFeature.properties.id, "is", distance) closestFeature = otherFeature closestDistance = distance; } diff --git a/Logic/FeatureSource/GeoJsonSource.ts b/Logic/FeatureSource/GeoJsonSource.ts index a8d3c79..dea7356 100644 --- a/Logic/FeatureSource/GeoJsonSource.ts +++ b/Logic/FeatureSource/GeoJsonSource.ts @@ -1,7 +1,6 @@ import FeatureSource from "./FeatureSource"; import {UIEventSource} from "../UIEventSource"; import * as $ from "jquery"; -import {Layer} from "leaflet"; /** * Fetches a geojson file somewhere and passes it along diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index 751e2b7..b8e2c1d 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -57,9 +57,8 @@ export default class TagRenderingQuestion extends UIElement { this._inputElement = this.GenerateInputElement() const self = this; const save = () => { - console.log("Save clicked!") const selection = self._inputElement.GetValue().data; - console.log("Selection is", selection) + console.log("Save button clicked, the tags are is", selection) if (selection) { (State.state?.changes ?? new Changes()) .addTag(tags.data.id, selection, tags); diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 9abc487..b077ea3 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -27,7 +27,9 @@ export default class ShowDataLayer { layoutToUse.addCallbackAndRun(layoutToUse => { for (const layer of layoutToUse.layers) { - self._layerDict[layer.id] = layer; + if (self._layerDict[layer.id] === undefined) { + self._layerDict[layer.id] = layer; + } } }); diff --git a/assets/themes/drinking_water/drinking_water.json b/assets/themes/drinking_water/drinking_water.json index 5b5d732..a783e2e 100644 --- a/assets/themes/drinking_water/drinking_water.json +++ b/assets/themes/drinking_water/drinking_water.json @@ -17,6 +17,8 @@ "startLon": 4.3516970, "startZoom": 16, "widenFactor": 0.05, - "layers": ["drinking_water"], + "layers": [ + "drinking_water", + ], "roamingRenderings": [] } \ No newline at end of file From 383725a5c22f792719079e8de5383649aac90810 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 13:00:27 +0200 Subject: [PATCH 07/10] Add a link to the closest drinking water point --- assets/themes/drinking_water/drinking_water.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/assets/themes/drinking_water/drinking_water.json b/assets/themes/drinking_water/drinking_water.json index a783e2e..09027e1 100644 --- a/assets/themes/drinking_water/drinking_water.json +++ b/assets/themes/drinking_water/drinking_water.json @@ -8,17 +8,20 @@ "en": "On this map, publicly accessible drinkging water spots are shown and can be easily added", "nl": "Op deze kaart staan publiek toegankelijke drinkwaterpunten en kan je makkelijk een nieuw drinkwaterpunt toevoegen" }, - "language": ["en", "nl"], + "language": [ + "en", + "nl" + ], "maintainer": "MapComplete", "icon": "./assets/themes/drinking_water/logo.svg", "version": "0", "startLat": 50.8465573, "defaultBackgroundId": "CartoDB.Voyager", - "startLon": 4.3516970, + "startLon": 4.3516970, "startZoom": 16, "widenFactor": 0.05, "layers": [ - "drinking_water", + "drinking_water" ], "roamingRenderings": [] } \ No newline at end of file From 86ecbbfc8fefeeff07a8562a9fe84bcd23c7e13f Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 13:59:49 +0200 Subject: [PATCH 08/10] Small rewording --- assets/layers/drinking_water/drinking_water.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 5a057db..8707891 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -129,8 +129,8 @@ }, { "render":{ - "en": "The closest other drinking water fountain is {_closest_other_drinking_water_distance} meter" + "en": "There is another drinking water fountain on {_closest_other_drinking_water_distance} meter" } } ] -} \ No newline at end of file +} From 3ea447af24772686fbfe8ce89e80f6c2bdecd760 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 18:03:47 +0200 Subject: [PATCH 09/10] Npm audit fix --- package-lock.json | 51 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5df99ed..1396f9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5740,11 +5740,18 @@ } }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "0.7.1" + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, "decamelize": { @@ -8225,18 +8232,11 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } + "minimist": "^1.2.5" } }, "mkdirp-classic": { @@ -8266,6 +8266,14 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=" }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, "escape-string-regexp": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", @@ -8289,6 +8297,19 @@ "sigmund": "~1.0.0" } }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, "supports-color": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", From 89033eedfe44ed1ce2dbf0362ad97c9a104395d4 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 29 Mar 2021 18:07:22 +0200 Subject: [PATCH 10/10] Add dutch translation --- assets/layers/drinking_water/drinking_water.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 8707891..acc7fe4 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -129,7 +129,8 @@ }, { "render":{ - "en": "There is another drinking water fountain on {_closest_other_drinking_water_distance} meter" + "en": "There is another drinking water fountain at {_closest_other_drinking_water_distance} meter", + "nl": "Er bevindt zich een ander drinkwaterpunt op {_closest_other_drinking_water_distance} meter" } } ]