diff --git a/assets/layers/ghost_bike/ghost_bike.json b/assets/layers/ghost_bike/ghost_bike.json
index c1ffc2e77..fe53f51a7 100644
--- a/assets/layers/ghost_bike/ghost_bike.json
+++ b/assets/layers/ghost_bike/ghost_bike.json
@@ -300,6 +300,19 @@
"type": "date"
},
"id": "ghost_bike-start_date"
+ },
+ {
+ "id": "wikidata",
+ "render": {
+ "special": {
+ "type": "wikipedia",
+ "keyToShowWikipediaFor": "subject:wikidata"
+ },
+ "before": {
+ "en": "
Wikipedia page about the deceased person
"
+ }
+ },
+ "condition": "subject:wikidata~*"
}
],
"deletion": {
diff --git a/assets/layers/toilet_at_amenity/toilet_at_amenity.json b/assets/layers/toilet_at_amenity/toilet_at_amenity.json
index cd4172bfc..e02da56a3 100644
--- a/assets/layers/toilet_at_amenity/toilet_at_amenity.json
+++ b/assets/layers/toilet_at_amenity/toilet_at_amenity.json
@@ -409,6 +409,8 @@
"toilet.toilet-changing_table:location",
"toilet.toilet-handwashing",
"toilet.toilet-has-paper",
+ "toilet.menstrual_products",
+ "toilet.menstrual_products_location",
{
"builtin": "description",
"override": {
diff --git a/src/UI/InputElement/Validators/FediverseValidator.ts b/src/UI/InputElement/Validators/FediverseValidator.ts
index 58fac6536..115eb52ba 100644
--- a/src/UI/InputElement/Validators/FediverseValidator.ts
+++ b/src/UI/InputElement/Validators/FediverseValidator.ts
@@ -17,6 +17,7 @@ export default class FediverseValidator extends Validator {
* @param s
*/
reformat(s: string): string {
+ s = s.trim()
if (!s.startsWith("@")) {
s = "@" + s
}
@@ -35,6 +36,7 @@ export default class FediverseValidator extends Validator {
return undefined
}
getFeedback(s: string): Translation | undefined {
+ s = s.trim()
const match = s.match(FediverseValidator.usernameAtServer)
console.log("Match:", match)
if (match) {
diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts
index 7d55060da..ed139844e 100644
--- a/src/UI/SpecialVisualizations.ts
+++ b/src/UI/SpecialVisualizations.ts
@@ -3,7 +3,11 @@ import { FixedUiElement } from "./Base/FixedUiElement"
import BaseUIElement from "./BaseUIElement"
import Title from "./Base/Title"
import Table from "./Base/Table"
-import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
+import {
+ RenderingSpecification,
+ SpecialVisualization,
+ SpecialVisualizationState,
+} from "./SpecialVisualization"
import { HistogramViz } from "./Popup/HistogramViz"
import { MinimapViz } from "./Popup/MinimapViz"
import { ShareLinkViz } from "./Popup/ShareLinkViz"
@@ -114,7 +118,7 @@ class NearbyImageVis implements SpecialVisualization {
tags: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const isOpen = args[0] === "open"
const readonly = args[1] === "readonly"
@@ -181,7 +185,7 @@ class StealViz implements SpecialVisualization {
selectedElement: otherFeature,
state,
layer,
- }),
+ })
)
}
if (elements.length === 1) {
@@ -189,8 +193,8 @@ class StealViz implements SpecialVisualization {
}
return new Combine(elements).SetClass("flex flex-col")
},
- [state.indexedFeatures.featuresById],
- ),
+ [state.indexedFeatures.featuresById]
+ )
)
}
@@ -229,7 +233,7 @@ export class QuestionViz implements SpecialVisualization {
tags: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const labels = args[0]
?.split(";")
@@ -265,38 +269,38 @@ export default class SpecialVisualizations {
viz.docs,
viz.args.length > 0
? new Table(
- ["name", "default", "description"],
- viz.args.map((arg) => {
- let defaultArg = arg.defaultValue ?? "_undefined_"
- if (defaultArg == "") {
- defaultArg = "_empty string_"
- }
- return [arg.name, defaultArg, arg.doc]
- }),
- )
+ ["name", "default", "description"],
+ viz.args.map((arg) => {
+ let defaultArg = arg.defaultValue ?? "_undefined_"
+ if (defaultArg == "") {
+ defaultArg = "_empty string_"
+ }
+ return [arg.name, defaultArg, arg.doc]
+ })
+ )
: undefined,
new Title("Example usage of " + viz.funcName, 4),
new FixedUiElement(
viz.example ??
- "`{" +
- viz.funcName +
- "(" +
- viz.args.map((arg) => arg.defaultValue).join(",") +
- ")}`",
+ "`{" +
+ viz.funcName +
+ "(" +
+ viz.args.map((arg) => arg.defaultValue).join(",") +
+ ")}`"
).SetClass("literal-code"),
])
}
public static constructSpecification(
template: string,
- extraMappings: SpecialVisualization[] = [],
+ extraMappings: SpecialVisualization[] = []
): RenderingSpecification[] {
return SpecialVisualisationUtils.constructSpecification(template, extraMappings)
}
public static HelpMessage() {
const helpTexts = SpecialVisualizations.specialVisualizations.map((viz) =>
- SpecialVisualizations.DocumentationFor(viz),
+ SpecialVisualizations.DocumentationFor(viz)
)
return new Combine([
@@ -330,10 +334,10 @@ export default class SpecialVisualizations {
},
},
null,
- " ",
- ),
+ " "
+ )
).SetClass("code"),
- "In other words: use `{ \"before\": ..., \"after\": ..., \"special\": {\"type\": ..., \"argname\": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)",
+ 'In other words: use `{ "before": ..., "after": ..., "special": {"type": ..., "argname": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)',
]).SetClass("flex flex-col"),
...helpTexts,
]).SetClass("flex flex-col")
@@ -342,20 +346,20 @@ export default class SpecialVisualizations {
// noinspection JSUnusedGlobalSymbols
public static renderExampleOfSpecial(
state: SpecialVisualizationState,
- s: SpecialVisualization,
+ s: SpecialVisualization
): BaseUIElement {
const examples =
s.structuredExamples === undefined
? []
: s.structuredExamples().map((e) => {
- return s.constr(
- state,
- new UIEventSource>(e.feature.properties),
- e.args,
- e.feature,
- undefined,
- )
- })
+ return s.constr(
+ state,
+ new UIEventSource>(e.feature.properties),
+ e.args,
+ e.feature,
+ undefined
+ )
+ })
return new Combine([new Title(s.funcName), s.docs, ...examples])
}
@@ -395,7 +399,7 @@ export default class SpecialVisualizations {
assignTo: state.userRelatedState.language,
availableLanguages: state.layout.language,
preferredLanguages: state.osmConnection.userDetails.map(
- (ud) => ud.languages,
+ (ud) => ud.languages
),
})
},
@@ -420,7 +424,7 @@ export default class SpecialVisualizations {
constr(
state: SpecialVisualizationState,
- tagSource: UIEventSource>,
+ tagSource: UIEventSource>
): BaseUIElement {
return new VariableUiElement(
tagSource
@@ -430,7 +434,7 @@ export default class SpecialVisualizations {
return new SplitRoadWizard(id, state)
}
return undefined
- }),
+ })
)
},
},
@@ -444,7 +448,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
if (feature.geometry.type !== "Point") {
return undefined
@@ -467,7 +471,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
if (!layer.deletion) {
return undefined
@@ -495,7 +499,7 @@ export default class SpecialVisualizations {
state: SpecialVisualizationState,
tagSource: UIEventSource>,
argument: string[],
- feature: Feature,
+ feature: Feature
): BaseUIElement {
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
return new SvelteUIElement(CreateNewNote, {
@@ -559,7 +563,7 @@ export default class SpecialVisualizations {
.map((tags) => tags[args[0]])
.map((wikidata) => {
wikidata = Utils.NoEmpty(
- wikidata?.split(";")?.map((wd) => wd.trim()) ?? [],
+ wikidata?.split(";")?.map((wd) => wd.trim()) ?? []
)[0]
const entry = Wikidata.LoadWikidataEntry(wikidata)
return new VariableUiElement(
@@ -569,9 +573,9 @@ export default class SpecialVisualizations {
}
const response = e["success"]
return Translation.fromMap(response.labels)
- }),
+ })
)
- }),
+ })
),
},
new MapillaryLinkVis(),
@@ -585,7 +589,7 @@ export default class SpecialVisualizations {
tags: UIEventSource>,
_,
__,
- layer: LayerConfig,
+ layer: LayerConfig
) => new SvelteUIElement(AllTagsPanel, { tags, layer }),
},
{
@@ -607,7 +611,7 @@ export default class SpecialVisualizations {
return new ImageCarousel(
AllImageProviders.LoadImagesFor(tags, imagePrefixes),
tags,
- state,
+ state
)
},
},
@@ -663,7 +667,7 @@ export default class SpecialVisualizations {
{
nameKey: nameKey,
fallbackName,
- },
+ }
)
return new SvelteUIElement(StarsBarIcon, {
score: reviews.average,
@@ -696,7 +700,7 @@ export default class SpecialVisualizations {
{
nameKey: nameKey,
fallbackName,
- },
+ }
)
return new SvelteUIElement(ReviewForm, { reviews, state, tags, feature, layer })
},
@@ -728,7 +732,7 @@ export default class SpecialVisualizations {
{
nameKey: nameKey,
fallbackName,
- },
+ }
)
return new SvelteUIElement(AllReviews, { reviews, state, tags, feature, layer })
},
@@ -753,7 +757,7 @@ export default class SpecialVisualizations {
doc: "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__",
},
],
-
+ needsUrls: [Constants.countryCoderEndpoint],
example:
"A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`",
constr: (state, tagSource: UIEventSource, args) => {
@@ -786,7 +790,7 @@ export default class SpecialVisualizations {
tags: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): SvelteUIElement {
const keyToUse = args[0]
const prefix = args[1]
@@ -823,17 +827,17 @@ export default class SpecialVisualizations {
return undefined
}
const allUnits: Unit[] = [].concat(
- ...(state?.layout?.layers?.map((lyr) => lyr.units) ?? []),
+ ...(state?.layout?.layers?.map((lyr) => lyr.units) ?? [])
)
const unit = allUnits.filter((unit) =>
- unit.isApplicableToKey(key),
+ unit.isApplicableToKey(key)
)[0]
if (unit === undefined) {
return value
}
const getCountry = () => tagSource.data._country
return unit.asHumanLongValue(value, getCountry)
- }),
+ })
)
},
},
@@ -850,7 +854,7 @@ export default class SpecialVisualizations {
new Combine([
t.downloadFeatureAsGeojson.SetClass("font-bold text-lg"),
t.downloadGeoJsonHelper.SetClass("subtle"),
- ]).SetClass("flex flex-col"),
+ ]).SetClass("flex flex-col")
)
.onClick(() => {
console.log("Exporting as Geojson")
@@ -863,7 +867,7 @@ export default class SpecialVisualizations {
title + "_mapcomplete_export.geojson",
{
mimetype: "application/vnd.geo+json",
- },
+ }
)
})
.SetClass("w-full")
@@ -899,7 +903,7 @@ export default class SpecialVisualizations {
constr: (state) => {
return new SubtleButton(
Svg.delete_icon_svg().SetStyle("height: 1.5rem"),
- Translations.t.general.removeLocationHistory,
+ Translations.t.general.removeLocationHistory
).onClick(() => {
state.historicalUserLocations.features.setData([])
state.selectedElement.setData(undefined)
@@ -937,10 +941,10 @@ export default class SpecialVisualizations {
.filter((c) => c.text !== "")
.map(
(c, i) =>
- new NoteCommentElement(c, state, i, comments.length),
- ),
+ new NoteCommentElement(c, state, i, comments.length)
+ )
).SetClass("flex flex-col")
- }),
+ })
),
},
{
@@ -974,7 +978,7 @@ export default class SpecialVisualizations {
tagsSource: UIEventSource>,
_: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
) =>
new VariableUiElement(
tagsSource.map((tags) => {
@@ -992,7 +996,7 @@ export default class SpecialVisualizations {
feature,
layer,
}).SetClass("px-1")
- }),
+ })
),
},
{
@@ -1008,8 +1012,8 @@ export default class SpecialVisualizations {
let challenge = Stores.FromPromise(
Utils.downloadJsonCached(
`${Maproulette.defaultEndpoint}/challenge/${parentId}`,
- 24 * 60 * 60 * 1000,
- ),
+ 24 * 60 * 60 * 1000
+ )
)
return new VariableUiElement(
@@ -1034,7 +1038,7 @@ export default class SpecialVisualizations {
} else {
return [title, new List(listItems)]
}
- }),
+ })
)
},
docs: "Fetches the metadata of MapRoulette campaign that this task is part of and shows those details (namely `title`, `description` and `instruction`).\n\nThis reads the property `mr_challengeId` to detect the parent campaign.",
@@ -1048,15 +1052,15 @@ export default class SpecialVisualizations {
"\n" +
"```json\n" +
"{\n" +
- " \"id\": \"mark_duplicate\",\n" +
- " \"render\": {\n" +
- " \"special\": {\n" +
- " \"type\": \"maproulette_set_status\",\n" +
- " \"message\": {\n" +
- " \"en\": \"Mark as not found or false positive\"\n" +
+ ' "id": "mark_duplicate",\n' +
+ ' "render": {\n' +
+ ' "special": {\n' +
+ ' "type": "maproulette_set_status",\n' +
+ ' "message": {\n' +
+ ' "en": "Mark as not found or false positive"\n' +
" },\n" +
- " \"status\": \"2\",\n" +
- " \"image\": \"close\"\n" +
+ ' "status": "2",\n' +
+ ' "image": "close"\n' +
" }\n" +
" }\n" +
"}\n" +
@@ -1088,12 +1092,19 @@ export default class SpecialVisualizations {
{
name: "ask_feedback",
doc: "If not an empty string, this will be used as question to ask some additional feedback. A text field will be added",
- defaultValue: ""
- }
+ defaultValue: "",
+ },
],
constr: (state, tagsSource, args) => {
- let [message, image, message_closed, statusToSet, maproulette_id_key, askFeedback] = args
+ let [
+ message,
+ image,
+ message_closed,
+ statusToSet,
+ maproulette_id_key,
+ askFeedback,
+ ] = args
if (image === "") {
image = "confirm"
}
@@ -1109,7 +1120,7 @@ export default class SpecialVisualizations {
message_closed,
statusToSet,
maproulette_id_key,
- askFeedback
+ askFeedback,
})
},
},
@@ -1129,8 +1140,8 @@ export default class SpecialVisualizations {
const fsBboxed = new BBoxFeatureSourceForLayer(fs, bbox)
return new StatisticsPanel(fsBboxed)
},
- [state.mapProperties.bounds],
- ),
+ [state.mapProperties.bounds]
+ )
)
},
},
@@ -1196,7 +1207,7 @@ export default class SpecialVisualizations {
constr(
state: SpecialVisualizationState,
tagSource: UIEventSource>,
- args: string[],
+ args: string[]
): BaseUIElement {
let [text, href, classnames, download, ariaLabel] = args
if (download === "") {
@@ -1208,13 +1219,16 @@ export default class SpecialVisualizations {
(tags) =>
new SvelteUIElement(Link, {
text: Utils.SubstituteKeys(text, tags),
- href: Utils.SubstituteKeys(href, tags).replaceAll(/ /g, "%20") /* Chromium based browsers eat the spaces */,
+ href: Utils.SubstituteKeys(href, tags).replaceAll(
+ / /g,
+ "%20"
+ ) /* Chromium based browsers eat the spaces */,
classnames,
download: Utils.SubstituteKeys(download, tags),
ariaLabel: Utils.SubstituteKeys(ariaLabel, tags),
newTab,
- }),
- ),
+ })
+ )
)
},
},
@@ -1236,7 +1250,7 @@ export default class SpecialVisualizations {
},
},
null,
- " ",
+ " "
) +
"\n```",
args: [
@@ -1260,7 +1274,7 @@ export default class SpecialVisualizations {
featureTags: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
) {
const [key, tr, classesRaw] = args
let classes = classesRaw ?? ""
@@ -1285,7 +1299,7 @@ export default class SpecialVisualizations {
elements.push(subsTr)
}
return elements
- }),
+ })
)
},
},
@@ -1305,7 +1319,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new VariableUiElement(
tagSource.map((tags) => {
@@ -1317,7 +1331,7 @@ export default class SpecialVisualizations {
console.error("Cannot create a translation for", v, "due to", e)
return JSON.stringify(v)
}
- }),
+ })
)
},
},
@@ -1337,7 +1351,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const key = argument[0]
const validator = new FediverseValidator()
@@ -1347,7 +1361,7 @@ export default class SpecialVisualizations {
.map((fediAccount) => {
fediAccount = validator.reformat(fediAccount)
const [_, username, host] = fediAccount.match(
- FediverseValidator.usernameAtServer,
+ FediverseValidator.usernameAtServer
)
const normalLink = new SvelteUIElement(Link, {
@@ -1359,10 +1373,10 @@ export default class SpecialVisualizations {
const loggedInContributorMastodon =
state.userRelatedState?.preferencesAsTags?.data?.[
"_mastodon_link"
- ]
+ ]
console.log(
"LoggedinContributorMastodon",
- loggedInContributorMastodon,
+ loggedInContributorMastodon
)
if (!loggedInContributorMastodon) {
return normalLink
@@ -1378,7 +1392,7 @@ export default class SpecialVisualizations {
newTab: true,
}).SetClass("button"),
])
- }),
+ })
)
},
},
@@ -1398,7 +1412,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new FixedUiElement("{" + args[0] + "}")
},
@@ -1419,7 +1433,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const key = argument[0] ?? "value"
return new VariableUiElement(
@@ -1437,12 +1451,12 @@ export default class SpecialVisualizations {
} catch (e) {
return new FixedUiElement(
"Could not parse this tag: " +
- JSON.stringify(value) +
- " due to " +
- e,
+ JSON.stringify(value) +
+ " due to " +
+ e
).SetClass("alert")
}
- }),
+ })
)
},
},
@@ -1463,7 +1477,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const giggityUrl = argument[0]
return new SvelteUIElement(Giggity, { tags: tagSource, state, giggityUrl })
@@ -1479,12 +1493,12 @@ export default class SpecialVisualizations {
_: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const tags = ((
state
)).geolocation.currentUserLocation.features.map(
- (features) => features[0]?.properties,
+ (features) => features[0]?.properties
)
return new Combine([
new SvelteUIElement(OrientationDebugPanel, {}),
@@ -1506,7 +1520,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new SvelteUIElement(MarkAsFavourite, {
tags: tagSource,
@@ -1526,7 +1540,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new SvelteUIElement(MarkAsFavouriteMini, {
tags: tagSource,
@@ -1546,7 +1560,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new SvelteUIElement(DirectionIndicator, { state, feature })
},
@@ -1561,7 +1575,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
argument: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
return new VariableUiElement(
tagSource
@@ -1583,9 +1597,9 @@ export default class SpecialVisualizations {
`${window.location.protocol}//${window.location.host}${window.location.pathname}?${layout}lat=${lat}&lon=${lon}&z=15` +
`#${id}`
return new Img(new Qr(url).toImageElement(75)).SetStyle(
- "width: 75px",
+ "width: 75px"
)
- }),
+ })
)
},
},
@@ -1605,7 +1619,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const key = args[0] === "" ? "_direction:centerpoint" : args[0]
return new VariableUiElement(
@@ -1616,11 +1630,11 @@ export default class SpecialVisualizations {
})
.mapD((value) => {
const dir = GeoOperations.bearingToHuman(
- GeoOperations.parseBearing(value),
+ GeoOperations.parseBearing(value)
)
console.log("Human dir", dir)
return Translations.t.general.visualFeedback.directionsAbsolute[dir]
- }),
+ })
)
},
},
@@ -1655,7 +1669,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource>,
args: string[],
feature: Feature,
- layer: LayerConfig,
+ layer: LayerConfig
): BaseUIElement {
const url = args[0]
const postprocessVelopark = args[2] === "velopark"
@@ -1673,13 +1687,21 @@ export default class SpecialVisualizations {
},
{
funcName: "login_button",
- args: [
- ],
+ args: [],
docs: "Show a login button",
needsUrls: [],
- constr(state: SpecialVisualizationState, tagSource: UIEventSource>, args: string[], feature: Feature, layer: LayerConfig): BaseUIElement {
- return new Toggle(undefined,
- new SvelteUIElement(LoginButton), state.osmConnection.isLoggedIn)
+ constr(
+ state: SpecialVisualizationState,
+ tagSource: UIEventSource>,
+ args: string[],
+ feature: Feature,
+ layer: LayerConfig
+ ): BaseUIElement {
+ return new Toggle(
+ undefined,
+ new SvelteUIElement(LoginButton),
+ state.osmConnection.isLoggedIn
+ )
},
},
]
@@ -1693,7 +1715,7 @@ export default class SpecialVisualizations {
throw (
"Invalid special visualisation found: funcName is undefined for " +
invalid.map((sp) => sp.i).join(", ") +
- ". Did you perhaps type \n funcName: \"funcname\" // type declaration uses COLON\ninstead of:\n funcName = \"funcName\" // value definition uses EQUAL"
+ '. Did you perhaps type \n funcName: "funcname" // type declaration uses COLON\ninstead of:\n funcName = "funcName" // value definition uses EQUAL'
)
}