forked from MapComplete/MapComplete
Merge branches
This commit is contained in:
commit
bae90d50bc
304 changed files with 49983 additions and 31589 deletions
|
@ -167,7 +167,7 @@ export class Denomination {
|
|||
* Returns null if it doesn't match this unit
|
||||
*/
|
||||
public StrippedValue(value: string, actAsDefault: boolean, inverted: boolean): string {
|
||||
if (value === undefined) {
|
||||
if (value === undefined || value === "") {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ export class Denomination {
|
|||
if (self.prefix) {
|
||||
return value.substring(key.length).trim()
|
||||
}
|
||||
let trimmed = value.substring(0, value.length - key.length).trim()
|
||||
let trimmed = value.substring(0, value.length - key.length).trim()
|
||||
if(!inverted){
|
||||
return trimmed
|
||||
}
|
||||
|
|
|
@ -100,6 +100,11 @@ export class MenuState {
|
|||
})
|
||||
|
||||
this.allToggles = [
|
||||
{
|
||||
toggle: this.privacyPanelIsOpened,
|
||||
name: "privacy",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.menuIsOpened,
|
||||
name: "menu",
|
||||
|
@ -120,11 +125,6 @@ export class MenuState {
|
|||
name: "community",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.privacyPanelIsOpened,
|
||||
name: "privacy",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.filtersPanelIsOpened,
|
||||
name: "filters",
|
||||
|
|
|
@ -258,11 +258,11 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[
|
|||
}
|
||||
}
|
||||
|
||||
let renderings = Array.isArray(rewrite.renderings)
|
||||
const renderings = Array.isArray(rewrite.renderings)
|
||||
? rewrite.renderings
|
||||
: [rewrite.renderings]
|
||||
for (let i = 0; i < keysToRewrite.into.length; i++) {
|
||||
let ts: T[] = <T[]>Utils.Clone(renderings)
|
||||
const ts: T[] = <T[]>Utils.Clone(renderings)
|
||||
for (const tx of ts) {
|
||||
let t = <T>tx
|
||||
const sourceKeysToIgnore: string[] = []
|
||||
|
|
|
@ -161,7 +161,9 @@ class ExpandTagRendering extends Conversion<
|
|||
private readonly _options: {
|
||||
/* If true, will copy the 'osmSource'-tags into the condition */
|
||||
applyCondition?: true | boolean
|
||||
noHardcodedStrings?: false | boolean
|
||||
noHardcodedStrings?: false | boolean,
|
||||
addToContext?: false | boolean
|
||||
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
@ -169,11 +171,13 @@ class ExpandTagRendering extends Conversion<
|
|||
self: LayerConfigJson,
|
||||
options?: {
|
||||
applyCondition?: true | boolean
|
||||
noHardcodedStrings?: false | boolean
|
||||
noHardcodedStrings?: false | boolean,
|
||||
// If set, a question will be added to the 'sharedTagRenderings'. Should only be used for 'questions.json'
|
||||
addToContext?: false | boolean
|
||||
}
|
||||
) {
|
||||
super(
|
||||
"Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question",
|
||||
"Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins",
|
||||
[],
|
||||
"ExpandTagRendering"
|
||||
)
|
||||
|
@ -204,8 +208,17 @@ class ExpandTagRendering extends Conversion<
|
|||
if (typeof tr === "string" || tr["builtin"] !== undefined) {
|
||||
const stable = this.convert(tr, ctx.inOperation("recursive_resolve"))
|
||||
result.push(...stable)
|
||||
if(this._options?.addToContext){
|
||||
for (const tr of stable) {
|
||||
this._state.tagRenderings?.set(tr.id, tr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.push(tr)
|
||||
if(this._options?.addToContext){
|
||||
this._state.tagRenderings?.set(tr["id"], <QuestionableTagRenderingConfigJson> tr)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +233,7 @@ class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
const result: TagRenderingConfigJson[] = []
|
||||
for (const tagRenderingConfigJson of direct) {
|
||||
let nm: string | string[] | undefined = tagRenderingConfigJson["builtin"]
|
||||
const nm: string | string[] | undefined = tagRenderingConfigJson["builtin"]
|
||||
if (nm !== undefined) {
|
||||
let indirect: TagRenderingConfigJson[]
|
||||
if (typeof nm === "string") {
|
||||
|
@ -1261,12 +1274,14 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
|
||||
export class PrepareLayer extends Fuse<LayerConfigJson> {
|
||||
constructor(state: DesugaringContext) {
|
||||
constructor(state: DesugaringContext, options?: {addTagRenderingsToContext?: false | boolean}) {
|
||||
super(
|
||||
"Fully prepares and expands a layer for the LayerConfig.",
|
||||
new On("tagRenderings", new Each(new RewriteSpecial())),
|
||||
new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
|
||||
new On("tagRenderings", (layer) => new Concat(new ExpandTagRendering(state, layer))),
|
||||
new On("tagRenderings", (layer) => new Concat(new ExpandTagRendering(state, layer, {
|
||||
addToContext: options?.addTagRenderingsToContext ?? false
|
||||
}))),
|
||||
new On("tagRenderings", new Each(new DetectInline())),
|
||||
new AddQuestionBox(),
|
||||
new AddEditingElements(state),
|
||||
|
|
|
@ -562,6 +562,65 @@ export class DetectNonErasedKeysInMappings extends DesugaringStep<QuestionableTa
|
|||
}
|
||||
}
|
||||
|
||||
export class DetectMappingsShadowedByCondition extends DesugaringStep<TagRenderingConfigJson> {
|
||||
private readonly _forceError: boolean
|
||||
|
||||
constructor(forceError: boolean = false) {
|
||||
super("Checks that, if the tagrendering has a condition, that a mapping is not contradictory to it, i.e. that there are no dead mappings", [], "DetectMappingsShadowedByCondition")
|
||||
this._forceError = forceError
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* const validator = new DetectMappingsShadowedByCondition(true)
|
||||
* const ctx = ConversionContext.construct([],["test"])
|
||||
* validator.convert({
|
||||
* condition: "count>0",
|
||||
* mappings:[
|
||||
* {
|
||||
* if: "count=0",
|
||||
* then:{
|
||||
* en: "No count"
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }, ctx)
|
||||
* ctx.hasErrors() // => true
|
||||
*/
|
||||
convert(json: TagRenderingConfigJson, context: ConversionContext): TagRenderingConfigJson {
|
||||
if(!json.condition && !json.metacondition){
|
||||
return json
|
||||
}
|
||||
if(!json.mappings || json.mappings?.length ==0){
|
||||
return json
|
||||
}
|
||||
let conditionJson = json.condition ?? json.metacondition
|
||||
if(json.condition !== undefined && json.metacondition !== undefined){
|
||||
conditionJson = {and: [json.condition, json.metacondition]}
|
||||
}
|
||||
const condition = TagUtils.Tag(conditionJson, context.path.join("."))
|
||||
|
||||
for (let i = 0; i < json.mappings.length; i++){
|
||||
const mapping = json.mappings[i]
|
||||
const tagIf = TagUtils.Tag(mapping.if, context.path.join("."))
|
||||
const optimized = new And([tagIf, condition]).optimize()
|
||||
if(optimized === false){
|
||||
const msg = ("Detected a conflicting mapping and condition. The mapping requires tags " + tagIf.asHumanString() + ", yet this can never happen because the set condition requires " + condition.asHumanString())
|
||||
const ctx = context.enters("mappings", i)
|
||||
if (this._forceError) {
|
||||
ctx.err(msg)
|
||||
} else {
|
||||
ctx.warn(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DetectShadowedMappings extends DesugaringStep<TagRenderingConfigJson> {
|
||||
private readonly _calculatedTagNames: string[]
|
||||
|
||||
|
@ -1088,6 +1147,8 @@ export class ValidateTagRenderings extends Fuse<TagRenderingConfigJson> {
|
|||
"Various validation on tagRenderingConfigs",
|
||||
new MiscTagRenderingChecks(),
|
||||
new DetectShadowedMappings(layerConfig),
|
||||
|
||||
new DetectMappingsShadowedByCondition(),
|
||||
new DetectConflictingAddExtraTags(),
|
||||
// TODO enable new DetectNonErasedKeysInMappings(),
|
||||
new DetectMappingsWithImages(doesImageExist),
|
||||
|
|
|
@ -554,4 +554,15 @@ export interface LayerConfigJson {
|
|||
* group: hidden
|
||||
*/
|
||||
fullNodeDatabase?: boolean
|
||||
|
||||
/**
|
||||
* question: Should a theme using this layer leak some location info when making changes?
|
||||
*
|
||||
* When a changeset is made, a 'distance to object'-class is written to the changeset.
|
||||
* For some particular themes and layers, this might leak too much information, and we want to obfuscate this
|
||||
*
|
||||
* ifunset: Write 'change_within_x_m' as usual and if GPS is enabled
|
||||
* iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey
|
||||
*/
|
||||
enableMorePrivacy?: boolean
|
||||
}
|
||||
|
|
|
@ -439,4 +439,16 @@ export interface LayoutConfigJson {
|
|||
* group: hidden
|
||||
*/
|
||||
enableNodeDatabase?: boolean
|
||||
|
||||
/**
|
||||
* question: Should this theme leak some location info when making changes?
|
||||
*
|
||||
* When a changeset is made, a 'distance to object'-class is written to the changeset.
|
||||
* For some particular themes and layers, this might leak too much information, and we want to obfuscate this
|
||||
*
|
||||
* ifunset: Write 'change_within_x_m' as usual and if GPS is enabled
|
||||
* iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey
|
||||
*/
|
||||
enableMorePrivacy: boolean
|
||||
|
||||
}
|
||||
|
|
|
@ -229,6 +229,7 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
|||
* A (translated) text that is shown (as gray text) within the textfield
|
||||
* type: translation
|
||||
* group: expert
|
||||
* ifunset: No specific placeholder is set, show the type of the textfield
|
||||
*/
|
||||
placeholder?: Translatable
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ export interface TagRenderingConfigJson {
|
|||
*
|
||||
* question: When should this item be shown?
|
||||
* type: tag
|
||||
* ifunset: No specific condition set; always show this tagRendering or ask the question if unkown
|
||||
* ifunset: No specific condition set; always show this tagRendering or show this question if unknown
|
||||
*
|
||||
* Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.
|
||||
*
|
||||
|
@ -132,9 +132,10 @@ export interface TagRenderingConfigJson {
|
|||
|
||||
/** question: When should this item be shown (including special conditions)?
|
||||
* type: tag
|
||||
* ifunset: No specific metacondition set which is evaluated against the <i>usersettings/application state</i>; always show this tagRendering or show this question if unknown
|
||||
*
|
||||
* If set, this tag will be evaluated agains the _usersettings/application state_ table.
|
||||
* Enable 'show debug info' in user settings to see available options.
|
||||
* If set, this tag will be evaluated against the _usersettings/application state_ table.
|
||||
* Enable 'show debug info' in user settings to see available options (at the settings-tab).
|
||||
* Note that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_
|
||||
*/
|
||||
metacondition?: TagConfigJson
|
||||
|
|
|
@ -67,6 +67,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
|
||||
public readonly _needsFullNodeDatabase: boolean
|
||||
public readonly popupInFloatover: boolean | string
|
||||
public readonly enableMorePrivacy: boolean
|
||||
|
||||
constructor(json: LayerConfigJson, context?: string, official: boolean = true) {
|
||||
context = context + "." + json.id
|
||||
|
@ -149,6 +150,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
this.shownByDefault = json.shownByDefault ?? true
|
||||
this.doCount = json.isCounted ?? this.shownByDefault ?? true
|
||||
this.forceLoad = json.forceLoad ?? false
|
||||
this.enableMorePrivacy = json.enableMorePrivacy ?? false
|
||||
if (json.presets === null) json.presets = undefined
|
||||
if (json.presets !== undefined && json.presets?.map === undefined) {
|
||||
throw "Presets should be a list of items (at " + context + ")"
|
||||
|
|
|
@ -63,6 +63,8 @@ export default class LayoutConfig implements LayoutInformation {
|
|||
public readonly enableExportButton: boolean
|
||||
public readonly enablePdfDownload: boolean
|
||||
public readonly enableTerrain: boolean
|
||||
public readonly enableMorePrivacy: boolean
|
||||
|
||||
|
||||
public readonly customCss?: string
|
||||
|
||||
|
@ -204,6 +206,7 @@ export default class LayoutConfig implements LayoutInformation {
|
|||
this.overpassTimeout = json.overpassTimeout ?? 30
|
||||
this.overpassMaxZoom = json.overpassMaxZoom ?? 16
|
||||
this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1
|
||||
this.enableMorePrivacy = json.enableMorePrivacy || json.layers.some(l => (<LayerConfigJson> l).enableMorePrivacy)
|
||||
|
||||
this.layersDict = new Map<string, LayerConfig>()
|
||||
for (const layer of this.layers) {
|
||||
|
|
|
@ -69,6 +69,7 @@ import {
|
|||
import summaryLayer from "../assets/generated/layers/summary.json"
|
||||
import { LayerConfigJson } from "./ThemeConfig/Json/LayerConfigJson"
|
||||
import Locale from "../UI/i18n/Locale"
|
||||
import Hash from "../Logic/Web/Hash"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -265,6 +266,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
featurePropertiesStore: this.featureProperties,
|
||||
osmConnection: this.osmConnection,
|
||||
historicalUserLocations: this.geolocation.historicalUserLocations,
|
||||
featureSwitches: this.featureSwitches
|
||||
},
|
||||
layout?.isLeftRightSensitive() ?? false
|
||||
)
|
||||
|
@ -495,6 +497,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||
Utils.LoadCustomCss(this.layout.customCss)
|
||||
}
|
||||
|
||||
Hash.hash.addCallbackAndRunD(hash => {
|
||||
if(hash === "current_view" || hash.match(/current_view_[0-9]+/)){
|
||||
this.selectCurrentView()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -820,4 +828,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
this.userRelatedState.preferredBackgroundLayer
|
||||
)
|
||||
}
|
||||
|
||||
public selectCurrentView(){
|
||||
this.guistate.closeAll()
|
||||
this.selectedElement.setData(this.currentView.features?.data?.[0])
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue