Move 'asChanges' into tagsFilter; add 'survey:date' option with automatic date to benches
This commit is contained in:
parent
fa5b92e6e1
commit
15a6794e59
10 changed files with 71 additions and 47 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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}];
|
||||
}
|
||||
}
|
|
@ -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}];
|
||||
}
|
||||
}
|
|
@ -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}[]
|
||||
|
||||
}
|
|
@ -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 =
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue