[#4033] added option to duplicate fields
This commit is contained in:
@@ -45,6 +45,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
function duplicateField(fieldIndex) {
|
||||
const field = collection.schema[fieldIndex];
|
||||
if (!field) {
|
||||
return; // nothing to duplicate
|
||||
}
|
||||
|
||||
field.onMountSelect = false;
|
||||
|
||||
const clone = structuredClone(field);
|
||||
clone.id = "";
|
||||
clone.name = getUniqueFieldName(clone.name + "_copy");
|
||||
clone.onMountSelect = true;
|
||||
|
||||
collection.schema.splice(fieldIndex + 1, 0, clone);
|
||||
collection.schema = collection.schema;
|
||||
}
|
||||
|
||||
function newField(fieldType = "text") {
|
||||
const field = CommonHelper.initSchemaField({
|
||||
name: getUniqueFieldName(),
|
||||
@@ -57,14 +74,21 @@
|
||||
collection.schema = collection.schema;
|
||||
}
|
||||
|
||||
function getUniqueFieldName(base = "field") {
|
||||
let counter = "";
|
||||
function getUniqueFieldName(name = "field") {
|
||||
let result = name;
|
||||
let counter = 2;
|
||||
|
||||
while (hasFieldWithName(base + counter)) {
|
||||
++counter;
|
||||
let suffix = name.match(/[123456789]+$/)?.[0] || ""; // extract numeric suffix
|
||||
|
||||
// name without the suffix
|
||||
let base = suffix ? name.substring(0, name.length - suffix.length) : name;
|
||||
|
||||
while (hasFieldWithName(result)) {
|
||||
result = base + ((suffix << 0) + counter);
|
||||
counter++;
|
||||
}
|
||||
|
||||
return base + counter;
|
||||
return result;
|
||||
}
|
||||
|
||||
function hasFieldWithName(name) {
|
||||
@@ -138,6 +162,7 @@
|
||||
key={getSchemaFieldIndex(field)}
|
||||
bind:field
|
||||
on:remove={() => removeField(i)}
|
||||
on:duplicate={() => duplicateField(i)}
|
||||
on:rename={(e) => replaceIndexesColumn(e.detail.oldName, e.detail.newName)}
|
||||
/>
|
||||
</Draggable>
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
|
||||
function remove() {
|
||||
if (!field.id) {
|
||||
collapse();
|
||||
dispatch("remove");
|
||||
} else {
|
||||
field.toDelete = true;
|
||||
@@ -67,6 +68,13 @@
|
||||
setErrors({});
|
||||
}
|
||||
|
||||
function duplicate() {
|
||||
if (!field.toDelete) {
|
||||
collapse();
|
||||
dispatch("duplicate");
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeFieldName(name) {
|
||||
return CommonHelper.slugify(name);
|
||||
}
|
||||
@@ -211,7 +219,7 @@
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={{
|
||||
text: `Requires the field value NOT to be ${CommonHelper.zeroDefaultStr(
|
||||
field
|
||||
field,
|
||||
)}.`,
|
||||
}}
|
||||
/>
|
||||
@@ -235,22 +243,29 @@
|
||||
|
||||
{#if !field.toDelete}
|
||||
<div class="m-l-auto txt-right">
|
||||
<div class="flex-fill" />
|
||||
<div class="inline-flex flex-gap-sm flex-nowrap">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="More"
|
||||
class="btn btn-circle btn-sm btn-transparent"
|
||||
>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div tabindex="0" aria-label="More" class="btn btn-circle btn-sm btn-transparent">
|
||||
<i class="ri-more-line" />
|
||||
<Toggler
|
||||
class="dropdown dropdown-sm dropdown-upside dropdown-right dropdown-nowrap no-min-width"
|
||||
>
|
||||
<button type="button" class="dropdown-item txt-right" on:click={remove}>
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item txt-right"
|
||||
on:click|preventDefault={duplicate}
|
||||
>
|
||||
<span class="txt">Duplicate</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item txt-right"
|
||||
on:click|preventDefault={remove}
|
||||
>
|
||||
<span class="txt">Remove</span>
|
||||
</button>
|
||||
</Toggler>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
export let key = "";
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps} />
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps} />
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="optionsFooter">
|
||||
<Field class="form-field form-field-toggle" name="schema.{key}.options.convertUrls" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.options.convertUrls} />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
export let key = "";
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment let:interactive>
|
||||
<div class="separator" />
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<Field class="form-field required m-b-sm" name="schema.{key}.options.maxSize" let:uniqueId>
|
||||
<label for={uniqueId}>Max size <small>(bytes)</small></label>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
export let key = "";
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment let:interactive>
|
||||
<div class="separator" />
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment let:interactive>
|
||||
<div class="separator" />
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
export let key = "";
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove {...$$restProps}>
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-3">
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
</script>
|
||||
|
||||
<!-- shares the same options with the email field -->
|
||||
<SchemaFieldEmail bind:field {key} on:rename on:remove {...$$restProps} />
|
||||
<SchemaFieldEmail bind:field {key} on:rename on:remove on:duplicate {...$$restProps} />
|
||||
|
||||
Reference in New Issue
Block a user