forked from MapComplete/MapComplete
		
	More fixes
This commit is contained in:
		
							parent
							
								
									2ae380f1a6
								
							
						
					
					
						commit
						9a73ae4c47
					
				
					 21 changed files with 203 additions and 148 deletions
				
			
		|  | @ -7,8 +7,6 @@ import {Utils} from "../../Utils"; | ||||||
| import {TagUtils} from "../../Logic/Tags/TagUtils"; | import {TagUtils} from "../../Logic/Tags/TagUtils"; | ||||||
| import {And} from "../../Logic/Tags/And"; | import {And} from "../../Logic/Tags/And"; | ||||||
| import {TagsFilter} from "../../Logic/Tags/TagsFilter"; | import {TagsFilter} from "../../Logic/Tags/TagsFilter"; | ||||||
| import {UIElement} from "../../UI/UIElement"; |  | ||||||
| import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation"; |  | ||||||
| 
 | 
 | ||||||
| /*** | /*** | ||||||
|  * The parsed version of TagRenderingConfigJSON |  * The parsed version of TagRenderingConfigJSON | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import { Utils } from "../Utils"; | ||||||
| 
 | 
 | ||||||
| export default class Constants { | export default class Constants { | ||||||
|      |      | ||||||
|     public static vNumber = "0.8.0"; |     public static vNumber = "0.8.0-rc0"; | ||||||
| 
 | 
 | ||||||
|     // The user journey states thresholds when a new feature gets unlocked
 |     // The user journey states thresholds when a new feature gets unlocked
 | ||||||
|     public static userJourney = { |     public static userJourney = { | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ export class SubtleButton extends UIElement { | ||||||
| 
 | 
 | ||||||
|     private static generateContent(imageUrl: string | BaseUIElement, messageT: string | BaseUIElement, linkTo: { url: string | UIEventSource<string>, newTab?: boolean } = undefined): BaseUIElement { |     private static generateContent(imageUrl: string | BaseUIElement, messageT: string | BaseUIElement, linkTo: { url: string | UIEventSource<string>, newTab?: boolean } = undefined): BaseUIElement { | ||||||
|         const message = Translations.W(messageT); |         const message = Translations.W(messageT); | ||||||
|  |         message | ||||||
|         let img; |         let img; | ||||||
|         if ((imageUrl ?? "") === "") { |         if ((imageUrl ?? "") === "") { | ||||||
|             img = undefined; |             img = undefined; | ||||||
|  | @ -36,7 +37,7 @@ export class SubtleButton extends UIElement { | ||||||
|             return new Combine([ |             return new Combine([ | ||||||
|                 image, |                 image, | ||||||
|                 message?.SetClass("blcok ml-4 overflow-ellipsis"), |                 message?.SetClass("blcok ml-4 overflow-ellipsis"), | ||||||
|             ]).SetClass("flex group"); |             ]).SetClass("flex group w-full"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -44,7 +45,7 @@ export class SubtleButton extends UIElement { | ||||||
|             new Combine([ |             new Combine([ | ||||||
|                 image, |                 image, | ||||||
|                 message?.SetClass("block ml-4 overflow-ellipsis") |                 message?.SetClass("block ml-4 overflow-ellipsis") | ||||||
|             ]).SetClass("flex group"), |             ]).SetClass("flex group w-full"), | ||||||
|             linkTo.url, |             linkTo.url, | ||||||
|             linkTo.newTab ?? false |             linkTo.newTab ?? false | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  | @ -23,14 +23,14 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen { | ||||||
|         const layoutToUse = State.state.layoutToUse.data; |         const layoutToUse = State.state.layoutToUse.data; | ||||||
|         super ( |         super ( | ||||||
|             () => layoutToUse.title.Clone(), |             () => layoutToUse.title.Clone(), | ||||||
|             () => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails), |             () => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails, isShown), | ||||||
|             "welcome" ,isShown |             "welcome" ,isShown | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     private static ConstructBaseTabs(layoutToUse: LayoutConfig): { header: string | BaseUIElement; content: BaseUIElement }[]{ |     private static ConstructBaseTabs(layoutToUse: LayoutConfig, isShown: UIEventSource<boolean>): { header: string | BaseUIElement; content: BaseUIElement }[]{ | ||||||
| 
 | 
 | ||||||
|         let welcome: BaseUIElement = new ThemeIntroductionPanel(); |         let welcome: BaseUIElement = new ThemeIntroductionPanel(isShown); | ||||||
|         if (layoutToUse.id === personal.id) { |         if (layoutToUse.id === personal.id) { | ||||||
|             welcome = new PersonalLayersPanel(); |             welcome = new PersonalLayersPanel(); | ||||||
|         } |         } | ||||||
|  | @ -58,10 +58,10 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen { | ||||||
|         return tabs; |         return tabs; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static GenerateContents(layoutToUse: LayoutConfig, userDetails: UIEventSource<UserDetails>) { |     private static GenerateContents(layoutToUse: LayoutConfig, userDetails: UIEventSource<UserDetails>, isShown: UIEventSource<boolean>) { | ||||||
| 
 | 
 | ||||||
|         const tabs = FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse) |         const tabs = FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse, isShown) | ||||||
|         const tabsWithAboutMc = [...FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse)] |         const tabsWithAboutMc = [...FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse, isShown)] | ||||||
|         tabsWithAboutMc.push({ |         tabsWithAboutMc.push({ | ||||||
|                 header: Svg.help, |                 header: Svg.help, | ||||||
|                 content: new Combine([Translations.t.general.aboutMapcomplete.Clone(), "<br/>Version " + Constants.vNumber]) |                 content: new Combine([Translations.t.general.aboutMapcomplete.Clone(), "<br/>Version " + Constants.vNumber]) | ||||||
|  |  | ||||||
|  | @ -4,10 +4,14 @@ import LanguagePicker from "../LanguagePicker"; | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations"; | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import {VariableUiElement} from "../Base/VariableUIElement"; | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle"; | ||||||
|  | import {SubtleButton} from "../Base/SubtleButton"; | ||||||
|  | import Svg from "../../Svg"; | ||||||
|  | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
|  | import {FixedUiElement} from "../Base/FixedUiElement"; | ||||||
| 
 | 
 | ||||||
| export default class ThemeIntroductionPanel extends VariableUiElement { | export default class ThemeIntroductionPanel extends VariableUiElement { | ||||||
| 
 | 
 | ||||||
|     constructor() { |     constructor(isShown: UIEventSource<boolean>) { | ||||||
| 
 | 
 | ||||||
|         const languagePicker = |         const languagePicker = | ||||||
|             new VariableUiElement( |             new VariableUiElement( | ||||||
|  | @ -15,9 +19,22 @@ export default class ThemeIntroductionPanel extends VariableUiElement { | ||||||
|             ) |             ) | ||||||
|         ; |         ; | ||||||
|          |          | ||||||
|  |         const toTheMap = new SubtleButton( | ||||||
|  |             new FixedUiElement(""), | ||||||
|  |             Translations.t.general.openTheMap.Clone().SetClass("text-xl font-bold w-full text-center") | ||||||
|  |         ).onClick(() =>{ | ||||||
|  |             isShown.setData(false) | ||||||
|  |         }).SetClass("only-on-mobile") | ||||||
|  | 
 | ||||||
|         const plzLogIn = |         const plzLogIn = | ||||||
|             Translations.t.general.loginWithOpenStreetMap |             new SubtleButton( | ||||||
|                 .Clone() |                 Svg.osm_logo_ui(), | ||||||
|  |                  | ||||||
|  |                 new Combine([Translations.t.general.loginWithOpenStreetMap | ||||||
|  |                     .Clone().SetClass("text-xl font-bold"), | ||||||
|  |                     Translations.t.general.loginOnlyNeededToEdit.Clone().SetClass("font-bold")] | ||||||
|  |                     ).SetClass("flex flex-col text-center w-full") | ||||||
|  |             ) | ||||||
|                 .onClick(() => { |                 .onClick(() => { | ||||||
|                     State.state.osmConnection.AttemptLogin() |                     State.state.osmConnection.AttemptLogin() | ||||||
|                 }); |                 }); | ||||||
|  | @ -25,6 +42,8 @@ export default class ThemeIntroductionPanel extends VariableUiElement { | ||||||
| 
 | 
 | ||||||
|         const welcomeBack = Translations.t.general.welcomeBack.Clone(); |         const welcomeBack = Translations.t.general.welcomeBack.Clone(); | ||||||
|          |          | ||||||
|  |          | ||||||
|  | 
 | ||||||
|         const loginStatus = |         const loginStatus = | ||||||
|             new Toggle( |             new Toggle( | ||||||
|                 new Toggle( |                 new Toggle( | ||||||
|  | @ -40,6 +59,7 @@ export default class ThemeIntroductionPanel extends VariableUiElement { | ||||||
|         super(State.state.layoutToUse.map (layout => new Combine([ |         super(State.state.layoutToUse.map (layout => new Combine([ | ||||||
|             layout.description.Clone(), |             layout.description.Clone(), | ||||||
|             "<br/><br/>", |             "<br/><br/>", | ||||||
|  |             toTheMap, | ||||||
|             loginStatus, |             loginStatus, | ||||||
|             layout.descriptionTail.Clone(), |             layout.descriptionTail.Clone(), | ||||||
|             "<br/>", |             "<br/>", | ||||||
|  |  | ||||||
|  | @ -13,7 +13,6 @@ export class SlideShow extends BaseUIElement { | ||||||
| 
 | 
 | ||||||
|     protected InnerConstructElement(): HTMLElement { |     protected InnerConstructElement(): HTMLElement { | ||||||
|         const el = document.createElement("div") |         const el = document.createElement("div") | ||||||
|         el.classList.add("slic-carousel") |  | ||||||
|         el.style.overflowX = "auto" |         el.style.overflowX = "auto" | ||||||
|         el.style.width = "min-content" |         el.style.width = "min-content" | ||||||
|         el.style.minWidth = "min-content" |         el.style.minWidth = "min-content" | ||||||
|  | @ -25,8 +24,9 @@ export class SlideShow extends BaseUIElement { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             for (const element of elements ?? []) { |             for (const element of elements ?? []) { | ||||||
|                 element.SetClass("block ml-1") |                 element | ||||||
|                     .SetStyle("width: 300px;  max-height: var(--image-carousel-height); height: var(--image-carousel-height)") |                     .SetClass("block ml-1; bg-gray-200") | ||||||
|  |                     .SetStyle("min-width: 150;  max-height: var(--image-carousel-height); min-height: var(--image-carousel-height)") | ||||||
| 
 | 
 | ||||||
|                 el.appendChild(element.ConstructElement()) |                 el.appendChild(element.ConstructElement()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -7,67 +7,19 @@ import BaseUIElement from "../BaseUIElement"; | ||||||
|  * Supports multi-input |  * Supports multi-input | ||||||
|  */ |  */ | ||||||
| export default class CheckBoxes extends InputElement<number[]> { | export default class CheckBoxes extends InputElement<number[]> { | ||||||
|     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); |  | ||||||
| 
 |  | ||||||
|      |  | ||||||
| private readonly _element : HTMLElement |  | ||||||
|      |  | ||||||
|     private static _nextId = 0; |     private static _nextId = 0; | ||||||
| private readonly value: UIEventSource<number[]> |     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|     constructor(elements: BaseUIElement[], value =new UIEventSource<number[]>([])) { |     private readonly value: UIEventSource<number[]> | ||||||
|  |     private readonly _elements: BaseUIElement[]; | ||||||
|  | 
 | ||||||
|  |     constructor(elements: BaseUIElement[], value = new UIEventSource<number[]>([])) { | ||||||
|         super(); |         super(); | ||||||
|         this.value = value; |         this.value = value; | ||||||
|         elements = Utils.NoNull(elements); |         this._elements = Utils.NoNull(elements); | ||||||
|          |         this.SetClass("flex flex-col") | ||||||
|         const el = document.createElement("form") |  | ||||||
|       |  | ||||||
|         for (let i = 0; i < elements.length; i++) { |  | ||||||
|             |  | ||||||
|             let inputI = elements[i]; |  | ||||||
|             const input = document.createElement("input") |  | ||||||
|             const id = CheckBoxes._nextId |  | ||||||
|             CheckBoxes._nextId ++; |  | ||||||
|             input.id = "checkbox"+id |  | ||||||
| 
 |  | ||||||
|             input.type = "checkbox" |  | ||||||
|             const label = document.createElement("label") |  | ||||||
|             label.htmlFor = input.id |  | ||||||
|             label.appendChild(inputI.ConstructElement()) |  | ||||||
| 
 |  | ||||||
|             value.addCallbackAndRun(selectedValues =>{ |  | ||||||
|                 if(selectedValues === undefined){ |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|                 if(selectedValues.indexOf(i) >= 0){ |  | ||||||
|                     input.checked = true; |  | ||||||
|                 } |  | ||||||
|             }) |  | ||||||
| 
 |  | ||||||
|             input.onchange = () => { |  | ||||||
|                 const index = value.data.indexOf(i); |  | ||||||
|                 if(input.checked && index < 0){ |  | ||||||
|                     value.data.push(i); |  | ||||||
|                     value.ping(); |  | ||||||
|                 }else if(index >= 0){ |  | ||||||
|                     value.data.splice(index,1); |  | ||||||
|                     value.ping(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|             el.appendChild(input) |  | ||||||
|             el.appendChild(document.createElement("br")) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected InnerConstructElement(): HTMLElement { |  | ||||||
|         return this._element |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     IsValid(ts: number[]): boolean { |     IsValid(ts: number[]): boolean { | ||||||
|         return ts !== undefined; |         return ts !== undefined; | ||||||
| 
 | 
 | ||||||
|  | @ -77,7 +29,61 @@ private readonly value: UIEventSource<number[]> | ||||||
|         return this.value; |         return this.value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     protected InnerConstructElement(): HTMLElement { | ||||||
|  |         const el = document.createElement("form") | ||||||
| 
 | 
 | ||||||
|  |         const value = this.value; | ||||||
|  |         const elements = this._elements; | ||||||
|  | 
 | ||||||
|  |         for (let i = 0; i < elements.length; i++) { | ||||||
|  | 
 | ||||||
|  |             let inputI = elements[i]; | ||||||
|  |             const input = document.createElement("input") | ||||||
|  |             const id = CheckBoxes._nextId | ||||||
|  |             CheckBoxes._nextId++; | ||||||
|  |             input.id = "checkbox" + id | ||||||
|  | 
 | ||||||
|  |             input.type = "checkbox" | ||||||
|  |             input.classList.add("p-1","cursor-pointer","ml-3","pl-3") | ||||||
|  | 
 | ||||||
|  |             const label = document.createElement("label") | ||||||
|  |             label.htmlFor = input.id | ||||||
|  |             label.appendChild(inputI.ConstructElement()) | ||||||
|  |             label.classList.add("block","w-full","p-2","cursor-pointer","bg-red") | ||||||
|  | 
 | ||||||
|  |             const wrapper = document.createElement("span") | ||||||
|  |             wrapper.classList.add("flex","w-full","border", "border-gray-400") | ||||||
|  |             wrapper.appendChild(input) | ||||||
|  |             wrapper.appendChild(label) | ||||||
|  |             el.appendChild(wrapper) | ||||||
|  |              | ||||||
|  |             value.addCallbackAndRun(selectedValues => { | ||||||
|  |                 if (selectedValues === undefined) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 if (selectedValues.indexOf(i) >= 0) { | ||||||
|  |                     input.checked = true; | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|  |             input.onchange = () => { | ||||||
|  |                 // Index = index in the list of already checked items
 | ||||||
|  |                 const index = value.data.indexOf(i); | ||||||
|  |                 if (input.checked && index < 0) { | ||||||
|  |                     value.data.push(i); | ||||||
|  |                     value.ping(); | ||||||
|  |                 } else if (index >= 0) { | ||||||
|  |                     value.data.splice(index, 1); | ||||||
|  |                     value.ping(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         return el; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -19,6 +19,7 @@ export default class DirectionInput extends InputElement<string> { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  | 
 | ||||||
|     protected InnerConstructElement(): HTMLElement { |     protected InnerConstructElement(): HTMLElement { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,12 +7,19 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); |     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|     private readonly value: UIEventSource<T>; |     private readonly value: UIEventSource<T>; | ||||||
|     private _elements: InputElement<T>[]; |     private _elements: InputElement<T>[]; | ||||||
|     private readonly _element: HTMLElement; |     private _selectFirstAsDefault: boolean; | ||||||
| 
 | 
 | ||||||
|     constructor(elements: InputElement<T>[], |     constructor(elements: InputElement<T>[], | ||||||
|                 selectFirstAsDefault = true) { |                 selectFirstAsDefault = true) { | ||||||
|         super() |         super() | ||||||
|         elements = Utils.NoNull(elements); |         this._selectFirstAsDefault = selectFirstAsDefault; | ||||||
|  |         this._elements = Utils.NoNull(elements); | ||||||
|  |         this.value = new UIEventSource<T>(undefined) | ||||||
|  |     } | ||||||
|  |     protected InnerConstructElement(): HTMLElement { | ||||||
|  |         const elements = this._elements; | ||||||
|  |         const selectFirstAsDefault = this._selectFirstAsDefault; | ||||||
|  |          | ||||||
|         const selectedElementIndex: UIEventSource<number> = new UIEventSource<number>(null); |         const selectedElementIndex: UIEventSource<number> = new UIEventSource<number>(null); | ||||||
|         const value = |         const value = | ||||||
|             UIEventSource.flatten(selectedElementIndex.map( |             UIEventSource.flatten(selectedElementIndex.map( | ||||||
|  | @ -22,6 +29,7 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             ), elements.map(e => e?.GetValue())); |             ), elements.map(e => e?.GetValue())); | ||||||
|  |         value.syncWith(this.value) | ||||||
|          |          | ||||||
|         if(selectFirstAsDefault){ |         if(selectFirstAsDefault){ | ||||||
|              |              | ||||||
|  | @ -61,7 +69,20 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|         RadioButton._nextId++ |         RadioButton._nextId++ | ||||||
| 
 | 
 | ||||||
|         const form = document.createElement("form") |         const form = document.createElement("form") | ||||||
|         this._element = form; |         const inputs = [] | ||||||
|  | 
 | ||||||
|  |         value.addCallbackAndRun( | ||||||
|  |             selected => { | ||||||
|  |                  | ||||||
|  |                 let somethingChecked = false; | ||||||
|  |                 for (let i = 0; i < inputs.length; i++){ | ||||||
|  |                     let input = inputs[i]; | ||||||
|  |                     input.checked = !somethingChecked && elements[i].IsValid(selected); | ||||||
|  |                     somethingChecked = somethingChecked || input.checked | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |          | ||||||
|         for (let i1 = 0; i1 < elements.length; i1++) { |         for (let i1 = 0; i1 < elements.length; i1++) { | ||||||
|             let element = elements[i1]; |             let element = elements[i1]; | ||||||
|             const labelHtml = element.ConstructElement(); |             const labelHtml = element.ConstructElement(); | ||||||
|  | @ -73,6 +94,7 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|             input.id = "radio" + groupId + "-" + i1; |             input.id = "radio" + groupId + "-" + i1; | ||||||
|             input.name = groupId; |             input.name = groupId; | ||||||
|             input.type = "radio" |             input.type = "radio" | ||||||
|  |                input.classList.add("p-1","cursor-pointer","ml-2","pl-2","pr-0","m-0","ml-3") | ||||||
| 
 | 
 | ||||||
|             input.onchange = () => { |             input.onchange = () => { | ||||||
|                 if(input.checked){ |                 if(input.checked){ | ||||||
|  | @ -80,30 +102,26 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             value.addCallbackAndRun( |             | ||||||
|                 selected => input.checked = element.IsValid(selected) |             inputs.push(input) | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|             const label = document.createElement("label") |             const label = document.createElement("label") | ||||||
|             label.appendChild(labelHtml) |             label.appendChild(labelHtml) | ||||||
|             label.htmlFor = input.id; |             label.htmlFor = input.id; | ||||||
|  |             label.classList.add("block","w-full","p-2","cursor-pointer","bg-red") | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|             const block = document.createElement("div") |             const block = document.createElement("div") | ||||||
|             block.appendChild(input) |             block.appendChild(input) | ||||||
|             block.appendChild(label) |             block.appendChild(label) | ||||||
|  |             block.classList.add("flex","w-full","border", "rounded-full", "border-gray-400") | ||||||
| 
 | 
 | ||||||
|             form.appendChild(block) |             form.appendChild(block) | ||||||
|             form.addEventListener("change", () => { |  | ||||||
|                     // TODO FIXME
 |  | ||||||
|                 } |  | ||||||
|             ); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         this.value = value; |  | ||||||
|         this._elements = elements; |  | ||||||
| 
 |  | ||||||
|         this.SetClass("flex flex-col") |         this.SetClass("flex flex-col") | ||||||
|  |         return form; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IsValid(t: T): boolean { |     IsValid(t: T): boolean { | ||||||
|  | @ -120,9 +138,6 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     protected InnerConstructElement(): HTMLElement { |  | ||||||
|         return this._element; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* |     /* | ||||||
|     public ShowValue(t: T): boolean { |     public ShowValue(t: T): boolean { | ||||||
|  |  | ||||||
|  | @ -67,10 +67,10 @@ export class TextField extends InputElement<string> { | ||||||
| 
 | 
 | ||||||
|         this.value.addCallbackAndRun(value => { |         this.value.addCallbackAndRun(value => { | ||||||
|             if (!(value !== undefined && value !== null)) { |             if (!(value !== undefined && value !== null)) { | ||||||
|  |                 field["value"] = ""; | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             // @ts-ignore
 |             field["value"] = value; | ||||||
|             field.value = value; |  | ||||||
|             if (self.IsValid(value)) { |             if (self.IsValid(value)) { | ||||||
|                 self.RemoveClass("invalid") |                 self.RemoveClass("invalid") | ||||||
|             } else { |             } else { | ||||||
|  |  | ||||||
|  | @ -8,15 +8,13 @@ import State from "../../State"; | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg"; | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; |  | ||||||
| 
 | 
 | ||||||
| export default class EditableTagRendering extends Toggle { | export default class EditableTagRendering extends Toggle { | ||||||
| 
 | 
 | ||||||
|     constructor(tags: UIEventSource<any>, |     constructor(tags: UIEventSource<any>, | ||||||
|                 configuration: TagRenderingConfig) { |                 configuration: TagRenderingConfig, | ||||||
| 
 |                 editMode = new UIEventSource<boolean>(false) | ||||||
|         const editMode = new UIEventSource<boolean>(false); |                 ) { | ||||||
| 
 |  | ||||||
|         const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration) |         const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration) | ||||||
|         answer.SetClass("w-full") |         answer.SetClass("w-full") | ||||||
|         let rendering = answer; |         let rendering = answer; | ||||||
|  |  | ||||||
|  | @ -26,8 +26,8 @@ export class SaveButton extends Toggle { | ||||||
|             isSaveable |             isSaveable | ||||||
|         ) |         ) | ||||||
|         super( |         super( | ||||||
|             save |             save,  | ||||||
|             , pleaseLogin, |             pleaseLogin, | ||||||
|             osmConnection?.userDetails?.map(userDetails => userDetails.loggedIn) ?? new UIEventSource<any>(false) |             osmConnection?.userDetails?.map(userDetails => userDetails.loggedIn) ?? new UIEventSource<any>(false) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,7 +71,8 @@ export default class TagRenderingQuestion extends UIElement { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         this._saveButton = new SaveButton(this._inputElement.GetValue(), State.state?.osmConnection) |         this._saveButton = new SaveButton(this._inputElement.GetValue(),  | ||||||
|  |             State.state?.osmConnection) | ||||||
|             .onClick(save) |             .onClick(save) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -92,7 +93,7 @@ export default class TagRenderingQuestion extends UIElement { | ||||||
|                     return tags.asHumanString(true, true, self._tags.data); |                     return tags.asHumanString(true, true, self._tags.data); | ||||||
|                 } |                 } | ||||||
|             ) |             ) | ||||||
|         ).SetClass("block") |         ).SetClass("block break-all") | ||||||
|          |          | ||||||
|          |          | ||||||
|          |          | ||||||
|  | @ -156,7 +157,9 @@ export default class TagRenderingQuestion extends UIElement { | ||||||
|                     oppositeTags.push(notSelected); |                     oppositeTags.push(notSelected); | ||||||
|                 } |                 } | ||||||
|                 tags.push(TagUtils.FlattenMultiAnswer(oppositeTags)); |                 tags.push(TagUtils.FlattenMultiAnswer(oppositeTags)); | ||||||
|                 return TagUtils.FlattenMultiAnswer(tags); |                 const actualTags = TagUtils.FlattenMultiAnswer(tags); | ||||||
|  |                 console.log("Converted ", indices.join(","), "into", actualTags.asHumanString(false, false, {}), "with elems", elements) | ||||||
|  |                 return actualTags; | ||||||
|             }, |             }, | ||||||
|             (tags: TagsFilter) => { |             (tags: TagsFilter) => { | ||||||
|                 // {key --> values[]}
 |                 // {key --> values[]}
 | ||||||
|  |  | ||||||
|  | @ -2,19 +2,14 @@ | ||||||
| Contains tweaks for small screens | Contains tweaks for small screens | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| .only-on-mobile { | @media only screen and (min-width: 769px) { | ||||||
|     display: none !important; |  | ||||||
|     background-color: var(--background-color); |  | ||||||
|     color: var(--foreground-color); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @media only screen and (max-width: 600px), only screen and (max-height: 600px) { |  | ||||||
| 
 | 
 | ||||||
|     .only-on-mobile { |     .only-on-mobile { | ||||||
|         display: unset !important; |         display: none !important; | ||||||
|         background-color: var(--background-color); |  | ||||||
|         color: var(--foreground-color); |  | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  | @media only screen and (max-width: 768px), only screen and (max-height: 768px) { | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     .hidden-on-mobile { |     .hidden-on-mobile { | ||||||
|         display: none !important; |         display: none !important; | ||||||
|  |  | ||||||
|  | @ -1,18 +0,0 @@ | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .slick-carousel-content { |  | ||||||
|     width: 300px; |  | ||||||
|     max-height: var(--image-carousel-height); |  | ||||||
|     display: block; |  | ||||||
|     margin-left: 10px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .slick-carousel-content img { |  | ||||||
|     /** |  | ||||||
| Workaround to patch images within a slick carousel |  | ||||||
|  */ |  | ||||||
|     height: var(--image-carousel-height); |  | ||||||
|     width: auto; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
|  | @ -226,10 +226,6 @@ li::marker { | ||||||
|     width: 100%; |     width: 100%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .question form input[type="radio"] { |  | ||||||
|     margin-right: 0.5em; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .invalid { | .invalid { | ||||||
|     box-shadow: 0 0 10px #ff5353; |     box-shadow: 0 0 10px #ff5353; | ||||||
|     height: min-content; |     height: min-content; | ||||||
|  |  | ||||||
|  | @ -70,7 +70,7 @@ | ||||||
| <div id="bottom-right" class="absolute bottom-3 right-2 rounded-3xl z-above-map"></div> | <div id="bottom-right" class="absolute bottom-3 right-2 rounded-3xl z-above-map"></div> | ||||||
| 
 | 
 | ||||||
| <div id="centermessage" | <div id="centermessage" | ||||||
|      class="clutter absolute h-24 left-24 right-24 top-56" style="z-index: 4000"> |      class="clutter absolute h-24 left-24 right-24 top-56 text-xl text-center" style="z-index: 4000"> | ||||||
|     Loading MapComplete, hang on... |     Loading MapComplete, hang on... | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ | ||||||
|     }, |     }, | ||||||
|     "general": { |     "general": { | ||||||
|         "loginWithOpenStreetMap": "Login with OpenStreetMap", |         "loginWithOpenStreetMap": "Login with OpenStreetMap", | ||||||
|  |         "loginOnlyNeededToEdit": "to make changes to the map", | ||||||
|         "welcomeBack": "You are logged in, welcome back!", |         "welcomeBack": "You are logged in, welcome back!", | ||||||
|         "loginToStart": "Login to answer this question", |         "loginToStart": "Login to answer this question", | ||||||
|         "testing":"Testing - changes won't be saved", |         "testing":"Testing - changes won't be saved", | ||||||
|  | @ -39,6 +40,7 @@ | ||||||
|             "error": "Something went wrong…" |             "error": "Something went wrong…" | ||||||
|         }, |         }, | ||||||
|         "returnToTheMap": "Return to the map", |         "returnToTheMap": "Return to the map", | ||||||
|  |         "openTheMap": "Open the map", | ||||||
|         "save": "Save", |         "save": "Save", | ||||||
|         "cancel": "Cancel", |         "cancel": "Cancel", | ||||||
|         "skip": "Skip this question", |         "skip": "Skip this question", | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import {Utils} from "../Utils"; | import {Utils} from "../Utils"; | ||||||
| 
 |  | ||||||
| Utils.runningFromConsole = true; | Utils.runningFromConsole = true; | ||||||
| import SpecialVisualizations from "../UI/SpecialVisualizations"; | import SpecialVisualizations from "../UI/SpecialVisualizations"; | ||||||
| import SimpleMetaTagger from "../Logic/SimpleMetaTagger"; | import SimpleMetaTagger from "../Logic/SimpleMetaTagger"; | ||||||
|  | @ -12,19 +11,19 @@ import {writeFileSync} from "fs"; | ||||||
| import LayoutConfig from "../Customizations/JSON/LayoutConfig"; | import LayoutConfig from "../Customizations/JSON/LayoutConfig"; | ||||||
| import State from "../State"; | import State from "../State"; | ||||||
| import {QueryParameters} from "../Logic/Web/QueryParameters"; | import {QueryParameters} from "../Logic/Web/QueryParameters"; | ||||||
| import Link from "../UI/Base/Link"; |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| function WriteFile(filename, html: string | BaseUIElement, autogenSource: string): void { | 
 | ||||||
|  | function WriteFile(filename, html: string | BaseUIElement, autogenSource: string[]): void { | ||||||
|     writeFileSync(filename, new Combine([Translations.W(html), |     writeFileSync(filename, new Combine([Translations.W(html), | ||||||
|         new Link("Generated from "+autogenSource, "../../../"+autogenSource) |         "Generated from "+autogenSource.join(", ") | ||||||
|     ]).AsMarkdown()); |     ]).AsMarkdown()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage, "UI/SpecialVisualisations.ts") | WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage, ["UI/SpecialVisualisations.ts"]) | ||||||
| WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"), | WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"), | ||||||
|     "SimpleMetaTagger and ExtraFunction") |     ["SimpleMetaTagger","ExtraFunction"]) | ||||||
| WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(),"ValidatedTextField.ts"); | WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(),["ValidatedTextField.ts"]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| new State(new LayoutConfig({ | new State(new LayoutConfig({ | ||||||
|  | @ -51,7 +50,7 @@ new State(new LayoutConfig({ | ||||||
| })) | })) | ||||||
| QueryParameters.GetQueryParameter("layer-<layer-id>", "true", "Wether or not the layer with id <layer-id> is shown") | QueryParameters.GetQueryParameter("layer-<layer-id>", "true", "Wether or not the layer with id <layer-id> is shown") | ||||||
| 
 | 
 | ||||||
| WriteFile("./Docs/URL_Parameters.md", QueryParameters.GenerateQueryParameterDocs(), "QueryParameters") | WriteFile("./Docs/URL_Parameters.md", QueryParameters.GenerateQueryParameterDocs(), ["QueryParameters"]) | ||||||
| 
 | 
 | ||||||
| console.log("Generated docs") | console.log("Generated docs") | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ | ||||||
| <head> | <head> | ||||||
|     <title>Small tests</title> |     <title>Small tests</title> | ||||||
|     <link href="index.css" rel="stylesheet"/> |     <link href="index.css" rel="stylesheet"/> | ||||||
|     <link href="css/slideshow.css" rel="stylesheet"/> |  | ||||||
|     <link href="css/tabbedComponent.css" rel="stylesheet"/> |     <link href="css/tabbedComponent.css" rel="stylesheet"/> | ||||||
|     <link href="css/openinghourstable.css" rel="stylesheet"/> |     <link href="css/openinghourstable.css" rel="stylesheet"/> | ||||||
|     <link href="css/tagrendering.css" rel="stylesheet"/> |     <link href="css/tagrendering.css" rel="stylesheet"/> | ||||||
|  |  | ||||||
							
								
								
									
										48
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										48
									
								
								test.ts
									
										
									
									
									
								
							|  | @ -1,10 +1,50 @@ | ||||||
| import ValidatedTextField from "./UI/Input/ValidatedTextField"; | import ValidatedTextField from "./UI/Input/ValidatedTextField"; | ||||||
| import Combine from "./UI/Base/Combine"; | import Combine from "./UI/Base/Combine"; | ||||||
| import {VariableUiElement} from "./UI/Base/VariableUIElement"; | import {VariableUiElement} from "./UI/Base/VariableUIElement"; | ||||||
|  | import {UIEventSource} from "./Logic/UIEventSource"; | ||||||
|  | import TagRenderingConfig from "./Customizations/JSON/TagRenderingConfig"; | ||||||
|  | import State from "./State"; | ||||||
|  | import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion"; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| new Combine(ValidatedTextField.tpList.map(tp => { | function TestTagRendering(){ | ||||||
|     const tf = ValidatedTextField.InputForType(tp.name); |     State.state = new State(undefined) | ||||||
|  |     const tagsSource = new UIEventSource({ | ||||||
|  |         id:"node/1" | ||||||
|  |     }) | ||||||
|  |     new TagRenderingQuestion( | ||||||
|  |         tagsSource, | ||||||
|  |         new TagRenderingConfig({ | ||||||
|  |             multiAnswer: false, | ||||||
|  |             freeform: { | ||||||
|  |                 key:"valve" | ||||||
|  |             }, | ||||||
|  |             question: "What valves are supported?", | ||||||
|  |             render: "This pump supports {valve}", | ||||||
|  |             mappings: [ | ||||||
|  |                 { | ||||||
|  |                     if: "valve=dunlop", | ||||||
|  |                     then: "This pump supports dunlop" | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     if:"valve=shrader", | ||||||
|  |                     then:"shrader is supported", | ||||||
|  |                 } | ||||||
|  |             ], | ||||||
|              |              | ||||||
|     return new Combine([tf, new VariableUiElement(tf.GetValue()).SetClass("alert")]); |         }, undefined, "test") | ||||||
| })).AttachTo("maindiv") |     ).AttachTo("maindiv") | ||||||
|  |     new VariableUiElement(tagsSource.map(tags => tags["valves"])).SetClass("alert").AttachTo("extradiv") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function TestAllInputMethods(){ | ||||||
|  | 
 | ||||||
|  |     new Combine(ValidatedTextField.tpList.map(tp => { | ||||||
|  |         const tf = ValidatedTextField.InputForType(tp.name); | ||||||
|  | 
 | ||||||
|  |         return new Combine([tf, new VariableUiElement(tf.GetValue()).SetClass("alert")]); | ||||||
|  |     })).AttachTo("maindiv")     | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | TestTagRendering() | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue