forked from MapComplete/MapComplete
		
	Formatting
This commit is contained in:
		
							parent
							
								
									d5d2c08706
								
							
						
					
					
						commit
						72ca67e3ab
					
				
					 34 changed files with 616 additions and 566 deletions
				
			
		|  | @ -27,10 +27,10 @@ export default class UserDetails { | ||||||
| 
 | 
 | ||||||
| export class OsmConnection { | export class OsmConnection { | ||||||
|     public static readonly oauth_configs = { |     public static readonly oauth_configs = { | ||||||
|         "osm": { |         osm: { | ||||||
|             oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem', |             oauth_consumer_key: "hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem", | ||||||
|             oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI', |             oauth_secret: "wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI", | ||||||
|             url: "https://www.openstreetmap.org" |             url: "https://www.openstreetmap.org", | ||||||
|             // OAUTH 1.0 application
 |             // OAUTH 1.0 application
 | ||||||
|             // https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/oauth_clients/7404
 |             // https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/oauth_clients/7404
 | ||||||
|         }, |         }, | ||||||
|  | @ -335,43 +335,52 @@ export class OsmConnection { | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public async uploadGpxTrack(gpx: string, options: { |     public async uploadGpxTrack( | ||||||
|         description: string, |         gpx: string, | ||||||
|         visibility:  "private" | "public" | "trackable" | "identifiable", |         options: { | ||||||
|         filename?: string |             description: string | ||||||
|         /** |             visibility: "private" | "public" | "trackable" | "identifiable" | ||||||
|          * Some words to give some properties; |             filename?: string | ||||||
|          * |             /** | ||||||
|          * Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words. |              * Some words to give some properties; | ||||||
|          */ |              * | ||||||
|         labels: string[] |              * Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words. | ||||||
|     }): Promise<{ id: number }> { |              */ | ||||||
|  |             labels: string[] | ||||||
|  |         } | ||||||
|  |     ): Promise<{ id: number }> { | ||||||
|         if (this._dryRun.data) { |         if (this._dryRun.data) { | ||||||
|             console.warn("Dryrun enabled - not actually uploading GPX ", gpx) |             console.warn("Dryrun enabled - not actually uploading GPX ", gpx) | ||||||
|             return new Promise<{ id: number }>((ok, error) => { |             return new Promise<{ id: number }>((ok, error) => { | ||||||
|                 window.setTimeout(() => ok({id: Math.floor(Math.random() * 1000)}), Math.random() * 5000) |                 window.setTimeout( | ||||||
|             }); |                     () => ok({ id: Math.floor(Math.random() * 1000) }), | ||||||
|  |                     Math.random() * 5000 | ||||||
|  |                 ) | ||||||
|  |             }) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const contents = { |         const contents = { | ||||||
|             "file": gpx, |             file: gpx, | ||||||
|             "description": options.description ?? "", |             description: options.description ?? "", | ||||||
|             "tags": options.labels?.join(",") ?? "", |             tags: options.labels?.join(",") ?? "", | ||||||
|             "visibility": options.visibility |             visibility: options.visibility, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const extras = { |         const extras = { | ||||||
|             "file": "; filename=\""+(options.filename ?? ("gpx_track_mapcomplete_"+(new Date().toISOString())))+"\"\r\nContent-Type: application/gpx+xml" |             file: | ||||||
|  |                 '; filename="' + | ||||||
|  |                 (options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) + | ||||||
|  |                 '"\r\nContent-Type: application/gpx+xml', | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const auth = this.auth; |         const auth = this.auth | ||||||
|         const boundary ="987654" |         const boundary = "987654" | ||||||
| 
 | 
 | ||||||
|         let body = "" |         let body = "" | ||||||
|         for (const key in contents) { |         for (const key in contents) { | ||||||
|             body += "--" + boundary + "\r\n" |             body += "--" + boundary + "\r\n" | ||||||
|             body += "Content-Disposition: form-data; name=\"" + key + "\"" |             body += 'Content-Disposition: form-data; name="' + key + '"' | ||||||
|             if(extras[key] !== undefined){ |             if (extras[key] !== undefined) { | ||||||
|                 body += extras[key] |                 body += extras[key] | ||||||
|             } |             } | ||||||
|             body += "\r\n\r\n" |             body += "\r\n\r\n" | ||||||
|  | @ -379,34 +388,31 @@ export class OsmConnection { | ||||||
|         } |         } | ||||||
|         body += "--" + boundary + "--\r\n" |         body += "--" + boundary + "--\r\n" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         return new Promise((ok, error) => { |         return new Promise((ok, error) => { | ||||||
|             auth.xhr({ |             auth.xhr( | ||||||
|                 method: 'POST', |                 { | ||||||
|                 path: `/api/0.6/gpx/create`, |                     method: "POST", | ||||||
|                 options: { |                     path: `/api/0.6/gpx/create`, | ||||||
|                     header: |                     options: { | ||||||
|                         { |                         header: { | ||||||
|                             "Content-Type": "multipart/form-data; boundary=" + boundary, |                             "Content-Type": "multipart/form-data; boundary=" + boundary, | ||||||
|                             "Content-Length": body.length |                             "Content-Length": body.length, | ||||||
|                         } |                         }, | ||||||
|  |                     }, | ||||||
|  |                     content: body, | ||||||
|                 }, |                 }, | ||||||
|                 content: body |                 function (err, response: string) { | ||||||
| 
 |                     console.log("RESPONSE IS", response) | ||||||
|             }, function ( |                     if (err !== null) { | ||||||
|                 err, |                         error(err) | ||||||
|                 response: string) { |                     } else { | ||||||
|                 console.log("RESPONSE IS", response) |                         const parsed = JSON.parse(response) | ||||||
|                 if (err !== null) { |                         console.log("Uploaded GPX track", parsed) | ||||||
|                     error(err) |                         ok({ id: parsed }) | ||||||
|                 } else { |                     } | ||||||
|                     const parsed = JSON.parse(response) |  | ||||||
|                     console.log("Uploaded GPX track", parsed) |  | ||||||
|                     ok({id: parsed}) |  | ||||||
|                 } |                 } | ||||||
|             }) |             ) | ||||||
|         }) |         }) | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public addCommentToNote(id: number | string, text: string): Promise<void> { |     public addCommentToNote(id: number | string, text: string): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -623,7 +623,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|             } |             } | ||||||
|             const param = special[arg.name] |             const param = special[arg.name] | ||||||
|             if (param === undefined) { |             if (param === undefined) { | ||||||
|                 errors.push(`At ${context}: Obligated parameter '${arg.name}' in special rendering of type ${vis.funcName} not found.\n${arg.doc}`) |                 errors.push( | ||||||
|  |                     `At ${context}: Obligated parameter '${arg.name}' in special rendering of type ${vis.funcName} not found.\n${arg.doc}` | ||||||
|  |                 ) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,19 +1,19 @@ | ||||||
| import {DesugaringStep, Each, Fuse, On} from "./Conversion" | import { DesugaringStep, Each, Fuse, On } from "./Conversion" | ||||||
| import {LayerConfigJson} from "../Json/LayerConfigJson" | import { LayerConfigJson } from "../Json/LayerConfigJson" | ||||||
| import LayerConfig from "../LayerConfig" | import LayerConfig from "../LayerConfig" | ||||||
| import {Utils} from "../../../Utils" | import { Utils } from "../../../Utils" | ||||||
| import Constants from "../../Constants" | import Constants from "../../Constants" | ||||||
| import {Translation} from "../../../UI/i18n/Translation" | import { Translation } from "../../../UI/i18n/Translation" | ||||||
| import {LayoutConfigJson} from "../Json/LayoutConfigJson" | import { LayoutConfigJson } from "../Json/LayoutConfigJson" | ||||||
| import LayoutConfig from "../LayoutConfig" | import LayoutConfig from "../LayoutConfig" | ||||||
| import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson" | import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" | ||||||
| import {TagUtils} from "../../../Logic/Tags/TagUtils" | import { TagUtils } from "../../../Logic/Tags/TagUtils" | ||||||
| import {ExtractImages} from "./FixImages" | import { ExtractImages } from "./FixImages" | ||||||
| import ScriptUtils from "../../../scripts/ScriptUtils" | import ScriptUtils from "../../../scripts/ScriptUtils" | ||||||
| import {And} from "../../../Logic/Tags/And" | import { And } from "../../../Logic/Tags/And" | ||||||
| import Translations from "../../../UI/i18n/Translations" | import Translations from "../../../UI/i18n/Translations" | ||||||
| import Svg from "../../../Svg" | import Svg from "../../../Svg" | ||||||
| import {QuestionableTagRenderingConfigJson} from "../Json/QuestionableTagRenderingConfigJson" | import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" | ||||||
| import FilterConfigJson from "../Json/FilterConfigJson" | import FilterConfigJson from "../Json/FilterConfigJson" | ||||||
| import DeleteConfig from "../DeleteConfig" | import DeleteConfig from "../DeleteConfig" | ||||||
| 
 | 
 | ||||||
|  | @ -619,20 +619,31 @@ export class DetectMappingsWithImages extends DesugaringStep<TagRenderingConfigJ | ||||||
| 
 | 
 | ||||||
| class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> { | class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super("Miscellanious checks on the tagrendering", ["special"], "MiscTagREnderingChecksRew"); |         super("Miscellanious checks on the tagrendering", ["special"], "MiscTagREnderingChecksRew") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { |     convert( | ||||||
|         const errors =  [] |         json: TagRenderingConfigJson, | ||||||
|         if(json["special"] !== undefined){ |         context: string | ||||||
|             errors.push("At "+context+": detected `special` on the top level. Did you mean `{\"render\":{ \"special\": ... }}`") |     ): { | ||||||
|  |         result: TagRenderingConfigJson | ||||||
|  |         errors?: string[] | ||||||
|  |         warnings?: string[] | ||||||
|  |         information?: string[] | ||||||
|  |     } { | ||||||
|  |         const errors = [] | ||||||
|  |         if (json["special"] !== undefined) { | ||||||
|  |             errors.push( | ||||||
|  |                 "At " + | ||||||
|  |                     context + | ||||||
|  |                     ': detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`' | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|         return { |         return { | ||||||
|             result: json, |             result: json, | ||||||
|             errors |             errors, | ||||||
|         }; |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class ValidateTagRenderings extends Fuse<TagRenderingConfigJson> { | export class ValidateTagRenderings extends Fuse<TagRenderingConfigJson> { | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import { SubstitutedTranslation } from "../../UI/SubstitutedTranslation" | ||||||
| import TagRenderingConfig from "./TagRenderingConfig" | import TagRenderingConfig from "./TagRenderingConfig" | ||||||
| import { ExtraFuncParams, ExtraFunctions } from "../../Logic/ExtraFunctions" | import { ExtraFuncParams, ExtraFunctions } from "../../Logic/ExtraFunctions" | ||||||
| import LayerConfig from "./LayerConfig" | import LayerConfig from "./LayerConfig" | ||||||
| import {SpecialVisualization} from "../../UI/SpecialVisualization"; | import { SpecialVisualization } from "../../UI/SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export default class DependencyCalculator { | export default class DependencyCalculator { | ||||||
|     public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] { |     public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] { | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ export default class FilterConfig { | ||||||
|             for (const field of fields) { |             for (const field of fields) { | ||||||
|                 for (let ln in question.translations) { |                 for (let ln in question.translations) { | ||||||
|                     const txt = question.translations[ln] |                     const txt = question.translations[ln] | ||||||
|                     if(ln.startsWith("_")){ |                     if (ln.startsWith("_")) { | ||||||
|                         continue |                         continue | ||||||
|                     } |                     } | ||||||
|                     if (txt.indexOf("{" + field.name + "}") < 0) { |                     if (txt.indexOf("{" + field.name + "}") < 0) { | ||||||
|  |  | ||||||
|  | @ -239,7 +239,7 @@ export default class TagRenderingConfig { | ||||||
|                 throw `${context}: Detected a freeform key without rendering... Key: ${this.freeform.key} in ${context}` |                 throw `${context}: Detected a freeform key without rendering... Key: ${this.freeform.key} in ${context}` | ||||||
|             } |             } | ||||||
|             for (const ln in this.render.translations) { |             for (const ln in this.render.translations) { | ||||||
|                 if(ln.startsWith("_")){ |                 if (ln.startsWith("_")) { | ||||||
|                     continue |                     continue | ||||||
|                 } |                 } | ||||||
|                 const txt: string = this.render.translations[ln] |                 const txt: string = this.render.translations[ln] | ||||||
|  |  | ||||||
|  | @ -73,11 +73,13 @@ export class SubtleButton extends UIElement { | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|         const loading = new Lazy(() => new Loading(loadingText)) |         const loading = new Lazy(() => new Loading(loadingText)) | ||||||
|         return new VariableUiElement(state.map(st => { |         return new VariableUiElement( | ||||||
|             if(st === "idle"){ |             state.map((st) => { | ||||||
|                 return button |                 if (st === "idle") { | ||||||
|             } |                     return button | ||||||
|             return loading |                 } | ||||||
|         })) |                 return loading | ||||||
|  |             }) | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,20 +1,20 @@ | ||||||
| import Combine from "../Base/Combine" | import Combine from "../Base/Combine" | ||||||
| import {FlowPanelFactory, FlowStep} from "../ImportFlow/FlowStep" | import { FlowPanelFactory, FlowStep } from "../ImportFlow/FlowStep" | ||||||
| import {ImmutableStore, Store, UIEventSource} from "../../Logic/UIEventSource" | import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import {InputElement} from "../Input/InputElement" | import { InputElement } from "../Input/InputElement" | ||||||
| import {SvgToPdf, SvgToPdfOptions} from "../../Utils/svgToPdf" | import { SvgToPdf, SvgToPdfOptions } from "../../Utils/svgToPdf" | ||||||
| import {FixedInputElement} from "../Input/FixedInputElement" | import { FixedInputElement } from "../Input/FixedInputElement" | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement" | import { FixedUiElement } from "../Base/FixedUiElement" | ||||||
| import FileSelectorButton from "../Input/FileSelectorButton" | import FileSelectorButton from "../Input/FileSelectorButton" | ||||||
| import InputElementMap from "../Input/InputElementMap" | import InputElementMap from "../Input/InputElementMap" | ||||||
| import {RadioButton} from "../Input/RadioButton" | import { RadioButton } from "../Input/RadioButton" | ||||||
| import {Utils} from "../../Utils" | import { Utils } from "../../Utils" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement" | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import Loading from "../Base/Loading" | import Loading from "../Base/Loading" | ||||||
| import BaseUIElement from "../BaseUIElement" | import BaseUIElement from "../BaseUIElement" | ||||||
| import Img from "../Base/Img" | import Img from "../Base/Img" | ||||||
| import Title from "../Base/Title" | import Title from "../Base/Title" | ||||||
| import {CheckBox} from "../Input/Checkboxes" | import { CheckBox } from "../Input/Checkboxes" | ||||||
| import Minimap from "../Base/Minimap" | import Minimap from "../Base/Minimap" | ||||||
| import SearchAndGo from "./SearchAndGo" | import SearchAndGo from "./SearchAndGo" | ||||||
| import Toggle from "../Input/Toggle" | import Toggle from "../Input/Toggle" | ||||||
|  | @ -25,7 +25,7 @@ import Toggleable from "../Base/Toggleable" | ||||||
| import Lazy from "../Base/Lazy" | import Lazy from "../Base/Lazy" | ||||||
| import LinkToWeblate from "../Base/LinkToWeblate" | import LinkToWeblate from "../Base/LinkToWeblate" | ||||||
| import Link from "../Base/Link" | import Link from "../Base/Link" | ||||||
| import {AllLanguagesSelector} from "../Popup/AllLanguagesSelector"; | import { AllLanguagesSelector } from "../Popup/AllLanguagesSelector" | ||||||
| 
 | 
 | ||||||
| class SelectTemplate extends Combine implements FlowStep<{ title: string; pages: string[] }> { | class SelectTemplate extends Combine implements FlowStep<{ title: string; pages: string[] }> { | ||||||
|     readonly IsValid: Store<boolean> |     readonly IsValid: Store<boolean> | ||||||
|  | @ -201,7 +201,7 @@ class PreparePdf extends Combine implements FlowStep<{ svgToPdf: SvgToPdf; langu | ||||||
| 
 | 
 | ||||||
|     constructor(title: string, pages: string[], options: SvgToPdfOptions) { |     constructor(title: string, pages: string[], options: SvgToPdfOptions) { | ||||||
|         const svgToPdf = new SvgToPdf(title, pages, options) |         const svgToPdf = new SvgToPdf(title, pages, options) | ||||||
|         const languageSelector = new AllLanguagesSelector(          ) |         const languageSelector = new AllLanguagesSelector() | ||||||
|         const isPrepared = UIEventSource.FromPromiseWithErr(svgToPdf.Prepare()) |         const isPrepared = UIEventSource.FromPromiseWithErr(svgToPdf.Prepare()) | ||||||
| 
 | 
 | ||||||
|         super([ |         super([ | ||||||
|  |  | ||||||
|  | @ -1,25 +1,23 @@ | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import {RadioButton} from "../Input/RadioButton"; | import { RadioButton } from "../Input/RadioButton" | ||||||
| import {FixedInputElement} from "../Input/FixedInputElement"; | import { FixedInputElement } from "../Input/FixedInputElement" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import {TextField} from "../Input/TextField"; | import { TextField } from "../Input/TextField" | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Title from "../Base/Title"; | import Title from "../Base/Title" | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import { SubtleButton } from "../Base/SubtleButton" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import {OsmConnection} from "../../Logic/Osm/OsmConnection"; | import { OsmConnection } from "../../Logic/Osm/OsmConnection" | ||||||
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | ||||||
| import {Translation} from "../i18n/Translation"; | import { Translation } from "../i18n/Translation" | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| export default class UploadTraceToOsmUI extends Toggle { | export default class UploadTraceToOsmUI extends Toggle { | ||||||
| 
 |     private static createDefault(s: string, defaultValue: string) { | ||||||
|     private static createDefault(s: string, defaultValue: string){ |         if (defaultValue.length < 1) { | ||||||
|         if(defaultValue.length < 1){ |  | ||||||
|             throw "Default value should have some characters" |             throw "Default value should have some characters" | ||||||
|         } |         } | ||||||
|         if(s === undefined || s === null || s === ""){ |         if (s === undefined || s === null || s === "") { | ||||||
|             return defaultValue |             return defaultValue | ||||||
|         } |         } | ||||||
|         return s |         return s | ||||||
|  | @ -28,43 +26,50 @@ export default class UploadTraceToOsmUI extends Toggle { | ||||||
|     constructor( |     constructor( | ||||||
|         trace: (title: string) => string, |         trace: (title: string) => string, | ||||||
|         state: { |         state: { | ||||||
|             layoutToUse: LayoutConfig; |             layoutToUse: LayoutConfig | ||||||
|             osmConnection: OsmConnection |             osmConnection: OsmConnection | ||||||
|         }, options?: { |         }, | ||||||
|  |         options?: { | ||||||
|             whenUploaded?: () => void | Promise<void> |             whenUploaded?: () => void | Promise<void> | ||||||
|         }) { |         } | ||||||
|  |     ) { | ||||||
|         const t = Translations.t.general.uploadGpx |         const t = Translations.t.general.uploadGpx | ||||||
|         const uploadFinished = new UIEventSource(false) |         const uploadFinished = new UIEventSource(false) | ||||||
|         const traceVisibilities: { |         const traceVisibilities: { | ||||||
|             key: "private" | "public", |             key: "private" | "public" | ||||||
|             name: Translation, |             name: Translation | ||||||
|             docs: Translation |             docs: Translation | ||||||
|         }[] = [ |         }[] = [ | ||||||
|             { |             { | ||||||
|                 key: "private", |                 key: "private", | ||||||
|                 ...t.modes.private |                 ...t.modes.private, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 key: "public", |                 key: "public", | ||||||
|                 ...t.modes.public |                 ...t.modes.public, | ||||||
|             } |             }, | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|         const dropdown = new RadioButton<"private" | "public">( |         const dropdown = new RadioButton<"private" | "public">( | ||||||
|             traceVisibilities.map(tv => new FixedInputElement<"private" | "public">( |             traceVisibilities.map( | ||||||
|                 new Combine([Translations.W( |                 (tv) => | ||||||
|                     tv.name |                     new FixedInputElement<"private" | "public">( | ||||||
|                 ).SetClass("font-bold"), tv.docs]).SetClass("flex flex-col") |                         new Combine([ | ||||||
|                 , tv.key)), |                             Translations.W(tv.name).SetClass("font-bold"), | ||||||
|  |                             tv.docs, | ||||||
|  |                         ]).SetClass("flex flex-col"), | ||||||
|  |                         tv.key | ||||||
|  |                     ) | ||||||
|  |             ), | ||||||
|             { |             { | ||||||
|                 value: <any>state?.osmConnection?.GetPreference("gps.trace.visibility") |                 value: <any>state?.osmConnection?.GetPreference("gps.trace.visibility"), | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
|         const description = new TextField({ |         const description = new TextField({ | ||||||
|             placeholder: t.meta.descriptionPlaceHolder |             placeholder: t.meta.descriptionPlaceHolder, | ||||||
|         }) |         }) | ||||||
|         const title = new TextField({ |         const title = new TextField({ | ||||||
|             placeholder: t.meta.titlePlaceholder |             placeholder: t.meta.titlePlaceholder, | ||||||
|         }) |         }) | ||||||
|         const clicked = new UIEventSource<boolean>(false) |         const clicked = new UIEventSource<boolean>(false) | ||||||
| 
 | 
 | ||||||
|  | @ -81,38 +86,48 @@ export default class UploadTraceToOsmUI extends Toggle { | ||||||
|             t.meta.descriptionIntro, |             t.meta.descriptionIntro, | ||||||
|             description, |             description, | ||||||
|             new Combine([ |             new Combine([ | ||||||
|                 new SubtleButton(Svg.close_svg(), Translations.t.general.cancel).onClick(() => { |                 new SubtleButton(Svg.close_svg(), Translations.t.general.cancel) | ||||||
|                     clicked.setData(false) |                     .onClick(() => { | ||||||
|                 }).SetClass(""), |                         clicked.setData(false) | ||||||
|                 new SubtleButton(Svg.upload_svg(), t.confirm).OnClickWithLoading(t.uploading, async () => { |  | ||||||
|                     const titleStr = UploadTraceToOsmUI.createDefault(title.GetValue().data, "Track with mapcomplete") |  | ||||||
|                     const descriptionStr = UploadTraceToOsmUI.createDefault(description.GetValue().data, "Track created with MapComplete with theme "+state?.layoutToUse?.id) |  | ||||||
|                     await state?.osmConnection?.uploadGpxTrack(trace(title.GetValue().data), { |  | ||||||
|                         visibility: dropdown.GetValue().data, |  | ||||||
|                         description: descriptionStr, |  | ||||||
|                         filename: titleStr +".gpx", |  | ||||||
|                         labels: ["MapComplete", state?.layoutToUse?.id] |  | ||||||
|                     }) |                     }) | ||||||
|  |                     .SetClass(""), | ||||||
|  |                 new SubtleButton(Svg.upload_svg(), t.confirm).OnClickWithLoading( | ||||||
|  |                     t.uploading, | ||||||
|  |                     async () => { | ||||||
|  |                         const titleStr = UploadTraceToOsmUI.createDefault( | ||||||
|  |                             title.GetValue().data, | ||||||
|  |                             "Track with mapcomplete" | ||||||
|  |                         ) | ||||||
|  |                         const descriptionStr = UploadTraceToOsmUI.createDefault( | ||||||
|  |                             description.GetValue().data, | ||||||
|  |                             "Track created with MapComplete with theme " + state?.layoutToUse?.id | ||||||
|  |                         ) | ||||||
|  |                         await state?.osmConnection?.uploadGpxTrack(trace(title.GetValue().data), { | ||||||
|  |                             visibility: dropdown.GetValue().data, | ||||||
|  |                             description: descriptionStr, | ||||||
|  |                             filename: titleStr + ".gpx", | ||||||
|  |                             labels: ["MapComplete", state?.layoutToUse?.id], | ||||||
|  |                         }) | ||||||
| 
 | 
 | ||||||
|                     if (options?.whenUploaded !== undefined) { |                         if (options?.whenUploaded !== undefined) { | ||||||
|                         await options.whenUploaded() |                             await options.whenUploaded() | ||||||
|  |                         } | ||||||
|  |                         uploadFinished.setData(true) | ||||||
|                     } |                     } | ||||||
|                     uploadFinished.setData(true) |                 ), | ||||||
| 
 |             ]).SetClass("flex flex-wrap flex-wrap-reverse justify-between items-stretch"), | ||||||
|                 }) |  | ||||||
|             ]).SetClass("flex flex-wrap flex-wrap-reverse justify-between items-stretch") |  | ||||||
|         ]).SetClass("flex flex-col p-4 rounded border-2 m-2 border-subtle") |         ]).SetClass("flex flex-col p-4 rounded border-2 m-2 border-subtle") | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         super( |         super( | ||||||
|             new Combine([Svg.confirm_svg().SetClass("w-12 h-12 mr-2"), |             new Combine([Svg.confirm_svg().SetClass("w-12 h-12 mr-2"), t.uploadFinished]).SetClass( | ||||||
|                 t.uploadFinished]) |                 "flex p-2 rounded-xl border-2 subtle-border items-center" | ||||||
|                 .SetClass("flex p-2 rounded-xl border-2 subtle-border items-center"), |             ), | ||||||
|             new Toggle( |             new Toggle( | ||||||
|                 confirmPanel, |                 confirmPanel, | ||||||
|                 new SubtleButton(Svg.upload_svg(), t.title) |                 new SubtleButton(Svg.upload_svg(), t.title).onClick(() => clicked.setData(true)), | ||||||
|                     .onClick(() => clicked.setData(true)), |  | ||||||
|                 clicked |                 clicked | ||||||
|             ), uploadFinished) |             ), | ||||||
|  |             uploadFinished | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,8 +13,8 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|     constructor( |     constructor( | ||||||
|         elements: InputElement<T>[], |         elements: InputElement<T>[], | ||||||
|         options?: { |         options?: { | ||||||
|             selectFirstAsDefault?: true | boolean, |             selectFirstAsDefault?: true | boolean | ||||||
|             dontStyle?: boolean, |             dontStyle?: boolean | ||||||
|             value?: UIEventSource<T> |             value?: UIEventSource<T> | ||||||
|         } |         } | ||||||
|     ) { |     ) { | ||||||
|  |  | ||||||
|  | @ -1,13 +1,13 @@ | ||||||
| import {UIElement} from "../UIElement" | import { UIElement } from "../UIElement" | ||||||
| import {InputElement} from "./InputElement" | import { InputElement } from "./InputElement" | ||||||
| import BaseUIElement from "../BaseUIElement" | import BaseUIElement from "../BaseUIElement" | ||||||
| import {Store, UIEventSource} from "../../Logic/UIEventSource" | import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Translations from "../i18n/Translations" | import Translations from "../i18n/Translations" | ||||||
| import Locale from "../i18n/Locale" | import Locale from "../i18n/Locale" | ||||||
| import Combine from "../Base/Combine" | import Combine from "../Base/Combine" | ||||||
| import {TextField} from "./TextField" | import { TextField } from "./TextField" | ||||||
| import Svg from "../../Svg" | import Svg from "../../Svg" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement" | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A single 'pill' which can hide itself if the search criteria is not met |  * A single 'pill' which can hide itself if the search criteria is not met | ||||||
|  | @ -28,7 +28,7 @@ class SelfHidingToggle extends UIElement implements InputElement<boolean> { | ||||||
|             searchTerms?: Record<string, string[]> |             searchTerms?: Record<string, string[]> | ||||||
|             selected?: UIEventSource<boolean> |             selected?: UIEventSource<boolean> | ||||||
|             forceSelected?: UIEventSource<boolean> |             forceSelected?: UIEventSource<boolean> | ||||||
|             squared?: boolean, |             squared?: boolean | ||||||
|             /* Hide, if not selected*/ |             /* Hide, if not selected*/ | ||||||
|             hide?: Store<boolean> |             hide?: Store<boolean> | ||||||
|         } |         } | ||||||
|  | @ -53,7 +53,7 @@ class SelfHidingToggle extends UIElement implements InputElement<boolean> { | ||||||
|         const selected = (this._selected = options?.selected ?? new UIEventSource<boolean>(false)) |         const selected = (this._selected = options?.selected ?? new UIEventSource<boolean>(false)) | ||||||
|         const forceSelected = (this.forceSelected = |         const forceSelected = (this.forceSelected = | ||||||
|             options?.forceSelected ?? new UIEventSource<boolean>(false)) |             options?.forceSelected ?? new UIEventSource<boolean>(false)) | ||||||
|         this.matchesSearchCriteria = search.map(s => { |         this.matchesSearchCriteria = search.map((s) => { | ||||||
|             if (s === undefined || s.length === 0) { |             if (s === undefined || s.length === 0) { | ||||||
|                 return true |                 return true | ||||||
|             } |             } | ||||||
|  | @ -152,13 +152,13 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement< | ||||||
|             show: BaseUIElement |             show: BaseUIElement | ||||||
|             value: T |             value: T | ||||||
|             mainTerm: Record<string, string> |             mainTerm: Record<string, string> | ||||||
|             searchTerms?: Record<string, string[]>, |             searchTerms?: Record<string, string[]> | ||||||
|             /* If there are more then 200 elements, should this element still be shown? */ |             /* If there are more then 200 elements, should this element still be shown? */ | ||||||
|             hasPriority?: Store<boolean> |             hasPriority?: Store<boolean> | ||||||
|         }[], |         }[], | ||||||
|         options?: { |         options?: { | ||||||
|             /* |             /* | ||||||
|             * If one single value can be selected (like a radio button) or if many values can be selected (like checkboxes) |              * If one single value can be selected (like a radio button) or if many values can be selected (like checkboxes) | ||||||
|              */ |              */ | ||||||
|             mode?: "select-one" | "select-many" |             mode?: "select-one" | "select-many" | ||||||
|             /** |             /** | ||||||
|  | @ -189,14 +189,14 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement< | ||||||
|             hideSearchBar?: false | boolean |             hideSearchBar?: false | boolean | ||||||
|         } |         } | ||||||
|     ) { |     ) { | ||||||
|         const search = new TextField({value: options?.searchValue}) |         const search = new TextField({ value: options?.searchValue }) | ||||||
| 
 | 
 | ||||||
|         const searchBar = options?.hideSearchBar |         const searchBar = options?.hideSearchBar | ||||||
|             ? undefined |             ? undefined | ||||||
|             : new Combine([ |             : new Combine([ | ||||||
|                 Svg.search_svg().SetClass("w-8 normal-background"), |                   Svg.search_svg().SetClass("w-8 normal-background"), | ||||||
|                 search.SetClass("w-full"), |                   search.SetClass("w-full"), | ||||||
|             ]).SetClass("flex items-center border-2 border-black m-2") |               ]).SetClass("flex items-center border-2 border-black m-2") | ||||||
| 
 | 
 | ||||||
|         const searchValue = search.GetValue().map((s) => s?.trim()?.toLowerCase()) |         const searchValue = search.GetValue().map((s) => s?.trim()?.toLowerCase()) | ||||||
|         const selectedElements = options?.selectedElements ?? new UIEventSource<T[]>([]) |         const selectedElements = options?.selectedElements ?? new UIEventSource<T[]>([]) | ||||||
|  | @ -238,7 +238,10 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement< | ||||||
|                 searchTerms: v.searchTerms, |                 searchTerms: v.searchTerms, | ||||||
|                 selected: vIsSelected, |                 selected: vIsSelected, | ||||||
|                 squared: mode === "select-many", |                 squared: mode === "select-many", | ||||||
|                 hide: v.hasPriority === undefined ? forceHide : forceHide.map(fh => fh && !v.hasPriority?.data, [v.hasPriority]) |                 hide: | ||||||
|  |                     v.hasPriority === undefined | ||||||
|  |                         ? forceHide | ||||||
|  |                         : forceHide.map((fh) => fh && !v.hasPriority?.data, [v.hasPriority]), | ||||||
|             }) |             }) | ||||||
| 
 | 
 | ||||||
|             return { |             return { | ||||||
|  | @ -249,16 +252,17 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement< | ||||||
| 
 | 
 | ||||||
|         // The total number of elements that would be displayed based on the search criteria alone
 |         // The total number of elements that would be displayed based on the search criteria alone
 | ||||||
|         let totalShown: Store<number> |         let totalShown: Store<number> | ||||||
|         totalShown = searchValue.map((_) => mappedValues.filter((mv) => mv.show.matchesSearchCriteria.data).length) |         totalShown = searchValue.map( | ||||||
|  |             (_) => mappedValues.filter((mv) => mv.show.matchesSearchCriteria.data).length | ||||||
|  |         ) | ||||||
|         const tooMuchElementsCutoff = 40 |         const tooMuchElementsCutoff = 40 | ||||||
|         totalShown.addCallbackAndRunD(shown => forceHide.setData(tooMuchElementsCutoff < shown)) |         totalShown.addCallbackAndRunD((shown) => forceHide.setData(tooMuchElementsCutoff < shown)) | ||||||
| 
 | 
 | ||||||
|         super([ |         super([ | ||||||
|             searchBar, |             searchBar, | ||||||
|             new VariableUiElement( |             new VariableUiElement( | ||||||
|                 Locale.language.map( |                 Locale.language.map( | ||||||
|                     (lng) => { |                     (lng) => { | ||||||
| 
 |  | ||||||
|                         if ( |                         if ( | ||||||
|                             options?.onNoSearchMade !== undefined && |                             options?.onNoSearchMade !== undefined && | ||||||
|                             (searchValue.data === undefined || searchValue.data.length === 0) |                             (searchValue.data === undefined || searchValue.data.length === 0) | ||||||
|  | @ -275,7 +279,10 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement< | ||||||
|                             .SetClass(options?.searchAreaClass ?? "") |                             .SetClass(options?.searchAreaClass ?? "") | ||||||
| 
 | 
 | ||||||
|                         if (totalShown.data >= tooMuchElementsCutoff) { |                         if (totalShown.data >= tooMuchElementsCutoff) { | ||||||
|                             pills = new Combine([options?.onManyElements ?? Translations.t.general.useSearch, pills]) |                             pills = new Combine([ | ||||||
|  |                                 options?.onManyElements ?? Translations.t.general.useSearch, | ||||||
|  |                                 pills, | ||||||
|  |                             ]) | ||||||
|                         } |                         } | ||||||
|                         return pills |                         return pills | ||||||
|                     }, |                     }, | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import {TextField} from "../Input/TextField"; | import { TextField } from "../Input/TextField" | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import { SubtleButton } from "../Base/SubtleButton" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import NoteCommentElement from "./NoteCommentElement"; | import NoteCommentElement from "./NoteCommentElement" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import {LoginToggle} from "./LoginButton"; | import { LoginToggle } from "./LoginButton" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import Title from "../Base/Title"; | import Title from "../Base/Title" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class AddNoteCommentViz implements SpecialVisualization { | export class AddNoteCommentViz implements SpecialVisualization { | ||||||
|     funcName = "add_note_comment" |     funcName = "add_note_comment" | ||||||
|  | @ -103,12 +103,8 @@ export class AddNoteCommentViz implements SpecialVisualization { | ||||||
|                     stateButtons.SetClass("sm:mr-2"), |                     stateButtons.SetClass("sm:mr-2"), | ||||||
|                     new Toggle( |                     new Toggle( | ||||||
|                         addCommentButton, |                         addCommentButton, | ||||||
|                         new Combine([t.typeText]).SetClass( |                         new Combine([t.typeText]).SetClass("flex items-center h-full subtle"), | ||||||
|                             "flex items-center h-full subtle" |                         textField.GetValue().map((t) => t !== undefined && t.length >= 1) | ||||||
|                         ), |  | ||||||
|                         textField |  | ||||||
|                             .GetValue() |  | ||||||
|                             .map((t) => t !== undefined && t.length >= 1) |  | ||||||
|                     ).SetClass("sm:mr-2"), |                     ).SetClass("sm:mr-2"), | ||||||
|                 ]).SetClass("sm:flex sm:justify-between sm:items-stretch"), |                 ]).SetClass("sm:flex sm:justify-between sm:items-stretch"), | ||||||
|             ]).SetClass("border-2 border-black rounded-xl p-4 block"), |             ]).SetClass("border-2 border-black rounded-xl p-4 block"), | ||||||
|  |  | ||||||
|  | @ -1,45 +1,46 @@ | ||||||
| import {SearchablePillsSelector} from "../Input/SearchableMappingsSelector"; | import { SearchablePillsSelector } from "../Input/SearchableMappingsSelector" | ||||||
| import {Store} from "../../Logic/UIEventSource"; | import { Store } from "../../Logic/UIEventSource" | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement" | ||||||
| import * as all_languages from "../../assets/language_translations.json"; | import * as all_languages from "../../assets/language_translations.json" | ||||||
| import {Translation} from "../i18n/Translation"; | import { Translation } from "../i18n/Translation" | ||||||
| 
 |  | ||||||
| export class AllLanguagesSelector extends SearchablePillsSelector <string> { |  | ||||||
| 
 | 
 | ||||||
|  | export class AllLanguagesSelector extends SearchablePillsSelector<string> { | ||||||
|     constructor(options?: { |     constructor(options?: { | ||||||
|                     mode?: "select-many" | "select-one" |         mode?: "select-many" | "select-one" | ||||||
|                     currentCountry?: Store<string>, |         currentCountry?: Store<string> | ||||||
|                     supportedLanguages?: Record<string, string> & { _meta?: { countries?: string[] } } |         supportedLanguages?: Record<string, string> & { _meta?: { countries?: string[] } } | ||||||
|                 }) { |     }) { | ||||||
| 
 |  | ||||||
|         const possibleValues: { |         const possibleValues: { | ||||||
|             show: BaseUIElement |             show: BaseUIElement | ||||||
|             value: string |             value: string | ||||||
|             mainTerm: Record<string, string> |             mainTerm: Record<string, string> | ||||||
|             searchTerms?: Record<string, string[]>, |             searchTerms?: Record<string, string[]> | ||||||
|             hasPriority?: Store<boolean> |             hasPriority?: Store<boolean> | ||||||
|         }[] = [] |         }[] = [] | ||||||
| 
 | 
 | ||||||
|         const langs = options?.supportedLanguages ?? all_languages["default"] ?? all_languages |         const langs = options?.supportedLanguages ?? all_languages["default"] ?? all_languages | ||||||
|         for (const ln in langs) { |         for (const ln in langs) { | ||||||
|             let languageInfo: Record<string, string> & { _meta?: { countries: string[] } } = all_languages[ln] |             let languageInfo: Record<string, string> & { _meta?: { countries: string[] } } = | ||||||
|             const countries = languageInfo._meta?.countries?.map(c => c.toLowerCase()) |                 all_languages[ln] | ||||||
|             languageInfo = {...languageInfo} |             const countries = languageInfo._meta?.countries?.map((c) => c.toLowerCase()) | ||||||
|  |             languageInfo = { ...languageInfo } | ||||||
|             delete languageInfo._meta |             delete languageInfo._meta | ||||||
|             const term = { |             const term = { | ||||||
|                 show: new Translation(languageInfo), |                 show: new Translation(languageInfo), | ||||||
|                 value: ln, |                 value: ln, | ||||||
|                 mainTerm: languageInfo, |                 mainTerm: languageInfo, | ||||||
|                 searchTerms: {"*": [ln]}, |                 searchTerms: { "*": [ln] }, | ||||||
|                 hasPriority: countries === undefined ? undefined : options?.currentCountry?.map(country => countries?.indexOf(country.toLowerCase()) >= 0) |                 hasPriority: | ||||||
|  |                     countries === undefined | ||||||
|  |                         ? undefined | ||||||
|  |                         : options?.currentCountry?.map( | ||||||
|  |                               (country) => countries?.indexOf(country.toLowerCase()) >= 0 | ||||||
|  |                           ), | ||||||
|             } |             } | ||||||
|             possibleValues.push(term) |             possibleValues.push(term) | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
|         super(possibleValues, |         super(possibleValues, { | ||||||
|             { |             mode: options?.mode ?? "select-many", | ||||||
|                 mode: options?.mode ?? 'select-many' |         }) | ||||||
|             }); |  | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ import FilteredLayer from "../../Models/FilteredLayer" | ||||||
| import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" | import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" | ||||||
| import Lazy from "../Base/Lazy" | import Lazy from "../Base/Lazy" | ||||||
| import List from "../Base/List" | import List from "../Base/List" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export interface AutoAction extends SpecialVisualization { | export interface AutoAction extends SpecialVisualization { | ||||||
|     supportsAutoAction: boolean |     supportsAutoAction: boolean | ||||||
|  |  | ||||||
|  | @ -1,13 +1,13 @@ | ||||||
| import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"; | import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement" | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import {Utils} from "../../Utils"; | import { Utils } from "../../Utils" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import Img from "../Base/Img"; | import Img from "../Base/Img" | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import { SubtleButton } from "../Base/SubtleButton" | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import {LoginToggle} from "./LoginButton"; | import { LoginToggle } from "./LoginButton" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class CloseNoteButton implements SpecialVisualization { | export class CloseNoteButton implements SpecialVisualization { | ||||||
|     public readonly funcName = "close_note" |     public readonly funcName = "close_note" | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" | ||||||
| import { Unit } from "../../Models/Unit" | import { Unit } from "../../Models/Unit" | ||||||
| import Lazy from "../Base/Lazy" | import Lazy from "../Base/Lazy" | ||||||
| import { FixedUiElement } from "../Base/FixedUiElement" | import { FixedUiElement } from "../Base/FixedUiElement" | ||||||
| import {EditButton} from "./SaveButton"; | import { EditButton } from "./SaveButton" | ||||||
| 
 | 
 | ||||||
| export default class EditableTagRendering extends Toggle { | export default class EditableTagRendering extends Toggle { | ||||||
|     constructor( |     constructor( | ||||||
|  | @ -71,7 +71,7 @@ export default class EditableTagRendering extends Toggle { | ||||||
|             // We have a question and editing is enabled
 |             // We have a question and editing is enabled
 | ||||||
|             const answerWithEditButton = new Combine([ |             const answerWithEditButton = new Combine([ | ||||||
|                 answer, |                 answer, | ||||||
|                 new EditButton(state.osmConnection,() => { |                 new EditButton(state.osmConnection, () => { | ||||||
|                     editMode.setData(true) |                     editMode.setData(true) | ||||||
|                 }), |                 }), | ||||||
|             ]).SetClass("flex justify-between w-full") |             ]).SetClass("flex justify-between w-full") | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import { SubtleButton } from "../Base/SubtleButton" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import {GeoOperations} from "../../Logic/GeoOperations"; | import { GeoOperations } from "../../Logic/GeoOperations" | ||||||
| import {Utils} from "../../Utils"; | import { Utils } from "../../Utils" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class ExportAsGpxViz implements SpecialVisualization { | export class ExportAsGpxViz implements SpecialVisualization { | ||||||
|     funcName = "export_as_gpx" |     funcName = "export_as_gpx" | ||||||
|  | @ -26,16 +26,10 @@ export class ExportAsGpxViz implements SpecialVisualization { | ||||||
|             const feature = state.allElements.ContainingFeatures.get(tags.id) |             const feature = state.allElements.ContainingFeatures.get(tags.id) | ||||||
|             const matchingLayer = state?.layoutToUse?.getMatchingLayer(tags) |             const matchingLayer = state?.layoutToUse?.getMatchingLayer(tags) | ||||||
|             const gpx = GeoOperations.AsGpx(feature, matchingLayer) |             const gpx = GeoOperations.AsGpx(feature, matchingLayer) | ||||||
|             const title = |             const title = matchingLayer.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "gpx_track" | ||||||
|                 matchingLayer.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? |             Utils.offerContentsAsDownloadableFile(gpx, title + "_mapcomplete_export.gpx", { | ||||||
|                 "gpx_track" |                 mimetype: "{gpx=application/gpx+xml}", | ||||||
|             Utils.offerContentsAsDownloadableFile( |             }) | ||||||
|                 gpx, |  | ||||||
|                 title + "_mapcomplete_export.gpx", |  | ||||||
|                 { |  | ||||||
|                     mimetype: "{gpx=application/gpx+xml}", |  | ||||||
|                 } |  | ||||||
|             ) |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| import {Store, UIEventSource} from "../../Logic/UIEventSource"; | import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; | import { FixedUiElement } from "../Base/FixedUiElement" | ||||||
| // import Histogram from "../BigComponents/Histogram";
 | // import Histogram from "../BigComponents/Histogram";
 | ||||||
| // import {SpecialVisualization} from "../SpecialVisualization";
 | // import {SpecialVisualization} from "../SpecialVisualization";
 | ||||||
| 
 | 
 | ||||||
| export class HistogramViz  { | export class HistogramViz { | ||||||
|     funcName = "histogram" |     funcName = "histogram" | ||||||
|     docs = "Create a histogram for a list of given values, read from the properties." |     docs = "Create a histogram for a list of given values, read from the properties." | ||||||
|     example = |     example = | ||||||
|  | @ -28,7 +28,7 @@ export class HistogramViz  { | ||||||
|             name: "colors*", |             name: "colors*", | ||||||
|             doc: "(Matches all resting arguments - optional) Matches a regex onto a color value, e.g. `3[a-zA-Z+-]*:#33cc33`", |             doc: "(Matches all resting arguments - optional) Matches a regex onto a color value, e.g. `3[a-zA-Z+-]*:#33cc33`", | ||||||
|         }, |         }, | ||||||
|     ]; |     ] | ||||||
| 
 | 
 | ||||||
|     constr(state, tagSource: UIEventSource<any>, args: string[]) { |     constr(state, tagSource: UIEventSource<any>, args: string[]) { | ||||||
|         let assignColors = undefined |         let assignColors = undefined | ||||||
|  | @ -39,7 +39,7 @@ export class HistogramViz  { | ||||||
|                 const splitted = c.split(":") |                 const splitted = c.split(":") | ||||||
|                 const value = splitted.pop() |                 const value = splitted.pop() | ||||||
|                 const regex = splitted.join(":") |                 const regex = splitted.join(":") | ||||||
|                 return {regex: "^" + regex + "$", color: value} |                 return { regex: "^" + regex + "$", color: value } | ||||||
|             }) |             }) | ||||||
|             assignColors = (key) => { |             assignColors = (key) => { | ||||||
|                 for (const kv of mapping) { |                 for (const kv of mapping) { | ||||||
|  | @ -59,10 +59,7 @@ export class HistogramViz  { | ||||||
|                 } |                 } | ||||||
|                 return JSON.parse(value) |                 return JSON.parse(value) | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error( |                 console.error("Could not load histogram: parsing  of the list failed: ", e) | ||||||
|                     "Could not load histogram: parsing  of the list failed: ", |  | ||||||
|                     e |  | ||||||
|                 ) |  | ||||||
|                 return undefined |                 return undefined | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ import { Changes } from "../../Logic/Osm/Changes" | ||||||
| import { ElementStorage } from "../../Logic/ElementStorage" | import { ElementStorage } from "../../Logic/ElementStorage" | ||||||
| import Hash from "../../Logic/Web/Hash" | import Hash from "../../Logic/Web/Hash" | ||||||
| import { PreciseInput } from "../../Models/ThemeConfig/PresetConfig" | import { PreciseInput } from "../../Models/ThemeConfig/PresetConfig" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A helper class for the various import-flows. |  * A helper class for the various import-flows. | ||||||
|  |  | ||||||
|  | @ -1,73 +1,68 @@ | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement" | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"; | import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import {OsmTags} from "../../Models/OsmFeature"; | import { OsmTags } from "../../Models/OsmFeature" | ||||||
| import * as all_languages from "../../assets/language_translations.json" | import * as all_languages from "../../assets/language_translations.json" | ||||||
| import {Translation} from "../i18n/Translation"; | import { Translation } from "../i18n/Translation" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import Title from "../Base/Title"; | import Title from "../Base/Title" | ||||||
| import Lazy from "../Base/Lazy"; | import Lazy from "../Base/Lazy" | ||||||
| import {SubstitutedTranslation} from "../SubstitutedTranslation"; | import { SubstitutedTranslation } from "../SubstitutedTranslation" | ||||||
| import List from "../Base/List"; | import List from "../Base/List" | ||||||
| import {AllLanguagesSelector} from "./AllLanguagesSelector"; | import { AllLanguagesSelector } from "./AllLanguagesSelector" | ||||||
| import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; | import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction" | ||||||
| import {And} from "../../Logic/Tags/And"; | import { And } from "../../Logic/Tags/And" | ||||||
| import {Tag} from "../../Logic/Tags/Tag"; | import { Tag } from "../../Logic/Tags/Tag" | ||||||
| import {EditButton, SaveButton} from "./SaveButton"; | import { EditButton, SaveButton } from "./SaveButton" | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; | import { FixedUiElement } from "../Base/FixedUiElement" | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import {On} from "../../Models/ThemeConfig/Conversion/Conversion"; | import { On } from "../../Models/ThemeConfig/Conversion/Conversion" | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| export class LanguageElement implements SpecialVisualization { | export class LanguageElement implements SpecialVisualization { | ||||||
|     funcName: string = "language_chooser" |     funcName: string = "language_chooser" | ||||||
| 
 | 
 | ||||||
|     docs: string | BaseUIElement = "The language element allows to show and pick all known (modern) languages. The key can be set"; |     docs: string | BaseUIElement = | ||||||
|  |         "The language element allows to show and pick all known (modern) languages. The key can be set" | ||||||
| 
 | 
 | ||||||
|     args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = |     args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [ | ||||||
|         [{ |         { | ||||||
|             name: "key", |             name: "key", | ||||||
|             required: true, |             required: true, | ||||||
|             doc: "What key to use, e.g. `language`, `tactile_writing:braille:language`, ... If a language is supported, the language code will be appended to this key, resulting in `language:nl=yes` if nl is picked " |             doc: "What key to use, e.g. `language`, `tactile_writing:braille:language`, ... If a language is supported, the language code will be appended to this key, resulting in `language:nl=yes` if nl is picked ", | ||||||
|         }, |         }, | ||||||
|             { |         { | ||||||
|                 name: "question", |             name: "question", | ||||||
|                 required: true, |             required: true, | ||||||
|                 doc: "What to ask if no questions are known" |             doc: "What to ask if no questions are known", | ||||||
|             }, |         }, | ||||||
|             { |         { | ||||||
|                 name: "render_list_item", |             name: "render_list_item", | ||||||
|                 doc: "How a single language will be shown in the list of languages. Use `{language}` to indicate the language (which it must contain).", |             doc: "How a single language will be shown in the list of languages. Use `{language}` to indicate the language (which it must contain).", | ||||||
|                 defaultValue: "{language()}" |             defaultValue: "{language()}", | ||||||
|             }, |         }, | ||||||
|             { |         { | ||||||
|                 name: "render_single_language", |             name: "render_single_language", | ||||||
|                 doc: "What will be shown if the feature only supports a single language", |             doc: "What will be shown if the feature only supports a single language", | ||||||
|                 required: true |             required: true, | ||||||
|             }, |         }, | ||||||
|             { |         { | ||||||
|                 name: "render_all", |             name: "render_all", | ||||||
|                 doc: "The full rendering. Use `{list}` to show where the list of languages must come. Optional if mode=single", |             doc: "The full rendering. Use `{list}` to show where the list of languages must come. Optional if mode=single", | ||||||
|                 defaultValue: "{list()}" |             defaultValue: "{list()}", | ||||||
|             }, |         }, | ||||||
|             { |         { | ||||||
|                 name: "no_known_languages", |             name: "no_known_languages", | ||||||
|                 doc: "The text that is shown if no languages are known for this key. If this text is omitted, the languages will be prompted instead" |             doc: "The text that is shown if no languages are known for this key. If this text is omitted, the languages will be prompted instead", | ||||||
|             }, |         }, | ||||||
|             { |         { | ||||||
|                 name: 'mode', |             name: "mode", | ||||||
|                 doc: "If one or many languages can be selected. Should be 'multi' or 'single'", |             doc: "If one or many languages can be selected. Should be 'multi' or 'single'", | ||||||
|                 defaultValue: 'multi' |             defaultValue: "multi", | ||||||
|             } |         }, | ||||||
| 
 |     ] | ||||||
| 
 |  | ||||||
|         ] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     ; |  | ||||||
| 
 | 
 | ||||||
|     example: ` |     example: ` | ||||||
|     \`\`\`json
 |     \`\`\`json
 | ||||||
|  | @ -83,8 +78,13 @@ export class LanguageElement implements SpecialVisualization { | ||||||
|      \`\`\` |      \`\`\` | ||||||
|     ` |     ` | ||||||
| 
 | 
 | ||||||
|     constr(state: FeaturePipelineState, tagSource: UIEventSource<OsmTags>, argument: string[]): BaseUIElement { |     constr( | ||||||
|         let [key, question, item_render, single_render, all_render, on_no_known_languages, mode] = argument |         state: FeaturePipelineState, | ||||||
|  |         tagSource: UIEventSource<OsmTags>, | ||||||
|  |         argument: string[] | ||||||
|  |     ): BaseUIElement { | ||||||
|  |         let [key, question, item_render, single_render, all_render, on_no_known_languages, mode] = | ||||||
|  |             argument | ||||||
|         if (mode === undefined || mode.length == 0) { |         if (mode === undefined || mode.length == 0) { | ||||||
|             mode = "multi" |             mode = "multi" | ||||||
|         } |         } | ||||||
|  | @ -95,7 +95,10 @@ export class LanguageElement implements SpecialVisualization { | ||||||
|             all_render = "{list()}" |             all_render = "{list()}" | ||||||
|         } |         } | ||||||
|         if (mode !== "single" && mode !== "multi") { |         if (mode !== "single" && mode !== "multi") { | ||||||
|             throw "Error while calling language_chooser: mode must be either 'single' or 'multi' but it is " + mode |             throw ( | ||||||
|  |                 "Error while calling language_chooser: mode must be either 'single' or 'multi' but it is " + | ||||||
|  |                 mode | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|         if (single_render.indexOf("{language()") < 0 || item_render.indexOf("{language()") < 0) { |         if (single_render.indexOf("{language()") < 0 || item_render.indexOf("{language()") < 0) { | ||||||
|             throw "Error while calling language_chooser: render_single_language and render_list_item must contain '{language()}'" |             throw "Error while calling language_chooser: render_single_language and render_list_item must contain '{language()}'" | ||||||
|  | @ -105,40 +108,39 @@ export class LanguageElement implements SpecialVisualization { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const prefix = key + ":" |         const prefix = key + ":" | ||||||
|         const foundLanguages = tagSource |         const foundLanguages = tagSource.map((tags) => { | ||||||
|             .map(tags => { |             const foundLanguages: string[] = [] | ||||||
|                 const foundLanguages: string[] = [] |             for (const k in tags) { | ||||||
|                 for (const k in tags) { |                 const v = tags[k] | ||||||
|                     const v = tags[k] |                 if (v !== "yes") { | ||||||
|                     if (v !== "yes") { |                     continue | ||||||
|                         continue |  | ||||||
|                     } |  | ||||||
|                     if (k.startsWith(prefix)) { |  | ||||||
|                         foundLanguages.push(k.substring(prefix.length)) |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|                 return foundLanguages |                 if (k.startsWith(prefix)) { | ||||||
|             }) |                     foundLanguages.push(k.substring(prefix.length)) | ||||||
|         const forceInputMode = new UIEventSource(false); |                 } | ||||||
|  |             } | ||||||
|  |             return foundLanguages | ||||||
|  |         }) | ||||||
|  |         const forceInputMode = new UIEventSource(false) | ||||||
|         const inputEl = new Lazy(() => { |         const inputEl = new Lazy(() => { | ||||||
|             const selector = new AllLanguagesSelector( |             const selector = new AllLanguagesSelector({ | ||||||
|                 { |                 mode: mode === "single" ? "select-one" : "select-many", | ||||||
|                     mode: mode === "single" ? "select-one" : "select-many", |                 currentCountry: tagSource.map((tgs) => tgs["_country"]), | ||||||
|                     currentCountry: tagSource.map(tgs => tgs["_country"]) |             }) | ||||||
|                 } |             const cancelButton = Toggle.If(forceInputMode, () => | ||||||
|             ) |                 Translations.t.general.cancel | ||||||
|             const cancelButton = Toggle.If(forceInputMode, |  | ||||||
|                 () => Translations.t.general.cancel |  | ||||||
|                     .Clone() |                     .Clone() | ||||||
|                     .SetClass("btn btn-secondary").onClick(() => forceInputMode.setData(false))) |                     .SetClass("btn btn-secondary") | ||||||
|  |                     .onClick(() => forceInputMode.setData(false)) | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|             const saveButton = new SaveButton( |             const saveButton = new SaveButton( | ||||||
|                 selector.GetValue().map(lngs => lngs.length > 0 ? "true" : undefined), |                 selector.GetValue().map((lngs) => (lngs.length > 0 ? "true" : undefined)), | ||||||
|                 state.osmConnection, |                 state.osmConnection | ||||||
|             ).onClick(() => { |             ).onClick(() => { | ||||||
|                 const selectedLanguages = selector.GetValue().data |                 const selectedLanguages = selector.GetValue().data | ||||||
|                 const currentLanguages = foundLanguages.data |                 const currentLanguages = foundLanguages.data | ||||||
|                 const selection: Tag[] = selectedLanguages.map(ln => new Tag(prefix + ln, "yes")); |                 const selection: Tag[] = selectedLanguages.map((ln) => new Tag(prefix + ln, "yes")) | ||||||
| 
 | 
 | ||||||
|                 for (const currentLanguage of currentLanguages) { |                 for (const currentLanguage of currentLanguages) { | ||||||
|                     if (selectedLanguages.indexOf(currentLanguage) >= 0) { |                     if (selectedLanguages.indexOf(currentLanguage) >= 0) { | ||||||
|  | @ -148,19 +150,23 @@ export class LanguageElement implements SpecialVisualization { | ||||||
|                     selection.push(new Tag(prefix + currentLanguage, "")) |                     selection.push(new Tag(prefix + currentLanguage, "")) | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|                 if (state.featureSwitchIsTesting.data) { |                 if (state.featureSwitchIsTesting.data) { | ||||||
|                     for (const tag of selection) { |                     for (const tag of selection) { | ||||||
|                         tagSource.data[tag.key] = tag.value |                         tagSource.data[tag.key] = tag.value | ||||||
|                     } |                     } | ||||||
|                     tagSource.ping() |                     tagSource.ping() | ||||||
|                 } else { |                 } else { | ||||||
|                     (state?.changes) |                     ;(state?.changes) | ||||||
|                         .applyAction( |                         .applyAction( | ||||||
|                             new ChangeTagAction(tagSource.data.id, new And(selection), tagSource.data, { |                             new ChangeTagAction( | ||||||
|                                 theme: state?.layoutToUse?.id ?? "unkown", |                                 tagSource.data.id, | ||||||
|                                 changeType: "answer", |                                 new And(selection), | ||||||
|                             }) |                                 tagSource.data, | ||||||
|  |                                 { | ||||||
|  |                                     theme: state?.layoutToUse?.id ?? "unkown", | ||||||
|  |                                     changeType: "answer", | ||||||
|  |                                 } | ||||||
|  |                             ) | ||||||
|                         ) |                         ) | ||||||
|                         .then((_) => { |                         .then((_) => { | ||||||
|                             console.log("Tagchanges applied") |                             console.log("Tagchanges applied") | ||||||
|  | @ -169,60 +175,72 @@ export class LanguageElement implements SpecialVisualization { | ||||||
|                 forceInputMode.setData(false) |                 forceInputMode.setData(false) | ||||||
|             }) |             }) | ||||||
| 
 | 
 | ||||||
|             return new Combine([new Title(question), selector, |             return new Combine([ | ||||||
|                 new Combine([cancelButton, saveButton]).SetClass("flex justify-end") |                 new Title(question), | ||||||
|             ]).SetClass("flex flex-col question disable-links"); |                 selector, | ||||||
|  |                 new Combine([cancelButton, saveButton]).SetClass("flex justify-end"), | ||||||
|  |             ]).SetClass("flex flex-col question disable-links") | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|         const editButton = new EditButton(state.osmConnection, () => forceInputMode.setData(true)) |         const editButton = new EditButton(state.osmConnection, () => forceInputMode.setData(true)) | ||||||
| 
 | 
 | ||||||
|         return new VariableUiElement(foundLanguages |         return new VariableUiElement( | ||||||
|             .map(foundLanguages => { |             foundLanguages.map( | ||||||
| 
 |                 (foundLanguages) => { | ||||||
|                 if (forceInputMode.data) { |                     if (forceInputMode.data) { | ||||||
|                     return inputEl |                         return inputEl | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if (foundLanguages.length === 0) { |  | ||||||
|                     // No languages found - we show the question and the input element
 |  | ||||||
|                     if (on_no_known_languages !== undefined && on_no_known_languages.length > 0) { |  | ||||||
|                         return new Combine([on_no_known_languages, editButton]).SetClass("flex justify-end") |  | ||||||
|                     } |                     } | ||||||
|                     return inputEl |  | ||||||
| 
 | 
 | ||||||
|                 } |                     if (foundLanguages.length === 0) { | ||||||
| 
 |                         // No languages found - we show the question and the input element
 | ||||||
|                 let rendered: BaseUIElement; |                         if ( | ||||||
|                 if (foundLanguages.length === 1) { |                             on_no_known_languages !== undefined && | ||||||
|                     const ln = foundLanguages[0] |                             on_no_known_languages.length > 0 | ||||||
|                     let mapping = new Map<string, BaseUIElement>(); |                         ) { | ||||||
|                     mapping.set("language", new Translation(all_languages[ln])) |                             return new Combine([on_no_known_languages, editButton]).SetClass( | ||||||
|                     rendered = new SubstitutedTranslation( |                                 "flex justify-end" | ||||||
|                         new Translation({"*": single_render}, undefined), |  | ||||||
|                         tagSource, state, mapping |  | ||||||
|                     ) |  | ||||||
|                 } else { |  | ||||||
| 
 |  | ||||||
|                     let mapping = new Map<string, BaseUIElement>(); |  | ||||||
|                     const languagesList = new List( |  | ||||||
|                         foundLanguages.map(ln => { |  | ||||||
|                             let mappingLn = new Map<string, BaseUIElement>(); |  | ||||||
|                             mappingLn.set("language", new Translation(all_languages[ln])) |  | ||||||
|                             return new SubstitutedTranslation( |  | ||||||
|                                 new Translation({"*": item_render}, undefined), |  | ||||||
|                                 tagSource, state, mappingLn |  | ||||||
|                             ) |                             ) | ||||||
|                         }) |                         } | ||||||
|                     ); |                         return inputEl | ||||||
|                     mapping.set("list", languagesList) |                     } | ||||||
|                     rendered = new SubstitutedTranslation( |  | ||||||
|                         new Translation({'*': all_render}, undefined), tagSource, |  | ||||||
|                         state, mapping |  | ||||||
|                     ) |  | ||||||
|                 } |  | ||||||
|                 return new Combine([rendered, editButton]).SetClass("flex justify-between") |  | ||||||
| 
 | 
 | ||||||
|             }, [forceInputMode])); |                     let rendered: BaseUIElement | ||||||
|  |                     if (foundLanguages.length === 1) { | ||||||
|  |                         const ln = foundLanguages[0] | ||||||
|  |                         let mapping = new Map<string, BaseUIElement>() | ||||||
|  |                         mapping.set("language", new Translation(all_languages[ln])) | ||||||
|  |                         rendered = new SubstitutedTranslation( | ||||||
|  |                             new Translation({ "*": single_render }, undefined), | ||||||
|  |                             tagSource, | ||||||
|  |                             state, | ||||||
|  |                             mapping | ||||||
|  |                         ) | ||||||
|  |                     } else { | ||||||
|  |                         let mapping = new Map<string, BaseUIElement>() | ||||||
|  |                         const languagesList = new List( | ||||||
|  |                             foundLanguages.map((ln) => { | ||||||
|  |                                 let mappingLn = new Map<string, BaseUIElement>() | ||||||
|  |                                 mappingLn.set("language", new Translation(all_languages[ln])) | ||||||
|  |                                 return new SubstitutedTranslation( | ||||||
|  |                                     new Translation({ "*": item_render }, undefined), | ||||||
|  |                                     tagSource, | ||||||
|  |                                     state, | ||||||
|  |                                     mappingLn | ||||||
|  |                                 ) | ||||||
|  |                             }) | ||||||
|  |                         ) | ||||||
|  |                         mapping.set("list", languagesList) | ||||||
|  |                         rendered = new SubstitutedTranslation( | ||||||
|  |                             new Translation({ "*": all_render }, undefined), | ||||||
|  |                             tagSource, | ||||||
|  |                             state, | ||||||
|  |                             mapping | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                     return new Combine([rendered, editButton]).SetClass("flex justify-between") | ||||||
|  |                 }, | ||||||
|  |                 [forceInputMode] | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| import {GeoOperations} from "../../Logic/GeoOperations"; | import { GeoOperations } from "../../Logic/GeoOperations" | ||||||
| import {MapillaryLink} from "../BigComponents/MapillaryLink"; | import { MapillaryLink } from "../BigComponents/MapillaryLink" | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Loc from "../../Models/Loc"; | import Loc from "../../Models/Loc" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class MapillaryLinkVis implements SpecialVisualization { | export class MapillaryLinkVis implements SpecialVisualization { | ||||||
|     funcName = "mapillary_link" |     funcName = "mapillary_link" | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| import {Store, UIEventSource} from "../../Logic/UIEventSource"; | import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Loc from "../../Models/Loc"; | import Loc from "../../Models/Loc" | ||||||
| import Minimap from "../Base/Minimap"; | import Minimap from "../Base/Minimap" | ||||||
| import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer"; | import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer" | ||||||
| import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"; | import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class MinimapViz implements SpecialVisualization { | export class MinimapViz implements SpecialVisualization { | ||||||
|     funcName = "minimap" |     funcName = "minimap" | ||||||
|  | @ -20,8 +20,7 @@ export class MinimapViz implements SpecialVisualization { | ||||||
|             defaultValue: "id", |             defaultValue: "id", | ||||||
|         }, |         }, | ||||||
|     ] |     ] | ||||||
|     example: |     example: "`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`" | ||||||
|         "`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`" |  | ||||||
| 
 | 
 | ||||||
|     constr(state, tagSource, args, _) { |     constr(state, tagSource, args, _) { | ||||||
|         if (state === undefined) { |         if (state === undefined) { | ||||||
|  | @ -30,8 +29,8 @@ export class MinimapViz implements SpecialVisualization { | ||||||
|         const keys = [...args] |         const keys = [...args] | ||||||
|         keys.splice(0, 1) |         keys.splice(0, 1) | ||||||
|         const featureStore = state.allElements.ContainingFeatures |         const featureStore = state.allElements.ContainingFeatures | ||||||
|         const featuresToShow: Store<{ freshness: Date; feature: any }[]> = |         const featuresToShow: Store<{ freshness: Date; feature: any }[]> = tagSource.map( | ||||||
|             tagSource.map((properties) => { |             (properties) => { | ||||||
|                 const features: { freshness: Date; feature: any }[] = [] |                 const features: { freshness: Date; feature: any }[] = [] | ||||||
|                 for (const key of keys) { |                 for (const key of keys) { | ||||||
|                     const value = properties[key] |                     const value = properties[key] | ||||||
|  | @ -58,7 +57,8 @@ export class MinimapViz implements SpecialVisualization { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 return features |                 return features | ||||||
|             }) |             } | ||||||
|  |         ) | ||||||
|         const properties = tagSource.data |         const properties = tagSource.data | ||||||
|         let zoom = 18 |         let zoom = 18 | ||||||
|         if (args[0]) { |         if (args[0]) { | ||||||
|  |  | ||||||
|  | @ -1,10 +1,11 @@ | ||||||
| import {Store} from "../../Logic/UIEventSource"; | import { Store } from "../../Logic/UIEventSource" | ||||||
| import MultiApply from "./MultiApply"; | import MultiApply from "./MultiApply" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class MultiApplyViz implements SpecialVisualization { | export class MultiApplyViz implements SpecialVisualization { | ||||||
|     funcName = "multi_apply" |     funcName = "multi_apply" | ||||||
|     docs = "A button to apply the tagging of this object onto a list of other features. This is an advanced feature for which you'll need calculatedTags" |     docs = | ||||||
|  |         "A button to apply the tagging of this object onto a list of other features. This is an advanced feature for which you'll need calculatedTags" | ||||||
|     args = [ |     args = [ | ||||||
|         { |         { | ||||||
|             name: "feature_ids", |             name: "feature_ids", | ||||||
|  | @ -52,17 +53,14 @@ export class MultiApplyViz implements SpecialVisualization { | ||||||
|                 return [] |                 return [] | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|         return new MultiApply( |         return new MultiApply({ | ||||||
|             { |             featureIds, | ||||||
|                 featureIds, |             keysToApply, | ||||||
|                 keysToApply, |             text, | ||||||
|                 text, |             autoapply, | ||||||
|                 autoapply, |             overwrite, | ||||||
|                 overwrite, |             tagsSource, | ||||||
|                 tagsSource, |             state, | ||||||
|                 state |         }) | ||||||
|             } |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,25 +1,25 @@ | ||||||
| import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"; | import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import {DefaultGuiState} from "../DefaultGuiState"; | import { DefaultGuiState } from "../DefaultGuiState" | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement" | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import {GeoOperations} from "../../Logic/GeoOperations"; | import { GeoOperations } from "../../Logic/GeoOperations" | ||||||
| import NearbyImages, {NearbyImageOptions, P4CPicture, SelectOneNearbyImage} from "./NearbyImages"; | import NearbyImages, { NearbyImageOptions, P4CPicture, SelectOneNearbyImage } from "./NearbyImages" | ||||||
| import {SubstitutedTranslation} from "../SubstitutedTranslation"; | import { SubstitutedTranslation } from "../SubstitutedTranslation" | ||||||
| import {Tag} from "../../Logic/Tags/Tag"; | import { Tag } from "../../Logic/Tags/Tag" | ||||||
| import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; | import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction" | ||||||
| import {And} from "../../Logic/Tags/And"; | import { And } from "../../Logic/Tags/And" | ||||||
| import {SaveButton} from "./SaveButton"; | import { SaveButton } from "./SaveButton" | ||||||
| import Lazy from "../Base/Lazy"; | import Lazy from "../Base/Lazy" | ||||||
| import {CheckBox} from "../Input/Checkboxes"; | import { CheckBox } from "../Input/Checkboxes" | ||||||
| import Slider from "../Input/Slider"; | import Slider from "../Input/Slider" | ||||||
| import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"; | import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import Title from "../Base/Title"; | import Title from "../Base/Title" | ||||||
| import {MapillaryLinkVis} from "./MapillaryLinkVis"; | import { MapillaryLinkVis } from "./MapillaryLinkVis" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class NearbyImageVis implements SpecialVisualization { | export class NearbyImageVis implements SpecialVisualization { | ||||||
|     args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [ |     args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [ | ||||||
|  | @ -116,7 +116,7 @@ export class NearbyImageVis implements SpecialVisualization { | ||||||
|                 towardsCenter, |                 towardsCenter, | ||||||
|                 new Combine([ |                 new Combine([ | ||||||
|                     new VariableUiElement( |                     new VariableUiElement( | ||||||
|                         radius.GetValue().map((radius) => t.withinRadius.Subs({radius})) |                         radius.GetValue().map((radius) => t.withinRadius.Subs({ radius })) | ||||||
|                     ), |                     ), | ||||||
|                     radius, |                     radius, | ||||||
|                 ]).SetClass("flex justify-between"), |                 ]).SetClass("flex justify-between"), | ||||||
|  |  | ||||||
|  | @ -1,29 +1,30 @@ | ||||||
| import {Store, UIEventSource} from "../../Logic/UIEventSource"; | import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle" | ||||||
| import Lazy from "../Base/Lazy"; | import Lazy from "../Base/Lazy" | ||||||
| import {ProvidedImage} from "../../Logic/ImageProviders/ImageProvider"; | import { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider" | ||||||
| import PlantNetSpeciesSearch from "../BigComponents/PlantNetSpeciesSearch"; | import PlantNetSpeciesSearch from "../BigComponents/PlantNetSpeciesSearch" | ||||||
| import Wikidata from "../../Logic/Web/Wikidata"; | import Wikidata from "../../Logic/Web/Wikidata" | ||||||
| import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; | import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction" | ||||||
| import {And} from "../../Logic/Tags/And"; | import { And } from "../../Logic/Tags/And" | ||||||
| import {Tag} from "../../Logic/Tags/Tag"; | import { Tag } from "../../Logic/Tags/Tag" | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import { SubtleButton } from "../Base/SubtleButton" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations" | ||||||
| import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"; | import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class PlantNetDetectionViz implements SpecialVisualization { | export class PlantNetDetectionViz implements SpecialVisualization { | ||||||
|     funcName = "plantnet_detection" |     funcName = "plantnet_detection" | ||||||
| 
 | 
 | ||||||
|     docs = "Sends the images linked to the current object to plantnet.org and asks it what plant species is shown on it. The user can then select the correct species; the corresponding wikidata-identifier will then be added to the object (together with `source:species:wikidata=plantnet.org AI`). " |     docs = | ||||||
|  |         "Sends the images linked to the current object to plantnet.org and asks it what plant species is shown on it. The user can then select the correct species; the corresponding wikidata-identifier will then be added to the object (together with `source:species:wikidata=plantnet.org AI`). " | ||||||
|     args = [ |     args = [ | ||||||
|         { |         { | ||||||
|             name: "image_key", |             name: "image_key", | ||||||
|             defaultValue: AllImageProviders.defaultKeys.join(","), |             defaultValue: AllImageProviders.defaultKeys.join(","), | ||||||
|             doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... Multiple values are allowed if ';'-separated ", |             doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... Multiple values are allowed if ';'-separated ", | ||||||
|         } |         }, | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     public constr(state, tags, args) { |     public constr(state, tags, args) { | ||||||
|  | @ -35,44 +36,40 @@ export class PlantNetDetectionViz implements SpecialVisualization { | ||||||
|         const detect = new UIEventSource(false) |         const detect = new UIEventSource(false) | ||||||
|         const toggle = new Toggle( |         const toggle = new Toggle( | ||||||
|             new Lazy(() => { |             new Lazy(() => { | ||||||
|                 const allProvidedImages: Store<ProvidedImage[]> = |                 const allProvidedImages: Store<ProvidedImage[]> = AllImageProviders.LoadImagesFor( | ||||||
|                     AllImageProviders.LoadImagesFor(tags, imagePrefixes) |                     tags, | ||||||
|  |                     imagePrefixes | ||||||
|  |                 ) | ||||||
|                 const allImages: Store<string[]> = allProvidedImages.map((pi) => |                 const allImages: Store<string[]> = allProvidedImages.map((pi) => | ||||||
|                     pi.map((pi) => pi.url) |                     pi.map((pi) => pi.url) | ||||||
|                 ) |                 ) | ||||||
|                 return new PlantNetSpeciesSearch( |                 return new PlantNetSpeciesSearch(allImages, async (selectedWikidata) => { | ||||||
|                     allImages, |                     selectedWikidata = Wikidata.ExtractKey(selectedWikidata) | ||||||
|                     async (selectedWikidata) => { |                     const change = new ChangeTagAction( | ||||||
|                         selectedWikidata = Wikidata.ExtractKey(selectedWikidata) |                         tags.data.id, | ||||||
|                         const change = new ChangeTagAction( |                         new And([ | ||||||
|                             tags.data.id, |                             new Tag("species:wikidata", selectedWikidata), | ||||||
|                             new And([ |                             new Tag("source:species:wikidata", "PlantNet.org AI"), | ||||||
|                                 new Tag("species:wikidata", selectedWikidata), |                         ]), | ||||||
|                                 new Tag("source:species:wikidata", "PlantNet.org AI"), |                         tags.data, | ||||||
|                             ]), |                         { | ||||||
|                             tags.data, |                             theme: state.layoutToUse.id, | ||||||
|                             { |                             changeType: "plantnet-ai-detection", | ||||||
|                                 theme: state.layoutToUse.id, |                         } | ||||||
|                                 changeType: "plantnet-ai-detection", |                     ) | ||||||
|                             } |                     await state.changes.applyAction(change) | ||||||
|                         ) |                 }) | ||||||
|                         await state.changes.applyAction(change) |  | ||||||
|                     } |  | ||||||
|                 ) |  | ||||||
|             }), |             }), | ||||||
|             new SubtleButton( |             new SubtleButton(undefined, "Detect plant species with plantnet.org").onClick(() => | ||||||
|                 undefined, |                 detect.setData(true) | ||||||
|                 "Detect plant species with plantnet.org" |             ), | ||||||
|             ).onClick(() => detect.setData(true)), |  | ||||||
|             detect |             detect | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         return new Combine([ |         return new Combine([ | ||||||
|             toggle, |             toggle, | ||||||
|             new Combine([ |             new Combine([ | ||||||
|                 Svg.plantnet_logo_svg().SetClass( |                 Svg.plantnet_logo_svg().SetClass("w-10 h-10 p-1 mr-1 bg-white rounded-full"), | ||||||
|                     "w-10 h-10 p-1 mr-1 bg-white rounded-full" |  | ||||||
|                 ), |  | ||||||
|                 Translations.t.plantDetection.poweredByPlantnet, |                 Translations.t.plantDetection.poweredByPlantnet, | ||||||
|             ]).SetClass("flex p-2 bg-gray-200 rounded-xl self-end"), |             ]).SetClass("flex p-2 bg-gray-200 rounded-xl self-end"), | ||||||
|         ]).SetClass("flex flex-col") |         ]).SetClass("flex flex-col") | ||||||
|  |  | ||||||
|  | @ -3,8 +3,8 @@ import Translations from "../i18n/Translations" | ||||||
| import { OsmConnection } from "../../Logic/Osm/OsmConnection" | import { OsmConnection } from "../../Logic/Osm/OsmConnection" | ||||||
| import Toggle from "../Input/Toggle" | import Toggle from "../Input/Toggle" | ||||||
| import BaseUIElement from "../BaseUIElement" | import BaseUIElement from "../BaseUIElement" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| 
 | 
 | ||||||
| export class EditButton extends Toggle { | export class EditButton extends Toggle { | ||||||
|     constructor(osmConnection: OsmConnection, onClick: () => void) { |     constructor(osmConnection: OsmConnection, onClick: () => void) { | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | ||||||
| import ShareButton from "../BigComponents/ShareButton"; | import ShareButton from "../BigComponents/ShareButton" | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg" | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; | import { FixedUiElement } from "../Base/FixedUiElement" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class ShareLinkViz implements SpecialVisualization { | export class ShareLinkViz implements SpecialVisualization { | ||||||
|     funcName = "share_link" |     funcName = "share_link" | ||||||
|  | @ -45,10 +45,7 @@ export class ShareLinkViz implements SpecialVisualization { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return new ShareButton( |             return new ShareButton(Svg.share_svg().SetClass("w-8 h-8"), generateShareData) | ||||||
|                 Svg.share_svg().SetClass("w-8 h-8"), |  | ||||||
|                 generateShareData |  | ||||||
|             ) |  | ||||||
|         } else { |         } else { | ||||||
|             return new FixedUiElement("") |             return new FixedUiElement("") | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1,15 +1,16 @@ | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import Loc from "../../Models/Loc"; | import Loc from "../../Models/Loc" | ||||||
| import Minimap from "../Base/Minimap"; | import Minimap from "../Base/Minimap" | ||||||
| import ShowDataLayer from "../ShowDataLayer/ShowDataLayer"; | import ShowDataLayer from "../ShowDataLayer/ShowDataLayer" | ||||||
| import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | ||||||
| import * as left_right_style_json from "../../assets/layers/left_right_style/left_right_style.json"; | import * as left_right_style_json from "../../assets/layers/left_right_style/left_right_style.json" | ||||||
| import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"; | import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class SidedMinimap implements SpecialVisualization { | export class SidedMinimap implements SpecialVisualization { | ||||||
|     funcName = "sided_minimap" |     funcName = "sided_minimap" | ||||||
|     docs = "A small map showing _only one side_ the selected feature. *This features requires to have linerenderings with offset* as only linerenderings with a postive or negative offset will be shown. Note: in most cases, this map will be automatically introduced" |     docs = | ||||||
|  |         "A small map showing _only one side_ the selected feature. *This features requires to have linerenderings with offset* as only linerenderings with a postive or negative offset will be shown. Note: in most cases, this map will be automatically introduced" | ||||||
|     args = [ |     args = [ | ||||||
|         { |         { | ||||||
|             doc: "The side to show, either `left` or `right`", |             doc: "The side to show, either `left` or `right`", | ||||||
|  | @ -33,18 +34,14 @@ export class SidedMinimap implements SpecialVisualization { | ||||||
|         }) |         }) | ||||||
|         const side = args[0] |         const side = args[0] | ||||||
|         const feature = state.allElements.ContainingFeatures.get(tagSource.data.id) |         const feature = state.allElements.ContainingFeatures.get(tagSource.data.id) | ||||||
|         const copy = {...feature} |         const copy = { ...feature } | ||||||
|         copy.properties = { |         copy.properties = { | ||||||
|             id: side, |             id: side, | ||||||
|         } |         } | ||||||
|         new ShowDataLayer({ |         new ShowDataLayer({ | ||||||
|             leafletMap: minimap["leafletMap"], |             leafletMap: minimap["leafletMap"], | ||||||
|             zoomToFeatures: true, |             zoomToFeatures: true, | ||||||
|             layerToShow: new LayerConfig( |             layerToShow: new LayerConfig(left_right_style_json, "all_known_layers", true), | ||||||
|                 left_right_style_json, |  | ||||||
|                 "all_known_layers", |  | ||||||
|                 true |  | ||||||
|             ), |  | ||||||
|             features: StaticFeatureSource.fromGeojson([copy]), |             features: StaticFeatureSource.fromGeojson([copy]), | ||||||
|             state, |             state, | ||||||
|         }) |         }) | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | ||||||
| import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; | import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement" | ||||||
| import EditableTagRendering from "./EditableTagRendering"; | import EditableTagRendering from "./EditableTagRendering" | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export class StealViz implements SpecialVisualization { | export class StealViz implements SpecialVisualization { | ||||||
|     funcName = "steal" |     funcName = "steal" | ||||||
|  | @ -27,9 +27,7 @@ export class StealViz implements SpecialVisualization { | ||||||
|         for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) { |         for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) { | ||||||
|             const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".") |             const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".") | ||||||
|             const layer = state.layoutToUse.layers.find((l) => l.id === layerId) |             const layer = state.layoutToUse.layers.find((l) => l.id === layerId) | ||||||
|             const tagRendering = layer.tagRenderings.find( |             const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId) | ||||||
|                 (tr) => tr.id === tagRenderingId |  | ||||||
|             ) |  | ||||||
|             tagRenderings.push([layer, tagRendering]) |             tagRenderings.push([layer, tagRendering]) | ||||||
|         } |         } | ||||||
|         if (tagRenderings.length === 0) { |         if (tagRenderings.length === 0) { | ||||||
|  |  | ||||||
|  | @ -14,9 +14,9 @@ import { Tag } from "../../Logic/Tags/Tag" | ||||||
| import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" | import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" | ||||||
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | ||||||
| import { Changes } from "../../Logic/Osm/Changes" | import { Changes } from "../../Logic/Osm/Changes" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| export default class TagApplyButton implements AutoAction , SpecialVisualization{ | export default class TagApplyButton implements AutoAction, SpecialVisualization { | ||||||
|     public readonly funcName = "tag_apply" |     public readonly funcName = "tag_apply" | ||||||
|     public readonly docs = |     public readonly docs = | ||||||
|         "Shows a big button; clicking this button will apply certain tags onto the feature.\n\nThe first argument takes a specification of which tags to add.\n" + |         "Shows a big button; clicking this button will apply certain tags onto the feature.\n\nThe first argument takes a specification of which tags to add.\n" + | ||||||
|  |  | ||||||
|  | @ -105,7 +105,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|                 TagUtils.FlattenAnd(inputElement.GetValue().data, tags.data) |                 TagUtils.FlattenAnd(inputElement.GetValue().data, tags.data) | ||||||
|             ) |             ) | ||||||
|             if (selection) { |             if (selection) { | ||||||
|                 (state?.changes) |                 ;(state?.changes) | ||||||
|                     .applyAction( |                     .applyAction( | ||||||
|                         new ChangeTagAction(tags.data.id, selection, tags.data, { |                         new ChangeTagAction(tags.data.id, selection, tags.data, { | ||||||
|                             theme: state?.layoutToUse?.id ?? "unkown", |                             theme: state?.layoutToUse?.id ?? "unkown", | ||||||
|  | @ -288,7 +288,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|         value: number |         value: number | ||||||
|         mainTerm: Record<string, string> |         mainTerm: Record<string, string> | ||||||
|         searchTerms?: Record<string, string[]> |         searchTerms?: Record<string, string[]> | ||||||
|         original: Mapping, |         original: Mapping | ||||||
|         hasPriority?: Store<boolean> |         hasPriority?: Store<boolean> | ||||||
|     }[] { |     }[] { | ||||||
|         const values: { |         const values: { | ||||||
|  | @ -296,7 +296,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|             value: number |             value: number | ||||||
|             mainTerm: Record<string, string> |             mainTerm: Record<string, string> | ||||||
|             searchTerms?: Record<string, string[]> |             searchTerms?: Record<string, string[]> | ||||||
|             original: Mapping, |             original: Mapping | ||||||
|             hasPriority?: Store<boolean> |             hasPriority?: Store<boolean> | ||||||
|         }[] = [] |         }[] = [] | ||||||
|         const addIcons = applicableMappings.some((m) => m.icon !== undefined) |         const addIcons = applicableMappings.some((m) => m.icon !== undefined) | ||||||
|  | @ -319,7 +319,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|                 mainTerm: tr.translations, |                 mainTerm: tr.translations, | ||||||
|                 searchTerms: mapping.searchTerms, |                 searchTerms: mapping.searchTerms, | ||||||
|                 original: mapping, |                 original: mapping, | ||||||
|                 hasPriority: tagsSource.map(tags => mapping.priorityIf?.matchesProperties(tags)) |                 hasPriority: tagsSource.map((tags) => mapping.priorityIf?.matchesProperties(tags)), | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
|         return values |         return values | ||||||
|  | @ -400,7 +400,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|         const values = TagRenderingQuestion.MappingToPillValue( |         const values = TagRenderingQuestion.MappingToPillValue( | ||||||
|             applicableMappings, |             applicableMappings, | ||||||
|             tagsSource, |             tagsSource, | ||||||
|             state, |             state | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         const searchValue: UIEventSource<string> = |         const searchValue: UIEventSource<string> = | ||||||
|  | @ -419,7 +419,7 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|             mode, |             mode, | ||||||
|             searchValue, |             searchValue, | ||||||
|             onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"), |             onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"), | ||||||
|             searchAreaClass: classes |             searchAreaClass: classes, | ||||||
|         }) |         }) | ||||||
|         const fallbackTag = searchValue.map((s) => { |         const fallbackTag = searchValue.map((s) => { | ||||||
|             if (s === undefined || ff?.key === undefined) { |             if (s === undefined || ff?.key === undefined) { | ||||||
|  |  | ||||||
|  | @ -1,27 +1,28 @@ | ||||||
| import {Utils} from "../../Utils"; | import { Utils } from "../../Utils" | ||||||
| import {Feature} from "geojson"; | import { Feature } from "geojson" | ||||||
| import {Point} from "@turf/turf"; | import { Point } from "@turf/turf" | ||||||
| import {GeoLocationPointProperties} from "../../Logic/Actors/GeoLocationHandler"; | import { GeoLocationPointProperties } from "../../Logic/Actors/GeoLocationHandler" | ||||||
| import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI"; | import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI" | ||||||
| import {SpecialVisualization} from "../SpecialVisualization"; | import { SpecialVisualization } from "../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Wrapper  around 'UploadTraceToOsmUI' |  * Wrapper  around 'UploadTraceToOsmUI' | ||||||
|  */ |  */ | ||||||
| export class UploadToOsmViz implements SpecialVisualization { | export class UploadToOsmViz implements SpecialVisualization { | ||||||
|     funcName = "upload_to_osm" |     funcName = "upload_to_osm" | ||||||
|     docs = "Uploads the GPS-history as GPX to OpenStreetMap.org; clears the history afterwards. The actual feature is ignored." |     docs = | ||||||
|     args =  [] |         "Uploads the GPS-history as GPX to OpenStreetMap.org; clears the history afterwards. The actual feature is ignored." | ||||||
|  |     args = [] | ||||||
| 
 | 
 | ||||||
|     constr(state, featureTags, args) { |     constr(state, featureTags, args) { | ||||||
| 
 |  | ||||||
|         function getTrace(title: string) { |         function getTrace(title: string) { | ||||||
|             title = title?.trim() |             title = title?.trim() | ||||||
|             if (title === undefined || title === "") { |             if (title === undefined || title === "") { | ||||||
|                 title = "Uploaded with MapComplete" |                 title = "Uploaded with MapComplete" | ||||||
|             } |             } | ||||||
|             title = Utils.EncodeXmlValue(title) |             title = Utils.EncodeXmlValue(title) | ||||||
|             const userLocations: Feature<Point, GeoLocationPointProperties>[] = state.historicalUserLocations.features.data.map(f => f.feature) |             const userLocations: Feature<Point, GeoLocationPointProperties>[] = | ||||||
|  |                 state.historicalUserLocations.features.data.map((f) => f.feature) | ||||||
|             const trackPoints: string[] = [] |             const trackPoints: string[] = [] | ||||||
|             for (const l of userLocations) { |             for (const l of userLocations) { | ||||||
|                 let trkpt = `    <trkpt lat="${l.geometry.coordinates[1]}" lon="${l.geometry.coordinates[0]}">` |                 let trkpt = `    <trkpt lat="${l.geometry.coordinates[1]}" lon="${l.geometry.coordinates[0]}">` | ||||||
|  | @ -32,14 +33,22 @@ export class UploadToOsmViz implements SpecialVisualization { | ||||||
|                 trkpt += "    </trkpt>" |                 trkpt += "    </trkpt>" | ||||||
|                 trackPoints.push(trkpt) |                 trackPoints.push(trkpt) | ||||||
|             } |             } | ||||||
|             const header = '<gpx version="1.1" creator="MapComplete track uploader" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">' |             const header = | ||||||
|             return header + "\n<name>" + title + "</name>\n<trk><trkseg>\n" + trackPoints.join("\n") + "\n</trkseg></trk></gpx>" |                 '<gpx version="1.1" creator="MapComplete track uploader" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">' | ||||||
|  |             return ( | ||||||
|  |                 header + | ||||||
|  |                 "\n<name>" + | ||||||
|  |                 title + | ||||||
|  |                 "</name>\n<trk><trkseg>\n" + | ||||||
|  |                 trackPoints.join("\n") + | ||||||
|  |                 "\n</trkseg></trk></gpx>" | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return new UploadTraceToOsmUI(getTrace, state, { |         return new UploadTraceToOsmUI(getTrace, state, { | ||||||
|             whenUploaded: async () => { |             whenUploaded: async () => { | ||||||
|                 state.historicalUserLocations.features.setData([]) |                 state.historicalUserLocations.features.setData([]) | ||||||
|             } |             }, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								test.ts
									
										
									
									
									
								
							|  | @ -1,24 +1,26 @@ | ||||||
| import {LanguageElement} from "./UI/Popup/LanguageElement"; | import { LanguageElement } from "./UI/Popup/LanguageElement" | ||||||
| import {ImmutableStore, UIEventSource} from "./Logic/UIEventSource"; | import { ImmutableStore, UIEventSource } from "./Logic/UIEventSource" | ||||||
| import {VariableUiElement} from "./UI/Base/VariableUIElement"; | import { VariableUiElement } from "./UI/Base/VariableUIElement" | ||||||
| import Locale from "./UI/i18n/Locale"; | import Locale from "./UI/i18n/Locale" | ||||||
| import {OsmConnection} from "./Logic/Osm/OsmConnection"; | import { OsmConnection } from "./Logic/Osm/OsmConnection" | ||||||
| 
 | 
 | ||||||
| const tgs = new UIEventSource({ | const tgs = new UIEventSource({ | ||||||
|     "name": "xyz", |     name: "xyz", | ||||||
|     "id": "node/1234", |     id: "node/1234", | ||||||
|     "_country" : "BE", |     _country: "BE", | ||||||
| }) | }) | ||||||
| Locale.language.setData("nl") | Locale.language.setData("nl") | ||||||
| console.log(tgs) | console.log(tgs) | ||||||
| console.log("Locale", Locale.language) | console.log("Locale", Locale.language) | ||||||
| const conn = new OsmConnection({}) | const conn = new OsmConnection({}) | ||||||
| new LanguageElement().constr(<any> {osmConnection: conn, featureSwitchIsTesting: new ImmutableStore(true)}, tgs, [ | new LanguageElement() | ||||||
|     "language", |     .constr(<any>{ osmConnection: conn, featureSwitchIsTesting: new ImmutableStore(true) }, tgs, [ | ||||||
|     "What languages are spoken here?", |         "language", | ||||||
|     "{language()} is spoken here", |         "What languages are spoken here?", | ||||||
|     "{language()} is the only language spoken here", |         "{language()} is spoken here", | ||||||
|     "The following languages are spoken here: {list()}" |         "{language()} is the only language spoken here", | ||||||
| ]).AttachTo("maindiv") |         "The following languages are spoken here: {list()}", | ||||||
|  |     ]) | ||||||
|  |     .AttachTo("maindiv") | ||||||
| 
 | 
 | ||||||
| new VariableUiElement(tgs.map(JSON.stringify)).AttachTo("extradiv") | new VariableUiElement(tgs.map(JSON.stringify)).AttachTo("extradiv") | ||||||
|  |  | ||||||
|  | @ -12,8 +12,11 @@ describe("SpecialVisualisations", () => { | ||||||
|                     "A special visualisation is not allowed to be named 'type', as this will conflict with the 'special'-blocks" |                     "A special visualisation is not allowed to be named 'type', as this will conflict with the 'special'-blocks" | ||||||
|                 ) |                 ) | ||||||
| 
 | 
 | ||||||
|                 if(special.args === undefined){ |                 if (special.args === undefined) { | ||||||
|                     throw "The field 'args' is undefined for special visualisation "+special.funcName |                     throw ( | ||||||
|  |                         "The field 'args' is undefined for special visualisation " + | ||||||
|  |                         special.funcName | ||||||
|  |                     ) | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 for (const arg of special.args) { |                 for (const arg of special.args) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue