forked from MapComplete/MapComplete
		
	Feature: allow to erase freeform values if there are no mappings
This commit is contained in:
		
							parent
							
								
									b7f044e976
								
							
						
					
					
						commit
						3483ac81b1
					
				
					 5 changed files with 192 additions and 158 deletions
				
			
		|  | @ -217,6 +217,7 @@ | ||||||
|         }, |         }, | ||||||
|         "enableGeolocationForSafari": "Did you not get the popup to ask for geopermission?", |         "enableGeolocationForSafari": "Did you not get the popup to ask for geopermission?", | ||||||
|         "enableGeolocationForSafariLink": "Learn how to enable the geolocation permission in settings", |         "enableGeolocationForSafariLink": "Learn how to enable the geolocation permission in settings", | ||||||
|  |         "eraseValue": "Erase this value", | ||||||
|         "error": "Something went wrong", |         "error": "Something went wrong", | ||||||
|         "example": "Example", |         "example": "Example", | ||||||
|         "examples": "Examples", |         "examples": "Examples", | ||||||
|  |  | ||||||
|  | @ -28,8 +28,12 @@ | ||||||
|    * This is only copied to 'value' when appropriate so that no invalid values leak outside; |    * This is only copied to 'value' when appropriate so that no invalid values leak outside; | ||||||
|    * Additionally, the unit is added when copying |    * Additionally, the unit is added when copying | ||||||
|    */ |    */ | ||||||
|   let _value = new UIEventSource(value.data ?? "") |   export let unvalidatedText = new UIEventSource(value.data ?? "") | ||||||
| 
 | 
 | ||||||
|  |    | ||||||
|  |   if(unvalidatedText == /*Compare by reference!*/ value){ | ||||||
|  |     throw "Value and unvalidatedText may not be the same store!" | ||||||
|  |   } | ||||||
|   let validator: Validator = Validators.get(type ?? "string") |   let validator: Validator = Validators.get(type ?? "string") | ||||||
|   if (validator === undefined) { |   if (validator === undefined) { | ||||||
|     console.warn("Didn't find a validator for type", type) |     console.warn("Didn't find a validator for type", type) | ||||||
|  | @ -41,13 +45,13 @@ | ||||||
|     if (unit && value.data) { |     if (unit && value.data) { | ||||||
|       const [v, denom] = unit?.findDenomination(value.data, getCountry) |       const [v, denom] = unit?.findDenomination(value.data, getCountry) | ||||||
|       if (denom) { |       if (denom) { | ||||||
|         _value.setData(v) |         unvalidatedText.setData(v) | ||||||
|         selectedUnit.setData(denom.canonical) |         selectedUnit.setData(denom.canonical) | ||||||
|       } else { |       } else { | ||||||
|         _value.setData(value.data ?? "") |         unvalidatedText.setData(value.data ?? "") | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       _value.setData(value.data ?? "") |       unvalidatedText.setData(value.data ?? "") | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -67,8 +71,8 @@ | ||||||
|     validator = Validators.get(type ?? "string") |     validator = Validators.get(type ?? "string") | ||||||
| 
 | 
 | ||||||
|     _placeholder = placeholder ?? validator?.getPlaceholder() ?? type |     _placeholder = placeholder ?? validator?.getPlaceholder() ?? type | ||||||
|     if (_value.data?.length > 0) { |     if (unvalidatedText.data?.length > 0) { | ||||||
|       feedback?.setData(validator?.getFeedback(_value.data, getCountry)) |       feedback?.setData(validator?.getFeedback(unvalidatedText.data, getCountry)) | ||||||
|     } else { |     } else { | ||||||
|       feedback?.setData(undefined) |       feedback?.setData(undefined) | ||||||
|     } |     } | ||||||
|  | @ -78,7 +82,7 @@ | ||||||
| 
 | 
 | ||||||
|   function setValues() { |   function setValues() { | ||||||
|     // Update the value stores |     // Update the value stores | ||||||
|     const v = _value.data |     const v = unvalidatedText.data | ||||||
|     if (v === "") { |     if (v === "") { | ||||||
|       value.setData(undefined) |       value.setData(undefined) | ||||||
|       feedback?.setData(undefined) |       feedback?.setData(undefined) | ||||||
|  | @ -103,12 +107,12 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onDestroy(_value.addCallbackAndRun((_) => setValues())) |   onDestroy(unvalidatedText.addCallbackAndRun((_) => setValues())) | ||||||
|   if (unit === undefined) { |   if (unit === undefined) { | ||||||
|     onDestroy( |     onDestroy( | ||||||
|       value.addCallbackAndRunD((fromUpstream) => { |       value.addCallbackAndRunD((fromUpstream) => { | ||||||
|         if (_value.data !== fromUpstream && fromUpstream !== "") { |         if (unvalidatedText.data !== fromUpstream && fromUpstream !== "") { | ||||||
|           _value.setData(fromUpstream) |           unvalidatedText.setData(fromUpstream) | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|     ) |     ) | ||||||
|  | @ -131,7 +135,7 @@ | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const isValid = _value.map((v) => validator?.isValid(v, getCountry) ?? true) |   const isValid = unvalidatedText.map((v) => validator?.isValid(v, getCountry) ?? true) | ||||||
| 
 | 
 | ||||||
|   let htmlElem: HTMLInputElement | HTMLTextAreaElement |   let htmlElem: HTMLInputElement | HTMLTextAreaElement | ||||||
| 
 | 
 | ||||||
|  | @ -149,7 +153,7 @@ | ||||||
| {#if validator?.textArea} | {#if validator?.textArea} | ||||||
|   <textarea |   <textarea | ||||||
|     class="w-full" |     class="w-full" | ||||||
|     bind:value={$_value} |     bind:value={$unvalidatedText} | ||||||
|     inputmode={validator?.inputmode ?? "text"} |     inputmode={validator?.inputmode ?? "text"} | ||||||
|     placeholder={_placeholder} |     placeholder={_placeholder} | ||||||
|     bind:this={htmlElem} |     bind:this={htmlElem} | ||||||
|  | @ -159,7 +163,7 @@ | ||||||
|   <div class={twMerge("inline-flex", cls)}> |   <div class={twMerge("inline-flex", cls)}> | ||||||
|     <input |     <input | ||||||
|       bind:this={htmlElem} |       bind:this={htmlElem} | ||||||
|       bind:value={$_value} |       bind:value={$unvalidatedText} | ||||||
|       class="w-full" |       class="w-full" | ||||||
|       inputmode={validator?.inputmode ?? "text"} |       inputmode={validator?.inputmode ?? "text"} | ||||||
|       placeholder={_placeholder} |       placeholder={_placeholder} | ||||||
|  | @ -170,7 +174,7 @@ | ||||||
|     {/if} |     {/if} | ||||||
| 
 | 
 | ||||||
|     {#if unit !== undefined} |     {#if unit !== undefined} | ||||||
|       <UnitInput {unit} {selectedUnit} textValue={_value} upstreamValue={value} {getCountry} /> |       <UnitInput {unit} {selectedUnit} textValue={unvalidatedText} upstreamValue={value} {getCountry} /> | ||||||
|     {/if} |     {/if} | ||||||
|   </div> |   </div> | ||||||
| {/if} | {/if} | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ | ||||||
|   import type { SpecialVisualizationState } from "../../SpecialVisualization" |   import type { SpecialVisualizationState } from "../../SpecialVisualization" | ||||||
| 
 | 
 | ||||||
|   export let value: UIEventSource<string> |   export let value: UIEventSource<string> | ||||||
|  |   export let unvalidatedText: UIEventSource<string> = new UIEventSource<string>(value.data) | ||||||
|   export let config: TagRenderingConfig |   export let config: TagRenderingConfig | ||||||
|   export let tags: UIEventSource<Record<string, string>> |   export let tags: UIEventSource<Record<string, string>> | ||||||
| 
 | 
 | ||||||
|  | @ -64,6 +65,7 @@ | ||||||
|       type={config.freeform.type} |       type={config.freeform.type} | ||||||
|       {placeholder} |       {placeholder} | ||||||
|       {value} |       {value} | ||||||
|  |       {unvalidatedText} | ||||||
|     /> |     /> | ||||||
|   {/if} |   {/if} | ||||||
| 
 | 
 | ||||||
|  | @ -74,5 +76,6 @@ | ||||||
|     {value} |     {value} | ||||||
|     {state} |     {state} | ||||||
|     on:submit |     on:submit | ||||||
|  |     {unvalidatedText} | ||||||
|   /> |   /> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ | ||||||
|         {state} |         {state} | ||||||
|         {layer} |         {layer} | ||||||
|         on:saved={() => (editMode = false)} |         on:saved={() => (editMode = false)} | ||||||
|  |         allowDeleteOfFreeform={true} | ||||||
|       > |       > | ||||||
|         <button |         <button | ||||||
|           slot="cancel" |           slot="cancel" | ||||||
|  |  | ||||||
|  | @ -22,17 +22,23 @@ | ||||||
|   import { Unit } from "../../../Models/Unit" |   import { Unit } from "../../../Models/Unit" | ||||||
|   import UserRelatedState from "../../../Logic/State/UserRelatedState" |   import UserRelatedState from "../../../Logic/State/UserRelatedState" | ||||||
|   import { twJoin } from "tailwind-merge" |   import { twJoin } from "tailwind-merge" | ||||||
|  |   import type { UploadableTag } from "../../../Logic/Tags/TagUtils" | ||||||
|   import { TagUtils } from "../../../Logic/Tags/TagUtils" |   import { TagUtils } from "../../../Logic/Tags/TagUtils" | ||||||
|  | 
 | ||||||
|   import Search from "../../../assets/svg/Search.svelte" |   import Search from "../../../assets/svg/Search.svelte" | ||||||
|   import Login from "../../../assets/svg/Login.svelte" |   import Login from "../../../assets/svg/Login.svelte" | ||||||
|   import { placeholder } from "../../../Utils/placeholder" |   import { placeholder } from "../../../Utils/placeholder" | ||||||
|  |   import { TrashIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||||
|  |   import { Tag } from "../../../Logic/Tags/Tag" | ||||||
| 
 | 
 | ||||||
|   export let config: TagRenderingConfig |   export let config: TagRenderingConfig | ||||||
|   export let tags: UIEventSource<Record<string, string>> |   export let tags: UIEventSource<Record<string, string>> | ||||||
|   export let selectedElement: Feature |   export let selectedElement: Feature | ||||||
|   export let state: SpecialVisualizationState |   export let state: SpecialVisualizationState | ||||||
|   export let layer: LayerConfig | undefined |   export let layer: LayerConfig | undefined | ||||||
|   export let selectedTags: TagsFilter = undefined |   export let selectedTags: UploadableTag = undefined | ||||||
|  | 
 | ||||||
|  |   export let allowDeleteOfFreeform: boolean = false | ||||||
| 
 | 
 | ||||||
|   let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined) |   let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined) | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +46,8 @@ | ||||||
| 
 | 
 | ||||||
|   // Will be bound if a freeform is available |   // Will be bound if a freeform is available | ||||||
|   let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key]) |   let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key]) | ||||||
|  |   let freeformInputUnvalidated = new UIEventSource<string>(freeformInput.data) | ||||||
|  |    | ||||||
|   let selectedMapping: number = undefined |   let selectedMapping: number = undefined | ||||||
|   /** |   /** | ||||||
|    * A list of booleans, used if multiAnswer is set |    * A list of booleans, used if multiAnswer is set | ||||||
|  | @ -145,20 +153,27 @@ | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
|   $: { |   $: { | ||||||
|     try { |     if (allowDeleteOfFreeform && $freeformInput === undefined && $freeformInputUnvalidated === "" && mappings.length === 0) { | ||||||
|       selectedTags = config?.constructChangeSpecification( |       selectedTags = new Tag(config.freeform.key, "") | ||||||
|         $freeformInput, |     } else { | ||||||
|         selectedMapping, | 
 | ||||||
|         checkedMappings, |       try { | ||||||
|         tags.data, |         selectedTags = config?.constructChangeSpecification( | ||||||
|       ) |           $freeformInput, | ||||||
|     } catch (e) { |           selectedMapping, | ||||||
|       console.error("Could not calculate changeSpecification:", e) |           checkedMappings, | ||||||
|       selectedTags = undefined |           tags.data, | ||||||
|  |         ) | ||||||
|  |       } catch (e) { | ||||||
|  |         console.error("Could not calculate changeSpecification:", e) | ||||||
|  |         selectedTags = undefined | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function onSave(e) { |   function onSave(e = undefined, deleteFreeform = false) { | ||||||
|  |     console.log("On click", deleteFreeform, ">>>", selectedTags) | ||||||
|  | 
 | ||||||
|     if (selectedTags === undefined) { |     if (selectedTags === undefined) { | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|  | @ -197,9 +212,9 @@ | ||||||
| 
 | 
 | ||||||
|   function onInputKeypress(e: KeyboardEvent) { |   function onInputKeypress(e: KeyboardEvent) { | ||||||
|     if (e.key === "Enter") { |     if (e.key === "Enter") { | ||||||
|         e.preventDefault() |       e.preventDefault() | ||||||
|         e.stopPropagation() |       e.stopPropagation() | ||||||
|         onSave(e) |       onSave() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -230,136 +245,139 @@ | ||||||
|       <fieldset> |       <fieldset> | ||||||
| 
 | 
 | ||||||
|         <legend> |         <legend> | ||||||
|             <div class="interactive sticky top-0 justify-between pt-1 font-bold" style="z-index: 11"> |           <div class="interactive sticky top-0 justify-between pt-1 font-bold" style="z-index: 11"> | ||||||
|                 <SpecialTranslation t={question} {tags} {state} {layer} feature={selectedElement} /> |             <SpecialTranslation t={question} {tags} {state} {layer} feature={selectedElement} /> | ||||||
|             </div> |           </div> | ||||||
| 
 | 
 | ||||||
|             {#if config.questionhint} |           {#if config.questionhint} | ||||||
|               <div class="max-h-60 overflow-y-auto"> |             <div class="max-h-60 overflow-y-auto"> | ||||||
|                 <SpecialTranslation |               <SpecialTranslation | ||||||
|                   t={config.questionhint} |                 t={config.questionhint} | ||||||
|                   {tags} |                 {tags} | ||||||
|                   {state} |                 {state} | ||||||
|                   {layer} |                 {layer} | ||||||
|                   feature={selectedElement} |                 feature={selectedElement} | ||||||
|                 /> |               /> | ||||||
|               </div> |             </div> | ||||||
|             {/if} |           {/if} | ||||||
|         </legend> |         </legend> | ||||||
| 
 | 
 | ||||||
|             {#if config.mappings?.length >= 8} |         {#if config.mappings?.length >= 8} | ||||||
|               <div class="sticky flex w-full" aria-hidden="true"> |           <div class="sticky flex w-full" aria-hidden="true"> | ||||||
|                 <Search class="h-6 w-6" /> |             <Search class="h-6 w-6" /> | ||||||
|                 <input |             <input | ||||||
|                   type="text" |               type="text" | ||||||
|                   bind:value={$searchTerm} |               bind:value={$searchTerm} | ||||||
|                   class="w-full" |               class="w-full" | ||||||
|                   use:placeholder={Translations.t.general.searchAnswer} |               use:placeholder={Translations.t.general.searchAnswer} | ||||||
|                 /> |             /> | ||||||
|               </div> |           </div> | ||||||
|             {/if} |         {/if} | ||||||
| 
 | 
 | ||||||
|             {#if config.freeform?.key && !(mappings?.length > 0)} |         {#if config.freeform?.key && !(mappings?.length > 0)} | ||||||
|               <!-- There are no options to choose from, simply show the input element: fill out the text field --> |           <!-- There are no options to choose from, simply show the input element: fill out the text field --> | ||||||
|               <FreeformInput |           <FreeformInput | ||||||
|                 {config} |             {config} | ||||||
|  |             {tags} | ||||||
|  |             {feedback} | ||||||
|  |             {unit} | ||||||
|  |             {state} | ||||||
|  |             feature={selectedElement} | ||||||
|  |             value={freeformInput} | ||||||
|  |             unvalidatedText={freeformInputUnvalidated} | ||||||
|  |             on:submit={onSave} | ||||||
|  |           /> | ||||||
|  |         {:else if mappings !== undefined && !config.multiAnswer} | ||||||
|  |           <!-- Simple radiobuttons as mapping --> | ||||||
|  |           <div class="flex flex-col"> | ||||||
|  |             {#each config.mappings as mapping, i (mapping.then)} | ||||||
|  |               <!-- Even though we have a list of 'mappings' already, we still iterate over the list as to keep the original indices--> | ||||||
|  |               <TagRenderingMappingInput | ||||||
|  |                 {mapping} | ||||||
|                 {tags} |                 {tags} | ||||||
|                 {feedback} |  | ||||||
|                 {unit} |  | ||||||
|                 {state} |                 {state} | ||||||
|                 feature={selectedElement} |                 {selectedElement} | ||||||
|                 value={freeformInput} |                 {layer} | ||||||
|                 on:submit={onSave} |                 {searchTerm} | ||||||
|               /> |                 mappingIsSelected={selectedMapping === i} | ||||||
|             {:else if mappings !== undefined && !config.multiAnswer} |               > | ||||||
|               <!-- Simple radiobuttons as mapping --> |                 <input | ||||||
|               <div class="flex flex-col"> |                   type="radio" | ||||||
|                 {#each config.mappings as mapping, i (mapping.then)} |                   bind:group={selectedMapping} | ||||||
|                   <!-- Even though we have a list of 'mappings' already, we still iterate over the list as to keep the original indices--> |                   name={"mappings-radio-" + config.id} | ||||||
|                   <TagRenderingMappingInput |                   value={i} | ||||||
|                     {mapping} |                   on:keypress={(e) => onInputKeypress(e)} | ||||||
|                     {tags} |                 /> | ||||||
|                     {state} |               </TagRenderingMappingInput> | ||||||
|                     {selectedElement} |             {/each} | ||||||
|                     {layer} |             {#if config.freeform?.key} | ||||||
|                     {searchTerm} |               <label class="flex gap-x-1"> | ||||||
|                     mappingIsSelected={selectedMapping === i} |                 <input | ||||||
|                   > |                   type="radio" | ||||||
|                     <input |                   bind:group={selectedMapping} | ||||||
|                       type="radio" |                   name={"mappings-radio-" + config.id} | ||||||
|                       bind:group={selectedMapping} |                   value={config.mappings?.length} | ||||||
|                       name={"mappings-radio-" + config.id} |                   on:keypress={(e) => onInputKeypress(e)} | ||||||
|                       value={i} |                 /> | ||||||
|                       on:keypress={(e) => onInputKeypress(e)} |                 <FreeformInput | ||||||
|                     /> |                   {config} | ||||||
|                   </TagRenderingMappingInput> |                   {tags} | ||||||
|                 {/each} |                   {feedback} | ||||||
|                 {#if config.freeform?.key} |                   {unit} | ||||||
|                   <label class="flex gap-x-1"> |                   {state} | ||||||
|                     <input |                   feature={selectedElement} | ||||||
|                       type="radio" |                   value={freeformInput} | ||||||
|                       bind:group={selectedMapping} |                   unvalidatedText={freeformInputUnvalidated} | ||||||
|                       name={"mappings-radio-" + config.id} |                   on:selected={() => (selectedMapping = config.mappings?.length)} | ||||||
|                       value={config.mappings?.length} |                   on:submit={onSave} | ||||||
|                       on:keypress={(e) => onInputKeypress(e)} |                 /> | ||||||
|                     /> |               </label> | ||||||
|                     <FreeformInput |  | ||||||
|                       {config} |  | ||||||
|                       {tags} |  | ||||||
|                       {feedback} |  | ||||||
|                       {unit} |  | ||||||
|                       {state} |  | ||||||
|                       feature={selectedElement} |  | ||||||
|                       value={freeformInput} |  | ||||||
|                       on:selected={() => (selectedMapping = config.mappings?.length)} |  | ||||||
|                       on:submit={onSave} |  | ||||||
|                     /> |  | ||||||
|                   </label> |  | ||||||
|                 {/if} |  | ||||||
|               </div> |  | ||||||
|             {:else if mappings !== undefined && config.multiAnswer} |  | ||||||
|               <!-- Multiple answers can be chosen: checkboxes --> |  | ||||||
|               <div class="flex flex-col"> |  | ||||||
|                 {#each config.mappings as mapping, i (mapping.then)} |  | ||||||
|                   <TagRenderingMappingInput |  | ||||||
|                     {mapping} |  | ||||||
|                     {tags} |  | ||||||
|                     {state} |  | ||||||
|                     {selectedElement} |  | ||||||
|                     {layer} |  | ||||||
|                     {searchTerm} |  | ||||||
|                     mappingIsSelected={checkedMappings[i]} |  | ||||||
|                   > |  | ||||||
|                     <input |  | ||||||
|                       type="checkbox" |  | ||||||
|                       name={"mappings-checkbox-" + config.id + "-" + i} |  | ||||||
|                       bind:checked={checkedMappings[i]} |  | ||||||
|                       on:keypress={(e) => onInputKeypress(e)} |  | ||||||
|                     /> |  | ||||||
|                   </TagRenderingMappingInput> |  | ||||||
|                 {/each} |  | ||||||
|                 {#if config.freeform?.key} |  | ||||||
|                   <label class="flex gap-x-1"> |  | ||||||
|                     <input |  | ||||||
|                       type="checkbox" |  | ||||||
|                       name={"mappings-checkbox-" + config.id + "-" + config.mappings?.length} |  | ||||||
|                       bind:checked={checkedMappings[config.mappings.length]} |  | ||||||
|                       on:keypress={(e) => onInputKeypress(e)} |  | ||||||
|                     /> |  | ||||||
|                     <FreeformInput |  | ||||||
|                       {config} |  | ||||||
|                       {tags} |  | ||||||
|                       {feedback} |  | ||||||
|                       {unit} |  | ||||||
|                       {state} |  | ||||||
|                       feature={selectedElement} |  | ||||||
|                       value={freeformInput} |  | ||||||
|                       on:submit={onSave} |  | ||||||
|                     /> |  | ||||||
|                   </label> |  | ||||||
|                 {/if} |  | ||||||
|               </div> |  | ||||||
|             {/if} |             {/if} | ||||||
|  |           </div> | ||||||
|  |         {:else if mappings !== undefined && config.multiAnswer} | ||||||
|  |           <!-- Multiple answers can be chosen: checkboxes --> | ||||||
|  |           <div class="flex flex-col"> | ||||||
|  |             {#each config.mappings as mapping, i (mapping.then)} | ||||||
|  |               <TagRenderingMappingInput | ||||||
|  |                 {mapping} | ||||||
|  |                 {tags} | ||||||
|  |                 {state} | ||||||
|  |                 {selectedElement} | ||||||
|  |                 {layer} | ||||||
|  |                 {searchTerm} | ||||||
|  |                 mappingIsSelected={checkedMappings[i]} | ||||||
|  |               > | ||||||
|  |                 <input | ||||||
|  |                   type="checkbox" | ||||||
|  |                   name={"mappings-checkbox-" + config.id + "-" + i} | ||||||
|  |                   bind:checked={checkedMappings[i]} | ||||||
|  |                   on:keypress={(e) => onInputKeypress(e)} | ||||||
|  |                 /> | ||||||
|  |               </TagRenderingMappingInput> | ||||||
|  |             {/each} | ||||||
|  |             {#if config.freeform?.key} | ||||||
|  |               <label class="flex gap-x-1"> | ||||||
|  |                 <input | ||||||
|  |                   type="checkbox" | ||||||
|  |                   name={"mappings-checkbox-" + config.id + "-" + config.mappings?.length} | ||||||
|  |                   bind:checked={checkedMappings[config.mappings.length]} | ||||||
|  |                   on:keypress={(e) => onInputKeypress(e)} | ||||||
|  |                 /> | ||||||
|  |                 <FreeformInput | ||||||
|  |                   {config} | ||||||
|  |                   {tags} | ||||||
|  |                   {feedback} | ||||||
|  |                   {unit} | ||||||
|  |                   {state} | ||||||
|  |                   feature={selectedElement} | ||||||
|  |                   value={freeformInput} | ||||||
|  |                   unvalidatedText={freeformInputUnvalidated} | ||||||
|  |                   on:submit={onSave} | ||||||
|  |                 /> | ||||||
|  |               </label> | ||||||
|  |             {/if} | ||||||
|  |           </div> | ||||||
|  |         {/if} | ||||||
|         <LoginToggle {state}> |         <LoginToggle {state}> | ||||||
|           <Loading slot="loading" /> |           <Loading slot="loading" /> | ||||||
|           <SubtleButton slot="not-logged-in" on:click={() => state?.osmConnection?.AttemptLogin()}> |           <SubtleButton slot="not-logged-in" on:click={() => state?.osmConnection?.AttemptLogin()}> | ||||||
|  | @ -378,12 +396,19 @@ | ||||||
|             <!-- TagRenderingQuestion-buttons --> |             <!-- TagRenderingQuestion-buttons --> | ||||||
|             <slot name="cancel" /> |             <slot name="cancel" /> | ||||||
|             <slot name="save-button" {selectedTags}> |             <slot name="save-button" {selectedTags}> | ||||||
|               <button |               {#if allowDeleteOfFreeform && mappings.length === 0 && $freeformInput === undefined && $freeformInputUnvalidated === ""} | ||||||
|                 on:click={onSave} |                 <button class="primary flex" on:click|stopPropagation|preventDefault={_ => onSave(_, true)}> | ||||||
|                 class={twJoin(selectedTags === undefined ? "disabled" : "button-shadow", "primary")} |                   <TrashIcon class="w-6 h-6 text-red-500" /> | ||||||
|               > |                   <Tr t={Translations.t.general.eraseValue}/> | ||||||
|                 <Tr t={Translations.t.general.save} /> |                 </button> | ||||||
|               </button> |               {:else} | ||||||
|  |                 <button | ||||||
|  |                   on:click={onSave} | ||||||
|  |                   class={twJoin(selectedTags === undefined ? "disabled" : "button-shadow", "primary")} | ||||||
|  |                 > | ||||||
|  |                   <Tr t={Translations.t.general.save} /> | ||||||
|  |                 </button> | ||||||
|  |               {/if} | ||||||
|             </slot> |             </slot> | ||||||
|           </div> |           </div> | ||||||
|           {#if UserRelatedState.SHOW_TAGS_VALUES.indexOf($showTags) >= 0 || ($showTags === "" && numberOfCs >= Constants.userJourney.tagsVisibleAt) || $featureSwitchIsTesting || $featureSwitchIsDebugging} |           {#if UserRelatedState.SHOW_TAGS_VALUES.indexOf($showTags) >= 0 || ($showTags === "" && numberOfCs >= Constants.userJourney.tagsVisibleAt) || $featureSwitchIsTesting || $featureSwitchIsDebugging} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue