diff --git a/Logic/Tags/And.ts b/Logic/Tags/And.ts index a5161b90f..78b6d4710 100644 --- a/Logic/Tags/And.ts +++ b/Logic/Tags/And.ts @@ -59,7 +59,7 @@ export class And extends TagsFilter { } asHumanString(linkToWiki: boolean, shorten: boolean, properties) { - return this.and.map(t => t.asHumanString(linkToWiki, shorten, properties)).join("&"); + return this.and.map(t => t.asHumanString(linkToWiki, shorten, properties)).filter(x => x !== "").join("&"); } isUsableAsAnswer(): boolean { diff --git a/Logic/Tags/Tag.ts b/Logic/Tags/Tag.ts index 2d3c8a4a3..90b2c8841 100644 --- a/Logic/Tags/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -48,7 +48,7 @@ export class Tag extends TagsFilter { } if(v === "" || v === undefined){ // This tag will be removed if in the properties, so we indicate this with special rendering - if(currentProperties !== undefined && (currentProperties[this.key] ?? "") !== ""){ + if(currentProperties !== undefined && (currentProperties[this.key] ?? "") === ""){ // This tag is not present in the current properties, so this tag doesn't change anything return "" } diff --git a/Logic/UIEventSource.ts b/Logic/UIEventSource.ts index 3aebda853..28f215257 100644 --- a/Logic/UIEventSource.ts +++ b/Logic/UIEventSource.ts @@ -281,10 +281,12 @@ export class UIEventSource { * @param f: The transforming function * @param extraSources: also trigger the update if one of these sources change * @param g: a 'backfunction to let the sync run in two directions. (data of the new UIEVEntSource, currentData) => newData + * @param allowUnregister: if set, the update will be halted if no listeners are registered */ public map(f: ((t: T) => J), extraSources: UIEventSource[] = [], - g: ((j: J, t: T) => T) = undefined): UIEventSource { + g: ((j: J, t: T) => T) = undefined, + allowUnregister = false): UIEventSource { const self = this; const stack = new Error().stack.split("\n"); @@ -297,6 +299,7 @@ export class UIEventSource { const update = function () { newSource.setData(f(self.data)); + return allowUnregister && newSource._callbacks.length === 0 } this.addCallback(update); diff --git a/UI/Input/ValidatedTextField.ts b/UI/Input/ValidatedTextField.ts index 12e043b39..800218606 100644 --- a/UI/Input/ValidatedTextField.ts +++ b/UI/Input/ValidatedTextField.ts @@ -406,9 +406,17 @@ export default class ValidatedTextField { if (str === undefined) { return false; } + if(str.startsWith("tel:")){ + str = str.substring("tel:".length) + } return parsePhoneNumberFromString(str, (country())?.toUpperCase() as any)?.isValid() ?? false }, - (str, country: () => string) => parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational(), + (str, country: () => string) => { + if(str.startsWith("tel:")){ + str = str.substring("tel:".length) + } + return parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational(); + }, undefined, "tel" ), diff --git a/UI/ShowDataLayer/ShowDataLayer.ts b/UI/ShowDataLayer/ShowDataLayer.ts index f306cadf2..d1af72001 100644 --- a/UI/ShowDataLayer/ShowDataLayer.ts +++ b/UI/ShowDataLayer/ShowDataLayer.ts @@ -145,7 +145,8 @@ export default class ShowDataLayer { pointToLayer: (feature, latLng) => self.pointToLayer(feature, latLng), onEachFeature: (feature, leafletLayer) => self.postProcessFeature(feature, leafletLayer) }); - + + const selfLayer = this.geoLayer; const allFeats = this._features.features.data; for (const feat of allFeats) { if (feat === undefined) { @@ -153,12 +154,11 @@ export default class ShowDataLayer { } try { if (feat.geometry.type === "LineString") { - const self = this; const coords = L.GeoJSON.coordsToLatLngs(feat.geometry.coordinates) const tagsSource = this.allElements?.addOrGetElement(feat) ?? new UIEventSource(feat.properties); let offsettedLine; tagsSource - .map(tags => this._layerToShow.lineRendering[feat.lineRenderingIndex].GenerateLeafletStyle(tags)) + .map(tags => this._layerToShow.lineRendering[feat.lineRenderingIndex].GenerateLeafletStyle(tags), [], undefined, true) .withEqualityStabilized((a, b) => { if (a === b) { return true @@ -176,6 +176,9 @@ export default class ShowDataLayer { offsettedLine = L.polyline(coords, lineStyle); this.postProcessFeature(feat, offsettedLine) offsettedLine.addTo(this.geoLayer) + + // If 'self.geoLayer' is not the same as the layer the feature is added to, we can safely remove this callback + return self.geoLayer !== selfLayer }) } else { this.geoLayer.addData(feat); @@ -186,11 +189,13 @@ export default class ShowDataLayer { } if (options.zoomToFeatures ?? false) { - try { - const bounds = this.geoLayer.getBounds() - mp.fitBounds(bounds, {animate: false}) - } catch (e) { - console.debug("Invalid bounds", e) + if(this.geoLayer.getLayers().length > 0){ + try { + const bounds = this.geoLayer.getBounds() + mp.fitBounds(bounds, {animate: false}) + } catch (e) { + console.debug("Invalid bounds", e) + } } } diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 25a9549ef..f43b36ad0 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -71,9 +71,17 @@ "ca": "Quin és el telèfon de {name}?" }, "render": "{phone}", + "mappings": [ + { + "if": "contact:phone~*", + "then": "{contact:phone}", + "hideInAnswer": true + } + ], "freeform": { "key": "phone", - "type": "phone" + "type": "phone", + "addExtraTags": ["contact:phone="] } }, "osmlink": { @@ -140,9 +148,17 @@ "hu": "Mi a(z) {name} e-mail címe?", "ca": "Quina és l'adreça de correu electrònic de {name}?" }, + "mappings": [ + { + "if": "contact:email~*", + "then": "{contact:email}", + "hideInAnswer": true + } + ], "freeform": { "key": "email", - "type": "email" + "type": "email", + "addExtraTags": ["contact:email="] } }, "website": { @@ -168,8 +184,16 @@ "render": "{website}", "freeform": { "key": "website", - "type": "url" - } + "type": "url", + "addExtraTags": ["contact:website="] + }, + "mappings": [ + { + "if": "contact:website~*", + "then": "{contact:website}", + "hideInAnswer": true + } + ] }, "wheelchair-access": { "question": {