forked from MapComplete/MapComplete
Add custom javascript snippets to calculate tags
This commit is contained in:
parent
3e130ebe80
commit
f124d9ded7
17 changed files with 799 additions and 14649 deletions
|
@ -28,6 +28,7 @@ export default class LayerConfig {
|
|||
name: Translation
|
||||
description: Translation;
|
||||
source: SourceConfig;
|
||||
calculatedTags: [string, string][]
|
||||
doNotDownload: boolean;
|
||||
passAllFeatures: boolean;
|
||||
minzoom: number;
|
||||
|
@ -51,8 +52,9 @@ export default class LayerConfig {
|
|||
}[];
|
||||
|
||||
tagRenderings: TagRenderingConfig [];
|
||||
|
||||
|
||||
constructor(json: LayerConfigJson,
|
||||
official: boolean= true,
|
||||
context?: string) {
|
||||
context = context + "." + json.id;
|
||||
const self = this;
|
||||
|
@ -65,9 +67,9 @@ export default class LayerConfig {
|
|||
// @ts-ignore
|
||||
legacy = FromJSON.Tag(json["overpassTags"], context + ".overpasstags");
|
||||
}
|
||||
if(json.source !== undefined){
|
||||
if (legacy !== undefined ) {
|
||||
throw context+"Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined"
|
||||
if (json.source !== undefined) {
|
||||
if (legacy !== undefined) {
|
||||
throw context + "Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined"
|
||||
}
|
||||
|
||||
let osmTags: TagsFilter = legacy;
|
||||
|
@ -81,15 +83,22 @@ export default class LayerConfig {
|
|||
geojsonSource: json.source["geoJsonSource"],
|
||||
overpassScript: json.source["overpassScript"],
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
this.source = new SourceConfig({
|
||||
osmTags : legacy
|
||||
osmTags: legacy
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
this.calculatedTags = undefined;
|
||||
if (json.calculatedTags !== undefined) {
|
||||
console.warn("Unofficial theme with custom javascript! This is a security risk")
|
||||
this.calculatedTags = [];
|
||||
for (const key in json.calculatedTags) {
|
||||
this.calculatedTags.push([key, json.calculatedTags[key]])
|
||||
}
|
||||
}
|
||||
|
||||
this.doNotDownload = json.doNotDownload ?? false;
|
||||
this.passAllFeatures = json.passAllFeatures ?? false;
|
||||
this.minzoom = json.minzoom ?? 0;
|
||||
|
@ -139,10 +148,10 @@ export default class LayerConfig {
|
|||
if (typeof renderingJson === "string") {
|
||||
|
||||
if (renderingJson === "questions") {
|
||||
if(readOnly){
|
||||
if (readOnly) {
|
||||
throw `A tagrendering has a question, but asking a question does not make sense here: is it a title icon or a geojson-layer? ${context}`
|
||||
}
|
||||
|
||||
|
||||
return new TagRenderingConfig("questions", undefined)
|
||||
}
|
||||
|
||||
|
@ -203,6 +212,13 @@ export default class LayerConfig {
|
|||
|
||||
}
|
||||
|
||||
public CustomCodeSnippets(): string[]{
|
||||
if(this.calculatedTags === undefined){
|
||||
return []
|
||||
}
|
||||
|
||||
return this.calculatedTags.map(code => code[1]);
|
||||
}
|
||||
|
||||
public AddRoamingRenderings(addAll: {
|
||||
tagRenderings: TagRenderingConfig[],
|
||||
|
|
|
@ -41,6 +41,11 @@ export interface LayerConfigJson {
|
|||
*/
|
||||
source: {osmTags: AndOrTagConfigJson | string} | {geoJsonSource: string} | {overpassScript: string}
|
||||
|
||||
/**
|
||||
* A dictionary of 'key': 'js-expression'. These js-expressions will be calculated for every feature, giving extra tags to work with in the rest of the pipieline
|
||||
*/
|
||||
calculatedTags? : any;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -31,7 +31,7 @@ export default class LayoutConfig {
|
|||
};
|
||||
|
||||
public readonly hideFromOverview: boolean;
|
||||
public readonly lockLocation: boolean | [[number,number],[number, number]];
|
||||
public readonly lockLocation: boolean | [[number, number], [number, number]];
|
||||
public readonly enableUserBadge: boolean;
|
||||
public readonly enableShareScreen: boolean;
|
||||
public readonly enableMoreQuests: boolean;
|
||||
|
@ -39,10 +39,12 @@ export default class LayoutConfig {
|
|||
public readonly enableLayers: boolean;
|
||||
public readonly enableSearch: boolean;
|
||||
public readonly enableGeolocation: boolean;
|
||||
private readonly _official : boolean;
|
||||
public readonly enableBackgroundLayerSelection: boolean;
|
||||
public readonly customCss?: string;
|
||||
|
||||
constructor(json: LayoutConfigJson, context?: string) {
|
||||
constructor(json: LayoutConfigJson, official=true, context?: string) {
|
||||
this._official = official;
|
||||
this.id = json.id;
|
||||
context = (context ?? "") + "." + this.id;
|
||||
this.maintainer = json.maintainer;
|
||||
|
@ -54,7 +56,7 @@ export default class LayoutConfig {
|
|||
} else {
|
||||
this.language = json.language;
|
||||
}
|
||||
if(this.language.length == 0){
|
||||
if (this.language.length == 0) {
|
||||
throw "No languages defined. Define at least one language"
|
||||
}
|
||||
if (json.title === undefined) {
|
||||
|
@ -66,7 +68,7 @@ export default class LayoutConfig {
|
|||
this.title = new Translation(json.title, context + ".title");
|
||||
this.description = new Translation(json.description, context + ".description");
|
||||
this.shortDescription = json.shortDescription === undefined ? this.description.FirstSentence() : new Translation(json.shortDescription, context + ".shortdescription");
|
||||
this.descriptionTail = json.descriptionTail === undefined ? new Translation({"*": ""}, context+".descriptionTail") : new Translation(json.descriptionTail, context + ".descriptionTail");
|
||||
this.descriptionTail = json.descriptionTail === undefined ? new Translation({"*": ""}, context + ".descriptionTail") : new Translation(json.descriptionTail, context + ".descriptionTail");
|
||||
this.icon = json.icon;
|
||||
this.socialImage = json.socialImage;
|
||||
this.startZoom = json.startZoom;
|
||||
|
@ -79,7 +81,7 @@ export default class LayoutConfig {
|
|||
return SharedTagRenderings.SharedTagRendering[tr];
|
||||
}
|
||||
}
|
||||
return new TagRenderingConfig(tr, undefined,`${this.id}.roaming_renderings[${i}]`);
|
||||
return new TagRenderingConfig(tr, undefined, `${this.id}.roaming_renderings[${i}]`);
|
||||
}
|
||||
);
|
||||
this.defaultBackgroundId = json.defaultBackgroundId;
|
||||
|
@ -104,32 +106,31 @@ export default class LayoutConfig {
|
|||
}
|
||||
|
||||
// @ts-ignore
|
||||
return new LayerConfig(layer, `${this.id}.layers[${i}]`)
|
||||
return new LayerConfig(layer, official,`${this.id}.layers[${i}]`)
|
||||
});
|
||||
|
||||
|
||||
// ALl the layers are constructed, let them share tags in now!
|
||||
const roaming : {r, source: LayerConfig}[] = []
|
||||
const roaming: { r, source: LayerConfig }[] = []
|
||||
for (const layer of this.layers) {
|
||||
roaming.push({r: layer.GetRoamingRenderings(), source:layer});
|
||||
roaming.push({r: layer.GetRoamingRenderings(), source: layer});
|
||||
}
|
||||
|
||||
for (const layer of this.layers) {
|
||||
for (const r of roaming) {
|
||||
if(r.source == layer){
|
||||
if (r.source == layer) {
|
||||
continue;
|
||||
}
|
||||
layer.AddRoamingRenderings(r.r);
|
||||
}
|
||||
}
|
||||
|
||||
for(const layer of this.layers) {
|
||||
|
||||
for (const layer of this.layers) {
|
||||
layer.AddRoamingRenderings(
|
||||
{
|
||||
titleIcons:[],
|
||||
titleIcons: [],
|
||||
iconOverlays: [],
|
||||
tagRenderings: this.roamingRenderings
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -151,8 +152,8 @@ export default class LayoutConfig {
|
|||
|
||||
this.hideFromOverview = json.hideFromOverview ?? false;
|
||||
// @ts-ignore
|
||||
if(json.hideInOverview){
|
||||
throw "The json for "+this.id+" contains a 'hideInOverview'. Did you mean hideFromOverview instead?"
|
||||
if (json.hideInOverview) {
|
||||
throw "The json for " + this.id + " contains a 'hideInOverview'. Did you mean hideFromOverview instead?"
|
||||
}
|
||||
this.lockLocation = json.lockLocation ?? false;
|
||||
this.enableUserBadge = json.enableUserBadge ?? true;
|
||||
|
@ -166,4 +167,19 @@ export default class LayoutConfig {
|
|||
this.customCss = json.customCss;
|
||||
}
|
||||
|
||||
public CustomCodeSnippets(): string[] {
|
||||
if(this._official){
|
||||
return [];
|
||||
}
|
||||
const msg = "<br/><b>This layout uses <span class='alert'>custom javascript</span>, loaded for the wide internet. The code is printed below, please report suspicious code on the issue tracker of MapComplete:</b><br/>"
|
||||
const custom = [];
|
||||
for (const layer of this.layers) {
|
||||
custom.push(...layer.CustomCodeSnippets().map(code => code+"<br />"))
|
||||
}
|
||||
if (custom.length === 0) {
|
||||
return custom;
|
||||
}
|
||||
custom.splice(0, 0, msg);
|
||||
return custom;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue