forked from MapComplete/MapComplete
		
	Fixes to the personal theme
This commit is contained in:
		
							parent
							
								
									ce1568f2bb
								
							
						
					
					
						commit
						9e6460030b
					
				
					 11 changed files with 126 additions and 102 deletions
				
			
		|  | @ -39,7 +39,42 @@ import {Utils} from "./Utils"; | |||
| export class InitUiElements { | ||||
| 
 | ||||
| 
 | ||||
|     static InitAll(layoutToUse: Layout, layoutFromBase64: string, testing: UIEventSource<string>, layoutName: string ) { | ||||
|     private static setupAllLayerElements() { | ||||
| 
 | ||||
|         // ------------- Setup the layers -------------------------------
 | ||||
| 
 | ||||
|         InitUiElements.InitLayers(); | ||||
|         InitUiElements.InitLayerSelection(); | ||||
| 
 | ||||
| 
 | ||||
|         // ------------------ Setup various other UI elements ------------
 | ||||
| 
 | ||||
| 
 | ||||
|         InitUiElements.OnlyIf(State.state.featureSwitchAddNew, () => { | ||||
| 
 | ||||
|             let presetCount = 0; | ||||
|             for (const layer of State.state.filteredLayers.data) { | ||||
|                 for (const preset of layer.layerDef.presets) { | ||||
|                     presetCount++; | ||||
|                 } | ||||
|             } | ||||
|             if (presetCount == 0) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             new StrayClickHandler(() => { | ||||
|                     return new SimpleAddUI(); | ||||
|                 } | ||||
|             ); | ||||
|         }); | ||||
| 
 | ||||
|         new CenterMessageBox().AttachTo("centermessage"); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     static InitAll(layoutToUse: Layout, layoutFromBase64: string, testing: UIEventSource<string>, layoutName: string, | ||||
|                    layoutDefinition: string = "") { | ||||
|         if (layoutToUse === undefined) { | ||||
|             console.log("Incorrect layout") | ||||
|             new FixedUiElement("Error: incorrect layout <i>" + layoutName + "</i><br/><a href='https://pietervdvn.github.io/MapComplete/index.html'>Go back</a>").AttachTo("centermessage").onClick(() => { | ||||
|  | @ -47,7 +82,6 @@ export class InitUiElements { | |||
|             throw "Incorrect layout" | ||||
|         } | ||||
| 
 | ||||
|         const hash = location.hash.substr(1); | ||||
|         console.log("Using layout: ", layoutToUse.id, "LayoutFromBase64 is ", layoutFromBase64); | ||||
|         State.state = new State(layoutToUse); | ||||
|          | ||||
|  | @ -60,8 +94,8 @@ export class InitUiElements { | |||
|         } | ||||
| 
 | ||||
|         if (layoutFromBase64 !== "false") { | ||||
|             State.state.layoutDefinition = hash; | ||||
|             console.log("Layout definition:",Utils.EllipsesAfter(State.state.layoutDefinition, 100)) | ||||
|             State.state.layoutDefinition = layoutDefinition; | ||||
|             console.log("Layout definition:", Utils.EllipsesAfter(State.state.layoutDefinition, 100)) | ||||
|             if (testing.data !== "true") { | ||||
|                 State.state.osmConnection.OnLoggedIn(() => { | ||||
|                     State.state.osmConnection.GetLongPreference("installed-theme-" + layoutToUse.id).setData(State.state.layoutDefinition); | ||||
|  | @ -74,41 +108,7 @@ export class InitUiElements { | |||
| 
 | ||||
|         new FixedUiElement("").AttachTo("decoration-desktop"); // Remove the decoration
 | ||||
| 
 | ||||
|         function setupAllLayerElements() { | ||||
| 
 | ||||
|             // ------------- Setup the layers -------------------------------
 | ||||
| 
 | ||||
|             InitUiElements.InitLayers(); | ||||
|             InitUiElements.InitLayerSelection(); | ||||
| 
 | ||||
| 
 | ||||
|             // ------------------ Setup various other UI elements ------------
 | ||||
| 
 | ||||
| 
 | ||||
|             InitUiElements.OnlyIf(State.state.featureSwitchAddNew, () => { | ||||
| 
 | ||||
|                 let presetCount = 0; | ||||
|                 for (const layer of State.state.filteredLayers.data) { | ||||
|                     for (const preset of layer.layerDef.presets) { | ||||
|                         presetCount++; | ||||
|                     } | ||||
|                 } | ||||
|                 if (presetCount == 0) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
|                 new StrayClickHandler(() => { | ||||
|                         return new SimpleAddUI(); | ||||
|                     } | ||||
|                 ); | ||||
|             }); | ||||
| 
 | ||||
|             new CenterMessageBox().AttachTo("centermessage"); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         setupAllLayerElements(); | ||||
|         InitUiElements.setupAllLayerElements(); | ||||
| 
 | ||||
| 
 | ||||
|         function updateFavs() { | ||||
|  | @ -133,9 +133,10 @@ export class InitUiElements { | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             setupAllLayerElements(); | ||||
|             InitUiElements.setupAllLayerElements(); | ||||
|             State.state.layerUpdater.ForceRefresh(); | ||||
|             State.state.locationControl.ping(); | ||||
|             State.state.layoutToUse.ping(); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         if (layoutToUse === AllKnownLayouts.allSets[PersonalLayout.NAME]) { | ||||
|  |  | |||
|  | @ -20,11 +20,13 @@ export class LayerUpdater { | |||
|      */ | ||||
|     private readonly previousBounds: Map<number, Bounds[]> = new Map<number, Bounds[]>(); | ||||
| 
 | ||||
|     private readonly state: State; | ||||
|      | ||||
|     /** | ||||
|      * The most important layer should go first, as that one gets first pick for the questions | ||||
|      */ | ||||
|     constructor(state: State) { | ||||
| 
 | ||||
|         this.state = state; | ||||
|         const self = this; | ||||
| 
 | ||||
|         this.sufficentlyZoomed = State.state.locationControl.map(location => { | ||||
|  | @ -178,6 +180,7 @@ export class LayerUpdater { | |||
|         for (let i = 0; i < 25; i++) { | ||||
|             this.previousBounds.set(i, []); | ||||
|         } | ||||
|         this.update(this.state); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -6,11 +6,11 @@ import {State} from "../../State"; | |||
| 
 | ||||
| export class ChangesetHandler { | ||||
| 
 | ||||
|     private _dryRun: boolean; | ||||
|     private userDetails: UIEventSource<UserDetails>; | ||||
|     private auth: any; | ||||
|     private readonly _dryRun: boolean; | ||||
|     private readonly userDetails: UIEventSource<UserDetails>; | ||||
|     private readonly auth: any; | ||||
| 
 | ||||
|     public currentChangeset: UIEventSource<string>; | ||||
|     public readonly currentChangeset: UIEventSource<string>; | ||||
| 
 | ||||
|     constructor(layoutName: string, dryRun: boolean, osmConnection: OsmConnection, auth) { | ||||
|         this._dryRun = dryRun; | ||||
|  | @ -29,6 +29,12 @@ export class ChangesetHandler { | |||
|         allElements: ElementStorage, | ||||
|         generateChangeXML: (csid: string) => string, | ||||
|          continuation: () => void) { | ||||
|          | ||||
|         if(this.userDetails.data.csCount == 0){ | ||||
|             // The user became a contributor!
 | ||||
|             this.userDetails.data.csCount = 1; | ||||
|             this.userDetails.ping(); | ||||
|         } | ||||
| 
 | ||||
|         if (this._dryRun) { | ||||
|             const changesetXML = generateChangeXML("123456"); | ||||
|  |  | |||
|  | @ -65,17 +65,16 @@ export class OsmPreferences { | |||
|                 source.setData(undefined); | ||||
|                 return; | ||||
|             } | ||||
|             if (l > 25) { | ||||
|             const prefsCount = Number(l); | ||||
|             if (prefsCount > 100) { | ||||
|                 throw "Length to long"; | ||||
|             } | ||||
|             const prefsCount = Number(l); | ||||
|             let str = ""; | ||||
|             for (let i = 0; i < prefsCount; i++) { | ||||
|                 str += self.GetPreference(allStartWith + "-" + i, "").data; | ||||
|             } | ||||
| 
 | ||||
|             source.setData(str); | ||||
|             source.ping(); | ||||
|             console.log("Long preference", key, "has", str.length, "chars"); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,19 +4,18 @@ import Translations from "../UI/i18n/Translations"; | |||
| import {UIEventSource} from "./UIEventSource"; | ||||
| import {AllKnownLayouts} from "../Customizations/AllKnownLayouts"; | ||||
| import Combine from "../UI/Base/Combine"; | ||||
| import {Img} from "../UI/Img"; | ||||
| import {CheckBox} from "../UI/Input/CheckBox"; | ||||
| import {PersonalLayout} from "./PersonalLayout"; | ||||
| import {Layout} from "../Customizations/Layout"; | ||||
| import {SubtleButton} from "../UI/Base/SubtleButton"; | ||||
| import {FixedUiElement} from "../UI/Base/FixedUiElement"; | ||||
| 
 | ||||
| export class PersonalLayersPanel extends UIElement { | ||||
|     private checkboxes: UIElement[] = []; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(State.state.favouriteLayers); | ||||
| 
 | ||||
|         this.ListenTo(State.state.osmConnection.userDetails); | ||||
|         this.ListenTo(State.state.favouriteLayers); | ||||
| 
 | ||||
|         this.UpdateView([]); | ||||
|         const self = this; | ||||
|  | @ -32,7 +31,6 @@ export class PersonalLayersPanel extends UIElement { | |||
|         const favs = State.state.favouriteLayers.data ?? []; | ||||
|         const controls = new Map<string, UIEventSource<boolean>>(); | ||||
|         const allLayouts = AllKnownLayouts.layoutsList.concat(extraThemes); | ||||
|             console.log("ALL LAYOUTS", allLayouts) | ||||
|         for (const layout of allLayouts) { | ||||
|             if (layout.id === PersonalLayout.NAME) { | ||||
|                 continue; | ||||
|  | @ -40,50 +38,41 @@ export class PersonalLayersPanel extends UIElement { | |||
| 
 | ||||
|             const header = | ||||
|                 new Combine([ | ||||
|                     `<div class="custom-layer-panel-header-img"><img src='${layout.icon}'></div>`, | ||||
|                     "<span><b>", | ||||
|                     `<img style="max-width: 3em;max-height: 3em; float: left; padding: 0.1em; margin-right: 0.3em;" src='${layout.icon}'>`, | ||||
|                     "<b>", | ||||
|                     layout.title, | ||||
|                     "</b><br/>", | ||||
|                     layout.description ?? "", | ||||
|                     "</span>", | ||||
|                 ], 'custom-layer-panel-header') | ||||
|                     layout.description ?? "" | ||||
|                 ]).SetStyle("background: #eee; display: block; padding: 0.5em; border-radius:0.5em; overflow:auto;") | ||||
|             this.checkboxes.push(header); | ||||
| 
 | ||||
|             for (const layer of layout.layers) { | ||||
|                 if(typeof layer === "string"){ | ||||
|                 if (typeof layer === "string") { | ||||
|                     continue; | ||||
|                 } | ||||
|                 let icon = layer.icon; | ||||
|                 if (icon !== undefined && typeof (icon) !== "string") { | ||||
|                     icon = icon.GetContent({"id": "node/-1"}).txt ?? "./assets/bug.svg"; | ||||
|                 let icon = layer.icon ?? "./assets/checkmark.svg"; | ||||
|                 if (typeof (icon) !== "string") { | ||||
|                     icon = icon.GetContent({"id": "node/-1"}).txt ?? "./assets/checkmark.svg"; | ||||
|                 } | ||||
|                 const image = (layer.icon ? `<img src='${layer.icon}'>` : Img.checkmark); | ||||
|                 const noimage = (layer.icon ? `<img src='${layer.icon}'>` : Img.no_checkmark); | ||||
| 
 | ||||
|                 let name = layer.name ?? layer.id; | ||||
|                 if (name === undefined) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (typeof (name) !== "string") { | ||||
|                     name = name.InnerRender(); | ||||
|                 } | ||||
| 
 | ||||
|                 const content = new Combine([ | ||||
|                     "<span>", | ||||
|                     "<b>", name ?? "", "</b> ", | ||||
|                     "<b>",  | ||||
|                     name,  | ||||
|                     "</b> ", | ||||
|                     layer.description !== undefined ? new Combine(["<br/>", layer.description]) : "", | ||||
|                     "</span>"]) | ||||
|                 ]) | ||||
|                 const cb = new CheckBox( | ||||
|                     new Combine([ | ||||
|                         image, content | ||||
|                     ]), | ||||
|                     new Combine([ | ||||
|                         "<span style='opacity: 0.1'>", | ||||
|                         noimage, "</span>", | ||||
|                         "<del>", | ||||
|                         content, | ||||
|                         "</del>" | ||||
|                     ]), | ||||
|                     new SubtleButton(icon ?? "./assets/checkmark.svg", content), | ||||
|                     new SubtleButton( | ||||
|                         new FixedUiElement(`<img src="${icon}">`).SetStyle("opacity:0.1"), | ||||
|                         new Combine(["<del>", | ||||
|                             content, | ||||
|                             "</del>" | ||||
|                         ])), | ||||
|                     controls[layer.id] ?? (favs.indexOf(layer.id) >= 0) | ||||
|                 ); | ||||
|                 cb.SetClass("custom-layer-checkbox"); | ||||
|  | @ -92,6 +81,9 @@ export class PersonalLayersPanel extends UIElement { | |||
|                 cb.isEnabled.addCallback((isEnabled) => { | ||||
|                     const favs = State.state.favouriteLayers; | ||||
|                     if (isEnabled) { | ||||
|                         if(favs.data.indexOf(layer.id)>= 0){ | ||||
|                             return; // Already added
 | ||||
|                         } | ||||
|                         favs.data.push(layer.id); | ||||
|                     } else { | ||||
|                         favs.data.splice(favs.data.indexOf(layer.id), 1); | ||||
|  | @ -103,13 +95,14 @@ export class PersonalLayersPanel extends UIElement { | |||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             State.state.favouriteLayers.addCallback((layers) => { | ||||
|                 for (const layerId of layers) { | ||||
|                     controls[layerId]?.setData(true); | ||||
|                 } | ||||
|             }) | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         State.state.favouriteLayers.addCallback((layers) => { | ||||
|             for (const layerId of layers) { | ||||
|                 controls[layerId]?.setData(true); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     InnerRender(): string { | ||||
|  | @ -122,7 +115,7 @@ export class PersonalLayersPanel extends UIElement { | |||
|         return new Combine([ | ||||
|             t.panelIntro, | ||||
|             ...this.checkboxes | ||||
|         ], "custom-layer-panel").Render(); | ||||
|         ]).Render(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,40 +1,51 @@ | |||
| import {UIElement} from "../UIElement"; | ||||
| import Translations from "../i18n/Translations"; | ||||
| import Combine from "./Combine"; | ||||
| import {FixedUiElement} from "./FixedUiElement"; | ||||
| 
 | ||||
| 
 | ||||
| export class SubtleButton extends UIElement{ | ||||
|     private readonly imageUrl: string; | ||||
|     private readonly image: UIElement; | ||||
|     private readonly message: UIElement; | ||||
|     private readonly linkTo: { url: string, newTab?: boolean } = undefined; | ||||
| 
 | ||||
|     constructor(imageUrl: string, message: string | UIElement, linkTo: { url: string, newTab?: boolean } = undefined) { | ||||
|     constructor(imageUrl: string | UIElement, message: string | UIElement, linkTo: { url: string, newTab?: boolean } = undefined) { | ||||
|         super(undefined); | ||||
|         this.linkTo = linkTo; | ||||
|         this.message = Translations.W(message); | ||||
|         this.imageUrl = imageUrl; | ||||
|         if(this.message !== null){ | ||||
|         this.message.dumbMode = false; | ||||
|         } | ||||
|         if ((imageUrl ?? "") === "") { | ||||
|             this.image = new FixedUiElement(""); | ||||
|         } else if (typeof (imageUrl) === "string") { | ||||
|             this.image = new FixedUiElement(`<img src="${imageUrl}">`); | ||||
|         } else { | ||||
|             this.image = imageUrl; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     InnerRender(): string { | ||||
|          | ||||
|         if(this.message !== null && this.message.IsEmpty()){ | ||||
|             // Message == null: special case to force empty text
 | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         if(this.linkTo != undefined){ | ||||
|             return new Combine([ | ||||
|                 `<a class="subtle-button" href="${this.linkTo.url}" ${this.linkTo.newTab ? 'target="_blank"' : ""}>`, | ||||
|                 this.imageUrl !== undefined ? `<img src='${this.imageUrl}'>` : "", | ||||
|                 this.message ?? "", | ||||
|                 this.image, | ||||
|                 this.message, | ||||
|                 '</a>' | ||||
|             ]).Render(); | ||||
|         } | ||||
|          | ||||
|         return new Combine([ | ||||
|             '<span class="subtle-button">', | ||||
|             this.imageUrl !== undefined ? `<img src='${this.imageUrl}'>` : "", | ||||
|             this.message ?? "", | ||||
|             this.image, | ||||
|             this.message, | ||||
|             '</span>' | ||||
|         ]).Render(); | ||||
|     } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ export class GenerateEmpty { | |||
|     public static createEmptyLayer(): LayerConfigJson { | ||||
|         return { | ||||
|             id: "yourlayer", | ||||
|             name: "Layer", | ||||
|             name: {}, | ||||
|             minzoom: 12, | ||||
|             overpassTags: {and: [""]}, | ||||
|             title: {}, | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import {OsmConnection} from "../../Logic/Osm/OsmConnection"; | |||
| import {FixedUiElement} from "../Base/FixedUiElement"; | ||||
| import {TextField} from "../Input/TextField"; | ||||
| import {SubtleButton} from "../Base/SubtleButton"; | ||||
| import {LayerConfigJson} from "../../Customizations/JSON/LayerConfigJson"; | ||||
| 
 | ||||
| export default class SavePanel extends UIElement { | ||||
|     private json: UIElement; | ||||
|  | @ -45,7 +46,8 @@ export default class SavePanel extends UIElement { | |||
|         this.loadFromJson = new SubtleButton("./assets/reload.svg", "<b>Load the JSON file below</b>") | ||||
|             .onClick(() => { | ||||
|                 const json = jsonTextField.GetValue().data; | ||||
|                 config.setData(JSON.parse(json)); | ||||
|                 const parsed : LayoutConfigJson = JSON.parse(json); | ||||
|                 config.setData(parsed); | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,15 +12,23 @@ export default class MultiLingualTextFields extends InputElement<any> { | |||
|                 value: UIEventSource<Map<string, UIEventSource<string>>> = undefined) { | ||||
|         super(undefined); | ||||
|         this._value = value ?? new UIEventSource({}); | ||||
|         const self = this; | ||||
|          | ||||
|         this._value.addCallbackAndRun(latestData =>  { | ||||
|             if(typeof(latestData) === "string"){ | ||||
|                 console.warn("Refusing string for multilingual input",latestData); | ||||
|                 self._value.setData({}); | ||||
|             } | ||||
|         }) | ||||
|          | ||||
|         const self = this; | ||||
| 
 | ||||
|         function setup(languages: string[]) { | ||||
|             if(languages === undefined){ | ||||
|             if (languages === undefined) { | ||||
|                 return; | ||||
|             } | ||||
|             const newFields = new Map<string, TextField<string>>(); | ||||
|             for (const language of languages) { | ||||
|                 if(language.length != 2){ | ||||
|                 if (language.length != 2) { | ||||
|                     continue; | ||||
|                 } | ||||
|                  | ||||
|  |  | |||
							
								
								
									
										1
									
								
								assets/checkmark.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/checkmark.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| <svg width="26" height="18" viewBox="0 0 26 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 7.28571L10.8261 15L23 3" stroke="black" stroke-width="4" stroke-linejoin="round"/></svg> | ||||
| After Width: | Height: | Size: 195 B | 
							
								
								
									
										4
									
								
								index.ts
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								index.ts
									
										
									
									
									
								
							|  | @ -82,7 +82,7 @@ if (layoutFromBase64.startsWith("wiki:")) { | |||
|                 console.log("DOWNLOADED:",layoutJson); | ||||
|                 const layout = FromJSON.LayoutFromJSON(JSON.parse(layoutJson)); | ||||
|                 layout.id = layoutFromBase64; | ||||
|                 InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64); | ||||
|                 InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64, btoa(layoutJson)); | ||||
|             } catch (e) { | ||||
|                 new FixedUiElement(`<a href="${cleanUrl}">${themeName}</a> is invalid:<br/>${e}`) | ||||
|                     .SetClass("clickable") | ||||
|  | @ -98,7 +98,7 @@ if (layoutFromBase64.startsWith("wiki:")) { | |||
| 
 | ||||
| } else if (layoutFromBase64 !== "false") { | ||||
|     layoutToUse = InitUiElements.LoadLayoutFromHash(userLayoutParam); | ||||
|     InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout); | ||||
|     InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout, location.hash.substr(1)); | ||||
| } else { | ||||
|     InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue