forked from MapComplete/MapComplete
		
	Fix bug with multiple image uploads, refactoring of TextField
This commit is contained in:
		
							parent
							
								
									8fd4270545
								
							
						
					
					
						commit
						e46ea51d44
					
				
					 13 changed files with 53 additions and 91 deletions
				
			
		|  | @ -20,7 +20,10 @@ export default class GeneralSettingsPanel extends UIElement { | ||||||
| 
 | 
 | ||||||
|         const languagesField = |         const languagesField = | ||||||
|             ValidatedTextField.Mapped( |             ValidatedTextField.Mapped( | ||||||
|                 str => str?.split(";")?.map(str => str.trim().toLowerCase()), |                 str => { | ||||||
|  |                     console.log("Language from str", str); | ||||||
|  |                     return str?.split(";")?.map(str => str.trim().toLowerCase()); | ||||||
|  |                 }, | ||||||
|                 languages => languages.join(";")); |                 languages => languages.join(";")); | ||||||
|         this.languages = languagesField.GetValue(); |         this.languages = languagesField.GetValue(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ import {OsmConnection} from "../../Logic/Osm/OsmConnection"; | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; | import {FixedUiElement} from "../Base/FixedUiElement"; | ||||||
| import {TextField} from "../Input/TextField"; | import {TextField} from "../Input/TextField"; | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; | import {SubtleButton} from "../Base/SubtleButton"; | ||||||
| import {LayerConfigJson} from "../../Customizations/JSON/LayerConfigJson"; |  | ||||||
| 
 | 
 | ||||||
| export default class SavePanel extends UIElement { | export default class SavePanel extends UIElement { | ||||||
|     private json: UIElement; |     private json: UIElement; | ||||||
|  | @ -35,10 +34,7 @@ export default class SavePanel extends UIElement { | ||||||
| 
 | 
 | ||||||
|        const jsonTextField = new TextField({ |        const jsonTextField = new TextField({ | ||||||
|             placeholder: "JSON Config", |             placeholder: "JSON Config", | ||||||
|             fromString: str => str, |  | ||||||
|             toString: str => str, |  | ||||||
|             value: jsonStr, |             value: jsonStr, | ||||||
|             startValidated: false, |  | ||||||
|             textArea: true, |             textArea: true, | ||||||
|             textAreaRows: 20 |             textAreaRows: 20 | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
| import {InputElement} from "../Input/InputElement"; | import {InputElement} from "../Input/InputElement"; | ||||||
| import SingleSetting from "./SingleSetting"; | import SingleSetting from "./SingleSetting"; | ||||||
| import SettingsTable from "./SettingsTable"; | import SettingsTable from "./SettingsTable"; | ||||||
| import {TextField, ValidatedTextField} from "../Input/TextField"; | import {TextField} from "../Input/TextField"; | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine"; | ||||||
| import MultiLingualTextFields from "../Input/MultiLingualTextFields"; | import MultiLingualTextFields from "../Input/MultiLingualTextFields"; | ||||||
| import {AndOrTagInput} from "../Input/AndOrTagInput"; | import {AndOrTagInput} from "../Input/AndOrTagInput"; | ||||||
|  | @ -16,6 +16,7 @@ import {UserDetails} from "../../Logic/Osm/OsmConnection"; | ||||||
| import {State} from "../../State"; | import {State} from "../../State"; | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import {VariableUiElement} from "../Base/VariableUIElement"; | ||||||
| import {FromJSON} from "../../Customizations/JSON/FromJSON"; | import {FromJSON} from "../../Customizations/JSON/FromJSON"; | ||||||
|  | import ValidatedTextField from "../Input/ValidatedTextField"; | ||||||
| 
 | 
 | ||||||
| export default class TagRenderingPanel extends InputElement<TagRenderingConfigJson> { | export default class TagRenderingPanel extends InputElement<TagRenderingConfigJson> { | ||||||
| 
 | 
 | ||||||
|  | @ -62,11 +63,11 @@ export default class TagRenderingPanel extends InputElement<TagRenderingConfigJs | ||||||
|         const questionSettings = [ |         const questionSettings = [ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             setting(options?.noLanguage ? TextField.StringInput() : new MultiLingualTextFields(languages) |             setting(options?.noLanguage ? new TextField({placeholder:"question"}) : new MultiLingualTextFields(languages) | ||||||
|                 , "question", "Question", "If the key or mapping doesn't match, this question is asked"), |                 , "question", "Question", "If the key or mapping doesn't match, this question is asked"), | ||||||
| 
 | 
 | ||||||
|             "<h3>Freeform key</h3>", |             "<h3>Freeform key</h3>", | ||||||
|             setting(TextField.KeyInput(true), ["freeform", "key"], "Freeform key<br/>", |             setting(ValidatedTextField.KeyInput(true), ["freeform", "key"], "Freeform key<br/>", | ||||||
|                 "If specified, the rendering will search if this key is present." + |                 "If specified, the rendering will search if this key is present." + | ||||||
|                 "If it is, the rendering above will be used to display the element.<br/>" + |                 "If it is, the rendering above will be used to display the element.<br/>" + | ||||||
|                 "The rendering will go into question mode if <ul><li>this key is not present</li><li>No single mapping matches</li><li>A question is given</li>"), |                 "The rendering will go into question mode if <ul><li>this key is not present</li><li>No single mapping matches</li><li>A question is given</li>"), | ||||||
|  | @ -80,7 +81,7 @@ export default class TagRenderingPanel extends InputElement<TagRenderingConfigJs | ||||||
| 
 | 
 | ||||||
|         const settings: (string | SingleSetting<any>)[] = [ |         const settings: (string | SingleSetting<any>)[] = [ | ||||||
|             setting( |             setting( | ||||||
|                 options?.noLanguage ? TextField.StringInput() : |                 options?.noLanguage ? new TextField({placeholder:"Rendering"}) : | ||||||
|                     new MultiLingualTextFields(languages), "render", "Value to show", " Renders this value. Note that <span class='literal-code'>{key}</span>-parts are substituted by the corresponding values of the element. If neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value."), |                     new MultiLingualTextFields(languages), "render", "Value to show", " Renders this value. Note that <span class='literal-code'>{key}</span>-parts are substituted by the corresponding values of the element. If neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value."), | ||||||
| 
 | 
 | ||||||
|             questionsNotUnlocked ? `You need at least ${State.userJourney.themeGeneratorFullUnlock} changesets to unlock the 'question'-field and to use your theme to edit OSM data` : "", |             questionsNotUnlocked ? `You need at least ${State.userJourney.themeGeneratorFullUnlock} changesets to unlock the 'question'-field and to use your theme to edit OSM data` : "", | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import Combine from "./Base/Combine"; | ||||||
| import {State} from "../State"; | import {State} from "../State"; | ||||||
| import {UIEventSource} from "../Logic/UIEventSource"; | import {UIEventSource} from "../Logic/UIEventSource"; | ||||||
| import {Imgur} from "../Logic/Web/Imgur"; | import {Imgur} from "../Logic/Web/Imgur"; | ||||||
|  | import {FixedUiElement} from "./Base/FixedUiElement"; | ||||||
| 
 | 
 | ||||||
| export class ImageUploadFlow extends UIElement { | export class ImageUploadFlow extends UIElement { | ||||||
|     private _licensePicker: UIElement; |     private _licensePicker: UIElement; | ||||||
|  | @ -69,7 +70,7 @@ export class ImageUploadFlow extends UIElement { | ||||||
|         if (this._isUploading.data == 1) { |         if (this._isUploading.data == 1) { | ||||||
|             currentState.push(t.uploadingPicture); |             currentState.push(t.uploadingPicture); | ||||||
|         } else if (this._isUploading.data > 0) { |         } else if (this._isUploading.data > 0) { | ||||||
|             currentState.push(t.uploadingMultiple.Subs({count: this._isUploading.data})); |             currentState.push(t.uploadingMultiple.Subs({count: ""+this._isUploading.data})); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this._didFail.data) { |         if (this._didFail.data) { | ||||||
|  | @ -80,14 +81,15 @@ export class ImageUploadFlow extends UIElement { | ||||||
|             currentState.push(t.uploadDone) |             currentState.push(t.uploadDone) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let currentStateHtml = ""; |         let currentStateHtml : UIElement = new FixedUiElement(""); | ||||||
|         if (currentState.length > 0) { |         if (currentState.length > 0) { | ||||||
|             currentStateHtml = new Combine(currentState).Render(); |             currentStateHtml = new Combine(currentState); | ||||||
|             if (!this._allDone.data) { |             if (!this._allDone.data) { | ||||||
|                 currentStateHtml = "<span class='alert'>" + |                 currentStateHtml.SetClass("alert"); | ||||||
|                     currentStateHtml + |             }else{ | ||||||
|                     "</span>"; |                 currentStateHtml.SetClass("thanks"); | ||||||
|             } |             } | ||||||
|  |             currentStateHtml.SetStyle("display:block ruby") | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const extraInfo = new Combine([ |         const extraInfo = new Combine([ | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ export default class InputElementMap<T, X> extends InputElement<X> { | ||||||
|             }), extraSources, x => { |             }), extraSources, x => { | ||||||
|                 return fromX(x); |                 return fromX(x); | ||||||
|             }); |             }); | ||||||
|     } |     }w | ||||||
| 
 | 
 | ||||||
|     GetValue(): UIEventSource<X> { |     GetValue(): UIEventSource<X> { | ||||||
|         return this._value; |         return this._value; | ||||||
|  |  | ||||||
|  | @ -1,42 +0,0 @@ | ||||||
| import {InputElement} from "./InputElement"; |  | ||||||
| import {UIElement} from "../UIElement"; |  | ||||||
| import Translations from "../i18n/Translations"; |  | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; |  | ||||||
| 
 |  | ||||||
| export class InputElementWrapper<T> extends InputElement<T>{ |  | ||||||
|     private pre: UIElement ; |  | ||||||
|     private input: InputElement<T>; |  | ||||||
|     private post: UIElement ; |  | ||||||
|      |  | ||||||
|     IsSelected: UIEventSource<boolean> |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     constructor( |  | ||||||
|         pre: UIElement | string, |  | ||||||
|         input: InputElement<T>, |  | ||||||
|         post: UIElement | string |  | ||||||
|          |  | ||||||
|     ) { |  | ||||||
|         super(undefined); |  | ||||||
|         // this.pre = typeof(pre) === 'string' ?  new FixedUiElement(pre) : pre
 |  | ||||||
|         this.pre = Translations.W(pre) |  | ||||||
|         this.input = input; |  | ||||||
|         // this.post =typeof(post) === 'string' ?  new FixedUiElement(post) : post
 |  | ||||||
|         this.post = Translations.W(post) |  | ||||||
|         this.IsSelected = input.IsSelected; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     GetValue(): UIEventSource<T> { |  | ||||||
|         return this.input.GetValue(); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     InnerRender(): string { |  | ||||||
|         return this.pre.Render() + this.input.Render() + this.post.Render(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     IsValid(t: T): boolean { |  | ||||||
|         return this.input.IsValid(t); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
| } |  | ||||||
|  | @ -3,19 +3,19 @@ import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
| import {TextField} from "./TextField"; | import {TextField} from "./TextField"; | ||||||
| 
 | 
 | ||||||
| export default class MultiLingualTextFields extends InputElement<any> { | export default class MultiLingualTextFields extends InputElement<any> { | ||||||
|     private _fields: Map<string, TextField<string>> = new Map<string, TextField<string>>(); |     private _fields: Map<string, TextField> = new Map<string, TextField>(); | ||||||
|     private _value: UIEventSource<any>; |     private readonly _value: UIEventSource<any>; | ||||||
|     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); |     public readonly IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
| 
 | 
 | ||||||
|     constructor(languages: UIEventSource<string[]>,  |     constructor(languages: UIEventSource<string[]>, | ||||||
|                 textArea: boolean = false, |                 textArea: boolean = false, | ||||||
|                 value: UIEventSource<Map<string, UIEventSource<string>>> = undefined) { |                 value: UIEventSource<Map<string, UIEventSource<string>>> = undefined) { | ||||||
|         super(undefined); |         super(undefined); | ||||||
|         this._value = value ?? new UIEventSource({}); |         this._value = value ?? new UIEventSource({}); | ||||||
|          | 
 | ||||||
|         this._value.addCallbackAndRun(latestData =>  { |         this._value.addCallbackAndRun(latestData => { | ||||||
|             if(typeof(latestData) === "string"){ |             if (typeof (latestData) === "string") { | ||||||
|                 console.warn("Refusing string for multilingual input",latestData); |                 console.warn("Refusing string for multilingual input", latestData); | ||||||
|                 self._value.setData({}); |                 self._value.setData({}); | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|  | @ -26,7 +26,7 @@ export default class MultiLingualTextFields extends InputElement<any> { | ||||||
|             if (languages === undefined) { |             if (languages === undefined) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             const newFields = new Map<string, TextField<string>>(); |             const newFields = new Map<string, TextField>(); | ||||||
|             for (const language of languages) { |             for (const language of languages) { | ||||||
|                 if (language.length != 2) { |                 if (language.length != 2) { | ||||||
|                     continue; |                     continue; | ||||||
|  | @ -34,7 +34,7 @@ export default class MultiLingualTextFields extends InputElement<any> { | ||||||
|                  |                  | ||||||
|                 let oldField = self._fields.get(language); |                 let oldField = self._fields.get(language); | ||||||
|                 if (oldField === undefined) { |                 if (oldField === undefined) { | ||||||
|                     oldField = TextField.StringInput(textArea); |                     oldField = new TextField({textArea: textArea}); | ||||||
|                     oldField.GetValue().addCallback(str => { |                     oldField.GetValue().addCallback(str => { | ||||||
|                         self._value.data[language] = str; |                         self._value.data[language] = str; | ||||||
|                         self._value.ping(); |                         self._value.ping(); | ||||||
|  |  | ||||||
|  | @ -1,10 +1,5 @@ | ||||||
| import {InputElement} from "./InputElement"; |  | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
| import {UIElement} from "../UIElement"; |  | ||||||
| import Combine from "../Base/Combine"; |  | ||||||
| import {SubtleButton} from "../Base/SubtleButton"; |  | ||||||
| import TagInput from "./SingleTagInput"; | import TagInput from "./SingleTagInput"; | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; |  | ||||||
| import {MultiInput} from "./MultiInput"; | import {MultiInput} from "./MultiInput"; | ||||||
| 
 | 
 | ||||||
| export class MultiTagInput extends MultiInput<string> { | export class MultiTagInput extends MultiInput<string> { | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ import {Utils} from "../../Utils"; | ||||||
| import {UIElement} from "../UIElement"; | import {UIElement} from "../UIElement"; | ||||||
| import {VariableUiElement} from "../Base/VariableUIElement"; | import {VariableUiElement} from "../Base/VariableUIElement"; | ||||||
| import {FromJSON} from "../../Customizations/JSON/FromJSON"; | import {FromJSON} from "../../Customizations/JSON/FromJSON"; | ||||||
|  | import ValidatedTextField from "./ValidatedTextField"; | ||||||
| 
 | 
 | ||||||
| export default class SingleTagInput extends InputElement<string> { | export default class SingleTagInput extends InputElement<string> { | ||||||
| 
 | 
 | ||||||
|  | @ -32,12 +33,10 @@ export default class SingleTagInput extends InputElement<string> { | ||||||
|             } |             } | ||||||
|         )); |         )); | ||||||
| 
 | 
 | ||||||
|         this.key = TextField.KeyInput(); |         this.key = ValidatedTextField.KeyInput(); | ||||||
| 
 | 
 | ||||||
|         this.value = new TextField<string>({ |         this.value = new TextField({ | ||||||
|                 placeholder: "value - if blank, matches if key is NOT present", |                 placeholder: "value - if blank, matches if key is NOT present", | ||||||
|                 fromString: str => str, |  | ||||||
|                 toString: str => str, |  | ||||||
|                 value: new UIEventSource<string>("") |                 value: new UIEventSource<string>("") | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|  | @ -51,6 +51,8 @@ export class TextField extends InputElement<string> { | ||||||
|             // @ts-ignore
 |             // @ts-ignore
 | ||||||
|             field.value = t; |             field.value = t; | ||||||
|         }); |         }); | ||||||
|  |         this.dumbMode = false; | ||||||
|  |         this.SetClass("deadbeef") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     GetValue(): UIEventSource<string> { |     GetValue(): UIEventSource<string> { | ||||||
|  | @ -60,17 +62,24 @@ export class TextField extends InputElement<string> { | ||||||
|     InnerRender(): string { |     InnerRender(): string { | ||||||
| 
 | 
 | ||||||
|         if (this._isArea) { |         if (this._isArea) { | ||||||
|             return `<textarea id="${this.id}" class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea>` |             return `<span id="${this.id}"><textarea id="txt-${this.id}" class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea></span>` | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const placeholder = this._placeholder.InnerRender().replace("'", "'"); |         const placeholder = this._placeholder.InnerRender().replace("'", "'"); | ||||||
| 
 | 
 | ||||||
|         return `<form onSubmit='return false' class='form-text-field'>` + |         return `<span id="${this.id}"><form onSubmit='return false' class='form-text-field'>` + | ||||||
|             `<input type='text' placeholder='${placeholder}' id='${this.id}'>` + |             `<input type='text' placeholder='${placeholder}' id='txt-${this.id}'>` + | ||||||
|             `</form>`; |             `</form></span>`; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     Update() { | ||||||
|  |         console.log("Updating TF") | ||||||
|  |         super.Update(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     InnerUpdate(field) { |     InnerUpdate() { | ||||||
|  |         console.log("Inner Updating TF") | ||||||
|  |         const field = document.getElementById("txt-" + this.id); | ||||||
|         const self = this; |         const self = this; | ||||||
|         field.oninput = () => { |         field.oninput = () => { | ||||||
|             // @ts-ignore
 |             // @ts-ignore
 | ||||||
|  |  | ||||||
|  | @ -186,7 +186,6 @@ export default class ValidatedTextField { | ||||||
|         isValid?: ((string: string) => boolean) |         isValid?: ((string: string) => boolean) | ||||||
|     }): InputElement<T> { |     }): InputElement<T> { | ||||||
|         const textField = new TextField(options); |         const textField = new TextField(options); | ||||||
| 
 |  | ||||||
|         return new InputElementMap( |         return new InputElementMap( | ||||||
|             textField, (a, b) => a === b, |             textField, (a, b) => a === b, | ||||||
|             fromString, toString |             fromString, toString | ||||||
|  |  | ||||||
|  | @ -157,7 +157,7 @@ export class ShareScreen extends UIElement { | ||||||
|         }, optionParts); |         }, optionParts); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         this.iframe = url.map(url => `<iframe src="${url}" width="100%" height="100%" title="${layout.title.InnerRender()} with MapComplete"></iframe>`); |         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) => { | ||||||
|  |  | ||||||
|  | @ -34,13 +34,13 @@ export default class Translations { | ||||||
|             }), |             }), | ||||||
| 
 | 
 | ||||||
|             uploadingMultiple: new T({ |             uploadingMultiple: new T({ | ||||||
|                 en: 'Uploading {count} of your picture...', |                 en: "Uploading {count} of your picture...", | ||||||
|                 nl: 'Bezig met {count} foto\'s te uploaden...', |                 nl: "Bezig met {count} foto's te uploaden...", | ||||||
|                 ca: 'Pujant {count} de la teva imatge...', |                 ca: "Pujant {count} de la teva imatge...", | ||||||
|                 es: 'Subiendo {count} de tus fotos...', |                 es: "Subiendo {count} de tus fotos...", | ||||||
|                 fr: 'Mettre votre {count} photos en ligne', |                 fr: "Mettre votre {count} photos en ligne", | ||||||
|                 gl: 'Subindo {count} das túas imaxes...', |                 gl: "Subindo {count} das túas imaxes...", | ||||||
|                 de: '{count} Ihrer Bilder hochgeladen...' |                 de: "{count} Ihrer Bilder hochgeladen..." | ||||||
|             }), |             }), | ||||||
| 
 | 
 | ||||||
|             pleaseLogin: new T({ |             pleaseLogin: new T({ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue