forked from MapComplete/MapComplete
Refactoring: automatically generate code files from layer/theme files to avoid using 'Eval'
This commit is contained in:
parent
865b0bc44f
commit
39944a01fb
17 changed files with 269 additions and 31 deletions
|
@ -454,12 +454,16 @@ export class ExtraFunctions {
|
|||
"To enable this feature, add a field `calculatedTags` in the layer object, e.g.:",
|
||||
"````",
|
||||
'"calculatedTags": [',
|
||||
' "_someKey=javascript-expression",',
|
||||
' "_someKey=javascript-expression (lazy execution)",',
|
||||
' "_some_other_key:=javascript expression (strict execution)',
|
||||
' "name=feat.properties.name ?? feat.properties.ref ?? feat.properties.operator",',
|
||||
" \"_distanceCloserThen3Km=distanceTo(feat)( some_lon, some_lat) < 3 ? 'yes' : 'no'\" ",
|
||||
" ]",
|
||||
"````",
|
||||
"",
|
||||
"By using `:=` as separator, the attribute will be calculated as soone as the data is loaded (strict evaluation)",
|
||||
"The default behaviour, using `=` as separator, is lazy loading",
|
||||
"",
|
||||
"The above code will be executed for every feature in the layer. The feature is accessible as `feat` and is an amended geojson object:",
|
||||
|
||||
new List([
|
||||
|
|
|
@ -9,7 +9,6 @@ import { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
|
|||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||
import { Utils } from "../Utils"
|
||||
import { Store, UIEventSource } from "./UIEventSource"
|
||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||
|
||||
/**
|
||||
* Metatagging adds various tags to the elements, e.g. lat, lon, surface area, ...
|
||||
|
@ -19,6 +18,7 @@ import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
|||
export default class MetaTagging {
|
||||
private static errorPrintCount = 0
|
||||
private static readonly stopErrorOutputAt = 10
|
||||
private static metataggingObject: any = undefined
|
||||
private static retaggingFuncCache = new Map<
|
||||
string,
|
||||
((feature: Feature, propertiesStore: UIEventSource<any>) => void)[]
|
||||
|
@ -77,6 +77,23 @@ export default class MetaTagging {
|
|||
})
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* The 'metaTagging'-object is an object which contains some functions.
|
||||
* Those functions are named `metaTaggging_for_<layer_name>` and are constructed based on the 'calculatedField' for this layer.
|
||||
*
|
||||
* If they are set, those functions will be used instead of parsing them at runtime.
|
||||
*
|
||||
* This means that we can avoid using eval, resulting in faster and safer code (at the cost of more complexity) - at least for official themes.
|
||||
*
|
||||
* Note: this function might appear unused while developing, it is used in the generated `index_<themename>.ts` files.
|
||||
*
|
||||
* @param metatagging
|
||||
*/
|
||||
public static setThemeMetatagging(metatagging: any) {
|
||||
MetaTagging.metataggingObject = metatagging
|
||||
}
|
||||
|
||||
/**
|
||||
* This method (re)calculates all metatags and calculated tags on every given feature.
|
||||
* The given features should be part of the given layer
|
||||
|
@ -298,6 +315,38 @@ export default class MetaTagging {
|
|||
layer: LayerConfig,
|
||||
helpers: Record<ExtraFuncType, (feature: Feature) => Function>
|
||||
): (feature: Feature, tags: UIEventSource<Record<string, any>>) => boolean {
|
||||
if (MetaTagging.metataggingObject) {
|
||||
const funcName = "metaTaggging_for_" + layer.id
|
||||
if (typeof MetaTagging.metataggingObject[funcName] !== "function") {
|
||||
console.log(MetaTagging.metataggingObject)
|
||||
throw (
|
||||
"Error: metatagging-object for this theme does not have an entry at " +
|
||||
funcName +
|
||||
" (or it is not a function)"
|
||||
)
|
||||
}
|
||||
// public metaTaggging_for_walls_and_buildings(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {
|
||||
//
|
||||
const func: (feat: Feature, helperFunctions: Record<string, any>) => void =
|
||||
MetaTagging.metataggingObject[funcName]
|
||||
return (feature: Feature) => {
|
||||
const tags = feature.properties
|
||||
if (tags === undefined) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
func(feature, helpers)
|
||||
} catch (e) {
|
||||
console.error("Could not calculate calculated tags in exported class: ", e)
|
||||
}
|
||||
return true // Something changed
|
||||
}
|
||||
}
|
||||
|
||||
console.warn(
|
||||
"Static MetataggingObject for theme is not set; using `new Function` (aka `eval`) to get calculated tags. This might trip up the CSP"
|
||||
)
|
||||
|
||||
const calculatedTags: [string, string, boolean][] = layer.calculatedTags
|
||||
if (calculatedTags === undefined || calculatedTags.length === 0) {
|
||||
return undefined
|
||||
|
|
|
@ -16,6 +16,7 @@ import LinkToWeblate from "../../UI/Base/LinkToWeblate"
|
|||
import FeatureSwitchState from "./FeatureSwitchState"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import { ThemeMetaTagging } from "./UserSettingsMetaTagging"
|
||||
|
||||
/**
|
||||
* The part of the state which keeps track of user-related stuff, e.g. the OSM-connection,
|
||||
|
@ -326,12 +327,15 @@ export default class UserRelatedState {
|
|||
},
|
||||
[translationMode]
|
||||
)
|
||||
|
||||
const usersettingMetaTagging = new ThemeMetaTagging()
|
||||
osmConnection.userDetails.addCallback((userDetails) => {
|
||||
for (const k in userDetails) {
|
||||
amendedPrefs.data["_" + k] = "" + userDetails[k]
|
||||
}
|
||||
|
||||
for (const [name, code, _] of usersettingsConfig.calculatedTags) {
|
||||
usersettingMetaTagging.metaTaggging_for_usersettings({ properties: amendedPrefs.data })
|
||||
/*for (const [name, code, _] of usersettingsConfig.calculatedTags) {
|
||||
try {
|
||||
let result = new Function("feat", "return " + code + ";")({
|
||||
properties: amendedPrefs.data,
|
||||
|
@ -349,7 +353,7 @@ export default class UserRelatedState {
|
|||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
const simplifiedName = userDetails.name.toLowerCase().replace(/\s+/g, "")
|
||||
const isTranslator = translators.contributors.find(
|
||||
|
|
13
src/Logic/State/UserSettingsMetaTagging.ts
Normal file
13
src/Logic/State/UserSettingsMetaTagging.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Utils } from "../../Utils"
|
||||
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
|
||||
export class ThemeMetaTagging {
|
||||
public static readonly themeName = "usersettings"
|
||||
|
||||
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
|
||||
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue