Move 'asChanges' into tagsFilter; add 'survey:date' option with automatic date to benches

This commit is contained in:
pietervdvn 2021-03-29 02:31:08 +02:00
parent fa5b92e6e1
commit 15a6794e59
10 changed files with 71 additions and 47 deletions

View file

@ -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<any>) {
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

View file

@ -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;
}
}

View file

@ -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"
}
}

View file

@ -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";
}
}

View file

@ -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}];
}
}

View file

@ -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}];
}
}

View file

@ -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}[]
}

View file

@ -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 = `<br/>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 =

View file

@ -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")

View file

@ -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,