forked from MapComplete/MapComplete
Studio: first working version for basic layer properties
This commit is contained in:
parent
5a49677d5a
commit
f18a2b9184
41 changed files with 4446 additions and 852 deletions
|
@ -39,8 +39,9 @@ export class ExtractImages extends Conversion<
|
|||
return (
|
||||
metapath.type?.some(
|
||||
(t) =>
|
||||
t["$ref"] == "#/definitions/TagRenderingConfigJson" ||
|
||||
t["$ref"] == "#/definitions/QuestionableTagRenderingConfigJson"
|
||||
t !== null &&
|
||||
(t["$ref"] == "#/definitions/TagRenderingConfigJson" ||
|
||||
t["$ref"] == "#/definitions/QuestionableTagRenderingConfigJson")
|
||||
) ?? false
|
||||
)
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ export class UpdateLegacyLayer extends DesugaringStep<
|
|||
delete preset["preciseInput"]
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof preset.snapToLayer === "string") {
|
||||
preset.snapToLayer = [preset.snapToLayer]
|
||||
}
|
||||
}
|
||||
|
||||
if (config.tagRenderings !== undefined) {
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
import { TagConfigJson } from "./TagConfigJson"
|
||||
|
||||
export interface DeleteConfigJson {
|
||||
/***
|
||||
* By default, the contributor needs 20 previous changesets to delete points edited by others.
|
||||
* For some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.
|
||||
*
|
||||
* type: nat
|
||||
* question: How many changesets must a contributor have before being allowed to delete a point?
|
||||
*/
|
||||
neededChangesets?: number
|
||||
|
||||
/***
|
||||
* By default, three reasons to delete a point are shown:
|
||||
*
|
||||
|
@ -18,12 +27,17 @@ export interface DeleteConfigJson {
|
|||
*/
|
||||
extraDeleteReasons?: {
|
||||
/**
|
||||
* The text that will be shown to the user - translatable
|
||||
* The text that will be shown to the user as option for why this point does not exist anymore.
|
||||
* Note that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default
|
||||
*
|
||||
* question: For what extra reason might this feature be removed in real-life?
|
||||
*/
|
||||
explanation: string | any
|
||||
/**
|
||||
* The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion
|
||||
* Should be a few words, in english
|
||||
*
|
||||
* question: What should be added to the changeset as delete reason?
|
||||
*/
|
||||
changesetMessage: string
|
||||
}[]
|
||||
|
@ -39,10 +53,14 @@ export interface DeleteConfigJson {
|
|||
/**
|
||||
* The tags that will be given to the object.
|
||||
* This must remove tags so that the 'source/osmTags' won't match anymore
|
||||
*
|
||||
* question: What tags should be applied to the object?
|
||||
*/
|
||||
if: TagConfigJson
|
||||
/**
|
||||
* The human explanation for the options
|
||||
*
|
||||
* question: What text should be shown to the contributor for this reason?
|
||||
*/
|
||||
then: string | any
|
||||
}[]
|
||||
|
@ -53,6 +71,7 @@ export interface DeleteConfigJson {
|
|||
* It is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!
|
||||
*
|
||||
* Example (note that "amenity=" erases the 'amenity'-key alltogether):
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* "and": ["disussed:amenity=public_bookcase", "amenity="]
|
||||
|
@ -60,22 +79,26 @@ export interface DeleteConfigJson {
|
|||
* ```
|
||||
*
|
||||
* or (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* "and": ["disused:shop:={shop}", "shop="]
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* question: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?
|
||||
* type: tag
|
||||
*/
|
||||
softDeletionTags?: TagConfigJson
|
||||
/***
|
||||
* By default, the contributor needs 20 previous changesets to delete points edited by others.
|
||||
* For some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.
|
||||
*/
|
||||
neededChangesets?: number
|
||||
|
||||
/**
|
||||
* Set this flag if the default delete reasons should be omitted from the dialog.
|
||||
* This requires at least one extraDeleteReason or nonDeleteMapping
|
||||
*
|
||||
* question: Should the default delete reasons be hidden?
|
||||
* iftrue: Hide the default delete reasons
|
||||
* iffalse: Show the default delete reasons
|
||||
* ifunset: Show the default delete reasons (default behaviour)
|
||||
*/
|
||||
omitDefaultDeleteReasons?: false | boolean
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface LayerConfigJson {
|
|||
* The id of this layer.
|
||||
* This should be a simple, lowercase, human readable string that is used to identify the layer.
|
||||
*
|
||||
* group: basic
|
||||
* group: Basic
|
||||
* question: What is the identifier of this layer?
|
||||
*/
|
||||
id: string
|
||||
|
@ -27,7 +27,7 @@ export interface LayerConfigJson {
|
|||
*
|
||||
* ifunset: This will hide the layer in the layer control, making it not filterable and not toggleable
|
||||
*
|
||||
* group: basic
|
||||
* group: Basic
|
||||
* question: What is the name of this layer?
|
||||
*/
|
||||
name?: string | Record<string, string>
|
||||
|
@ -36,7 +36,7 @@ export interface LayerConfigJson {
|
|||
* A description for the features shown in this layer.
|
||||
* This often resembles the introduction of the wiki.osm.org-page for this feature.
|
||||
*
|
||||
* group: basic
|
||||
* group: Basic
|
||||
* question: How would you describe the features that are shown on this layer?
|
||||
*/
|
||||
description?: string | Record<string, string>
|
||||
|
@ -54,7 +54,8 @@ export interface LayerConfigJson {
|
|||
* Note: a source must always be defined. 'special' is only allowed if this is a builtin-layer
|
||||
*
|
||||
* types: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;
|
||||
* group: basic
|
||||
* typesdefault: 0
|
||||
* group: Basic
|
||||
*/
|
||||
source:
|
||||
| "special"
|
||||
|
@ -71,6 +72,7 @@ export interface LayerConfigJson {
|
|||
* The maximum amount of seconds that a tile is allowed to linger in the cache
|
||||
*
|
||||
* type: nat
|
||||
* default: 30 days
|
||||
*/
|
||||
maxCacheAge?: number
|
||||
}
|
||||
|
@ -128,45 +130,31 @@ export interface LayerConfigJson {
|
|||
* "_some_key:=some_javascript_expression"
|
||||
* ]
|
||||
*
|
||||
* group: advanced
|
||||
* See the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]
|
||||
*
|
||||
* group: expert
|
||||
* question: What extra attributes should be calculated with javascript?
|
||||
*
|
||||
*/
|
||||
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.
|
||||
* Works well together with 'passAllFeatures', to add decoration
|
||||
*
|
||||
* group: advanced
|
||||
*/
|
||||
doNotDownload?: boolean
|
||||
|
||||
/**
|
||||
* If set, only features matching this extra tag will be shown.
|
||||
* This is useful to hide certain features from view.
|
||||
*
|
||||
* The default value is 'yes'
|
||||
* This is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.
|
||||
*
|
||||
* question: What other tags should features match for being shown?
|
||||
* group: advanced
|
||||
* ifunset: all features which match the 'source'-specification are shown.
|
||||
*/
|
||||
isShown?: TagConfigJson
|
||||
|
||||
/**
|
||||
* Advanced option - might be set by the theme compiler
|
||||
*
|
||||
* If true, this data will _always_ be loaded, even if the theme is disabled
|
||||
*
|
||||
* group: advanced
|
||||
*/
|
||||
forceLoad?: false | boolean
|
||||
|
||||
/**
|
||||
* The minimum needed zoomlevel required to start loading and displaying the data.
|
||||
* This can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).
|
||||
* This prevents cluttering the map with thousands of parkings if one is looking to an entire city.
|
||||
*
|
||||
* Default: 0
|
||||
* group: basic
|
||||
* group: Basic
|
||||
* type: nat
|
||||
* question: At what zoom level should features of the layer be shown?
|
||||
* ifunset: Always load this layer, even if the entire world is in view.
|
||||
|
@ -175,8 +163,12 @@ export interface LayerConfigJson {
|
|||
|
||||
/**
|
||||
* Indicates if this layer is shown by default;
|
||||
* can be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)
|
||||
* can be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)
|
||||
*
|
||||
* question: Should this layer be enabled when opening the map for the first time?
|
||||
* iftrue: the layer is enabled when opening the map
|
||||
* iffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)
|
||||
* default: true
|
||||
* group: advanced
|
||||
*/
|
||||
shownByDefault?: true | boolean
|
||||
|
@ -185,7 +177,7 @@ export interface LayerConfigJson {
|
|||
* The zoom level at which point the data is hidden again
|
||||
* Default: 100 (thus: always visible
|
||||
*
|
||||
* group: advanced
|
||||
* group: expert
|
||||
*/
|
||||
minzoomVisible?: number
|
||||
|
||||
|
@ -196,6 +188,19 @@ export interface LayerConfigJson {
|
|||
*/
|
||||
title?: string | TagRenderingConfigJson
|
||||
|
||||
/**
|
||||
*
|
||||
* Question: Should the information for this layer be shown in the sidebar or in a splash screen?
|
||||
*
|
||||
* If set, open the selectedElementView in a floatOver instead of on the right.
|
||||
*
|
||||
* iftrue: show the infobox in the splashscreen floating over the entire UI
|
||||
* iffalse: show the infobox in a sidebar on the right
|
||||
* group: advanced
|
||||
* default: sidebar
|
||||
*/
|
||||
popupInFloatover?: boolean
|
||||
|
||||
/**
|
||||
* Small icons shown next to the title.
|
||||
* If not specified, the OsmLink and wikipedia links will be used by default.
|
||||
|
@ -228,11 +233,40 @@ 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. directions on cameras
|
||||
*
|
||||
* group: advanced
|
||||
* iftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers
|
||||
* iffalse: normal behaviour: don't pass features allong
|
||||
* question: should this layer pass features to the next layers?
|
||||
* group: expert
|
||||
*/
|
||||
passAllFeatures?: boolean
|
||||
|
||||
/**
|
||||
* 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
|
||||
* The opposite of `forceLoad`
|
||||
*
|
||||
* iftrue: Do not attempt to query the data for this layer from overpass/the OSM API
|
||||
* iffalse: download the data as usual
|
||||
* group: expert
|
||||
* question: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?
|
||||
* default: false
|
||||
*/
|
||||
doNotDownload?: boolean
|
||||
|
||||
/**
|
||||
* Advanced option - might be set by the theme compiler
|
||||
*
|
||||
* If true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.
|
||||
* The opposite of `doNotDownload`
|
||||
*
|
||||
* question: Should this layer be forcibly loaded?
|
||||
* ifftrue: always download this layer, even if it is disabled
|
||||
* iffalse: only download data for this layer when needed (default)
|
||||
* default: false
|
||||
* group: expert
|
||||
*/
|
||||
forceLoad?: false | boolean
|
||||
|
||||
/**
|
||||
* Presets for this layer.
|
||||
* A preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);
|
||||
|
@ -246,7 +280,7 @@ export interface LayerConfigJson {
|
|||
* 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
|
||||
*
|
||||
* group: basic
|
||||
* group: presets
|
||||
*/
|
||||
presets?: {
|
||||
/**
|
||||
|
@ -290,9 +324,16 @@ export interface LayerConfigJson {
|
|||
exampleImages?: string[]
|
||||
|
||||
/**
|
||||
* If specified, these layers will be shown to and the new point will be snapped towards it
|
||||
* question: Should the created point be snapped to a line layer?
|
||||
*
|
||||
* If specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.
|
||||
* For example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)
|
||||
* or to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.
|
||||
*
|
||||
* suggestions: return Array.from(layers.keys()).map(key => ({if: "value="+key, then: key+" - "+layers.get(key).description}))
|
||||
*/
|
||||
snapToLayer?: string | string[]
|
||||
snapToLayer?: string[]
|
||||
|
||||
/**
|
||||
* If specified, a new point will only be snapped if it is within this range.
|
||||
* Distance in meter
|
||||
|
@ -362,62 +403,70 @@ export interface LayerConfigJson {
|
|||
* - undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future
|
||||
* - or: a hash with options (see below)
|
||||
*
|
||||
* The delete dialog
|
||||
* =================
|
||||
* ### The delete dialog
|
||||
*
|
||||
*
|
||||
*
|
||||
#### Hard deletion if enough experience
|
||||
* #### Hard deletion if enough experience
|
||||
|
||||
A feature can only be deleted from OpenStreetMap by mapcomplete if:
|
||||
* A feature can only be deleted from OpenStreetMap by mapcomplete if:
|
||||
|
||||
- It is a node
|
||||
- No ways or relations use the node
|
||||
- The logged-in user has enough experience OR the user is the only one to have edited the point previously
|
||||
- The logged-in user has no unread messages (or has a ton of experience)
|
||||
- The user did not select one of the 'non-delete-options' (see below)
|
||||
|
||||
In all other cases, a 'soft deletion' is used.
|
||||
|
||||
#### Soft deletion
|
||||
|
||||
A 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.
|
||||
This makes it look like it was deleted, without doing damage. A fixme will be added to the point.
|
||||
|
||||
Note that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme
|
||||
|
||||
#### No-delete options
|
||||
|
||||
In some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed "because the path is on their private property").
|
||||
However, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice "hey, there is a path missing here! Let me redraw it in OSM!)
|
||||
|
||||
The correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.
|
||||
A no-delete option is offered as 'reason to delete it', but secretly retags.
|
||||
|
||||
group: editing
|
||||
|
||||
*/
|
||||
deletion?: boolean | DeleteConfigJson
|
||||
* - It is a node
|
||||
* - No ways or relations use the node
|
||||
* - The logged-in user has enough experience OR the user is the only one to have edited the point previously
|
||||
* - The logged-in user has no unread messages (or has a ton of experience)
|
||||
* - The user did not select one of the 'non-delete-options' (see below)
|
||||
*
|
||||
* In all other cases, a 'soft deletion' is used.
|
||||
*
|
||||
* #### Soft deletion
|
||||
*
|
||||
* A 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.
|
||||
* This makes it look like it was deleted, without doing damage. A fixme will be added to the point.
|
||||
*
|
||||
* Note that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme
|
||||
*
|
||||
* ##### No-delete options
|
||||
*
|
||||
* In some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed "because the path is on their private property").
|
||||
* However, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice "hey, there is a path missing here! Let me redraw it in OSM!)
|
||||
*
|
||||
* The correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.
|
||||
* A no-delete option is offered as 'reason to delete it', but secretly retags.
|
||||
*
|
||||
* group: editing
|
||||
* types: use an advanced delete configuration ; boolean
|
||||
* iftrue: Allow deletion
|
||||
* iffalse: Do not allow deletion
|
||||
*
|
||||
**/
|
||||
deletion?: DeleteConfigJson | boolean
|
||||
|
||||
/**
|
||||
* Indicates if a point can be moved and configures the modalities.
|
||||
* Indicates if a point can be moved and why.
|
||||
*
|
||||
* A feature can be moved by MapComplete if:
|
||||
*
|
||||
* - It is a point
|
||||
* - The point is _not_ part of a way or a a relation.
|
||||
*
|
||||
* Off by default. Can be enabled by setting this flag or by configuring.
|
||||
*
|
||||
* types: use an advanced move configuration ; boolean
|
||||
* group: editing
|
||||
* question: Is deleting a point allowed?
|
||||
* iftrue: Allow contributors to move a point (for accuracy or a relocation)
|
||||
* iffalse: Don't allow contributors to move points
|
||||
* ifunset: Don't allow contributors to move points (default)
|
||||
*/
|
||||
allowMove?: boolean | MoveConfigJson
|
||||
allowMove?: MoveConfigJson | boolean
|
||||
|
||||
/**
|
||||
* If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.
|
||||
*
|
||||
* If the way is part of a relation, MapComplete will attempt to update this relation as well
|
||||
*
|
||||
* question: Should the contributor be able to split ways using this layer?
|
||||
* iftrue: enable the 'split-roads'-component
|
||||
* iffalse: don't enable the split-roads componenet
|
||||
* ifunset: don't enable the split-roads component
|
||||
* group: editing
|
||||
*/
|
||||
allowSplit?: boolean
|
||||
|
@ -432,12 +481,9 @@ export interface LayerConfigJson {
|
|||
/**
|
||||
* If set, synchronizes whether or not this layer is enabled.
|
||||
*
|
||||
* no: Do not sync at all, always revert to default
|
||||
* local: keep selection on local storage
|
||||
* theme-only: sync via OSM, but this layer will only be toggled in this theme
|
||||
* global: all layers with this ID will be synced accross all themes
|
||||
*
|
||||
* group: advanced
|
||||
* question: Should enabling/disabling the layer be saved (locally or in the cloud)?
|
||||
* suggestions: return [{if: "value=no", then: "Don't save, always revert to the default"}, {if: "value=local", then: "Save selection in local storage"}, {if: "value=theme-only", then: "Save the state in the OSM-usersettings, but apply on this theme only (default)"}, {if: "value=global", then: "Save in OSM-usersettings and toggle on _all_ themes using this layer"}]
|
||||
*/
|
||||
syncSelection?: "no" | "local" | "theme-only" | "global"
|
||||
|
||||
|
@ -446,17 +492,10 @@ export interface LayerConfigJson {
|
|||
*
|
||||
* no-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering
|
||||
*
|
||||
* group: special
|
||||
* group: hidden
|
||||
*/
|
||||
"#"?: string | "no-question-hint-check"
|
||||
|
||||
/**
|
||||
* If set, open the selectedElementView in a floatOver instead of on the right
|
||||
*
|
||||
* group: advanced
|
||||
*/
|
||||
popupInFloatover?: boolean
|
||||
|
||||
/**
|
||||
* _Set automatically by MapComplete, please ignore_
|
||||
*
|
||||
|
|
|
@ -109,7 +109,7 @@ export interface MappingConfigJson {
|
|||
* {
|
||||
* "if": "crossing:marking=rainbow",
|
||||
* "then": "This is a rainbow crossing",
|
||||
* "addExtraTags": "not:crossing:marking="
|
||||
* "addExtraTags": ["not:crossing:marking="]
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
|
|
|
@ -238,13 +238,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
throw "Layer " + this.id + " still uses the old 'preciseInput'-field"
|
||||
}
|
||||
if (pr.snapToLayer !== undefined) {
|
||||
let snapToLayers: string[]
|
||||
if (typeof pr.snapToLayer === "string") {
|
||||
snapToLayers = [pr.snapToLayer]
|
||||
} else {
|
||||
snapToLayers = pr.snapToLayer
|
||||
}
|
||||
|
||||
let snapToLayers = pr.snapToLayer
|
||||
preciseInput = {
|
||||
snapToLayers,
|
||||
maxSnapDistance: pr.maxSnapDistance ?? 10,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue