forked from MapComplete/MapComplete
Feature: allow to remove an answer (in most cases), fix #2008
This commit is contained in:
parent
7565f13e39
commit
55c89085a3
8 changed files with 181 additions and 86 deletions
|
@ -12,11 +12,15 @@
|
|||
</script>
|
||||
|
||||
{#if !onlyLink}
|
||||
<Popup {shown} {bodyPadding} {fullscreen}/>
|
||||
<Popup {shown} {bodyPadding} {fullscreen}>
|
||||
<slot name="header" slot="header" />
|
||||
<slot />
|
||||
<slot name="footer" slot="footer" />
|
||||
</Popup>
|
||||
{:else}
|
||||
<button class="as-link sidebar-button" on:click={() => shown.setData(true)}>
|
||||
<slot name="link">
|
||||
<slot name="header" />
|
||||
<slot name="header" />
|
||||
</slot>
|
||||
</button>
|
||||
{/if}
|
||||
|
@ -27,9 +31,9 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
:global(.page-header svg) {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
:global(.page-header svg) {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<Modal open={_shown} on:close={() => shown.set(false)} outsideclose
|
||||
size="xl"
|
||||
dismissable={false}
|
||||
dismissable={false}P
|
||||
{defaultClass} {bodyClass} {dialogClass} {headerClass}
|
||||
color="none">
|
||||
<h1 slot="header" class="page-header w-full">
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
import Markdown from "../../Base/Markdown.svelte"
|
||||
import { Utils } from "../../../Utils"
|
||||
import type { UploadableTag } from "../../../Logic/Tags/TagTypes"
|
||||
import { Modal } from "flowbite-svelte"
|
||||
import Popup from "../../Base/Popup.svelte"
|
||||
import If from "../../Base/If.svelte"
|
||||
|
||||
export let config: TagRenderingConfig
|
||||
export let tags: UIEventSource<Record<string, string>>
|
||||
|
@ -48,6 +51,8 @@
|
|||
let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined)
|
||||
|
||||
let unit: Unit = layer?.units?.find((unit) => unit.appliesToKeys.has(config.freeform?.key))
|
||||
let isKnown = tags.mapD(tags => config.GetRenderValue(tags) !== undefined)
|
||||
let matchesEmpty = config.GetRenderValue({}) !== undefined
|
||||
|
||||
// Will be bound if a freeform is available
|
||||
let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key])
|
||||
|
@ -59,6 +64,12 @@
|
|||
*/
|
||||
let checkedMappings: boolean[]
|
||||
|
||||
/**
|
||||
* IF set: we can remove the current answer by deleting all those keys
|
||||
*/
|
||||
let settableKeys = config.removeToSetUnknown()
|
||||
let unknownModal = new UIEventSource(false)
|
||||
|
||||
let searchTerm: UIEventSource<string> = new UIEventSource("")
|
||||
|
||||
let dispatch = createEventDispatcher<{
|
||||
|
@ -80,7 +91,7 @@
|
|||
return !m.hideInAnswer.matchesProperties(tgs)
|
||||
})
|
||||
selectedMapping = mappings?.findIndex(
|
||||
(mapping) => mapping.if.matchesProperties(tgs) || mapping.alsoShowIf?.matchesProperties(tgs)
|
||||
(mapping) => mapping.if.matchesProperties(tgs) || mapping.alsoShowIf?.matchesProperties(tgs),
|
||||
)
|
||||
if (selectedMapping < 0) {
|
||||
selectedMapping = undefined
|
||||
|
@ -142,7 +153,6 @@
|
|||
|
||||
let usedKeys: string[] = Utils.Dedup(config.usedTags().flatMap((t) => t.usedKeys()))
|
||||
|
||||
let keysToDeleteOnUnknown = config.settableKeys()
|
||||
/**
|
||||
* The 'minimalTags' is a subset of the tags of the feature, only containing the values relevant for this object.
|
||||
* The main goal is to be stable and only 'ping' when an actual change is relevant
|
||||
|
@ -189,7 +199,7 @@
|
|||
if (freeformValue?.length > 0) {
|
||||
selectedMapping = config.mappings.length
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
$: {
|
||||
|
@ -207,7 +217,7 @@
|
|||
$freeformInput,
|
||||
selectedMapping,
|
||||
checkedMappings,
|
||||
tags.data
|
||||
tags.data,
|
||||
)
|
||||
if (featureSwitchIsDebugging?.data) {
|
||||
console.log(
|
||||
|
@ -219,7 +229,7 @@
|
|||
currentTags: tags.data,
|
||||
},
|
||||
" --> ",
|
||||
selectedTags
|
||||
selectedTags,
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -241,7 +251,7 @@
|
|||
selectedTags = new And([...selectedTags.and, ...extraTagsArray])
|
||||
} else {
|
||||
console.error(
|
||||
"selectedTags is not of type Tag or And, it is a " + JSON.stringify(selectedTags)
|
||||
"selectedTags is not of type Tag or And, it is a " + JSON.stringify(selectedTags),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -310,9 +320,24 @@
|
|||
onDestroy(
|
||||
state.osmConnection?.userDetails?.addCallbackAndRun((ud) => {
|
||||
numberOfCs = ud.csCount
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function clearAnswer() {
|
||||
const tagsToSet = settableKeys.map(k => new Tag(k, ""))
|
||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, {
|
||||
theme: tags.data["_orig_theme"] ?? state.layout.id,
|
||||
changeType: "answer",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
selectedMapping = undefined
|
||||
selectedTags = undefined
|
||||
change
|
||||
.CreateChangeDescriptions()
|
||||
.then((changes) => state.changes.applyChanges(changes))
|
||||
.catch(console.error)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if question !== undefined}
|
||||
|
@ -491,36 +516,74 @@
|
|||
<Tr t={$feedback} />
|
||||
</div>
|
||||
{/if}
|
||||
<!--{#if keysToDeleteOnUnknown?.some(k => !! $tags[k])}
|
||||
Mark as unknown (delete {keysToDeleteOnUnknown?.filter(k => !! $tags[k]).join(";")})
|
||||
{/if}-->
|
||||
|
||||
|
||||
<Popup shown={unknownModal}>
|
||||
<h2 slot="header">
|
||||
<Tr t={Translations.t.unknown.title} />
|
||||
</h2>
|
||||
<Tr t={Translations.t.unknown.explanation} />
|
||||
<If condition={state.userRelatedState.showTags.map(v => v === "yes" || v === "full" || v === "always")}>
|
||||
<div class="subtle">
|
||||
<Tr t={Translations.t.unknown.removedKeys}/>
|
||||
{#each settableKeys as key}
|
||||
<code>
|
||||
<del>
|
||||
{key}
|
||||
</del>
|
||||
</code>
|
||||
{/each}
|
||||
</div>
|
||||
</If>
|
||||
<div class="flex justify-end w-full" slot="footer">
|
||||
<button on:click={() => unknownModal.set(false)}>
|
||||
<Tr t={Translations.t.unknown.keep} />
|
||||
</button>
|
||||
<button class="primary" on:click={() => {unknownModal.set(false); clearAnswer()}}>
|
||||
<Tr t={Translations.t.unknown.clear} />
|
||||
</button>
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
<div
|
||||
class="sticky bottom-0 flex flex-wrap-reverse items-stretch justify-end sm:flex-nowrap"
|
||||
class="sticky bottom-0 flex justify-between flex-wrap"
|
||||
style="z-index: 11"
|
||||
>
|
||||
<!-- TagRenderingQuestion-buttons -->
|
||||
<slot name="cancel" />
|
||||
<slot name="save-button" {selectedTags}>
|
||||
{#if config.freeform?.key && !checkedMappings?.some((m) => m) && !$freeformInput && !$freeformInputUnvalidated && $tags[config.freeform.key]}
|
||||
<button
|
||||
class="primary flex"
|
||||
on:click|stopPropagation|preventDefault={() => onSave()}
|
||||
>
|
||||
<TrashIcon class="h-6 w-6 text-red-500" />
|
||||
<Tr t={Translations.t.general.eraseValue} />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => onSave()}
|
||||
class={twJoin(
|
||||
|
||||
{#if settableKeys && $isKnown && !matchesEmpty }
|
||||
<button class="as-link small text-sm" on:click={() => unknownModal.set(true)}>
|
||||
<Tr t={Translations.t.unknown.markUnknown} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
|
||||
<div class="flex flex-wrap-reverse items-stretch justify-end sm:flex-nowrap self-end flex-grow">
|
||||
|
||||
<!-- TagRenderingQuestion-buttons -->
|
||||
<slot name="cancel" />
|
||||
<slot name="save-button" {selectedTags}>
|
||||
{#if config.freeform?.key && !checkedMappings?.some((m) => m) && !$freeformInput && !$freeformInputUnvalidated && $tags[config.freeform.key]}
|
||||
<button
|
||||
class="primary flex"
|
||||
on:click|stopPropagation|preventDefault={() => onSave()}
|
||||
>
|
||||
<TrashIcon class="h-6 w-6 text-red-500" />
|
||||
<Tr t={Translations.t.general.eraseValue} />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => onSave()}
|
||||
class={twJoin(
|
||||
selectedTags === undefined ? "disabled" : "button-shadow",
|
||||
"primary"
|
||||
)}
|
||||
>
|
||||
<Tr t={Translations.t.general.save} />
|
||||
</button>
|
||||
{/if}
|
||||
</slot>
|
||||
>
|
||||
<Tr t={Translations.t.general.save} />
|
||||
</button>
|
||||
{/if}
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{#if UserRelatedState.SHOW_TAGS_VALUES.indexOf($showTags) >= 0 || ($showTags === "" && numberOfCs >= Constants.userJourney.tagsVisibleAt) || $featureSwitchIsTesting || $featureSwitchIsDebugging}
|
||||
<span class="flex flex-wrap justify-between">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue