forked from MapComplete/MapComplete
Feature(NSI): support using NSI-images as icon, test on shops
This commit is contained in:
parent
80192f003a
commit
b913ea867f
14 changed files with 1173790 additions and 71 deletions
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"#":"no-translations",
|
"#":"no-translations",
|
||||||
|
"#no-index": "yes",
|
||||||
"#dont-translate": "*",
|
"#dont-translate": "*",
|
||||||
"#filter": "no-auto",
|
"#filter": "no-auto",
|
||||||
"pointRendering": [
|
"pointRendering": [
|
||||||
|
|
569064
assets/layers/nsi_brand/nsi_brand.json
Normal file
569064
assets/layers/nsi_brand/nsi_brand.json
Normal file
File diff suppressed because it is too large
Load diff
604545
assets/layers/nsi_operator/nsi_operator.json
Normal file
604545
assets/layers/nsi_operator/nsi_operator.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -109,7 +109,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"icon": {
|
"icon": {
|
||||||
"builtin": "id_presets.shop_rendering",
|
"builtin": "nsi_brand.icon",
|
||||||
"override": {
|
"override": {
|
||||||
"render": "./assets/layers/id_presets/maki-shop.svg",
|
"render": "./assets/layers/id_presets/maki-shop.svg",
|
||||||
"+mappings": [
|
"+mappings": [
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
"reset:translations": "vite-node scripts/generateTranslations.ts -- --ignore-weblate",
|
"reset:translations": "vite-node scripts/generateTranslations.ts -- --ignore-weblate",
|
||||||
"generate:layouts": "vite-node scripts/generateLayouts.ts",
|
"generate:layouts": "vite-node scripts/generateLayouts.ts",
|
||||||
"generate:docs": "rm -rf Docs/Themes/* && rm -rf Docs/Layers/* && rm -rf Docs/TagInfo && mkdir Docs/TagInfo && export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateDocs.ts && vite-node scripts/generateTaginfoProjectFiles.ts",
|
"generate:docs": "rm -rf Docs/Themes/* && rm -rf Docs/Layers/* && rm -rf Docs/TagInfo && mkdir Docs/TagInfo && export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateDocs.ts && vite-node scripts/generateTaginfoProjectFiles.ts",
|
||||||
"generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts",
|
"generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateLayerOverview.ts",
|
||||||
"generate:mapcomplete-changes-theme": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --generate-change-map",
|
"generate:mapcomplete-changes-theme": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --generate-change-map",
|
||||||
"refresh:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --force",
|
"refresh:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --force",
|
||||||
"generate:licenses": "vite-node scripts/generateLicenseInfo.ts -- --no-fail",
|
"generate:licenses": "vite-node scripts/generateLicenseInfo.ts -- --no-fail",
|
||||||
|
|
|
@ -5,10 +5,9 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
import { Utils } from "../src/Utils"
|
import { Utils } from "../src/Utils"
|
||||||
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import FilterConfigJson, { FilterConfigOptionJson } from "../src/Models/ThemeConfig/Json/FilterConfigJson"
|
import { FilterConfigOptionJson } from "../src/Models/ThemeConfig/Json/FilterConfigJson"
|
||||||
import { TagConfigJson } from "../src/Models/ThemeConfig/Json/TagConfigJson"
|
|
||||||
import { TagUtils } from "../src/Logic/Tags/TagUtils"
|
import { TagUtils } from "../src/Logic/Tags/TagUtils"
|
||||||
import { And } from "../src/Logic/Tags/And"
|
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||||
|
|
||||||
class DownloadNsiLogos extends Script {
|
class DownloadNsiLogos extends Script {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -129,39 +128,61 @@ class DownloadNsiLogos extends Script {
|
||||||
private async generateRendering(type: string) {
|
private async generateRendering(type: string) {
|
||||||
const nsi = await NameSuggestionIndex.getNsiIndex()
|
const nsi = await NameSuggestionIndex.getNsiIndex()
|
||||||
const items = nsi.allPossible(type)
|
const items = nsi.allPossible(type)
|
||||||
const brandPrefix = [type, "name", "alt_name", "operator","brand"]
|
|
||||||
const filterOptions: FilterConfigOptionJson[] = items.map(item => {
|
const filterOptions: FilterConfigOptionJson[] = items.map(item => {
|
||||||
let brandDetection: string[] = []
|
|
||||||
let required: string[] = []
|
|
||||||
const tags: Record<string, string> = item.tags
|
|
||||||
for (const k in tags) {
|
|
||||||
if (brandPrefix.some(br => k === br || k.startsWith(br + ":"))) {
|
|
||||||
brandDetection.push(k + "=" + tags[k])
|
|
||||||
} else {
|
|
||||||
required.push(k + "=" + tags[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const osmTags = <TagConfigJson>TagUtils.optimzeJson({ and: [...required, { or: brandDetection }] })
|
|
||||||
return ({
|
return ({
|
||||||
question: item.displayName,
|
question: item.displayName,
|
||||||
icon: nsi.getIconUrl(item, type),
|
icon: nsi.getIconUrl(item, type),
|
||||||
osmTags,
|
osmTags: NameSuggestionIndex.asFilterTags(item),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
const mappings = items.map(item => ({
|
||||||
|
if: NameSuggestionIndex.asFilterTags(item),
|
||||||
|
then: nsi.getIconUrl(item, type),
|
||||||
|
}))
|
||||||
|
|
||||||
|
console.log("Checking for shadow-mappings...")
|
||||||
|
for (let i = mappings.length - 1; i >= 0 ; i--) {
|
||||||
|
const condition = TagUtils.Tag(mappings[i].if)
|
||||||
|
if(i % 100 === 0){
|
||||||
|
console.log("Checking for shadow-mappings...",i,"/",mappings.length )
|
||||||
|
|
||||||
|
}
|
||||||
|
const shadowsSomething = mappings.some((m,j) => {
|
||||||
|
if(i===j ){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return condition.shadows(TagUtils.Tag(m.if))
|
||||||
|
})
|
||||||
|
// If this one matches, the other one will match as well
|
||||||
|
// We can thus remove this one in favour of the other one
|
||||||
|
if(shadowsSomething){
|
||||||
|
mappings.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconsTr: TagRenderingConfigJson = <any>{
|
||||||
|
strict: true,
|
||||||
|
id: "icon",
|
||||||
|
mappings,
|
||||||
|
}
|
||||||
|
|
||||||
const config: LayerConfigJson = {
|
const config: LayerConfigJson = {
|
||||||
"#dont-translate": "*",
|
"#dont-translate": "*",
|
||||||
|
"#no-index": "yes",
|
||||||
id: "nsi_" + type,
|
id: "nsi_" + type,
|
||||||
source: "special:library",
|
source: "special:library",
|
||||||
description: {
|
description: {
|
||||||
en: "Exposes part of the NSI to reuse in other themes, e.g. for rendering",
|
en: "Exposes part of the NSI to reuse in other themes, e.g. for rendering",
|
||||||
},
|
},
|
||||||
pointRendering: null,
|
pointRendering: null,
|
||||||
|
tagRenderings: [
|
||||||
|
iconsTr,
|
||||||
|
],
|
||||||
filter: [
|
filter: [
|
||||||
<any> {
|
<any>{
|
||||||
id: type,
|
id: type,
|
||||||
strict: true,
|
strict: true,
|
||||||
options: [{question: type}, ...filterOptions],
|
options: [{ question: type }, ...filterOptions],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
allowMove: false,
|
allowMove: false,
|
||||||
|
|
|
@ -497,6 +497,8 @@ class LayerOverviewUtils extends Script {
|
||||||
priviliged.delete(key)
|
priviliged.delete(key)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// These two get a free pass
|
// These two get a free pass
|
||||||
priviliged.delete("summary")
|
priviliged.delete("summary")
|
||||||
priviliged.delete("last_click")
|
priviliged.delete("last_click")
|
||||||
|
@ -527,7 +529,7 @@ class LayerOverviewUtils extends Script {
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
"./src/assets/generated/known_layers.json",
|
"./src/assets/generated/known_layers.json",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
layers: Array.from(sharedLayers.values()).filter((l) => l.id !== "favourite"),
|
layers: Array.from(sharedLayers.values()).filter((l) => !(l["#no-index"] === "yes")),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||||
import { Utils } from "../Utils"
|
import { Utils } from "../Utils"
|
||||||
import known_layers from "../assets/generated/known_layers.json"
|
import * as known_layers from "../assets/generated/known_layers.json"
|
||||||
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
|
|
||||||
export class AllSharedLayers {
|
export class AllSharedLayers {
|
||||||
public static sharedLayers: Map<string, LayerConfig> = AllSharedLayers.getSharedLayers()
|
public static sharedLayers: Map<string, LayerConfig> = AllSharedLayers.getSharedLayers()
|
||||||
public static getSharedLayersConfigs(): Map<string, LayerConfigJson> {
|
public static getSharedLayersConfigs(): Map<string, LayerConfigJson> {
|
||||||
const sharedLayers = new Map<string, LayerConfigJson>()
|
const sharedLayers = new Map<string, LayerConfigJson>()
|
||||||
for (const layer of known_layers["layers"]) {
|
for (const layer of (known_layers).layers) {
|
||||||
// @ts-ignore
|
if(layer.id === undefined){
|
||||||
sharedLayers.set(layer.id, layer)
|
console.error("Layer without id! "+JSON.stringify(layer).slice(0,80), known_layers.layers.length)
|
||||||
|
continue
|
||||||
|
}else{
|
||||||
|
console.log("Loaded",layer.id)
|
||||||
|
}
|
||||||
|
sharedLayers.set(layer.id, <any> layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sharedLayers
|
return sharedLayers
|
||||||
|
|
|
@ -690,6 +690,17 @@ export class TagUtils {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static removeKnownParts(tag: TagsFilter, known: TagsFilter, valueOfKnown = true): TagsFilter | boolean{
|
||||||
|
const tagOrBool = And.construct([tag]).optimize()
|
||||||
|
if(tagOrBool === true || tagOrBool === false){
|
||||||
|
return tagOrBool
|
||||||
|
}
|
||||||
|
if(tagOrBool instanceof And){
|
||||||
|
return tagOrBool.removePhraseConsideredKnown(known, valueOfKnown)
|
||||||
|
}
|
||||||
|
return tagOrBool
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `true` if at least one element of the 'guards' shadows one element of the 'listToFilter'.
|
* Returns `true` if at least one element of the 'guards' shadows one element of the 'listToFilter'.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { Mapping } from "../../Models/ThemeConfig/TagRenderingConfig"
|
||||||
import { Tag } from "../Tags/Tag"
|
import { Tag } from "../Tags/Tag"
|
||||||
import { TypedTranslation } from "../../UI/i18n/Translation"
|
import { TypedTranslation } from "../../UI/i18n/Translation"
|
||||||
import { RegexTag } from "../Tags/RegexTag"
|
import { RegexTag } from "../Tags/RegexTag"
|
||||||
|
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
|
||||||
|
import { TagUtils } from "../Tags/TagUtils"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main name suggestion index file
|
* Main name suggestion index file
|
||||||
|
@ -52,6 +54,7 @@ export interface NSIItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class NameSuggestionIndex {
|
export default class NameSuggestionIndex {
|
||||||
|
|
||||||
public static readonly supportedTypes = ["brand", "flag", "operator", "transit"] as const
|
public static readonly supportedTypes = ["brand", "flag", "operator", "transit"] as const
|
||||||
private readonly nsiFile: Readonly<NSIFile>
|
private readonly nsiFile: Readonly<NSIFile>
|
||||||
private readonly nsiWdFile: Readonly<
|
private readonly nsiWdFile: Readonly<
|
||||||
|
@ -399,4 +402,27 @@ export default class NameSuggestionIndex {
|
||||||
}
|
}
|
||||||
return icon
|
return icon
|
||||||
}
|
}
|
||||||
|
private static readonly brandPrefix = ["name", "alt_name", "operator","brand"] as const
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An NSI-item might have tags such as `name=X`, `alt_name=brand X`, `brand=X`, `brand:wikidata`, `shop=Y`, `service:abc=yes`
|
||||||
|
* Many of those tags are all added, but having only one of them is a good indication that it should match this item.
|
||||||
|
*
|
||||||
|
* This method is a heuristic which attempts to move all the brand-related tags into an `or` but still requiring the `shop` and other tags
|
||||||
|
*
|
||||||
|
* (More of an extension method on NSIItem)
|
||||||
|
*/
|
||||||
|
static asFilterTags(item: NSIItem): string | { and: TagConfigJson[] } | { or: TagConfigJson[] } {
|
||||||
|
let brandDetection: string[] = []
|
||||||
|
let required: string[] = []
|
||||||
|
const tags: Record<string, string> = item.tags
|
||||||
|
for (const k in tags) {
|
||||||
|
if (NameSuggestionIndex.brandPrefix.some(br => k === br || k.startsWith(br + ":"))) {
|
||||||
|
brandDetection.push(k + "=" + tags[k])
|
||||||
|
} else {
|
||||||
|
required.push(k + "=" + tags[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <TagConfigJson>TagUtils.optimzeJson({ and: [...required, { or: brandDetection }] })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,8 @@ export class PruneFilters extends DesugaringStep<LayerConfigJson>{
|
||||||
if(!option.osmTags){
|
if(!option.osmTags){
|
||||||
return option
|
return option
|
||||||
}
|
}
|
||||||
let basetags: TagsFilter = <TagsFilter> And.construct([TagUtils.Tag(option.osmTags)]).optimize()
|
let basetags = TagUtils.Tag(option.osmTags)
|
||||||
if(basetags instanceof And){
|
return {...option, osmTags: (<TagsFilter>TagUtils.removeKnownParts(basetags ,sourceTags)).asJson()}
|
||||||
basetags = <TagsFilter> basetags.removePhraseConsideredKnown(sourceTags, true)
|
|
||||||
}
|
|
||||||
return {...option, osmTags: basetags.asJson()}
|
|
||||||
})
|
})
|
||||||
const countAfter = newOptions.length
|
const countAfter = newOptions.length
|
||||||
if(countAfter !== countBefore){
|
if(countAfter !== countBefore){
|
||||||
|
|
|
@ -159,11 +159,15 @@ class ExpandTagRendering extends Conversion<
|
||||||
ctx: ConversionContext
|
ctx: ConversionContext
|
||||||
): QuestionableTagRenderingConfigJson[] {
|
): QuestionableTagRenderingConfigJson[] {
|
||||||
const trs = this.convertOnce(spec, ctx)
|
const trs = this.convertOnce(spec, ctx)
|
||||||
|
|
||||||
const result = []
|
const result = []
|
||||||
|
if(!Array.isArray(trs)){
|
||||||
|
ctx.err("Result of lookup for "+spec+" is not iterable; got "+trs)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
for (const tr of trs) {
|
for (const tr of trs) {
|
||||||
if (typeof tr === "string" || tr["builtin"] !== undefined) {
|
if (typeof tr === "string" || tr["builtin"] !== undefined) {
|
||||||
const stable = this.convert(tr, ctx.inOperation("recursive_resolve"))
|
const stable = this.convert(tr, ctx.inOperation("recursive_resolve"))
|
||||||
|
.map(tr => this.pruneMappings(tr, ctx))
|
||||||
result.push(...stable)
|
result.push(...stable)
|
||||||
if (this._options?.addToContext) {
|
if (this._options?.addToContext) {
|
||||||
for (const tr of stable) {
|
for (const tr of stable) {
|
||||||
|
@ -181,6 +185,40 @@ class ExpandTagRendering extends Conversion<
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pruneMappings(tagRendering: QuestionableTagRenderingConfigJson, ctx: ConversionContext): QuestionableTagRenderingConfigJson{
|
||||||
|
if(!tagRendering["strict"]){
|
||||||
|
return tagRendering
|
||||||
|
}
|
||||||
|
const before = tagRendering.mappings?.length ?? 0
|
||||||
|
|
||||||
|
const alwaysTags = TagUtils.Tag(this._self.source["osmTags"])
|
||||||
|
const newMappings = tagRendering.mappings?.filter(mapping => {
|
||||||
|
const condition = TagUtils.Tag( mapping.if)
|
||||||
|
return condition.shadows(alwaysTags);
|
||||||
|
|
||||||
|
}).map(mapping => {
|
||||||
|
const newIf =TagUtils.removeKnownParts(
|
||||||
|
TagUtils.Tag(mapping.if), alwaysTags )
|
||||||
|
if(typeof newIf === "boolean"){
|
||||||
|
throw "Invalid removeKnownParts"
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...mapping,
|
||||||
|
if: newIf.asJson()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const after = newMappings?.length ?? 0
|
||||||
|
if(before - after > 0){
|
||||||
|
ctx.info(`Pruned mappings for ${tagRendering.id}, from ${before} to ${after} (removed ${before - after})`)
|
||||||
|
}
|
||||||
|
const tr = {
|
||||||
|
...tagRendering,
|
||||||
|
mappings: newMappings
|
||||||
|
}
|
||||||
|
delete tr["strict"]
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
private lookup(name: string, ctx: ConversionContext): TagRenderingConfigJson[] | undefined {
|
private lookup(name: string, ctx: ConversionContext): TagRenderingConfigJson[] | undefined {
|
||||||
const direct = this.directLookup(name)
|
const direct = this.directLookup(name)
|
||||||
|
|
||||||
|
@ -285,41 +323,40 @@ class ExpandTagRendering extends Conversion<
|
||||||
const state = this._state
|
const state = this._state
|
||||||
|
|
||||||
if (typeof tr === "string") {
|
if (typeof tr === "string") {
|
||||||
let lookup
|
|
||||||
if (this._state.tagRenderings !== null) {
|
if (this._state.tagRenderings !== null) {
|
||||||
lookup = this.lookup(tr, ctx)
|
const lookup = this.lookup(tr, ctx)
|
||||||
|
if(lookup){
|
||||||
|
return lookup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (lookup === undefined) {
|
if (
|
||||||
if (
|
this._state.sharedLayers?.size > 0 &&
|
||||||
this._state.sharedLayers?.size > 0 &&
|
ctx.path.at(-1) !== "icon" &&
|
||||||
ctx.path.at(-1) !== "icon" &&
|
!ctx.path.find((p) => p === "pointRendering")
|
||||||
!ctx.path.find((p) => p === "pointRendering")
|
) {
|
||||||
) {
|
ctx.warn(
|
||||||
ctx.warn(
|
`A literal rendering was detected: ${tr}
|
||||||
`A literal rendering was detected: ${tr}
|
|
||||||
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
|
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
|
||||||
Array.from(state.sharedLayers.keys()).join(", ")
|
Array.from(state.sharedLayers.keys()).join(", "),
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) {
|
|
||||||
ctx.err(
|
|
||||||
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
|
|
||||||
tr +
|
|
||||||
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
|
|
||||||
tr +
|
|
||||||
"`? "
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
<any>{
|
|
||||||
render: tr,
|
|
||||||
id: tr.replace(/[^a-zA-Z0-9]/g, ""),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
return lookup
|
|
||||||
|
if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) {
|
||||||
|
ctx.err(
|
||||||
|
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
|
||||||
|
tr +
|
||||||
|
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
|
||||||
|
tr +
|
||||||
|
"`? ",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
<any>{
|
||||||
|
render: tr,
|
||||||
|
id: tr.replace(/[^a-zA-Z0-9]/g, ""),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tr["builtin"] !== undefined) {
|
if (tr["builtin"] !== undefined) {
|
||||||
|
@ -356,6 +393,9 @@ class ExpandTagRendering extends Conversion<
|
||||||
let candidates = Array.from(state.tagRenderings.keys())
|
let candidates = Array.from(state.tagRenderings.keys())
|
||||||
if (name.indexOf(".") > 0) {
|
if (name.indexOf(".") > 0) {
|
||||||
const [layerName] = name.split(".")
|
const [layerName] = name.split(".")
|
||||||
|
if(layerName === undefined){
|
||||||
|
ctx.err("Layername is undefined", name)
|
||||||
|
}
|
||||||
let layer = state.sharedLayers.get(layerName)
|
let layer = state.sharedLayers.get(layerName)
|
||||||
if (layerName === this._self?.id) {
|
if (layerName === this._self?.id) {
|
||||||
layer = this._self
|
layer = this._self
|
||||||
|
@ -363,7 +403,7 @@ class ExpandTagRendering extends Conversion<
|
||||||
if (layer === undefined) {
|
if (layer === undefined) {
|
||||||
const candidates = Utils.sortedByLevenshteinDistance(
|
const candidates = Utils.sortedByLevenshteinDistance(
|
||||||
layerName,
|
layerName,
|
||||||
Array.from(state.sharedLayers.keys()),
|
Utils.NoNull(Array.from(state.sharedLayers.keys())),
|
||||||
(s) => s
|
(s) => s
|
||||||
)
|
)
|
||||||
if (state.sharedLayers.size === 0) {
|
if (state.sharedLayers.size === 0) {
|
||||||
|
@ -1017,7 +1057,8 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
||||||
class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
|
class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
|
||||||
constructor(state: DesugaringContext, layer: LayerConfigJson) {
|
constructor(state: DesugaringContext, layer: LayerConfigJson) {
|
||||||
super(
|
super(
|
||||||
"Prepares point renderings by expanding 'icon' and 'iconBadges'",
|
"Prepares point renderings by expanding 'icon' and 'iconBadges'." +
|
||||||
|
" A tagRendering from the host tagRenderings will be substituted in",
|
||||||
new On(
|
new On(
|
||||||
"marker",
|
"marker",
|
||||||
new Each(
|
new Each(
|
||||||
|
|
|
@ -110,13 +110,11 @@ export class DoesImageExist extends DesugaringStep<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._knownImagePaths.has(image)) {
|
if (!this._knownImagePaths.has(image)) {
|
||||||
if (this.doesPathExist === undefined) {
|
if (this.doesPathExist === undefined || image.indexOf("nsi/logos/") >= 0) {
|
||||||
|
// pass
|
||||||
|
} else if (!this.doesPathExist(image) ) {
|
||||||
context.err(
|
context.err(
|
||||||
`Image with path ${image} not found or not attributed; it is used in ${context}`
|
`Image with path ${image} does not exist.\n Check for typo's and missing directories in the path. `
|
||||||
)
|
|
||||||
} else if (!this.doesPathExist(image)) {
|
|
||||||
context.err(
|
|
||||||
`Image with path ${image} does not exist.\n Check for typo's and missing directories in the path.`
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
context.err(
|
context.err(
|
||||||
|
|
|
@ -4,8 +4,16 @@ import { TagConfigJson } from "./TagConfigJson"
|
||||||
export interface IconConfigJson {
|
export interface IconConfigJson {
|
||||||
/**
|
/**
|
||||||
* question: What icon should be used?
|
* question: What icon should be used?
|
||||||
|
*
|
||||||
|
* To reuse icons from a different layer of a library:
|
||||||
|
* - The library layer has, within tagRenderings one which will output the URL of the image (e.g. mappings: {"if": "shop=xyz", then: "./assets/icons/shop_xyz.png"})
|
||||||
|
* - Use "layer_id.tagrendering_id"
|
||||||
|
*
|
||||||
|
* Note that if you reuse icons from a different icon set, you'll probably want to use `override` to set a default rendering
|
||||||
|
*
|
||||||
|
*
|
||||||
* types: <span class="text-lg font-bold">Use a different icon depending on the value of some attributes</span> ; icon
|
* types: <span class="text-lg font-bold">Use a different icon depending on the value of some attributes</span> ; icon
|
||||||
* suggestions: return Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))
|
* suggestions: return [ "nsi_brand.icon", "nsi_operator.icon", "id_presets.shop_rendering", ...Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))]
|
||||||
*/
|
*/
|
||||||
icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
|
icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue