forked from MapComplete/MapComplete
		
	More work
This commit is contained in:
		
							parent
							
								
									2052976909
								
							
						
					
					
						commit
						e68d9d99a5
					
				
					 5 changed files with 170 additions and 68 deletions
				
			
		|  | @ -60,7 +60,7 @@ export class UIEventSource<T>{ | ||||||
| 
 | 
 | ||||||
|         this.addCallback(update); |         this.addCallback(update); | ||||||
|         for (const extraSource of extraSources) { |         for (const extraSource of extraSources) { | ||||||
|             extraSource.addCallback(update); |             extraSource?.addCallback(update); | ||||||
|         } |         } | ||||||
|        |        | ||||||
|         if(g !== undefined) { |         if(g !== undefined) { | ||||||
|  |  | ||||||
|  | @ -13,21 +13,12 @@ export default class SharePanel extends UIElement { | ||||||
|         super(undefined); |         super(undefined); | ||||||
|         this._config = config; |         this._config = config; | ||||||
| 
 | 
 | ||||||
|         const json = new VariableUiElement(config.map(config => { |  | ||||||
|             return JSON.stringify(config, null, 2) |  | ||||||
|                 .replace(/\n/g, "<br/>") |  | ||||||
|                 .replace(/ /g, " "); |  | ||||||
|         })); |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         this._panel = new Combine([ |         this._panel = new Combine([ | ||||||
|             "<h2>share</h2>", |             "<h2>share</h2>", | ||||||
|             "Share the following link with friends:<br/>", |             "Share the following link with friends:<br/>", | ||||||
|             new VariableUiElement(liveUrl.map(url => `<a href='${url}' target="_blank">${url}</a>`)), |             new VariableUiElement(liveUrl.map(url => `<a href='${url}' target="_blank">${url}</a>`)), | ||||||
|             "<h3>Json</h3>", |  | ||||||
|             "The json configuration is included for debugging purposes", |  | ||||||
|             "<div class='literal-code json'>", |  | ||||||
|             json, |  | ||||||
|             "</div>" |             "</div>" | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
							
								
								
									
										90
									
								
								UI/Input/AndOrTagInput.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								UI/Input/AndOrTagInput.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | ||||||
|  | import {InputElement} from "./InputElement"; | ||||||
|  | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
|  | import {UIElement} from "../UIElement"; | ||||||
|  | import Combine from "../Base/Combine"; | ||||||
|  | import {SubtleButton} from "../Base/SubtleButton"; | ||||||
|  | import TagInput from "./TagInput"; | ||||||
|  | import {FixedUiElement} from "../Base/FixedUiElement"; | ||||||
|  | 
 | ||||||
|  | export class AndOrTagInput extends InputElement<(string | AndOrTagInput)[]> { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private readonly _value: UIEventSource<string[]>; | ||||||
|  |     IsSelected: UIEventSource<boolean>; | ||||||
|  |     private elements: UIElement[] = []; | ||||||
|  |     private inputELements: (InputElement<string> | InputElement<AndOrTagInput>)[] = []; | ||||||
|  |     private addTag: UIElement; | ||||||
|  | 
 | ||||||
|  |     constructor(value: UIEventSource<string[]> = new UIEventSource<string[]>([])) { | ||||||
|  |         super(undefined); | ||||||
|  |         this._value = value; | ||||||
|  | 
 | ||||||
|  |         this.addTag = new SubtleButton("./assets/addSmall.svg", "Add a tag") | ||||||
|  |             .SetClass("small-button") | ||||||
|  |             .onClick(() => { | ||||||
|  |                 this.IsSelected.setData(true); | ||||||
|  |                 value.data.push(""); | ||||||
|  |                 value.ping(); | ||||||
|  |             }); | ||||||
|  |         const self = this; | ||||||
|  |         value.map<number>((tags: string[]) => tags.length).addCallback(() => self.createElements()); | ||||||
|  |         this.createElements(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         this._value.addCallback(tags => self.load(tags)); | ||||||
|  |         this.IsSelected = new UIEventSource<boolean>(false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private load(tags: string[]) { | ||||||
|  |         if (tags === undefined) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         for (let i = 0; i < tags.length; i++) { | ||||||
|  |             console.log("Setting tag ", i) | ||||||
|  |             this.inputELements[i].GetValue().setData(tags[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private UpdateIsSelected(){ | ||||||
|  |         this.IsSelected.setData(this.inputELements.map(input => input.IsSelected.data).reduce((a,b) => a && b)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private createElements() { | ||||||
|  |         this.inputELements = []; | ||||||
|  |         this.elements = []; | ||||||
|  |         for (let i = 0; i < this._value.data.length; i++) { | ||||||
|  |             let tag = this._value.data[i]; | ||||||
|  |             const input = new TagInput(new UIEventSource<string>(tag)); | ||||||
|  |             input.GetValue().addCallback(tag => { | ||||||
|  |                     console.log("Writing ", tag) | ||||||
|  |                     this._value.data[i] = tag; | ||||||
|  |                     this._value.ping(); | ||||||
|  |                 } | ||||||
|  |             ); | ||||||
|  |             this.inputELements.push(input); | ||||||
|  |             input.IsSelected.addCallback(() => this.UpdateIsSelected()); | ||||||
|  |             const deleteBtn = new FixedUiElement("<img src='./assets/delete.svg' style='max-width: 1.5em; margin-left: 5px;'>") | ||||||
|  |                 .onClick(() => { | ||||||
|  |                     this._value.data.splice(i, 1); | ||||||
|  |                     this._value.ping(); | ||||||
|  |                 }); | ||||||
|  |             this.elements.push(new Combine([input, deleteBtn, "<br/>"]).SetClass("tag-input-row")) | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         this.Update(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     InnerRender(): string { | ||||||
|  |         return new Combine([...this.elements, this.addTag]).SetClass("bordered").Render(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     IsValid(t: string[]): boolean { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     GetValue(): UIEventSource<string[]> { | ||||||
|  |         return this._value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -13,16 +13,20 @@ import {Utils} from "../Utils"; | ||||||
| import {UIEventSource} from "../Logic/UIEventSource"; | import {UIEventSource} from "../Logic/UIEventSource"; | ||||||
| import Translation from "./i18n/Translation"; | import Translation from "./i18n/Translation"; | ||||||
| import {SubtleButton} from "./Base/SubtleButton"; | import {SubtleButton} from "./Base/SubtleButton"; | ||||||
|  | import {Layout} from "../Customizations/Layout"; | ||||||
| 
 | 
 | ||||||
| export class ShareScreen extends UIElement { | export class ShareScreen extends UIElement { | ||||||
|     private readonly _options: UIElement; |     private readonly _options: UIElement; | ||||||
|     private readonly _iframeCode: UIElement; |     private readonly _iframeCode: UIElement; | ||||||
|  |     public iframe: UIEventSource<string>; | ||||||
|     private readonly _link: UIElement; |     private readonly _link: UIElement; | ||||||
|     private readonly _linkStatus: UIEventSource<string | UIElement>; |     private readonly _linkStatus: UIEventSource<string | UIElement>; | ||||||
|     private readonly _editLayout: UIElement; |     private readonly _editLayout: UIElement; | ||||||
| 
 | 
 | ||||||
|     constructor() { |     constructor(layout: Layout = undefined, layoutDefinition: string = undefined) { | ||||||
|         super(undefined) |         super(undefined) | ||||||
|  |         layout = layout ?? State.state?.layoutToUse?.data; | ||||||
|  |         layoutDefinition = layoutDefinition ?? State.state?.layoutDefinition; | ||||||
|         const tr = Translations.t.general.sharescreen; |         const tr = Translations.t.general.sharescreen; | ||||||
| 
 | 
 | ||||||
|         const optionCheckboxes: UIElement[] = [] |         const optionCheckboxes: UIElement[] = [] | ||||||
|  | @ -35,10 +39,12 @@ export class ShareScreen extends UIElement { | ||||||
|         ) |         ) | ||||||
|         optionCheckboxes.push(includeLocation); |         optionCheckboxes.push(includeLocation); | ||||||
| 
 | 
 | ||||||
|         const currentLocation = State.state.locationControl; |         const currentLocation = State.state?.locationControl; | ||||||
|         const layout = State.state.layoutToUse.data; |  | ||||||
| 
 | 
 | ||||||
|         optionParts.push(includeLocation.isEnabled.map((includeL) => { |         optionParts.push(includeLocation.isEnabled.map((includeL) => { | ||||||
|  |             if (currentLocation === undefined) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|             if (includeL) { |             if (includeL) { | ||||||
|                 return `z=${currentLocation.data.zoom}&lat=${currentLocation.data.lat}&lon=${currentLocation.data.lon}` |                 return `z=${currentLocation.data.zoom}&lat=${currentLocation.data.lat}&lon=${currentLocation.data.lon}` | ||||||
|             } else { |             } else { | ||||||
|  | @ -47,6 +53,16 @@ export class ShareScreen extends UIElement { | ||||||
|         }, [currentLocation])); |         }, [currentLocation])); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |         function fLayerToParam(flayer: FilteredLayer) { | ||||||
|  |             if (flayer.isDisplayed.data) { | ||||||
|  |                 return null; // Being displayed is the default
 | ||||||
|  |             } | ||||||
|  |             return "layer-" + flayer.layerDef.id + "=" + flayer.isDisplayed.data | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         if (State.state !== undefined) { | ||||||
|  | 
 | ||||||
|             const currentLayer: UIEventSource<{ id: string, name: string, layer: any }> = (State.state.bm as Basemap).CurrentLayer; |             const currentLayer: UIEventSource<{ id: string, name: string, layer: any }> = (State.state.bm as Basemap).CurrentLayer; | ||||||
|             const currentBackground = tr.fsIncludeCurrentBackgroundMap.Subs({name: layout.id}); |             const currentBackground = tr.fsIncludeCurrentBackgroundMap.Subs({name: layout.id}); | ||||||
|             const includeCurrentBackground = new CheckBox( |             const includeCurrentBackground = new CheckBox( | ||||||
|  | @ -71,13 +87,6 @@ export class ShareScreen extends UIElement { | ||||||
|             ) |             ) | ||||||
|             optionCheckboxes.push(includeLayerChoices); |             optionCheckboxes.push(includeLayerChoices); | ||||||
| 
 | 
 | ||||||
|         function fLayerToParam(flayer: FilteredLayer){ |  | ||||||
|             if(flayer.isDisplayed.data){ |  | ||||||
|                 return null; // Being displayed is the default
 |  | ||||||
|             } |  | ||||||
|             return "layer-"+flayer.layerDef.id+"="+flayer.isDisplayed.data |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|             optionParts.push(includeLayerChoices.isEnabled.map((includeLayerSelection) => { |             optionParts.push(includeLayerChoices.isEnabled.map((includeLayerSelection) => { | ||||||
|                 if (includeLayerSelection) { |                 if (includeLayerSelection) { | ||||||
|                     return Utils.NoNull(State.state.filteredLayers.data.map(fLayerToParam)).join("&") |                     return Utils.NoNull(State.state.filteredLayers.data.map(fLayerToParam)).join("&") | ||||||
|  | @ -86,6 +95,7 @@ export class ShareScreen extends UIElement { | ||||||
|                 } |                 } | ||||||
|             }, State.state.filteredLayers.data.map((flayer) => flayer.isDisplayed))); |             }, State.state.filteredLayers.data.map((flayer) => flayer.isDisplayed))); | ||||||
| 
 | 
 | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const switches = [ |         const switches = [ | ||||||
|             {urlName: "fs-userbadge", human: tr.fsUserbadge}, |             {urlName: "fs-userbadge", human: tr.fsUserbadge}, | ||||||
|  | @ -93,7 +103,7 @@ export class ShareScreen extends UIElement { | ||||||
|             {urlName: "fs-welcome-message", human: tr.fsWelcomeMessage}, |             {urlName: "fs-welcome-message", human: tr.fsWelcomeMessage}, | ||||||
|             {urlName: "fs-layers", human: tr.fsLayers}, |             {urlName: "fs-layers", human: tr.fsLayers}, | ||||||
|             {urlName: "layer-control-toggle", human: tr.fsLayerControlToggle, reverse: true}, |             {urlName: "layer-control-toggle", human: tr.fsLayerControlToggle, reverse: true}, | ||||||
|             {urlName: "fs-addXXXnew", human:  tr.fsAddNew}, |             {urlName: "fs-add-new", human: tr.fsAddNew}, | ||||||
|             {urlName: "fs-geolocation", human: tr.fsGeolocation}, |             {urlName: "fs-geolocation", human: tr.fsGeolocation}, | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|  | @ -124,7 +134,7 @@ export class ShareScreen extends UIElement { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         this._options = new VerticalCombine(optionCheckboxes) |         this._options = new VerticalCombine(optionCheckboxes) | ||||||
|         const url = currentLocation.map(() => { |         const url = (currentLocation ?? new UIEventSource(undefined)).map(() => { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             let literalText = "https://pietervdvn.github.io/MapComplete/" + layout.id.toLowerCase() + ".html" |             let literalText = "https://pietervdvn.github.io/MapComplete/" + layout.id.toLowerCase() + ".html" | ||||||
|  | @ -132,8 +142,8 @@ export class ShareScreen extends UIElement { | ||||||
|             const parts = Utils.NoEmpty(Utils.NoNull(optionParts.map((eventSource) => eventSource.data))); |             const parts = Utils.NoEmpty(Utils.NoNull(optionParts.map((eventSource) => eventSource.data))); | ||||||
| 
 | 
 | ||||||
|             let hash = ""; |             let hash = ""; | ||||||
|             if (State.state.layoutDefinition !== undefined) { |             if (layoutDefinition !== undefined) { | ||||||
|                 hash = ("#" + State.state.layoutDefinition) |                 hash = ("#" + layoutDefinition) | ||||||
|                 literalText = "https://pietervdvn.github.io/MapComplete/index.html" |                 literalText = "https://pietervdvn.github.io/MapComplete/index.html" | ||||||
|                 parts.push("userlayout=true"); |                 parts.push("userlayout=true"); | ||||||
|             } |             } | ||||||
|  | @ -145,10 +155,13 @@ export class ShareScreen extends UIElement { | ||||||
| 
 | 
 | ||||||
|             return literalText + "?" + parts.join("&") + hash; |             return literalText + "?" + parts.join("&") + hash; | ||||||
|         }, optionParts); |         }, optionParts); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         this.iframe = url.map(url => `<iframe src="${url}" width="100%" height="100%" title="${layout.title.InnerRender()} with MapComplete"></iframe>`); | ||||||
|  |          | ||||||
|         this._iframeCode = new VariableUiElement( |         this._iframeCode = new VariableUiElement( | ||||||
|             url.map((url) => { |             url.map((url) => { | ||||||
|                 return `<span class='literal-code iframe-code-block'>
 |                 return `<span class='literal-code iframe-code-block'>
 | ||||||
|                         <iframe src="${url}" width="100%" height="100%" title="${layout.title.InnerRender()} with MapComplete"></iframe>  |  | ||||||
|                     </span>` |                     </span>` | ||||||
|             }) |             }) | ||||||
|         ); |         ); | ||||||
|  | @ -157,7 +170,7 @@ export class ShareScreen extends UIElement { | ||||||
|       |       | ||||||
| 
 | 
 | ||||||
|         this._editLayout = new FixedUiElement(""); |         this._editLayout = new FixedUiElement(""); | ||||||
|         if ((State.state.layoutDefinition !== undefined)) { |         if ((layoutDefinition !== undefined && State.state?.osmConnection !== undefined)) { | ||||||
|             this._editLayout = |             this._editLayout = | ||||||
|                 new VariableUiElement( |                 new VariableUiElement( | ||||||
|                     State.state.osmConnection.userDetails.map( |                     State.state.osmConnection.userDetails.map( | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ import GeneralSettings from "./UI/CustomGenerator/GeneralSettings"; | ||||||
| import {SubtleButton} from "./UI/Base/SubtleButton"; | import {SubtleButton} from "./UI/Base/SubtleButton"; | ||||||
| import {TabbedComponent} from "./UI/Base/TabbedComponent"; | import {TabbedComponent} from "./UI/Base/TabbedComponent"; | ||||||
| import AllLayersPanel from "./UI/CustomGenerator/AllLayersPanel"; | import AllLayersPanel from "./UI/CustomGenerator/AllLayersPanel"; | ||||||
|  | import {ShareScreen} from "./UI/ShareScreen"; | ||||||
|  | import {FromJSON} from "./Customizations/JSON/FromJSON"; | ||||||
| import SharePanel from "./UI/CustomGenerator/SharePanel"; | import SharePanel from "./UI/CustomGenerator/SharePanel"; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -46,6 +48,7 @@ const es = new UIEventSource(test); | ||||||
| const encoded = es.map(config => btoa(JSON.stringify(config))); | const encoded = es.map(config => btoa(JSON.stringify(config))); | ||||||
| const testUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}&test=true#${encoded}`) | const testUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}&test=true#${encoded}`) | ||||||
| const liveUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}#${encoded}`) | const liveUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}#${encoded}`) | ||||||
|  | const iframe = liveUrl.map(url => `<iframe src='${url}' width='100%' height='99%' style="box-sizing: border-box" title='Theme Preview'></iframe>`); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| const currentSetting = new UIEventSource<SingleSetting<any>>(undefined) | const currentSetting = new UIEventSource<SingleSetting<any>>(undefined) | ||||||
|  | @ -63,7 +66,12 @@ new TabbedComponent([ | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         header: "<img src='./assets/floppy.svg'>", |         header: "<img src='./assets/floppy.svg'>", | ||||||
|         content: "Save" |         content: new VariableUiElement(es.map(config => { | ||||||
|  |             return JSON.stringify(config, null, 2) | ||||||
|  |                 .replace(/\n/g, "<br/>") | ||||||
|  |                 .replace(/ /g, " "); | ||||||
|  |         })) | ||||||
|  | 
 | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         header: "<img src='./assets/share.svg'>", |         header: "<img src='./assets/share.svg'>", | ||||||
|  | @ -103,7 +111,7 @@ new Combine([helpText, | ||||||
| 
 | 
 | ||||||
| // The preview
 | // The preview
 | ||||||
| new Combine([ | new Combine([ | ||||||
|     new VariableUiElement(testUrl.map(testUrl => `<iframe src='${testUrl}' width='100%' height='99%' style="box-sizing: border-box" title='Theme Preview'></iframe>`)) |     new VariableUiElement(iframe) | ||||||
| ]).AttachTo("bottomright"); | ]).AttachTo("bottomright"); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue