forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
423618847b
334 changed files with 9307 additions and 6025 deletions
|
|
@ -55,7 +55,7 @@
|
|||
|
||||
for (const preset of layer.presets) {
|
||||
const tags = TagUtils.KVtoProperties(preset.tags ?? [])
|
||||
if(preset.preciseInput.snapToLayers){
|
||||
if (preset.preciseInput.snapToLayers) {
|
||||
tags["_referencing_ways"] = '["way/-1"]'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
import type { MapProperties } from "../../Models/MapProperties"
|
||||
import type { Feature, Point } from "geojson"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import LocationInput from "../InputElement/Helpers/LocationInput.svelte"
|
||||
import OpenBackgroundSelectorButton from "../BigComponents/OpenBackgroundSelectorButton.svelte"
|
||||
import If from "../Base/If.svelte"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
|
@ -19,6 +18,8 @@
|
|||
import ChevronLeft from "@babeard/svelte-heroicons/solid/ChevronLeft"
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import Icon from "../Map/Icon.svelte"
|
||||
import NewPointLocationInput from "../BigComponents/NewPointLocationInput.svelte"
|
||||
import type { WayId } from "../../Models/OsmFeature"
|
||||
|
||||
export let state: ThemeViewState
|
||||
|
||||
|
|
@ -34,20 +35,22 @@
|
|||
|
||||
let newLocation = new UIEventSource<{ lon: number; lat: number }>(undefined)
|
||||
|
||||
function initMapProperties() {
|
||||
let snappedTo = new UIEventSource<WayId | undefined>(undefined)
|
||||
|
||||
function initMapProperties(reason: MoveReason) {
|
||||
return <any>{
|
||||
allowMoving: new UIEventSource(true),
|
||||
allowRotating: new UIEventSource(false),
|
||||
allowZooming: new UIEventSource(true),
|
||||
bounds: new UIEventSource(undefined),
|
||||
location: new UIEventSource({ lon, lat }),
|
||||
minzoom: new UIEventSource($reason.minZoom),
|
||||
minzoom: new UIEventSource(reason.minZoom),
|
||||
rasterLayer: state.mapProperties.rasterLayer,
|
||||
zoom: new UIEventSource($reason?.startZoom ?? 16),
|
||||
zoom: new UIEventSource(reason?.startZoom ?? 16),
|
||||
}
|
||||
}
|
||||
|
||||
let moveWizardState = new MoveWizardState(id, layer.allowMove, state)
|
||||
let moveWizardState = new MoveWizardState(id, layer.allowMove, layer, state)
|
||||
if (moveWizardState.reasons.length === 1) {
|
||||
reason.setData(moveWizardState.reasons[0])
|
||||
}
|
||||
|
|
@ -55,8 +58,8 @@
|
|||
let currentMapProperties: MapProperties = undefined
|
||||
</script>
|
||||
|
||||
<LoginToggle {state}>
|
||||
{#if moveWizardState.reasons.length > 0}
|
||||
{#if moveWizardState.reasons.length > 0}
|
||||
<LoginToggle {state}>
|
||||
{#if $notAllowed}
|
||||
<div class="m-2 flex rounded-lg bg-gray-200 p-2">
|
||||
<Move_not_allowed class="m-2 h-8 w-8" />
|
||||
|
|
@ -79,7 +82,7 @@
|
|||
<span class="flex flex-col p-2">
|
||||
{#if currentStep === "reason" && moveWizardState.reasons.length > 1}
|
||||
{#each moveWizardState.reasons as reasonSpec}
|
||||
<button
|
||||
<button class="flex justify-start"
|
||||
on:click={() => {
|
||||
reason.setData(reasonSpec)
|
||||
currentStep = "pick_location"
|
||||
|
|
@ -91,10 +94,16 @@
|
|||
{/each}
|
||||
{:else if currentStep === "pick_location" || currentStep === "reason"}
|
||||
<div class="relative h-64 w-full">
|
||||
<LocationInput
|
||||
mapProperties={(currentMapProperties = initMapProperties())}
|
||||
<NewPointLocationInput
|
||||
mapProperties={(currentMapProperties = initMapProperties($reason))}
|
||||
value={newLocation}
|
||||
initialCoordinate={{ lon, lat }}
|
||||
{state}
|
||||
coordinate={{ lon, lat }}
|
||||
{snappedTo}
|
||||
maxSnapDistance={$reason.maxSnapDistance ?? 5}
|
||||
snapToLayers={$reason.snapTo}
|
||||
targetLayer={layer}
|
||||
dontShow={[id]}
|
||||
/>
|
||||
<div class="absolute bottom-0 left-0">
|
||||
<OpenBackgroundSelectorButton {state} />
|
||||
|
|
@ -114,7 +123,7 @@
|
|||
<button
|
||||
class="primary w-full"
|
||||
on:click={() => {
|
||||
moveWizardState.moveFeature(newLocation.data, reason.data, featureToMove)
|
||||
moveWizardState.moveFeature(newLocation.data, snappedTo.data, reason.data, featureToMove)
|
||||
currentStep = "moved"
|
||||
}}
|
||||
>
|
||||
|
|
@ -153,5 +162,5 @@
|
|||
</span>
|
||||
</AccordionSingle>
|
||||
{/if}
|
||||
{/if}
|
||||
</LoginToggle>
|
||||
</LoginToggle>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import { Feature, Point } from "geojson"
|
|||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import Relocation from "../../assets/svg/Relocation.svelte"
|
||||
import Location from "../../assets/svg/Location.svelte"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { WayId } from "../../Models/OsmFeature"
|
||||
|
||||
export interface MoveReason {
|
||||
text: Translation | string
|
||||
|
|
@ -24,25 +26,40 @@ export interface MoveReason {
|
|||
startZoom: number
|
||||
minZoom: number
|
||||
eraseAddressFields: false | boolean
|
||||
/**
|
||||
* Snap to these layers
|
||||
*/
|
||||
snapTo?: string[]
|
||||
maxSnapDistance?: number
|
||||
}
|
||||
|
||||
export class MoveWizardState {
|
||||
public readonly reasons: ReadonlyArray<MoveReason>
|
||||
|
||||
public readonly moveDisallowedReason = new UIEventSource<Translation>(undefined)
|
||||
private readonly layer: LayerConfig
|
||||
private readonly _state: SpecialVisualizationState
|
||||
private readonly featureToMoveId: string
|
||||
|
||||
constructor(id: string, options: MoveConfig, state: SpecialVisualizationState) {
|
||||
/**
|
||||
* Initialize the movestate for the feature of the given ID
|
||||
* @param id of the feature that should be moved
|
||||
* @param options
|
||||
* @param layer
|
||||
* @param state
|
||||
*/
|
||||
constructor(id: string, options: MoveConfig, layer: LayerConfig, state: SpecialVisualizationState) {
|
||||
this.layer = layer
|
||||
this._state = state
|
||||
this.reasons = MoveWizardState.initReasons(options)
|
||||
this.featureToMoveId = id
|
||||
this.reasons = this.initReasons(options)
|
||||
if (this.reasons.length > 0) {
|
||||
this.checkIsAllowed(id)
|
||||
}
|
||||
}
|
||||
|
||||
private static initReasons(options: MoveConfig): MoveReason[] {
|
||||
private initReasons(options: MoveConfig): MoveReason[] {
|
||||
const t = Translations.t.move
|
||||
|
||||
const reasons: MoveReason[] = []
|
||||
if (options.enableRelocation) {
|
||||
reasons.push({
|
||||
|
|
@ -72,20 +89,52 @@ export class MoveWizardState {
|
|||
eraseAddressFields: false,
|
||||
})
|
||||
}
|
||||
|
||||
const tags = this._state.featureProperties.getStore(this.featureToMoveId).data
|
||||
const matchingPresets = this.layer.presets.filter(preset => preset.preciseInput.snapToLayers && new And(preset.tags).matchesProperties(tags))
|
||||
const matchingPreset = matchingPresets.flatMap(pr => pr.preciseInput?.snapToLayers)
|
||||
for (const layerId of matchingPreset) {
|
||||
const snapOntoLayer = this._state.layout.getLayer(layerId)
|
||||
const text = <Translation> t.reasons.reasonSnapTo.PartialSubsTr("name", snapOntoLayer.snapName)
|
||||
reasons.push({
|
||||
text,
|
||||
invitingText: text,
|
||||
icon: "snap",
|
||||
changesetCommentValue: "snap",
|
||||
lockBounds: true,
|
||||
includeSearch: false,
|
||||
background: "photo",
|
||||
startZoom: 19,
|
||||
minZoom: 16,
|
||||
eraseAddressFields: false,
|
||||
snapTo: [snapOntoLayer.id],
|
||||
maxSnapDistance: 5,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return reasons
|
||||
}
|
||||
|
||||
public async moveFeature(
|
||||
loc: { lon: number; lat: number },
|
||||
snappedTo: WayId,
|
||||
reason: MoveReason,
|
||||
featureToMove: Feature<Point>
|
||||
featureToMove: Feature<Point>,
|
||||
) {
|
||||
const state = this._state
|
||||
if(snappedTo !== undefined){
|
||||
this.moveDisallowedReason.set(Translations.t.move.partOfAWay)
|
||||
}
|
||||
await state.changes.applyAction(
|
||||
new ChangeLocationAction(featureToMove.properties.id, [loc.lon, loc.lat], {
|
||||
reason: reason.changesetCommentValue,
|
||||
theme: state.layout.id,
|
||||
})
|
||||
new ChangeLocationAction(state,
|
||||
featureToMove.properties.id,
|
||||
[loc.lon, loc.lat],
|
||||
snappedTo,
|
||||
{
|
||||
reason: reason.changesetCommentValue,
|
||||
theme: state.layout.id,
|
||||
}),
|
||||
)
|
||||
featureToMove.properties._lat = loc.lat
|
||||
featureToMove.properties._lon = loc.lon
|
||||
|
|
@ -104,8 +153,8 @@ export class MoveWizardState {
|
|||
{
|
||||
changeType: "relocated",
|
||||
theme: state.layout.id,
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@
|
|||
>([])
|
||||
|
||||
async function calculateQuestions() {
|
||||
console.log("Applying questions to ask")
|
||||
const qta = questionsToAsk.data
|
||||
firstQuestion.setData(undefined)
|
||||
//allQuestionsToAsk.setData([])
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@
|
|||
{state}
|
||||
{layer}
|
||||
on:saved={() => (editMode = false)}
|
||||
allowDeleteOfFreeform={true}
|
||||
>
|
||||
<button
|
||||
slot="cancel"
|
||||
|
|
|
|||
|
|
@ -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>>
|
||||
|
|
@ -43,13 +46,13 @@
|
|||
export let selectedTags: UploadableTag = undefined
|
||||
export let extraTags: UIEventSource<Record<string, string>> = new UIEventSource({})
|
||||
|
||||
export let allowDeleteOfFreeform: boolean = true
|
||||
|
||||
export let clss = "interactive border-interactive"
|
||||
|
||||
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])
|
||||
|
|
@ -61,6 +64,12 @@
|
|||
*/
|
||||
let checkedMappings: boolean[]
|
||||
|
||||
/**
|
||||
* IF set: we can remove the current answer by deleting all those keys
|
||||
*/
|
||||
let settableKeys = tags.mapD(tags => config.removeToSetUnknown(layer, tags))
|
||||
let unknownModal = new UIEventSource(false)
|
||||
|
||||
let searchTerm: UIEventSource<string> = new UIEventSource("")
|
||||
|
||||
let dispatch = createEventDispatcher<{
|
||||
|
|
@ -82,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
|
||||
|
|
@ -144,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
|
||||
|
|
@ -191,13 +199,12 @@
|
|||
if (freeformValue?.length > 0) {
|
||||
selectedMapping = config.mappings.length
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
$: {
|
||||
if (
|
||||
config.freeform?.key &&
|
||||
allowDeleteOfFreeform &&
|
||||
!$freeformInput &&
|
||||
!$freeformInputUnvalidated &&
|
||||
!checkedMappings?.some((m) => m) &&
|
||||
|
|
@ -210,7 +217,7 @@
|
|||
$freeformInput,
|
||||
selectedMapping,
|
||||
checkedMappings,
|
||||
tags.data
|
||||
tags.data,
|
||||
)
|
||||
if (featureSwitchIsDebugging?.data) {
|
||||
console.log(
|
||||
|
|
@ -222,7 +229,7 @@
|
|||
currentTags: tags.data,
|
||||
},
|
||||
" --> ",
|
||||
selectedTags
|
||||
selectedTags,
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -244,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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -313,9 +320,24 @@
|
|||
onDestroy(
|
||||
state.osmConnection?.userDetails?.addCallbackAndRun((ud) => {
|
||||
numberOfCs = ud.csCount
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function clearAnswer() {
|
||||
const tagsToSet = settableKeys.data.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}
|
||||
|
|
@ -324,7 +346,7 @@
|
|||
class="relative flex flex-col overflow-y-auto px-2"
|
||||
style="max-height: 75vh"
|
||||
on:submit|preventDefault={() => {
|
||||
/*onSave(); This submit is not needed and triggers to early, causing bugs: see #1808*/
|
||||
/*onSave(); This submit is not needed and triggers too early, causing bugs: see #1808*/
|
||||
}}
|
||||
>
|
||||
<fieldset>
|
||||
|
|
@ -386,7 +408,7 @@
|
|||
/>
|
||||
{:else if config.mappings !== undefined && !config.multiAnswer}
|
||||
<!-- Simple radiobuttons as mapping -->
|
||||
<div class="flex flex-col no-bold">
|
||||
<div class="no-bold 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
|
||||
|
|
@ -401,7 +423,7 @@
|
|||
>
|
||||
<input
|
||||
type="radio"
|
||||
class="self-center mr-1"
|
||||
class="mr-1 self-center"
|
||||
bind:group={selectedMapping}
|
||||
name={"mappings-radio-" + config.id}
|
||||
value={i}
|
||||
|
|
@ -413,7 +435,7 @@
|
|||
<label class="flex gap-x-1">
|
||||
<input
|
||||
type="radio"
|
||||
class="self-center mr-1"
|
||||
class="mr-1 self-center"
|
||||
bind:group={selectedMapping}
|
||||
name={"mappings-radio-" + config.id}
|
||||
value={config.mappings?.length}
|
||||
|
|
@ -436,7 +458,7 @@
|
|||
</div>
|
||||
{:else if config.mappings !== undefined && config.multiAnswer}
|
||||
<!-- Multiple answers can be chosen: checkboxes -->
|
||||
<div class="flex flex-col no-bold">
|
||||
<div class="no-bold flex flex-col">
|
||||
{#each config.mappings as mapping, i (mapping.then)}
|
||||
<TagRenderingMappingInput
|
||||
{mapping}
|
||||
|
|
@ -450,7 +472,7 @@
|
|||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="self-center mr-1"
|
||||
class="mr-1 self-center"
|
||||
name={"mappings-checkbox-" + config.id + "-" + i}
|
||||
bind:checked={checkedMappings[i]}
|
||||
on:keypress={(e) => onInputKeypress(e)}
|
||||
|
|
@ -461,7 +483,7 @@
|
|||
<label class="flex gap-x-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="self-center mr-1"
|
||||
class="mr-1 self-center"
|
||||
name={"mappings-checkbox-" + config.id + "-" + config.mappings?.length}
|
||||
bind:checked={checkedMappings[config.mappings.length]}
|
||||
on:keypress={(e) => onInputKeypress(e)}
|
||||
|
|
@ -494,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 && allowDeleteOfFreeform && !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">
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
export let selectedTags: UploadableTag = undefined
|
||||
export let extraTags: UIEventSource<Record<string, string>> = new UIEventSource({})
|
||||
|
||||
export let allowDeleteOfFreeform: boolean = true
|
||||
|
||||
let dynamicConfig = TagRenderingConfigUtils.withNameSuggestionIndex(config, tags, selectedElement)
|
||||
</script>
|
||||
|
||||
|
|
@ -40,7 +38,6 @@
|
|||
{selectedElement}
|
||||
{layer}
|
||||
{selectedTags}
|
||||
{allowDeleteOfFreeform}
|
||||
{extraTags}
|
||||
>
|
||||
<slot name="cancel" slot="cancel" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue