Cleanup of NSI feature breanch
This commit is contained in:
parent
f6d93a6ab1
commit
3146fa0d26
14 changed files with 143 additions and 537 deletions
File diff suppressed because one or more lines are too long
|
@ -20,6 +20,7 @@ class Utilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenerateStats extends Script {
|
class GenerateStats extends Script {
|
||||||
|
|
||||||
async createOptimizationFile(includeTags = true) {
|
async createOptimizationFile(includeTags = true) {
|
||||||
|
@ -71,8 +72,8 @@ class GenerateStats extends Script {
|
||||||
tagTotal.set(key, new Map<string, number>())
|
tagTotal.set(key, new Map<string, number>())
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from(values).map(async (value) => {
|
Array.from(values).map(async (value) => {
|
||||||
const tagData: TagInfoStats= await TagInfo.global.getStats(key, value)
|
const tagData: TagInfoStats = await TagInfo.global.getStats(key, value)
|
||||||
const count = tagData.data .find((item) => item.type === "all").count
|
const count = tagData.data.find((item) => item.type === "all").count
|
||||||
tagTotal.get(key).set(value, count)
|
tagTotal.get(key).set(value, count)
|
||||||
console.log(key + "=" + value, "-->", count)
|
console.log(key + "=" + value, "-->", count)
|
||||||
})
|
})
|
||||||
|
@ -134,33 +135,33 @@ class GenerateStats extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async createNameSuggestionIndexFile(basepath: string,type: "brand" | "operator") {
|
async createNameSuggestionIndexFile(basepath: string, type: "brand" | "operator" | string) {
|
||||||
const path = basepath+type+'.json'
|
const path = basepath + type + ".json"
|
||||||
let allBrands = <Record<string, Record<string, number>>>{}
|
let allBrands = <Record<string, Record<string, number>>>{}
|
||||||
if (existsSync(path)) {
|
if (existsSync(path)) {
|
||||||
allBrands = JSON.parse(readFileSync(path, "utf8"))
|
allBrands = JSON.parse(readFileSync(path, "utf8"))
|
||||||
console.log("Loaded",Object.keys(allBrands).length," previously loaded brands")
|
console.log("Loaded", Object.keys(allBrands).length, " previously loaded brands")
|
||||||
}
|
}
|
||||||
let lastWrite = new Date()
|
const lastWrite = new Date()
|
||||||
let skipped = 0
|
let skipped = 0
|
||||||
const allBrandNames: string[] = Utils.Dedup(NameSuggestionIndex.allPossible(type).map(item => item.tags[type]))
|
const allBrandNames: string[] = Utils.Dedup(NameSuggestionIndex.allPossible(type).map(item => item.tags[type]))
|
||||||
for (let i = 0; i < allBrandNames.length; i++){
|
for (let i = 0; i < allBrandNames.length; i++) {
|
||||||
if(i % 100 == 0){
|
if (i % 100 == 0) {
|
||||||
console.log("Downloading ",i+"/"+allBrandNames.length,"; skipped",skipped)
|
console.log("Downloading ", i + "/" + allBrandNames.length, "; skipped", skipped)
|
||||||
}
|
}
|
||||||
const brand = allBrandNames[i]
|
const brand = allBrandNames[i]
|
||||||
if(!!allBrands[brand] && Object.keys(allBrands[brand]).length == 0){
|
if (!!allBrands[brand] && Object.keys(allBrands[brand]).length == 0) {
|
||||||
delete allBrands[brand]
|
delete allBrands[brand]
|
||||||
console.log("Deleted", brand, "as no entries at all")
|
console.log("Deleted", brand, "as no entries at all")
|
||||||
}
|
}
|
||||||
if(allBrands[brand] !== undefined){
|
if (allBrands[brand] !== undefined) {
|
||||||
const max = Math.max(...Object.values(allBrands[brand]))
|
const max = Math.max(...Object.values(allBrands[brand]))
|
||||||
skipped++
|
skipped++
|
||||||
if(max < 0){
|
if (max < 0) {
|
||||||
console.log("HMMMM:", allBrands[brand])
|
console.log("HMMMM:", allBrands[brand])
|
||||||
delete allBrands[brand]
|
delete allBrands[brand]
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,11 +180,13 @@ class GenerateStats extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
async main(_: string[]) {
|
async main(_: string[]) {
|
||||||
await this.createOptimizationFile()
|
|
||||||
const type = "brand"
|
|
||||||
const basepath = "./src/assets/generated/stats/"
|
const basepath = "./src/assets/generated/stats/"
|
||||||
await this.createNameSuggestionIndexFile(basepath, type)
|
for (const type of ["operator","brand"]) {
|
||||||
this.summarizeNSI(basepath+type+".json", "./public/assets/data/stats/"+type)
|
await this.createNameSuggestionIndexFile(basepath, type)
|
||||||
|
this.summarizeNSI(basepath + type + ".json", "./public/assets/data/nsi/stats/" + type)
|
||||||
|
}
|
||||||
|
await this.createOptimizationFile()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ export interface NSIItem {
|
||||||
export default class NameSuggestionIndex {
|
export default class NameSuggestionIndex {
|
||||||
|
|
||||||
private static readonly nsiFile: Readonly<NSIFile> = <any>nsi
|
private static readonly nsiFile: Readonly<NSIFile> = <any>nsi
|
||||||
|
private static readonly nsiWdFile: Readonly<Record<string, {
|
||||||
|
logos: { wikidata?: string, facebook?: string }
|
||||||
|
}>> = <any>nsiWD["wikidata"]
|
||||||
|
|
||||||
private static loco = new LocationConflation(nsiFeatures) // Some additional boundaries
|
private static loco = new LocationConflation(nsiFeatures) // Some additional boundaries
|
||||||
|
|
||||||
private static _supportedTypes: string[]
|
private static _supportedTypes: string[]
|
||||||
|
@ -68,7 +72,12 @@ export default class NameSuggestionIndex {
|
||||||
}
|
}
|
||||||
const keys = Object.keys(NameSuggestionIndex.nsiFile.nsi)
|
const keys = Object.keys(NameSuggestionIndex.nsiFile.nsi)
|
||||||
const all = keys.map(k => NameSuggestionIndex.nsiFile.nsi[k].properties.path.split("/")[0])
|
const all = keys.map(k => NameSuggestionIndex.nsiFile.nsi[k].properties.path.split("/")[0])
|
||||||
this._supportedTypes = Utils.Dedup(all)
|
this._supportedTypes = Utils.Dedup(all).map(s => {
|
||||||
|
if(s.endsWith("s")){
|
||||||
|
s = s.substring(0, s.length - 1)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
})
|
||||||
return this._supportedTypes
|
return this._supportedTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +91,6 @@ export default class NameSuggestionIndex {
|
||||||
private static async fetchFrequenciesFor(type: string, countries: string[]) {
|
private static async fetchFrequenciesFor(type: string, countries: string[]) {
|
||||||
let stats = await Promise.all(countries.map(c => {
|
let stats = await Promise.all(countries.map(c => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return Utils.downloadJsonCached<Record<string, number>>(`./assets/data/nsi/stats/${type}.${c.toUpperCase()}.json`, 24 * 60 * 60 * 1000)
|
return Utils.downloadJsonCached<Record<string, number>>(`./assets/data/nsi/stats/${type}.${c.toUpperCase()}.json`, 24 * 60 * 60 * 1000)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Could not fetch " + type + " statistics due to", e)
|
console.error("Could not fetch " + type + " statistics due to", e)
|
||||||
|
@ -93,6 +101,9 @@ export default class NameSuggestionIndex {
|
||||||
if (stats.length === 1) {
|
if (stats.length === 1) {
|
||||||
return stats[0]
|
return stats[0]
|
||||||
}
|
}
|
||||||
|
if(stats.length === 0){
|
||||||
|
return {}
|
||||||
|
}
|
||||||
const merged = stats[0]
|
const merged = stats[0]
|
||||||
for (let i = 1; i < stats.length; i++) {
|
for (let i = 1; i < stats.length; i++) {
|
||||||
for (const countryCode in stats[i]) {
|
for (const countryCode in stats[i]) {
|
||||||
|
@ -103,10 +114,7 @@ export default class NameSuggestionIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static isSvg(nsiItem: NSIItem, type: string): boolean | undefined {
|
public static isSvg(nsiItem: NSIItem, type: string): boolean | undefined {
|
||||||
const logos = nsiWD["wikidata"][nsiItem?.tags?.[type + ":wikidata"]]?.logos
|
const logos = this.nsiWdFile[nsiItem?.tags?.[type + ":wikidata"]]?.logos
|
||||||
if(nsiItem.id === "axa-2f6feb"){
|
|
||||||
console.trace(">>> HI")
|
|
||||||
}
|
|
||||||
if (!logos) {
|
if (!logos) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -120,37 +128,45 @@ export default class NameSuggestionIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async generateMappings(type: string, key: string, value: string, country: string[], location?: [number, number]) {
|
public static async generateMappings(type: string, tags: Record<string, string>, country: string[], location?: [number, number]): Promise<Mapping[]> {
|
||||||
const mappings: Mapping[] = []
|
const mappings: Mapping[] = []
|
||||||
const frequencies = await NameSuggestionIndex.fetchFrequenciesFor(type, country)
|
const frequencies = await NameSuggestionIndex.fetchFrequenciesFor(type, country)
|
||||||
const actualBrands = NameSuggestionIndex.getSuggestionsFor(type, key, value, country.join(";"), location)
|
for (const key in tags) {
|
||||||
for (const nsiItem of actualBrands) {
|
if (key.startsWith("_")) {
|
||||||
const tags = nsiItem.tags
|
continue
|
||||||
const frequency = frequencies[nsiItem.displayName]
|
}
|
||||||
const logos = nsiWD["wikidata"][nsiItem.tags[type + ":wikidata"]]?.logos
|
const value = tags[key]
|
||||||
let iconUrl = logos?.facebook ?? logos?.wikidata
|
const actualBrands = NameSuggestionIndex.getSuggestionsForKV(type, key, value, country.join(";"), location)
|
||||||
const hasIcon = iconUrl !== undefined
|
if(!actualBrands){
|
||||||
let icon = undefined
|
continue
|
||||||
if (hasIcon) {
|
}
|
||||||
// Using <img src=...> works fine without an extension for JPG and PNG, but _not_ svg :(
|
for (const nsiItem of actualBrands) {
|
||||||
icon = "./assets/data/nsi/logos/" + nsiItem.id
|
const tags = nsiItem.tags
|
||||||
if (NameSuggestionIndex.isSvg(nsiItem, type)) {
|
const frequency = frequencies[nsiItem.displayName]
|
||||||
console.log("Is svg:", nsiItem.displayName)
|
const logos = this.nsiWdFile[nsiItem.tags[type + ":wikidata"]]?.logos
|
||||||
icon = icon + ".svg"
|
const iconUrl = logos?.facebook ?? logos?.wikidata
|
||||||
}
|
const hasIcon = iconUrl !== undefined
|
||||||
|
let icon = undefined
|
||||||
|
if (hasIcon) {
|
||||||
|
// Using <img src=...> works fine without an extension for JPG and PNG, but _not_ svg :(
|
||||||
|
icon = "./assets/data/nsi/logos/" + nsiItem.id
|
||||||
|
if (NameSuggestionIndex.isSvg(nsiItem, type)) {
|
||||||
|
icon = icon + ".svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mappings.push({
|
||||||
|
if: new Tag(type, tags[type]),
|
||||||
|
addExtraTags: Object.keys(tags).filter(k => k !== type).map(k => new Tag(k, tags[k])),
|
||||||
|
then: new TypedTranslation<Record<string, never>>({ "*": nsiItem.displayName }),
|
||||||
|
hideInAnswer: false,
|
||||||
|
ifnot: undefined,
|
||||||
|
alsoShowIf: undefined,
|
||||||
|
icon,
|
||||||
|
iconClass: "medium",
|
||||||
|
priorityIf: frequency > 0 ? new RegexTag("id", /.*/) : undefined,
|
||||||
|
searchTerms: { "*": [nsiItem.displayName, nsiItem.id] }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
mappings.push({
|
|
||||||
if: new Tag(type, tags[type]),
|
|
||||||
addExtraTags: Object.keys(tags).filter(k => k !== type).map(k => new Tag(k, tags[k])),
|
|
||||||
then: new TypedTranslation<{}>({ "*": nsiItem.displayName }),
|
|
||||||
hideInAnswer: false,
|
|
||||||
ifnot: undefined,
|
|
||||||
alsoShowIf: undefined,
|
|
||||||
icon,
|
|
||||||
iconClass: "medium",
|
|
||||||
priorityIf: frequency > 0 ? new RegexTag("id", /.*/) : undefined,
|
|
||||||
searchTerms: { "*": [nsiItem.displayName, nsiItem.id] }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return mappings
|
return mappings
|
||||||
}
|
}
|
||||||
|
@ -184,7 +200,7 @@ export default class NameSuggestionIndex {
|
||||||
for (const osmKey in tags) {
|
for (const osmKey in tags) {
|
||||||
const values = tags[osmKey]
|
const values = tags[osmKey]
|
||||||
for (const osmValue of values) {
|
for (const osmValue of values) {
|
||||||
const suggestions = this.getSuggestionsFor(type, osmKey, osmValue)
|
const suggestions = this.getSuggestionsForKV(type, osmKey, osmValue)
|
||||||
options.push(...suggestions)
|
options.push(...suggestions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,11 +209,19 @@ export default class NameSuggestionIndex {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param path
|
|
||||||
* @param country: a string containing one or more country codes, separated by ";"
|
* @param country: a string containing one or more country codes, separated by ";"
|
||||||
* @param location: center point of the feature, should be [lon, lat]
|
* @param location: center point of the feature, should be [lon, lat]
|
||||||
*/
|
*/
|
||||||
public static getSuggestionsFor(type: string, key: string, value: string, country: string = undefined, location: [number, number] = undefined): NSIItem[] {
|
public static getSuggestionsFor(type: string, tags: {key: string, value: string}[], country: string = undefined, location: [number, number] = undefined): NSIItem[] {
|
||||||
|
return tags.flatMap(tag => this.getSuggestionsForKV(type, tag.key, tag.value, country, location))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param country: a string containing one or more country codes, separated by ";"
|
||||||
|
* @param location: center point of the feature, should be [lon, lat]
|
||||||
|
*/
|
||||||
|
public static getSuggestionsForKV(type: string, key: string, value: string, country: string = undefined, location: [number, number] = undefined): NSIItem[] {
|
||||||
const path = `${type}s/${key}/${value}`
|
const path = `${type}s/${key}/${value}`
|
||||||
const entry = NameSuggestionIndex.nsiFile.nsi[path]
|
const entry = NameSuggestionIndex.nsiFile.nsi[path]
|
||||||
return entry?.items?.filter(i => {
|
return entry?.items?.filter(i => {
|
||||||
|
|
|
@ -927,8 +927,10 @@ class CheckTranslation extends DesugaringStep<Translatable> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
|
class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
|
||||||
constructor() {
|
private readonly _layerConfig: LayerConfigJson
|
||||||
|
constructor(layerConfig?: LayerConfigJson) {
|
||||||
super("Miscellaneous checks on the tagrendering", ["special"], "MiscTagRenderingChecks")
|
super("Miscellaneous checks on the tagrendering", ["special"], "MiscTagRenderingChecks")
|
||||||
|
this._layerConfig = layerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(
|
convert(
|
||||||
|
@ -1092,13 +1094,14 @@ class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(json.freeform.type === "nsi"){
|
if(this._layerConfig?.source?.osmTags && NameSuggestionIndex.supportedTypes().indexOf(json.freeform.key) >= 0){
|
||||||
const [key, value] = json.freeform.helperArgs[0].split("=")
|
const tags= TagUtils.TagD(this._layerConfig?.source?.osmTags)?.usedTags()
|
||||||
const path = `${json.freeform.key}s/${key}/${value}`
|
const suggestions = NameSuggestionIndex.getSuggestionsFor(json.freeform.key, tags)
|
||||||
const suggestions = NameSuggestionIndex.getSuggestionsFor(json.freeform.key, key, value)
|
|
||||||
if(suggestions === undefined){
|
if(suggestions === undefined){
|
||||||
context.enters("freeform","type").err("No entry found in the 'Name Suggestion Index' for "+path)
|
context.enters("freeform","type").err("No entry found in the 'Name Suggestion Index'. None of the 'osmSource'-tags match an entry in the NSI.\n\tOsmSource-tags are "+tags.map(t => t.asHumanString()).join(" ; "))
|
||||||
}
|
}
|
||||||
|
}else if(json.freeform.type === "nsi"){
|
||||||
|
context.enters("freeform","type").warn("No need to explicitly set type to 'NSI', autodetected based on freeform type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (json.render && json["question"] && json.freeform === undefined) {
|
if (json.render && json["question"] && json.freeform === undefined) {
|
||||||
|
@ -1145,7 +1148,7 @@ export class ValidateTagRenderings extends Fuse<TagRenderingConfigJson> {
|
||||||
constructor(layerConfig?: LayerConfigJson, doesImageExist?: DoesImageExist) {
|
constructor(layerConfig?: LayerConfigJson, doesImageExist?: DoesImageExist) {
|
||||||
super(
|
super(
|
||||||
"Various validation on tagRenderingConfigs",
|
"Various validation on tagRenderingConfigs",
|
||||||
new MiscTagRenderingChecks(),
|
new MiscTagRenderingChecks(layerConfig),
|
||||||
new DetectShadowedMappings(layerConfig),
|
new DetectShadowedMappings(layerConfig),
|
||||||
|
|
||||||
new DetectMappingsShadowedByCondition(),
|
new DetectMappingsShadowedByCondition(),
|
||||||
|
@ -1156,7 +1159,7 @@ export class ValidateTagRenderings extends Fuse<TagRenderingConfigJson> {
|
||||||
new On("question", new ValidatePossibleLinks()),
|
new On("question", new ValidatePossibleLinks()),
|
||||||
new On("questionHint", new ValidatePossibleLinks()),
|
new On("questionHint", new ValidatePossibleLinks()),
|
||||||
new On("mappings", new Each(new On("then", new ValidatePossibleLinks()))),
|
new On("mappings", new Each(new On("then", new ValidatePossibleLinks()))),
|
||||||
new MiscTagRenderingChecks()
|
new MiscTagRenderingChecks(layerConfig)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,12 +233,6 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
||||||
*/
|
*/
|
||||||
placeholder?: Translatable
|
placeholder?: Translatable
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra parameters to initialize the input helper arguments.
|
|
||||||
* For semantics, see the 'SpecialInputElements.md'
|
|
||||||
* group: expert
|
|
||||||
*/
|
|
||||||
helperArgs?: (string | number | boolean | any)[]
|
|
||||||
/**
|
/**
|
||||||
* If a value is added with the textfield, these extra tag is addded.
|
* If a value is added with the textfield, these extra tag is addded.
|
||||||
* Useful to add a 'fixme=freeform textfield used - to be checked'
|
* Useful to add a 'fixme=freeform textfield used - to be checked'
|
||||||
|
|
|
@ -72,12 +72,11 @@ export default class TagRenderingConfig {
|
||||||
readonly addExtraTags: UploadableTag[]
|
readonly addExtraTags: UploadableTag[]
|
||||||
readonly inline: boolean
|
readonly inline: boolean
|
||||||
readonly default?: string
|
readonly default?: string
|
||||||
readonly helperArgs?: (string | number | boolean)[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly multiAnswer: boolean
|
public readonly multiAnswer: boolean
|
||||||
|
|
||||||
public readonly mappings: Mapping[]
|
public mappings: Mapping[]
|
||||||
public readonly editButtonAriaLabel?: Translation
|
public readonly editButtonAriaLabel?: Translation
|
||||||
public readonly labels: string[]
|
public readonly labels: string[]
|
||||||
public readonly classes: string[] | undefined
|
public readonly classes: string[] | undefined
|
||||||
|
@ -202,8 +201,7 @@ export default class TagRenderingConfig {
|
||||||
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`)
|
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`)
|
||||||
) ?? [],
|
) ?? [],
|
||||||
inline: json.freeform.inline ?? false,
|
inline: json.freeform.inline ?? false,
|
||||||
default: json.freeform.default,
|
default: json.freeform.default
|
||||||
helperArgs: json.freeform.helperArgs
|
|
||||||
}
|
}
|
||||||
if (json.freeform["extraTags"] !== undefined) {
|
if (json.freeform["extraTags"] !== undefined) {
|
||||||
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
|
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
|
||||||
|
@ -251,7 +249,7 @@ export default class TagRenderingConfig {
|
||||||
commonIconSize
|
commonIconSize
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}else{
|
} else {
|
||||||
this.mappings = []
|
this.mappings = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,8 +369,8 @@ export default class TagRenderingConfig {
|
||||||
|
|
||||||
let icon = undefined
|
let icon = undefined
|
||||||
let iconClass = commonSize
|
let iconClass = commonSize
|
||||||
if (!!mapping.icon) {
|
if (mapping.icon) {
|
||||||
if (typeof mapping.icon === "string" && mapping.icon !== "") {
|
if (typeof mapping.icon === "string") {
|
||||||
icon = mapping.icon.trim()
|
icon = mapping.icon.trim()
|
||||||
} else if (mapping.icon["path"]) {
|
} else if (mapping.icon["path"]) {
|
||||||
icon = mapping.icon["path"].trim()
|
icon = mapping.icon["path"].trim()
|
||||||
|
@ -467,8 +465,8 @@ export default class TagRenderingConfig {
|
||||||
|
|
||||||
// A flag to check that the freeform key isn't matched multiple times
|
// A flag to check that the freeform key isn't matched multiple times
|
||||||
// If it is undefined, it is "used" already, or at least we don't have to check for it anymore
|
// If it is undefined, it is "used" already, or at least we don't have to check for it anymore
|
||||||
let freeformKeyDefined = this.freeform?.key !== undefined
|
const freeformKeyDefined = this.freeform?.key !== undefined
|
||||||
let usedFreeformValues = new Set<string>()
|
const usedFreeformValues = new Set<string>()
|
||||||
// We run over all the mappings first, to check if the mapping matches
|
// We run over all the mappings first, to check if the mapping matches
|
||||||
const applicableMappings: {
|
const applicableMappings: {
|
||||||
then: TypedTranslation<Record<string, string>>
|
then: TypedTranslation<Record<string, string>>
|
||||||
|
@ -556,9 +554,6 @@ export default class TagRenderingConfig {
|
||||||
EnumerateTranslations(): Translation[] {
|
EnumerateTranslations(): Translation[] {
|
||||||
const translations: Translation[] = []
|
const translations: Translation[] = []
|
||||||
for (const key in this) {
|
for (const key in this) {
|
||||||
if (!this.hasOwnProperty(key)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const o = this[key]
|
const o = this[key]
|
||||||
if (o instanceof Translation) {
|
if (o instanceof Translation) {
|
||||||
translations.push(o)
|
translations.push(o)
|
||||||
|
@ -572,7 +567,7 @@ export default class TagRenderingConfig {
|
||||||
const key = this.freeform?.key
|
const key = this.freeform?.key
|
||||||
const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true)
|
const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true)
|
||||||
if (key === undefined) {
|
if (key === undefined) {
|
||||||
let values: { k: string; v: string }[][] = Utils.NoNull(
|
const values: { k: string; v: string }[][] = Utils.NoNull(
|
||||||
answerMappings?.map((m) => m.if.asChange({})) ?? []
|
answerMappings?.map((m) => m.if.asChange({})) ?? []
|
||||||
)
|
)
|
||||||
if (values.length === 0) {
|
if (values.length === 0) {
|
||||||
|
@ -870,21 +865,25 @@ export default class TagRenderingConfig {
|
||||||
export class TagRenderingConfigUtils {
|
export class TagRenderingConfigUtils {
|
||||||
|
|
||||||
public static withNameSuggestionIndex(config: TagRenderingConfig, tags: UIEventSource<Record<string, string>>, feature?: Feature): Store<TagRenderingConfig> {
|
public static withNameSuggestionIndex(config: TagRenderingConfig, tags: UIEventSource<Record<string, string>>, feature?: Feature): Store<TagRenderingConfig> {
|
||||||
if(config.freeform?.type !== "nsi"){
|
const isNSI = NameSuggestionIndex.supportedTypes().indexOf(config.freeform?.key) >= 0
|
||||||
|
if (!isNSI) {
|
||||||
return new ImmutableStore(config)
|
return new ImmutableStore(config)
|
||||||
}
|
}
|
||||||
const extraMappings = tags.mapD(tags => tags._country).bindD(country => {
|
const extraMappings = tags
|
||||||
const [k, v] = ("" + config.freeform.helperArgs[0]).split("=")
|
.bindD(tags => {
|
||||||
const center = GeoOperations.centerpointCoordinates(feature)
|
const country = tags._country
|
||||||
return UIEventSource.FromPromise(NameSuggestionIndex.generateMappings(config.freeform.key, k, v, country.split(";"), center))
|
if(country === undefined){
|
||||||
})
|
return undefined
|
||||||
return extraMappings.map(extraMappings => {
|
}
|
||||||
if(!extraMappings || extraMappings.length == 0){
|
const center = GeoOperations.centerpointCoordinates(feature)
|
||||||
|
return UIEventSource.FromPromise(NameSuggestionIndex.generateMappings(config.freeform.key, tags, country.split(";"), center))
|
||||||
|
})
|
||||||
|
return extraMappings.map(extraMappings => {
|
||||||
|
if (!extraMappings || extraMappings.length == 0) {
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
const clone: TagRenderingConfig = Object.create(config)
|
const clone: TagRenderingConfig = Object.create(config)
|
||||||
/// SHHHTTT, this is not cheating at all!
|
clone.mappings = [...clone.mappings ?? [], ...extraMappings]
|
||||||
clone.mappings.splice(clone.mappings.length, 0, ...extraMappings)
|
|
||||||
return clone
|
return clone
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,7 +391,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
if (fs.layer.layerDef.source.geojsonSource !== undefined) {
|
if (fs.layer.layerDef.source.geojsonSource !== undefined) {
|
||||||
return // We don't cache external data layers
|
return // We don't cache external data layers
|
||||||
}
|
}
|
||||||
console.log("Setting up a local store feature sink for", layerId)
|
|
||||||
const storage = new SaveFeatureSourceToLocalStorage(
|
const storage = new SaveFeatureSourceToLocalStorage(
|
||||||
this.osmConnection.Backend(),
|
this.osmConnection.Backend(),
|
||||||
fs.layer.layerDef.id,
|
fs.layer.layerDef.id,
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
function animate(opened: boolean) {
|
function animate(opened: boolean) {
|
||||||
const moveToElem = moveTo.data
|
const moveToElem = moveTo.data
|
||||||
console.log("Animating", debug," to", opened)
|
|
||||||
if (opened) {
|
if (opened) {
|
||||||
copySizeOf(targetOuter)
|
copySizeOf(targetOuter)
|
||||||
elem.style.background = "var(--background-color)"
|
elem.style.background = "var(--background-color)"
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
import UserRelatedState from "../../Logic/State/UserRelatedState"
|
import UserRelatedState from "../../Logic/State/UserRelatedState"
|
||||||
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
||||||
import BackButton from "../Base/BackButton.svelte"
|
import BackButton from "../Base/BackButton.svelte"
|
||||||
import TagRenderingEditableDynamic from "../Popup/TagRendering/TagRenderingEditableDynamic.svelte"
|
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
export let selectedElement: Feature
|
export let selectedElement: Feature
|
||||||
|
@ -69,7 +68,7 @@
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
{#each $knownTagRenderings as config (config.id)}
|
{#each $knownTagRenderings as config (config.id)}
|
||||||
<TagRenderingEditableDynamic
|
<TagRenderingEditable
|
||||||
{tags}
|
{tags}
|
||||||
{config}
|
{config}
|
||||||
{state}
|
{state}
|
||||||
|
|
22
src/UI/Popup/TagRendering/TagRenderingAnswerDynamic.svelte
Normal file
22
src/UI/Popup/TagRendering/TagRenderingAnswerDynamic.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import TagRenderingConfig, { TagRenderingConfigUtils } from "../../../Models/ThemeConfig/TagRenderingConfig"
|
||||||
|
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||||
|
import type { Feature } from "geojson"
|
||||||
|
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||||
|
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||||
|
import TagRenderingAnswer from "./TagRenderingAnswer.svelte"
|
||||||
|
|
||||||
|
export let tags: UIEventSource<Record<string, string> | undefined>
|
||||||
|
|
||||||
|
export let state: SpecialVisualizationState
|
||||||
|
export let selectedElement: Feature
|
||||||
|
export let layer: LayerConfig
|
||||||
|
export let config: TagRenderingConfig
|
||||||
|
export let extraClasses: string | undefined = undefined
|
||||||
|
|
||||||
|
export let id: string = undefined
|
||||||
|
let dynamicConfig = TagRenderingConfigUtils.withNameSuggestionIndex(config, tags, selectedElement)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<TagRenderingAnswer {selectedElement} {layer} config={$dynamicConfig} {extraClasses} {id} {tags} {state} />
|
|
@ -3,8 +3,6 @@
|
||||||
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
||||||
import type { Feature } from "geojson"
|
import type { Feature } from "geojson"
|
||||||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||||
import TagRenderingAnswer from "./TagRenderingAnswer.svelte"
|
|
||||||
import { PencilAltIcon } from "@rgossiaux/svelte-heroicons/solid"
|
|
||||||
import TagRenderingQuestion from "./TagRenderingQuestion.svelte"
|
import TagRenderingQuestion from "./TagRenderingQuestion.svelte"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
import Tr from "../../Base/Tr.svelte"
|
import Tr from "../../Base/Tr.svelte"
|
||||||
|
@ -12,9 +10,8 @@
|
||||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge"
|
||||||
import { ariaLabel } from "../../../Utils/ariaLabel"
|
|
||||||
import EditButton from "./EditButton.svelte"
|
import EditButton from "./EditButton.svelte"
|
||||||
import EditItemButton from "../../Studio/EditItemButton.svelte"
|
import TagRenderingAnswerDynamic from "./TagRenderingAnswerDynamic.svelte"
|
||||||
|
|
||||||
export let config: TagRenderingConfig
|
export let config: TagRenderingConfig
|
||||||
export let tags: UIEventSource<Record<string, string>>
|
export let tags: UIEventSource<Record<string, string>>
|
||||||
|
@ -103,7 +100,7 @@
|
||||||
</TagRenderingQuestion>
|
</TagRenderingQuestion>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="low-interaction flex items-center justify-between overflow-hidden rounded px-2">
|
<div class="low-interaction flex items-center justify-between overflow-hidden rounded px-2">
|
||||||
<TagRenderingAnswer id={answerId} {config} {tags} {selectedElement} {state} {layer} />
|
<TagRenderingAnswerDynamic id={answerId} {config} {tags} {selectedElement} {state} {layer} />
|
||||||
<EditButton
|
<EditButton
|
||||||
arialabel={config.editButtonAriaLabel}
|
arialabel={config.editButtonAriaLabel}
|
||||||
ariaLabelledBy={answerId}
|
ariaLabelledBy={answerId}
|
||||||
|
@ -115,7 +112,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="h-full w-full overflow-hidden">
|
<div class="h-full w-full overflow-hidden">
|
||||||
<TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer} />
|
<TagRenderingAnswerDynamic {config} {tags} {selectedElement} {state} {layer} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<script lang="ts">/**
|
|
||||||
* Wrapper around 'tagRenderingEditable' but might add mappings dynamically
|
|
||||||
*/
|
|
||||||
import TagRenderingConfig, { TagRenderingConfigUtils } from "../../../Models/ThemeConfig/TagRenderingConfig"
|
|
||||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
|
||||||
import type { Feature } from "geojson"
|
|
||||||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
|
||||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
|
||||||
import TagRenderingEditable from "./TagRenderingEditable.svelte"
|
|
||||||
|
|
||||||
export let config: TagRenderingConfig
|
|
||||||
export let tags: UIEventSource<Record<string, string>>
|
|
||||||
export let selectedElement: Feature | undefined
|
|
||||||
export let state: SpecialVisualizationState
|
|
||||||
export let layer: LayerConfig = undefined
|
|
||||||
|
|
||||||
|
|
||||||
export let highlightedRendering: UIEventSource<string> = undefined
|
|
||||||
export let clss = undefined
|
|
||||||
|
|
||||||
let dynamicConfig = TagRenderingConfigUtils.withNameSuggestionIndex(config, tags, selectedElement)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<TagRenderingEditable
|
|
||||||
{tags}
|
|
||||||
config={$dynamicConfig}
|
|
||||||
{state}
|
|
||||||
{selectedElement}
|
|
||||||
{layer}
|
|
||||||
{highlightedRendering}
|
|
||||||
{clss}
|
|
||||||
/>
|
|
|
@ -72,7 +72,6 @@
|
||||||
/**
|
/**
|
||||||
* Prepares and fills the checkedMappings
|
* Prepares and fills the checkedMappings
|
||||||
*/
|
*/
|
||||||
console.log("Initing ", config.id)
|
|
||||||
|
|
||||||
function initialize(tgs: Record<string, string>, confg: TagRenderingConfig): void {
|
function initialize(tgs: Record<string, string>, confg: TagRenderingConfig): void {
|
||||||
mappings = confg.mappings?.filter((m) => {
|
mappings = confg.mappings?.filter((m) => {
|
||||||
|
@ -160,7 +159,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (somethingChanged) {
|
if (somethingChanged) {
|
||||||
console.log("Updating minimal tags to", newMinimal, "of", config.id)
|
|
||||||
minimalTags.setData(newMinimal)
|
minimalTags.setData(newMinimal)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -224,7 +222,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extraTags.data) {
|
if (extraTags.data && selectedTags !== undefined) {
|
||||||
// Map the extraTags into an array of Tag objects
|
// Map the extraTags into an array of Tag objects
|
||||||
const extraTagsArray = Object.entries(extraTags.data).map(([k, v]) => new Tag(k, v))
|
const extraTagsArray = Object.entries(extraTags.data).map(([k, v]) => new Tag(k, v))
|
||||||
|
|
||||||
|
@ -236,7 +234,7 @@
|
||||||
// Add the extraTags to the existing And
|
// Add the extraTags to the existing And
|
||||||
selectedTags = new And([...selectedTags.and, ...extraTagsArray])
|
selectedTags = new And([...selectedTags.and, ...extraTagsArray])
|
||||||
} else {
|
} else {
|
||||||
console.error("selectedTags is not of type Tag or And")
|
console.error("selectedTags is not of type Tag or And, it is a "+JSON.stringify(selectedTags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,4 @@ import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
||||||
import Test from "./UI/Test.svelte"
|
import Test from "./UI/Test.svelte"
|
||||||
import NameSuggestionIndex from "./Logic/Web/NameSuggestionIndex"
|
import NameSuggestionIndex from "./Logic/Web/NameSuggestionIndex"
|
||||||
|
|
||||||
const nsi = NameSuggestionIndex.get()
|
|
||||||
const secondhandshops = nsi.getSuggestionsFor("brands/shop/second_hand", ["be"])
|
|
||||||
console.log(secondhandshops)
|
|
||||||
new SvelteUIElement(Test).AttachTo("maindiv")
|
new SvelteUIElement(Test).AttachTo("maindiv")
|
||||||
|
|
Loading…
Reference in a new issue