multi select context menu readonly and required
This commit is contained in:
@@ -319,7 +319,7 @@ export default {
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to', 'add-custom-field', 'click-title'],
|
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to', 'add-custom-field', 'click-title', 'multi-select'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isContenteditable: false,
|
isContenteditable: false,
|
||||||
@@ -798,6 +798,8 @@ export default {
|
|||||||
this.selectedAreasRef.value.splice(this.selectedAreasRef.value.indexOf(this.area), 1)
|
this.selectedAreasRef.value.splice(this.selectedAreasRef.value.indexOf(this.area), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$emit('multi-select', e)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
@scroll-to="$emit('scroll-to', $event)"
|
@scroll-to="$emit('scroll-to', $event)"
|
||||||
@add-custom-field="$emit('add-custom-field', $event)"
|
@add-custom-field="$emit('add-custom-field', $event)"
|
||||||
@contextmenu="openAreaContextMenu($event, item.area, item.field)"
|
@contextmenu="openAreaContextMenu($event, item.area, item.field)"
|
||||||
|
@multi-select="openMultiSelectContextMenu"
|
||||||
@click-title="closeContextMenu"
|
@click-title="closeContextMenu"
|
||||||
/>
|
/>
|
||||||
<FieldArea
|
<FieldArea
|
||||||
@@ -408,6 +409,12 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.selectedAreasRef.value.length >= 2) {
|
||||||
|
this.openSelectionContextMenu(event)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|
||||||
@@ -443,6 +450,13 @@ export default {
|
|||||||
areas: this.selectedAreasRef.value
|
areas: this.selectedAreasRef.value
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
openMultiSelectContextMenu (event) {
|
||||||
|
if (this.selectedAreasRef.value.length >= 2) {
|
||||||
|
this.openSelectionContextMenu(event)
|
||||||
|
} else {
|
||||||
|
this.closeContextMenu()
|
||||||
|
}
|
||||||
|
},
|
||||||
handleSelectionCopy () {
|
handleSelectionCopy () {
|
||||||
this.$emit('copy-selected-areas')
|
this.$emit('copy-selected-areas')
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,62 @@
|
|||||||
@mousedown.stop
|
@mousedown.stop
|
||||||
@pointerdown.stop
|
@pointerdown.stop
|
||||||
>
|
>
|
||||||
|
<label
|
||||||
|
v-if="requiredFields.length"
|
||||||
|
class="field-settings-required w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:checked="isAllRequired"
|
||||||
|
:indeterminate="isMixedRequired"
|
||||||
|
type="checkbox"
|
||||||
|
class="toggle toggle-xs"
|
||||||
|
:disabled="!editable"
|
||||||
|
@change="handleToggleRequired($event.target.checked)"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<span>{{ t('required') }}</span>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
v-if="readOnlyFields.length"
|
||||||
|
class="field-settings-read-only w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:checked="isAllReadOnly"
|
||||||
|
:indeterminate="isMixedReadOnly"
|
||||||
|
type="checkbox"
|
||||||
|
class="toggle toggle-xs"
|
||||||
|
:disabled="!editable"
|
||||||
|
@change="handleToggleReadOnly($event.target.checked)"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<span>{{ t('read_only') }}</span>
|
||||||
|
</label>
|
||||||
|
<hr
|
||||||
|
v-if="requiredFields.length || readOnlyFields.length"
|
||||||
|
class="my-1 border-neutral-200"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-if="showFont"
|
||||||
|
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
|
||||||
|
@click.stop="openFontModal"
|
||||||
|
>
|
||||||
|
<IconTypography class="w-4 h-4" />
|
||||||
|
<span>{{ t('font') }}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="showCondition"
|
||||||
|
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
|
||||||
|
@click.stop="openConditionModal"
|
||||||
|
>
|
||||||
|
<IconRouteAltLeft class="w-4 h-4" />
|
||||||
|
<span>{{ t('condition') }}</span>
|
||||||
|
</button>
|
||||||
|
<hr
|
||||||
|
v-if="showFont || showCondition"
|
||||||
|
class="my-1 border-neutral-200"
|
||||||
|
>
|
||||||
<ContextSubmenu
|
<ContextSubmenu
|
||||||
:icon="IconLayoutAlignMiddle"
|
:icon="IconLayoutAlignMiddle"
|
||||||
:label="t('align')"
|
:label="t('align')"
|
||||||
@@ -61,26 +117,6 @@
|
|||||||
<span>{{ t('height') }}</span>
|
<span>{{ t('height') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</ContextSubmenu>
|
</ContextSubmenu>
|
||||||
<hr
|
|
||||||
v-if="showFont || showCondition"
|
|
||||||
class="my-1 border-neutral-200"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-if="showFont"
|
|
||||||
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
|
|
||||||
@click.stop="openFontModal"
|
|
||||||
>
|
|
||||||
<IconTypography class="w-4 h-4" />
|
|
||||||
<span>{{ t('font') }}</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-if="showCondition"
|
|
||||||
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
|
|
||||||
@click.stop="openConditionModal"
|
|
||||||
>
|
|
||||||
<IconRouteAltLeft class="w-4 h-4" />
|
|
||||||
<span>{{ t('condition') }}</span>
|
|
||||||
</button>
|
|
||||||
<hr class="my-1 border-neutral-200">
|
<hr class="my-1 border-neutral-200">
|
||||||
<button
|
<button
|
||||||
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center justify-between text-sm"
|
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center justify-between text-sm"
|
||||||
@@ -192,6 +228,24 @@ export default {
|
|||||||
return this.template.fields.find((f) => f.areas?.includes(area))
|
return this.template.fields.find((f) => f.areas?.includes(area))
|
||||||
}).filter(Boolean)
|
}).filter(Boolean)
|
||||||
},
|
},
|
||||||
|
requiredFields () {
|
||||||
|
return this.selectedFields.filter((f) => !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(f.type))
|
||||||
|
},
|
||||||
|
readOnlyFields () {
|
||||||
|
return this.selectedFields.filter((f) => ['text', 'number', 'radio', 'multiple', 'select'].includes(f.type))
|
||||||
|
},
|
||||||
|
isAllRequired () {
|
||||||
|
return this.requiredFields.every((f) => f.required)
|
||||||
|
},
|
||||||
|
isMixedRequired () {
|
||||||
|
return !this.isAllRequired && this.requiredFields.some((f) => f.required)
|
||||||
|
},
|
||||||
|
isAllReadOnly () {
|
||||||
|
return this.readOnlyFields.every((f) => f.readonly)
|
||||||
|
},
|
||||||
|
isMixedReadOnly () {
|
||||||
|
return !this.isAllReadOnly && this.readOnlyFields.some((f) => f.readonly)
|
||||||
|
},
|
||||||
isMac () {
|
isMac () {
|
||||||
return (navigator.userAgentData?.platform || navigator.platform)?.toLowerCase()?.includes('mac')
|
return (navigator.userAgentData?.platform || navigator.platform)?.toLowerCase()?.includes('mac')
|
||||||
},
|
},
|
||||||
@@ -234,6 +288,16 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
handleToggleRequired (value) {
|
||||||
|
this.requiredFields.forEach((field) => { field.required = value })
|
||||||
|
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
|
handleToggleReadOnly (value) {
|
||||||
|
this.readOnlyFields.forEach((field) => { field.readonly = value })
|
||||||
|
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
onKeyDown (event) {
|
onKeyDown (event) {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|||||||
Reference in New Issue
Block a user