Work on automatically creating an import layer for every feature
This commit is contained in:
parent
f67d0701b0
commit
a65afbbb58
13 changed files with 165 additions and 8 deletions
|
@ -3,7 +3,7 @@ import RelationsTracker from "./RelationsTracker";
|
|||
import {Utils} from "../../Utils";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {BBox} from "../BBox";
|
||||
import osmtogeojson from "osmtogeojson";
|
||||
import * as osmtogeojson from "osmtogeojson";
|
||||
|
||||
/**
|
||||
* Interfaces overpass to get all the latest data
|
||||
|
@ -52,7 +52,8 @@ export class Overpass {
|
|||
}
|
||||
|
||||
self._relationTracker.RegisterRelations(json)
|
||||
const geojson = osmtogeojson.toGeoJSON(json);
|
||||
console.warn("OSMTOGEOJSON:", osmtogeojson)
|
||||
const geojson = osmtogeojson.default(json);
|
||||
const osmTime = new Date(json.osm3s.timestamp_osm_base);
|
||||
return [geojson, osmTime];
|
||||
}
|
||||
|
|
|
@ -117,4 +117,10 @@ export class And extends TagsFilter {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return {
|
||||
and: this.and.map(a => a.AsJson())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,5 +38,9 @@ export default class ComparingTag implements TagsFilter {
|
|||
usedKeys(): string[] {
|
||||
return [this._key];
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return this.asHumanString(false, false, {})
|
||||
}
|
||||
|
||||
}
|
|
@ -65,6 +65,12 @@ export class Or extends TagsFilter {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return {
|
||||
or: this.or.map(o => o.AsJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -109,4 +109,8 @@ export class RegexTag extends TagsFilter {
|
|||
console.error("Cannot export regex tag to asChange; ", this.key, this.value)
|
||||
return []
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return this.asHumanString()
|
||||
}
|
||||
}
|
|
@ -12,7 +12,8 @@ import {TagsFilter} from "./TagsFilter";
|
|||
export default class SubstitutingTag implements TagsFilter {
|
||||
private readonly _key: string;
|
||||
private readonly _value: string;
|
||||
private readonly _invert: boolean
|
||||
private readonly _invert: boolean
|
||||
|
||||
constructor(key: string, value: string, invert = false) {
|
||||
this._key = key;
|
||||
this._value = value;
|
||||
|
@ -59,11 +60,17 @@ private readonly _invert: boolean
|
|||
}
|
||||
|
||||
asChange(properties: any): { k: string; v: string }[] {
|
||||
if(this._invert){throw "An inverted substituting tag can not be used to create a change"}
|
||||
if (this._invert) {
|
||||
throw "An inverted substituting tag can not be used to create a change"
|
||||
}
|
||||
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}];
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return this._key + (this._invert ? '!' : '') + "=" + this._value
|
||||
}
|
||||
}
|
|
@ -83,4 +83,8 @@ export class Tag extends TagsFilter {
|
|||
asChange(properties: any): { k: string; v: string }[] {
|
||||
return [{k: this.key, v: this.value}];
|
||||
}
|
||||
|
||||
AsJson() {
|
||||
return this.asHumanString(false, false)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ export abstract class TagsFilter {
|
|||
|
||||
abstract matchesProperties(properties: any): boolean;
|
||||
|
||||
abstract asHumanString(linkToWiki: boolean, shorten: boolean, properties: any) : string;
|
||||
abstract asHumanString(linkToWiki: boolean, shorten: boolean, properties: any): string;
|
||||
|
||||
abstract usedKeys(): string[];
|
||||
|
||||
|
@ -20,4 +20,5 @@ export abstract class TagsFilter {
|
|||
*/
|
||||
abstract asChange(properties: any): { k: string, v: string }[]
|
||||
|
||||
abstract AsJson() ;
|
||||
}
|
118
Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts
Normal file
118
Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts
Normal file
|
@ -0,0 +1,118 @@
|
|||
import {Conversion, DesugaringContext} from "./LegacyJsonConvert";
|
||||
import LayerConfig from "../LayerConfig";
|
||||
import {LayerConfigJson} from "../Json/LayerConfigJson";
|
||||
import Translations from "../../../UI/i18n/Translations";
|
||||
import {TagsFilter} from "../../../Logic/Tags/TagsFilter";
|
||||
import {Tag} from "../../../Logic/Tags/Tag";
|
||||
import {And} from "../../../Logic/Tags/And";
|
||||
|
||||
export default class CreateNoteImportLayer extends Conversion<LayerConfig, LayerConfigJson> {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
"Advanced conversion which deducts a layer showing all notes that are 'importable' (i.e. a note that contains a link to some MapComplete theme, with hash '#import').",
|
||||
"The import buttons and matches will be based on the presets of the given theme",
|
||||
].join("\n\n"), [])
|
||||
}
|
||||
|
||||
convert(state: DesugaringContext, layer: LayerConfig, context: string): { result: LayerConfigJson; errors: string[]; warnings: string[] } {
|
||||
const errors = []
|
||||
const warnings = []
|
||||
const t = Translations.t.importLayer;
|
||||
|
||||
const possibleTags: TagsFilter[] = layer.presets.map(p => new And(p.tags))
|
||||
|
||||
const result : LayerConfigJson = {
|
||||
"id": "note_import_"+layer.id,
|
||||
"name": t.layerName.Subs({title: layer.title.render}).translations,
|
||||
"description": t.description.Subs({title: layer.title.render}).translations,
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"id~*"
|
||||
]
|
||||
},
|
||||
"geoJson": "https://api.openstreetmap.org/api/0.6/notes.json?closed=0&bbox={x_min},{y_min},{x_max},{y_max}",
|
||||
"geoJsonZoomLevel": 12,
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"minzoom": 10,
|
||||
"title": {
|
||||
"render": t.popupTitle.Subs({title: layer.presets[0].title}).translations
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_first_comment:=feat.get('comments')[0].text.toLowerCase()",
|
||||
"_trigger_index:=(() => {const lines = feat.properties['_first_comment'].split('\\n'); const matchesMapCompleteURL = lines.map(l => l.match(\".*https://mapcomplete.osm.be/\\([a-zA-Z_-]+\\)\\(.html\\).*#import\")); const matchedIndexes = matchesMapCompleteURL.map((doesMatch, i) => [doesMatch !== null, i]).filter(v => v[0]).map(v => v[1]); return matchedIndexes[0] })()",
|
||||
"_intro:=(() => {const lines = feat.properties['_first_comment'].split('\\n'); lines.splice(feat.get('_trigger_index')-1, lines.length); return lines.map(l => l == '' ? '<br/>' : l).join('');})()",
|
||||
"_tags:=(() => {let lines = feat.properties['_first_comment'].split('\\n').map(l => l.trim()); lines.splice(0, feat.get('_trigger_index') + 1); lines = lines.filter(l => l != ''); return lines.join(';');})()"
|
||||
],
|
||||
"isShown": {
|
||||
"render": "no",
|
||||
"mappings": [
|
||||
{
|
||||
"if": {and:
|
||||
["_trigger_index~*",
|
||||
{or: possibleTags.map(tf => tf.AsJson())}
|
||||
]},
|
||||
"then": "yes"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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(comments,1)}"
|
||||
},
|
||||
{
|
||||
"id": "Intro",
|
||||
"render": "{_intro}"
|
||||
},
|
||||
{
|
||||
"id": "import",
|
||||
"render": "{import_button(public_bookcase, _tags, There might be a public bookcase here,./assets/svg/addSmall.svg,,,id)}"
|
||||
},
|
||||
{
|
||||
"id": "close_note_",
|
||||
"render": "{close_note(Does not exist<br/>, ./assets/svg/close.svg, id, This feature does not exist)}"
|
||||
},
|
||||
{
|
||||
"id": "close_note_mapped",
|
||||
"render": "{close_note(Already mapped, ./assets/svg/checkmark.svg, id, Already mapped)}"
|
||||
},
|
||||
{
|
||||
"id": "comment",
|
||||
"render": "{add_note_comment()}"
|
||||
},
|
||||
{
|
||||
"id": "add_image",
|
||||
"render": "{add_image_to_note()}"
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
],
|
||||
"icon": {
|
||||
"render": "teardrop:#3333cc"
|
||||
},
|
||||
"iconSize": "40,40,bottom"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
result,
|
||||
errors, warnings
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@ export interface DesugaringContext {
|
|||
sharedLayers: Map<string, LayerConfigJson>
|
||||
}
|
||||
|
||||
abstract class Conversion<TIn, TOut> {
|
||||
export abstract class Conversion<TIn, TOut> {
|
||||
protected readonly doc: string;
|
||||
public readonly modifiedAttributes: string[];
|
||||
|
||||
|
@ -58,7 +58,7 @@ abstract class Conversion<TIn, TOut> {
|
|||
|
||||
}
|
||||
|
||||
abstract class DesugaringStep<T> extends Conversion<T, T> {
|
||||
export abstract class DesugaringStep<T> extends Conversion<T, T> {
|
||||
}
|
||||
|
||||
class OnEvery<X, T> extends DesugaringStep<T> {
|
||||
|
|
2
Utils.ts
2
Utils.ts
|
@ -262,7 +262,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
const date: Date = el;
|
||||
v = date.toISOString()
|
||||
}
|
||||
|
||||
|
||||
if (useLang !== undefined && v?.translations !== undefined) {
|
||||
v = v.translations[useLang] ?? v.translations["*"] ?? (v.textFor !== undefined ? v.textFor(useLang) : v);
|
||||
}
|
||||
|
|
|
@ -453,5 +453,10 @@
|
|||
"noteLayerHasFilters": "Some notes might be hidden by a filter",
|
||||
"disableAllNoteFilters": "Disable all filters",
|
||||
"noteLayerDoEnable": "Enable the layer showing notes"
|
||||
},
|
||||
"importLayer": {
|
||||
"layerName": "Possible {title}",
|
||||
"description": "A layer which imports entries for {title}",
|
||||
"popupTitle": "Possible {title}"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"generate:polygon-features": "cd assets/ && wget https://raw.githubusercontent.com/tyrasd/osm-polygon-features/master/polygon-features.json --output-document=polygon-features.json",
|
||||
"generate:images": "ts-node scripts/generateIncludedImages.ts",
|
||||
"generate:translations": "ts-node scripts/generateTranslations.ts",
|
||||
"watch:translations": "cd langs && ls | entr npm run generate:translations",
|
||||
"reset:translations": "ts-node scripts/generateTranslations.ts --ignore-weblate",
|
||||
"generate:layouts": "ts-node scripts/generateLayouts.ts",
|
||||
"generate:docs": "ts-node scripts/generateDocs.ts && ts-node scripts/generateTaginfoProjectFiles.ts",
|
||||
|
|
Loading…
Reference in a new issue