Fix: actually search for keywords in theme view
This commit is contained in:
parent
821c1fabd7
commit
cdc1e05499
9 changed files with 193 additions and 95 deletions
|
@ -25,6 +25,31 @@
|
||||||
"cs": "Vrstva zobrazující (veřejné) toalety",
|
"cs": "Vrstva zobrazující (veřejné) toalety",
|
||||||
"sl": "Prikaz (javnih) stranišč"
|
"sl": "Prikaz (javnih) stranišč"
|
||||||
},
|
},
|
||||||
|
"searchTerms": {
|
||||||
|
"en": [
|
||||||
|
"Toilets",
|
||||||
|
"Bathroom",
|
||||||
|
"Lavatory",
|
||||||
|
"Water Closet",
|
||||||
|
"outhouse",
|
||||||
|
"privy",
|
||||||
|
"head",
|
||||||
|
"latrine",
|
||||||
|
"WC",
|
||||||
|
"W.C."
|
||||||
|
],
|
||||||
|
"nl": [
|
||||||
|
"WC",
|
||||||
|
"WCs",
|
||||||
|
"plee",
|
||||||
|
"gemak",
|
||||||
|
"opschik",
|
||||||
|
"kabinet",
|
||||||
|
"latrine",
|
||||||
|
"retirade",
|
||||||
|
"piesemopsantee"
|
||||||
|
]
|
||||||
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"osmTags": "amenity=toilets"
|
"osmTags": "amenity=toilets"
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,10 @@ import Translations from "../src/UI/i18n/Translations"
|
||||||
import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
||||||
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||||
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
|
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
|
||||||
|
import {
|
||||||
|
MinimalTagRenderingConfigJson,
|
||||||
|
TagRenderingConfigJson,
|
||||||
|
} from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||||
|
|
||||||
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
|
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
|
||||||
// It spits out an overview of those to be used to load them
|
// It spits out an overview of those to be used to load them
|
||||||
|
@ -56,7 +60,7 @@ class ParseLayer extends Conversion<
|
||||||
|
|
||||||
convert(
|
convert(
|
||||||
path: string,
|
path: string,
|
||||||
context: ConversionContext
|
context: ConversionContext,
|
||||||
): {
|
): {
|
||||||
parsed: LayerConfig
|
parsed: LayerConfig
|
||||||
raw: LayerConfigJson
|
raw: LayerConfigJson
|
||||||
|
@ -85,7 +89,7 @@ class ParseLayer extends Conversion<
|
||||||
context
|
context
|
||||||
.enter("source")
|
.enter("source")
|
||||||
.err(
|
.err(
|
||||||
"No source is configured. (Tags might be automatically derived if presets are given)"
|
"No source is configured. (Tags might be automatically derived if presets are given)",
|
||||||
)
|
)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -116,7 +120,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
|
||||||
const fixed = json.raw
|
const fixed = json.raw
|
||||||
const layerConfig = json.parsed
|
const layerConfig = json.parsed
|
||||||
const pointRendering: PointRenderingConfig = layerConfig.mapRendering.find((pr) =>
|
const pointRendering: PointRenderingConfig = layerConfig.mapRendering.find((pr) =>
|
||||||
pr.location.has("point")
|
pr.location.has("point"),
|
||||||
)
|
)
|
||||||
const defaultTags = layerConfig.GetBaseTags()
|
const defaultTags = layerConfig.GetBaseTags()
|
||||||
fixed["_layerIcon"] = Utils.NoNull(
|
fixed["_layerIcon"] = Utils.NoNull(
|
||||||
|
@ -131,7 +135,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
|
||||||
result["color"] = c
|
result["color"] = c
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
return { raw: fixed, parsed: layerConfig }
|
return { raw: fixed, parsed: layerConfig }
|
||||||
}
|
}
|
||||||
|
@ -153,7 +157,7 @@ class LayerOverviewUtils extends Script {
|
||||||
|
|
||||||
private static extractLayerIdsFrom(
|
private static extractLayerIdsFrom(
|
||||||
themeFile: LayoutConfigJson,
|
themeFile: LayoutConfigJson,
|
||||||
includeInlineLayers = true
|
includeInlineLayers = true,
|
||||||
): string[] {
|
): string[] {
|
||||||
const publicLayerIds: string[] = []
|
const publicLayerIds: string[] = []
|
||||||
if (!Array.isArray(themeFile.layers)) {
|
if (!Array.isArray(themeFile.layers)) {
|
||||||
|
@ -220,19 +224,63 @@ class LayerOverviewUtils extends Script {
|
||||||
| LayerConfigJson
|
| LayerConfigJson
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
builtin
|
builtin
|
||||||
}
|
}
|
||||||
)[]
|
)[]
|
||||||
}[]
|
}[],
|
||||||
) {
|
) {
|
||||||
const perId = new Map<string, any>()
|
const perId = new Map<string, any>()
|
||||||
for (const theme of themes) {
|
for (const theme of themes) {
|
||||||
const keywords: {}[] = []
|
const keywords: Record<string, string[]> = {}
|
||||||
|
|
||||||
|
function addWord(language: string, word: string | string[]) {
|
||||||
|
if(Array.isArray(word)){
|
||||||
|
word.forEach(w => addWord(language, w))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
word = Utils.SubstituteKeys(word, {}).trim()
|
||||||
|
if(!word){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(language, "--->", word)
|
||||||
|
if (!keywords[language]) {
|
||||||
|
keywords[language] = []
|
||||||
|
}
|
||||||
|
keywords[language].push(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWords(tr: string | Record<string, string> | Record<string, string[]> | TagRenderingConfigJson) {
|
||||||
|
if(!tr){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (typeof tr === "string") {
|
||||||
|
addWord("*", tr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (tr["render"] !== undefined || tr["mappings"] !== undefined) {
|
||||||
|
tr = <TagRenderingConfigJson>tr
|
||||||
|
addWords(<Translatable>tr.render)
|
||||||
|
for (let mapping of tr.mappings ?? []) {
|
||||||
|
if (typeof mapping === "string") {
|
||||||
|
addWords(mapping)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addWords(mapping.then)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const lang in tr) {
|
||||||
|
addWord(lang, tr[lang])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const layer of theme.layers ?? []) {
|
for (const layer of theme.layers ?? []) {
|
||||||
const l = <LayerConfigJson>layer
|
const l = <LayerConfigJson>layer
|
||||||
keywords.push({ "*": l.id })
|
addWord("*", l.id)
|
||||||
keywords.push(l.title)
|
addWords(l.title)
|
||||||
keywords.push(l.description)
|
addWords(l.description)
|
||||||
|
addWords(l.searchTerms)
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -242,7 +290,7 @@ class LayerOverviewUtils extends Script {
|
||||||
icon: theme.icon,
|
icon: theme.icon,
|
||||||
hideFromOverview: theme.hideFromOverview,
|
hideFromOverview: theme.hideFromOverview,
|
||||||
mustHaveLanguage: theme.mustHaveLanguage,
|
mustHaveLanguage: theme.mustHaveLanguage,
|
||||||
keywords: Utils.NoNull(keywords),
|
keywords,
|
||||||
}
|
}
|
||||||
perId.set(theme.id, data)
|
perId.set(theme.id, data)
|
||||||
}
|
}
|
||||||
|
@ -264,7 +312,7 @@ class LayerOverviewUtils extends Script {
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
"./src/assets/generated/theme_overview.json",
|
"./src/assets/generated/theme_overview.json",
|
||||||
JSON.stringify(sorted, null, " "),
|
JSON.stringify(sorted, null, " "),
|
||||||
{ encoding: "utf8" }
|
{ encoding: "utf8" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +324,7 @@ class LayerOverviewUtils extends Script {
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
`${LayerOverviewUtils.themePath}${theme.id}.json`,
|
`${LayerOverviewUtils.themePath}${theme.id}.json`,
|
||||||
JSON.stringify(theme, null, " "),
|
JSON.stringify(theme, null, " "),
|
||||||
{ encoding: "utf8" }
|
{ encoding: "utf8" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,12 +335,12 @@ class LayerOverviewUtils extends Script {
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
`${LayerOverviewUtils.layerPath}${layer.id}.json`,
|
`${LayerOverviewUtils.layerPath}${layer.id}.json`,
|
||||||
JSON.stringify(layer, null, " "),
|
JSON.stringify(layer, null, " "),
|
||||||
{ encoding: "utf8" }
|
{ encoding: "utf8" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static asDict(
|
static asDict(
|
||||||
trs: QuestionableTagRenderingConfigJson[]
|
trs: QuestionableTagRenderingConfigJson[],
|
||||||
): Map<string, QuestionableTagRenderingConfigJson> {
|
): Map<string, QuestionableTagRenderingConfigJson> {
|
||||||
const d = new Map<string, QuestionableTagRenderingConfigJson>()
|
const d = new Map<string, QuestionableTagRenderingConfigJson>()
|
||||||
for (const tr of trs) {
|
for (const tr of trs) {
|
||||||
|
@ -305,12 +353,12 @@ class LayerOverviewUtils extends Script {
|
||||||
getSharedTagRenderings(
|
getSharedTagRenderings(
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson>,
|
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson>,
|
||||||
bootstrapTagRenderingsOrder: string[]
|
bootstrapTagRenderingsOrder: string[],
|
||||||
): QuestionableTagRenderingConfigJson[]
|
): QuestionableTagRenderingConfigJson[]
|
||||||
getSharedTagRenderings(
|
getSharedTagRenderings(
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson> = null,
|
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson> = null,
|
||||||
bootstrapTagRenderingsOrder: string[] = []
|
bootstrapTagRenderingsOrder: string[] = [],
|
||||||
): QuestionableTagRenderingConfigJson[] {
|
): QuestionableTagRenderingConfigJson[] {
|
||||||
const prepareLayer = new PrepareLayer(
|
const prepareLayer = new PrepareLayer(
|
||||||
{
|
{
|
||||||
|
@ -321,7 +369,7 @@ class LayerOverviewUtils extends Script {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
addTagRenderingsToContext: true,
|
addTagRenderingsToContext: true,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const path = "assets/layers/questions/questions.json"
|
const path = "assets/layers/questions/questions.json"
|
||||||
|
@ -341,7 +389,7 @@ class LayerOverviewUtils extends Script {
|
||||||
return this.getSharedTagRenderings(
|
return this.getSharedTagRenderings(
|
||||||
doesImageExist,
|
doesImageExist,
|
||||||
dict,
|
dict,
|
||||||
sharedQuestions.tagRenderings.map((tr) => tr["id"])
|
sharedQuestions.tagRenderings.map((tr) => tr["id"]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,8 +429,8 @@ class LayerOverviewUtils extends Script {
|
||||||
if (contents.indexOf("<text") > 0) {
|
if (contents.indexOf("<text") > 0) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"The SVG at " +
|
"The SVG at " +
|
||||||
path +
|
path +
|
||||||
" contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path"
|
" contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path",
|
||||||
)
|
)
|
||||||
errCount++
|
errCount++
|
||||||
}
|
}
|
||||||
|
@ -398,14 +446,14 @@ class LayerOverviewUtils extends Script {
|
||||||
args
|
args
|
||||||
.find((a) => a.startsWith("--themes="))
|
.find((a) => a.startsWith("--themes="))
|
||||||
?.substring("--themes=".length)
|
?.substring("--themes=".length)
|
||||||
?.split(",") ?? []
|
?.split(",") ?? [],
|
||||||
)
|
)
|
||||||
|
|
||||||
const layerWhitelist = new Set(
|
const layerWhitelist = new Set(
|
||||||
args
|
args
|
||||||
.find((a) => a.startsWith("--layers="))
|
.find((a) => a.startsWith("--layers="))
|
||||||
?.substring("--layers=".length)
|
?.substring("--layers=".length)
|
||||||
?.split(",") ?? []
|
?.split(",") ?? [],
|
||||||
)
|
)
|
||||||
|
|
||||||
const forceReload = args.some((a) => a == "--force")
|
const forceReload = args.some((a) => a == "--force")
|
||||||
|
@ -440,11 +488,11 @@ class LayerOverviewUtils extends Script {
|
||||||
sharedLayers,
|
sharedLayers,
|
||||||
recompiledThemes,
|
recompiledThemes,
|
||||||
forceReload,
|
forceReload,
|
||||||
themeWhitelist
|
themeWhitelist,
|
||||||
)
|
)
|
||||||
|
|
||||||
new ValidateThemeEnsemble().convertStrict(
|
new ValidateThemeEnsemble().convertStrict(
|
||||||
Array.from(sharedThemes.values()).map((th) => new LayoutConfig(th, true))
|
Array.from(sharedThemes.values()).map((th) => new LayoutConfig(th, true)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (recompiledThemes.length > 0) {
|
if (recompiledThemes.length > 0) {
|
||||||
|
@ -452,7 +500,7 @@ class LayerOverviewUtils extends Script {
|
||||||
"./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.id !== "favourite"),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,7 +521,7 @@ class LayerOverviewUtils extends Script {
|
||||||
const proto: LayoutConfigJson = JSON.parse(
|
const proto: LayoutConfigJson = JSON.parse(
|
||||||
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
|
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
const protolayer = <LayerConfigJson>(
|
const protolayer = <LayerConfigJson>(
|
||||||
proto.layers.filter((l) => l["id"] === "mapcomplete-changes")[0]
|
proto.layers.filter((l) => l["id"] === "mapcomplete-changes")[0]
|
||||||
|
@ -490,12 +538,12 @@ class LayerOverviewUtils extends Script {
|
||||||
layers: ScriptUtils.getLayerFiles().map((f) => f.parsed),
|
layers: ScriptUtils.getLayerFiles().map((f) => f.parsed),
|
||||||
themes: ScriptUtils.getThemeFiles().map((f) => f.parsed),
|
themes: ScriptUtils.getThemeFiles().map((f) => f.parsed),
|
||||||
},
|
},
|
||||||
ConversionContext.construct([], [])
|
ConversionContext.construct([], []),
|
||||||
)
|
)
|
||||||
|
|
||||||
for (const [_, theme] of sharedThemes) {
|
for (const [_, theme] of sharedThemes) {
|
||||||
theme.layers = theme.layers.filter(
|
theme.layers = theme.layers.filter(
|
||||||
(l) => Constants.added_by_default.indexOf(l["id"]) < 0
|
(l) => Constants.added_by_default.indexOf(l["id"]) < 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +552,7 @@ class LayerOverviewUtils extends Script {
|
||||||
"./src/assets/generated/known_themes.json",
|
"./src/assets/generated/known_themes.json",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
themes: Array.from(sharedThemes.values()),
|
themes: Array.from(sharedThemes.values()),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,7 +564,7 @@ class LayerOverviewUtils extends Script {
|
||||||
private parseLayer(
|
private parseLayer(
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
prepLayer: PrepareLayer,
|
prepLayer: PrepareLayer,
|
||||||
sharedLayerPath: string
|
sharedLayerPath: string,
|
||||||
): {
|
): {
|
||||||
raw: LayerConfigJson
|
raw: LayerConfigJson
|
||||||
parsed: LayerConfig
|
parsed: LayerConfig
|
||||||
|
@ -527,7 +575,7 @@ class LayerOverviewUtils extends Script {
|
||||||
const parsed = parser.convertStrict(sharedLayerPath, context)
|
const parsed = parser.convertStrict(sharedLayerPath, context)
|
||||||
const result = AddIconSummary.singleton.convertStrict(
|
const result = AddIconSummary.singleton.convertStrict(
|
||||||
parsed,
|
parsed,
|
||||||
context.inOperation("AddIconSummary")
|
context.inOperation("AddIconSummary"),
|
||||||
)
|
)
|
||||||
return { ...result, context }
|
return { ...result, context }
|
||||||
}
|
}
|
||||||
|
@ -535,7 +583,7 @@ class LayerOverviewUtils extends Script {
|
||||||
private buildLayerIndex(
|
private buildLayerIndex(
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
forceReload: boolean,
|
forceReload: boolean,
|
||||||
whitelist: Set<string>
|
whitelist: Set<string>,
|
||||||
): Map<string, LayerConfigJson> {
|
): Map<string, LayerConfigJson> {
|
||||||
// First, we expand and validate all builtin layers. These are written to src/assets/generated/layers
|
// First, we expand and validate all builtin layers. These are written to src/assets/generated/layers
|
||||||
// At the same time, an index of available layers is built.
|
// At the same time, an index of available layers is built.
|
||||||
|
@ -590,17 +638,17 @@ class LayerOverviewUtils extends Script {
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"Recompiled layers " +
|
"Recompiled layers " +
|
||||||
recompiledLayers.join(", ") +
|
recompiledLayers.join(", ") +
|
||||||
" and skipped " +
|
" and skipped " +
|
||||||
skippedLayers.length +
|
skippedLayers.length +
|
||||||
" layers. Detected " +
|
" layers. Detected " +
|
||||||
warningCount +
|
warningCount +
|
||||||
" warnings"
|
" warnings",
|
||||||
)
|
)
|
||||||
// We always need the calculated tags of 'usersettings', so we export them separately
|
// We always need the calculated tags of 'usersettings', so we export them separately
|
||||||
this.extractJavascriptCodeForLayer(
|
this.extractJavascriptCodeForLayer(
|
||||||
state.sharedLayers.get("usersettings"),
|
state.sharedLayers.get("usersettings"),
|
||||||
"./src/Logic/State/UserSettingsMetaTagging.ts"
|
"./src/Logic/State/UserSettingsMetaTagging.ts",
|
||||||
)
|
)
|
||||||
|
|
||||||
return sharedLayers
|
return sharedLayers
|
||||||
|
@ -617,8 +665,8 @@ class LayerOverviewUtils extends Script {
|
||||||
private extractJavascriptCode(themeFile: LayoutConfigJson) {
|
private extractJavascriptCode(themeFile: LayoutConfigJson) {
|
||||||
const allCode = [
|
const allCode = [
|
||||||
"import {Feature} from 'geojson'",
|
"import {Feature} from 'geojson'",
|
||||||
'import { ExtraFuncType } from "../../../Logic/ExtraFunctions";',
|
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";",
|
||||||
'import { Utils } from "../../../Utils"',
|
"import { Utils } from \"../../../Utils\"",
|
||||||
"export class ThemeMetaTagging {",
|
"export class ThemeMetaTagging {",
|
||||||
" public static readonly themeName = " + JSON.stringify(themeFile.id),
|
" public static readonly themeName = " + JSON.stringify(themeFile.id),
|
||||||
"",
|
"",
|
||||||
|
@ -630,8 +678,8 @@ class LayerOverviewUtils extends Script {
|
||||||
|
|
||||||
allCode.push(
|
allCode.push(
|
||||||
" public metaTaggging_for_" +
|
" public metaTaggging_for_" +
|
||||||
id +
|
id +
|
||||||
"(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {"
|
"(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {",
|
||||||
)
|
)
|
||||||
allCode.push(" const {" + ExtraFunctions.types.join(", ") + "} = helperFunctions")
|
allCode.push(" const {" + ExtraFunctions.types.join(", ") + "} = helperFunctions")
|
||||||
for (const line of code) {
|
for (const line of code) {
|
||||||
|
@ -642,10 +690,10 @@ class LayerOverviewUtils extends Script {
|
||||||
if (!isStrict) {
|
if (!isStrict) {
|
||||||
allCode.push(
|
allCode.push(
|
||||||
" Utils.AddLazyProperty(feat.properties, '" +
|
" Utils.AddLazyProperty(feat.properties, '" +
|
||||||
attributeName +
|
attributeName +
|
||||||
"', () => " +
|
"', () => " +
|
||||||
expression +
|
expression +
|
||||||
" ) "
|
" ) ",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
attributeName = attributeName.substring(0, attributeName.length - 1).trim()
|
attributeName = attributeName.substring(0, attributeName.length - 1).trim()
|
||||||
|
@ -690,7 +738,7 @@ class LayerOverviewUtils extends Script {
|
||||||
const code = l.calculatedTags ?? []
|
const code = l.calculatedTags ?? []
|
||||||
|
|
||||||
allCode.push(
|
allCode.push(
|
||||||
" public metaTaggging_for_" + l.id + "(feat: {properties: Record<string, string>}) {"
|
" public metaTaggging_for_" + l.id + "(feat: {properties: Record<string, string>}) {",
|
||||||
)
|
)
|
||||||
for (const line of code) {
|
for (const line of code) {
|
||||||
const firstEq = line.indexOf("=")
|
const firstEq = line.indexOf("=")
|
||||||
|
@ -700,10 +748,10 @@ class LayerOverviewUtils extends Script {
|
||||||
if (!isStrict) {
|
if (!isStrict) {
|
||||||
allCode.push(
|
allCode.push(
|
||||||
" Utils.AddLazyProperty(feat.properties, '" +
|
" Utils.AddLazyProperty(feat.properties, '" +
|
||||||
attributeName +
|
attributeName +
|
||||||
"', () => " +
|
"', () => " +
|
||||||
expression +
|
expression +
|
||||||
" ) "
|
" ) ",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
attributeName = attributeName.substring(0, attributeName.length - 2).trim()
|
attributeName = attributeName.substring(0, attributeName.length - 2).trim()
|
||||||
|
@ -728,14 +776,14 @@ class LayerOverviewUtils extends Script {
|
||||||
sharedLayers: Map<string, LayerConfigJson>,
|
sharedLayers: Map<string, LayerConfigJson>,
|
||||||
recompiledThemes: string[],
|
recompiledThemes: string[],
|
||||||
forceReload: boolean,
|
forceReload: boolean,
|
||||||
whitelist: Set<string>
|
whitelist: Set<string>,
|
||||||
): Map<string, LayoutConfigJson> {
|
): Map<string, LayoutConfigJson> {
|
||||||
console.log(" ---------- VALIDATING BUILTIN THEMES ---------")
|
console.log(" ---------- VALIDATING BUILTIN THEMES ---------")
|
||||||
const themeFiles = ScriptUtils.getThemeFiles()
|
const themeFiles = ScriptUtils.getThemeFiles()
|
||||||
const fixed = new Map<string, LayoutConfigJson>()
|
const fixed = new Map<string, LayoutConfigJson>()
|
||||||
|
|
||||||
const publicLayers = LayerOverviewUtils.publicLayerIdsFrom(
|
const publicLayers = LayerOverviewUtils.publicLayerIdsFrom(
|
||||||
themeFiles.map((th) => th.parsed)
|
themeFiles.map((th) => th.parsed),
|
||||||
)
|
)
|
||||||
|
|
||||||
const trs = this.getSharedTagRenderings(new DoesImageExist(licensePaths, existsSync))
|
const trs = this.getSharedTagRenderings(new DoesImageExist(licensePaths, existsSync))
|
||||||
|
@ -775,15 +823,15 @@ class LayerOverviewUtils extends Script {
|
||||||
LayerOverviewUtils.themePath + "/" + themePath.substring(themePath.lastIndexOf("/"))
|
LayerOverviewUtils.themePath + "/" + themePath.substring(themePath.lastIndexOf("/"))
|
||||||
|
|
||||||
const usedLayers = Array.from(
|
const usedLayers = Array.from(
|
||||||
LayerOverviewUtils.extractLayerIdsFrom(themeFile, false)
|
LayerOverviewUtils.extractLayerIdsFrom(themeFile, false),
|
||||||
).map((id) => LayerOverviewUtils.layerPath + id + ".json")
|
).map((id) => LayerOverviewUtils.layerPath + id + ".json")
|
||||||
|
|
||||||
if (!forceReload && !this.shouldBeUpdated([themePath, ...usedLayers], targetPath)) {
|
if (!forceReload && !this.shouldBeUpdated([themePath, ...usedLayers], targetPath)) {
|
||||||
fixed.set(
|
fixed.set(
|
||||||
themeFile.id,
|
themeFile.id,
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(LayerOverviewUtils.themePath + themeFile.id + ".json", "utf8")
|
readFileSync(LayerOverviewUtils.themePath + themeFile.id + ".json", "utf8"),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
ScriptUtils.erasableLog("Skipping", themeFile.id)
|
ScriptUtils.erasableLog("Skipping", themeFile.id)
|
||||||
skippedThemes.push(themeFile.id)
|
skippedThemes.push(themeFile.id)
|
||||||
|
@ -794,23 +842,23 @@ class LayerOverviewUtils extends Script {
|
||||||
|
|
||||||
new PrevalidateTheme().convertStrict(
|
new PrevalidateTheme().convertStrict(
|
||||||
themeFile,
|
themeFile,
|
||||||
ConversionContext.construct([themePath], ["PrepareLayer"])
|
ConversionContext.construct([themePath], ["PrepareLayer"]),
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
themeFile = new PrepareTheme(convertState, {
|
themeFile = new PrepareTheme(convertState, {
|
||||||
skipDefaultLayers: true,
|
skipDefaultLayers: true,
|
||||||
}).convertStrict(
|
}).convertStrict(
|
||||||
themeFile,
|
themeFile,
|
||||||
ConversionContext.construct([themePath], ["PrepareLayer"])
|
ConversionContext.construct([themePath], ["PrepareLayer"]),
|
||||||
)
|
)
|
||||||
new ValidateThemeAndLayers(
|
new ValidateThemeAndLayers(
|
||||||
new DoesImageExist(licensePaths, existsSync, knownTagRenderings),
|
new DoesImageExist(licensePaths, existsSync, knownTagRenderings),
|
||||||
themePath,
|
themePath,
|
||||||
true,
|
true,
|
||||||
knownTagRenderings
|
knownTagRenderings,
|
||||||
).convertStrict(
|
).convertStrict(
|
||||||
themeFile,
|
themeFile,
|
||||||
ConversionContext.construct([themePath], ["PrepareLayer"])
|
ConversionContext.construct([themePath], ["PrepareLayer"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (themeFile.icon.endsWith(".svg")) {
|
if (themeFile.icon.endsWith(".svg")) {
|
||||||
|
@ -860,7 +908,7 @@ class LayerOverviewUtils extends Script {
|
||||||
const usedImages = Utils.Dedup(
|
const usedImages = Utils.Dedup(
|
||||||
new ExtractImages(true, knownTagRenderings)
|
new ExtractImages(true, knownTagRenderings)
|
||||||
.convertStrict(themeFile)
|
.convertStrict(themeFile)
|
||||||
.map((x) => x.path)
|
.map((x) => x.path),
|
||||||
)
|
)
|
||||||
usedImages.sort()
|
usedImages.sort()
|
||||||
|
|
||||||
|
@ -886,16 +934,16 @@ class LayerOverviewUtils extends Script {
|
||||||
t.shortDescription ?? new Translation(t.description).FirstSentence(),
|
t.shortDescription ?? new Translation(t.description).FirstSentence(),
|
||||||
mustHaveLanguage: t.mustHaveLanguage?.length > 0,
|
mustHaveLanguage: t.mustHaveLanguage?.length > 0,
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"Recompiled themes " +
|
"Recompiled themes " +
|
||||||
recompiledThemes.join(", ") +
|
recompiledThemes.join(", ") +
|
||||||
" and skipped " +
|
" and skipped " +
|
||||||
skippedThemes.length +
|
skippedThemes.length +
|
||||||
" themes"
|
" themes",
|
||||||
)
|
)
|
||||||
|
|
||||||
return fixed
|
return fixed
|
||||||
|
|
|
@ -41,14 +41,22 @@ export interface LayerConfigJson {
|
||||||
name?: Translatable
|
name?: Translatable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* question: How would you describe the features that are shown on this layer?
|
||||||
|
*
|
||||||
* A description for the features shown in this layer.
|
* A description for the features shown in this layer.
|
||||||
* This often resembles the introduction of the wiki.osm.org-page for this feature.
|
* This often resembles the introduction of the wiki.osm.org-page for this feature.
|
||||||
*
|
*
|
||||||
* group: Basic
|
* group: Basic
|
||||||
* question: How would you describe the features that are shown on this layer?
|
|
||||||
*/
|
*/
|
||||||
description?: Translatable
|
description?: Translatable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* question: What are some other terms used to describe these objects?
|
||||||
|
*
|
||||||
|
* This is used in the search functionality
|
||||||
|
*/
|
||||||
|
searchTerms?: Record<string, string[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Question: Where should the data be fetched from?
|
* Question: Where should the data be fetched from?
|
||||||
* title: Data Source
|
* title: Data Source
|
||||||
|
|
|
@ -29,6 +29,7 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
public readonly id: string
|
public readonly id: string
|
||||||
public readonly name: Translation
|
public readonly name: Translation
|
||||||
public readonly description: Translation
|
public readonly description: Translation
|
||||||
|
public readonly searchTerms: Record<string, string[]>
|
||||||
/**
|
/**
|
||||||
* Only 'null' for special, privileged layers
|
* Only 'null' for special, privileged layers
|
||||||
*/
|
*/
|
||||||
|
@ -113,8 +114,8 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
json.description = undefined
|
json.description = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.description = Translations.T(json.description, translationContext + ".description")
|
this.description = Translations.T(json.description, translationContext + ".description")
|
||||||
|
this.searchTerms = json.searchTerms ?? {}
|
||||||
|
|
||||||
this.calculatedTags = undefined
|
this.calculatedTags = undefined
|
||||||
if (json.calculatedTags !== undefined) {
|
if (json.calculatedTags !== undefined) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class MinimalLayoutInformation {
|
||||||
definition?: Translatable
|
definition?: Translatable
|
||||||
mustHaveLanguage?: boolean
|
mustHaveLanguage?: boolean
|
||||||
hideFromOverview?: boolean
|
hideFromOverview?: boolean
|
||||||
keywords?: (Translatable | TagRenderingConfigJson)[]
|
keywords?: Record<string, string[]>
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Minimal information about a theme
|
* Minimal information about a theme
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default class MoreScreen {
|
||||||
MoreScreen.officialThemesById.set(th.id, th)
|
MoreScreen.officialThemesById.set(th.id, th)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static applySearch(searchTerm: string) {
|
public static applySearch(searchTerm: string) {
|
||||||
searchTerm = searchTerm.toLowerCase()
|
searchTerm = searchTerm.toLowerCase()
|
||||||
if (!searchTerm) {
|
if (!searchTerm) {
|
||||||
|
@ -43,13 +44,13 @@ export default class MoreScreen {
|
||||||
(th) =>
|
(th) =>
|
||||||
th.hideFromOverview == false &&
|
th.hideFromOverview == false &&
|
||||||
th.id !== "personal" &&
|
th.id !== "personal" &&
|
||||||
MoreScreen.MatchesLayout(th, searchTerm)
|
MoreScreen.MatchesLayout(th, searchTerm),
|
||||||
)
|
)
|
||||||
if (publicTheme !== undefined) {
|
if (publicTheme !== undefined) {
|
||||||
window.location.href = MoreScreen.createUrlFor(publicTheme, false)
|
window.location.href = MoreScreen.createUrlFor(publicTheme, false)
|
||||||
}
|
}
|
||||||
const hiddenTheme = MoreScreen.officialThemes.find(
|
const hiddenTheme = MoreScreen.officialThemes.find(
|
||||||
(th) => th.id !== "personal" && MoreScreen.MatchesLayout(th, searchTerm)
|
(th) => th.id !== "personal" && MoreScreen.MatchesLayout(th, searchTerm),
|
||||||
)
|
)
|
||||||
if (hiddenTheme !== undefined) {
|
if (hiddenTheme !== undefined) {
|
||||||
window.location.href = MoreScreen.createUrlFor(hiddenTheme, false)
|
window.location.href = MoreScreen.createUrlFor(hiddenTheme, false)
|
||||||
|
@ -57,34 +58,47 @@ export default class MoreScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MatchesLayout(
|
public static MatchesLayout(
|
||||||
layout: {
|
layout: MinimalLayoutInformation,
|
||||||
id: string
|
search: string,
|
||||||
title: Translatable
|
language?: string,
|
||||||
shortDescription: Translatable
|
|
||||||
keywords?: (Translatable | TagRenderingConfigJson)[]
|
|
||||||
},
|
|
||||||
search: string
|
|
||||||
): boolean {
|
): boolean {
|
||||||
if (search === undefined) {
|
if (search === undefined) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
search = Utils.RemoveDiacritics(search.toLocaleLowerCase()) // See #1729
|
search = Utils.simplifyStringForSearch(search.toLocaleLowerCase()) // See #1729
|
||||||
if (search.length > 3 && layout.id.toLowerCase().indexOf(search) >= 0) {
|
if (search.length > 3 && layout.id.toLowerCase().indexOf(search) >= 0) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (layout.id === "personal") {
|
if (layout.id === "personal") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if(Utils.simplifyStringForSearch(layout.id) === Utils.simplifyStringForSearch(search)){
|
if (Utils.simplifyStringForSearch(layout.id) === Utils.simplifyStringForSearch(search)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const entitiesToSearch = [layout.shortDescription, layout.title, ...(layout.keywords ?? [])]
|
language ??= Locale.language.data
|
||||||
|
|
||||||
|
const entitiesToSearch: (string | Record<string, string> | Record<string, string[]>)[] = [layout.shortDescription, layout.title, layout.keywords]
|
||||||
for (const entity of entitiesToSearch) {
|
for (const entity of entitiesToSearch) {
|
||||||
if (entity === undefined) {
|
if (entity === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const term: string = entity["*"] ?? entity[Locale.language.data]
|
|
||||||
if (Utils.RemoveDiacritics(term?.toLowerCase())?.indexOf(search) >= 0) {
|
let term: string[]
|
||||||
|
if (typeof entity === "string") {
|
||||||
|
term = [entity]
|
||||||
|
} else {
|
||||||
|
const terms = [].concat(entity["*"], entity[language])
|
||||||
|
if (Array.isArray(terms)) {
|
||||||
|
term = terms
|
||||||
|
} else {
|
||||||
|
term = [terms]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const minLevehnstein = Math.min(...Utils.NoNull(term).map(t => Utils.levenshteinDistance(search,
|
||||||
|
Utils.simplifyStringForSearch(t).slice(0, search.length))))
|
||||||
|
|
||||||
|
if (minLevehnstein < 1 || minLevehnstein / search.length < 0.2) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +109,7 @@ export default class MoreScreen {
|
||||||
public static createUrlFor(
|
public static createUrlFor(
|
||||||
layout: { id: string },
|
layout: { id: string },
|
||||||
isCustom: boolean,
|
isCustom: boolean,
|
||||||
state?: { layoutToUse?: { id } }
|
state?: { layoutToUse?: { id } },
|
||||||
): string {
|
): string {
|
||||||
if (layout === undefined) {
|
if (layout === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
|
@ -141,7 +155,7 @@ export default class MoreScreen {
|
||||||
new Set<string>(
|
new Set<string>(
|
||||||
Object.keys(preferences)
|
Object.keys(preferences)
|
||||||
.filter((key) => key.startsWith(prefix))
|
.filter((key) => key.startsWith(prefix))
|
||||||
.map((key) => key.substring(prefix.length, key.length - "-enabled".length))
|
.map((key) => key.substring(prefix.length, key.length - "-enabled".length)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import UserDetails, { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import UserDetails, { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import Constants from "../../Models/Constants"
|
import Constants from "../../Models/Constants"
|
||||||
import type { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
||||||
import Marker from "../Map/Marker.svelte"
|
import Marker from "../Map/Marker.svelte"
|
||||||
|
|
||||||
export let theme: LayoutInformation
|
export let theme: MinimalLayoutInformation
|
||||||
export let isCustom: boolean = false
|
export let isCustom: boolean = false
|
||||||
export let userDetails: UIEventSource<UserDetails>
|
export let userDetails: UIEventSource<UserDetails>
|
||||||
export let state: { layoutToUse?: { id: string }; osmConnection: OsmConnection }
|
export let state: { layoutToUse?: { id: string }; osmConnection: OsmConnection }
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import ThemeButton from "./ThemeButton.svelte"
|
import ThemeButton from "./ThemeButton.svelte"
|
||||||
import { LayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import { LayoutInformation, MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import MoreScreen from "./MoreScreen"
|
import MoreScreen from "./MoreScreen"
|
||||||
import themeOverview from "../../assets/generated/theme_overview.json"
|
import themeOverview from "../../assets/generated/theme_overview.json"
|
||||||
|
|
||||||
export let search: UIEventSource<string>
|
export let search: UIEventSource<string>
|
||||||
export let themes: LayoutInformation[]
|
export let themes: MinimalLayoutInformation[]
|
||||||
export let state: { osmConnection: OsmConnection }
|
export let state: { osmConnection: OsmConnection }
|
||||||
export let isCustom: boolean = false
|
export let isCustom: boolean = false
|
||||||
export let hideThemes: boolean = true
|
export let hideThemes: boolean = true
|
||||||
|
|
|
@ -1602,6 +1602,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
* @constructor
|
* @constructor
|
||||||
*
|
*
|
||||||
* Utils.RemoveDiacritics("bâtiments") // => "batiments"
|
* Utils.RemoveDiacritics("bâtiments") // => "batiments"
|
||||||
|
* Utils.RemoveDiacritics(undefined) // => undefined
|
||||||
*/
|
*/
|
||||||
public static RemoveDiacritics(str?: string): string {
|
public static RemoveDiacritics(str?: string): string {
|
||||||
// See #1729
|
// See #1729
|
||||||
|
@ -1616,9 +1617,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
* @param str
|
* @param str
|
||||||
* Utils.simplifyStringForSearch("abc def; ghi 564") // => "abcdefghi564"
|
* Utils.simplifyStringForSearch("abc def; ghi 564") // => "abcdefghi564"
|
||||||
* Utils.simplifyStringForSearch("âbc déf; ghi 564") // => "abcdefghi564"
|
* Utils.simplifyStringForSearch("âbc déf; ghi 564") // => "abcdefghi564"
|
||||||
|
* Utils.simplifyStringForSearch(undefined) // => undefined
|
||||||
*/
|
*/
|
||||||
public static simplifyStringForSearch(str: string): string {
|
public static simplifyStringForSearch(str: string): string {
|
||||||
return Utils.RemoveDiacritics(str).toLowerCase().replace(/[^a-z0-9]/g, "")
|
return Utils.RemoveDiacritics(str)?.toLowerCase()?.replace(/[^a-z0-9]/g, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static randomString(length: number): string {
|
public static randomString(length: number): string {
|
||||||
|
|
Loading…
Reference in a new issue