add ability to draw areas for radio options
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
:class="{ 'text-[1.5vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'bg-red-100 border cursor-pointer ': submittable, 'border-red-100': !isActive && submittable, 'bg-opacity-70': !isActive && !isValueSet && submittable, 'border-red-500 border-dashed z-10': isActive && submittable, 'bg-opacity-30': (isActive || isValueSet) && submittable }"
|
:class="{ 'text-[1.5vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'bg-red-100 border cursor-pointer ': submittable, 'border-red-100': !isActive && submittable, 'bg-opacity-70': !isActive && !isValueSet && submittable, 'border-red-500 border-dashed z-10': isActive && submittable, 'bg-opacity-30': (isActive || isValueSet) && submittable }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="!isActive && !isValueSet && field.type !== 'checkbox' && submittable"
|
v-if="!isActive && !isValueSet && field.type !== 'checkbox' && submittable && !area.option_uuid"
|
||||||
class="absolute top-0 bottom-0 right-0 left-0 items-center justify-center h-full w-full"
|
class="absolute top-0 bottom-0 right-0 left-0 items-center justify-center h-full w-full"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="isActive && withLabel"
|
v-if="isActive && withLabel && !area.option_uuid"
|
||||||
class="absolute -top-7 rounded bg-base-content text-base-100 px-2 text-sm whitespace-nowrap"
|
class="absolute -top-7 rounded bg-base-content text-base-100 px-2 text-sm whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{{ field.name || fieldNames[field.type] }}
|
{{ field.name || fieldNames[field.type] }}
|
||||||
@@ -87,6 +87,44 @@
|
|||||||
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="field.type === 'radio' && area.option_uuid"
|
||||||
|
class="w-full p-[0.2vw] flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="submittable"
|
||||||
|
type="radio"
|
||||||
|
:value="false"
|
||||||
|
class="aspect-square base-radio"
|
||||||
|
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
||||||
|
:checked="modelValue && modelValue === field.options.find((o) => o.uuid === area.option_uuid)?.value"
|
||||||
|
@click="$emit('update:model-value', field.options.find((o) => o.uuid === area.option_uuid)?.value)"
|
||||||
|
>
|
||||||
|
<IconCheck
|
||||||
|
v-else-if="modelValue && modelValue === field.options.find((o) => o.uuid === area.option_uuid)?.value"
|
||||||
|
class="aspect-square"
|
||||||
|
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="field.type === 'multiple' && area.option_uuid"
|
||||||
|
class="w-full p-[0.2vw] flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="submittable"
|
||||||
|
type="checkbox"
|
||||||
|
:value="false"
|
||||||
|
class="aspect-square base-checkbox"
|
||||||
|
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
||||||
|
:checked="modelValue && modelValue.includes(field.options.find((o) => o.uuid === area.option_uuid)?.value)"
|
||||||
|
@change="updateMultipleSelectValue(field.options.find((o) => o.uuid === area.option_uuid)?.value)"
|
||||||
|
>
|
||||||
|
<IconCheck
|
||||||
|
v-else-if="modelValue && modelValue.includes(field.options.find((o) => o.uuid === area.option_uuid)?.value)"
|
||||||
|
class="aspect-square"
|
||||||
|
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="field.type === 'cells'"
|
v-else-if="field.type === 'cells'"
|
||||||
class="w-full flex items-center"
|
class="w-full flex items-center"
|
||||||
@@ -271,6 +309,23 @@ export default {
|
|||||||
this.textOverflowChars = this.$refs.textContainer.scrollHeight > this.$refs.textContainer.clientHeight ? this.modelValue.length : 0
|
this.textOverflowChars = this.$refs.textContainer.scrollHeight > this.$refs.textContainer.clientHeight ? this.modelValue.length : 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateMultipleSelectValue (value) {
|
||||||
|
if (this.modelValue?.includes(value)) {
|
||||||
|
const newValue = [...this.modelValue]
|
||||||
|
|
||||||
|
newValue.splice(newValue.indexOf(value), 1)
|
||||||
|
|
||||||
|
this.$emit('update:model-value', newValue)
|
||||||
|
} else {
|
||||||
|
const newValue = this.modelValue ? [...this.modelValue] : []
|
||||||
|
|
||||||
|
newValue.push(value)
|
||||||
|
|
||||||
|
this.$emit('update:model-value', newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
@keydown.enter.prevent="onNameEnter"
|
@keydown.enter.prevent="onNameEnter"
|
||||||
@focus="onNameFocus"
|
@focus="onNameFocus"
|
||||||
@blur="onNameBlur"
|
@blur="onNameBlur"
|
||||||
>{{ field.name || defaultName }}</span>
|
>{{ optionIndexText }} {{ field.name || defaultName }}</span>
|
||||||
<div
|
<div
|
||||||
v-if="isNameFocus && !['checkbox', 'phone'].includes(field.type)"
|
v-if="isNameFocus && !['checkbox', 'phone'].includes(field.type)"
|
||||||
class="flex items-center ml-1.5"
|
class="flex items-center ml-1.5"
|
||||||
@@ -185,6 +185,13 @@ export default {
|
|||||||
defaultName: Field.computed.defaultName,
|
defaultName: Field.computed.defaultName,
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
fieldIcons: FieldType.computed.fieldIcons,
|
fieldIcons: FieldType.computed.fieldIcons,
|
||||||
|
optionIndexText () {
|
||||||
|
if (this.area.option_uuid && this.field.options) {
|
||||||
|
return `${this.field.options.findIndex((o) => o.uuid === this.area.option_uuid) + 1}.`
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
cells () {
|
cells () {
|
||||||
const cells = []
|
const cells = []
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,7 @@
|
|||||||
:selected-submitter="selectedSubmitter"
|
:selected-submitter="selectedSubmitter"
|
||||||
class="md:hidden"
|
class="md:hidden"
|
||||||
:editable="editable"
|
:editable="editable"
|
||||||
@cancel="drawField = null"
|
@cancel="[drawField = null, drawOption = null]"
|
||||||
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
||||||
/>
|
/>
|
||||||
<FieldType
|
<FieldType
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
<p>
|
<p>
|
||||||
<button
|
<button
|
||||||
class="base-button"
|
class="base-button"
|
||||||
@click="drawField = null"
|
@click="[drawField = null, drawOption = null]"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
:default-fields="defaultFields"
|
:default-fields="defaultFields"
|
||||||
:with-sticky-submitters="withStickySubmitters"
|
:with-sticky-submitters="withStickySubmitters"
|
||||||
:editable="editable"
|
:editable="editable"
|
||||||
@set-draw="drawField = $event"
|
@set-draw="[drawField = $event.field, drawOption = $event.option]"
|
||||||
@set-drag="dragField = $event"
|
@set-drag="dragField = $event"
|
||||||
@change-submitter="selectedSubmitter = $event"
|
@change-submitter="selectedSubmitter = $event"
|
||||||
@drag-end="dragField = null"
|
@drag-end="dragField = null"
|
||||||
@@ -354,6 +354,7 @@ export default {
|
|||||||
isSaving: false,
|
isSaving: false,
|
||||||
selectedSubmitter: null,
|
selectedSubmitter: null,
|
||||||
drawField: null,
|
drawField: null,
|
||||||
|
drawOption: null,
|
||||||
dragField: null
|
dragField: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -433,6 +434,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.drawField = field
|
this.drawField = field
|
||||||
|
this.drawOption = null
|
||||||
},
|
},
|
||||||
undo () {
|
undo () {
|
||||||
if (this.undoStack.length > 1) {
|
if (this.undoStack.length > 1) {
|
||||||
@@ -482,6 +484,7 @@ export default {
|
|||||||
onKeyUp (e) {
|
onKeyUp (e) {
|
||||||
if (e.code === 'Escape') {
|
if (e.code === 'Escape') {
|
||||||
this.drawField = null
|
this.drawField = null
|
||||||
|
this.drawOption = null
|
||||||
this.selectedAreaRef.value = null
|
this.selectedAreaRef.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +531,16 @@ export default {
|
|||||||
},
|
},
|
||||||
onDraw (area) {
|
onDraw (area) {
|
||||||
if (this.drawField) {
|
if (this.drawField) {
|
||||||
|
if (this.drawOption) {
|
||||||
|
const areaWithoutOption = this.drawField.areas?.find((a) => !a.option_uuid)
|
||||||
|
|
||||||
|
if (areaWithoutOption && !this.drawField.areas.find((a) => a.option_uuid === this.drawField.options[0].uuid)) {
|
||||||
|
areaWithoutOption.option_uuid = this.drawField.options[0].uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
area.option_uuid = this.drawOption.uuid
|
||||||
|
}
|
||||||
|
|
||||||
this.drawField.areas ||= []
|
this.drawField.areas ||= []
|
||||||
this.drawField.areas.push(area)
|
this.drawField.areas.push(area)
|
||||||
|
|
||||||
@@ -536,6 +549,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.drawField = null
|
this.drawField = null
|
||||||
|
this.drawOption = null
|
||||||
|
|
||||||
this.selectedAreaRef.value = area
|
this.selectedAreaRef.value = area
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
v-if="field && !field.areas.length"
|
v-if="field && !field.areas.length"
|
||||||
title="Draw"
|
title="Draw"
|
||||||
class="relative cursor-pointer text-transparent group-hover:text-base-content"
|
class="relative cursor-pointer text-transparent group-hover:text-base-content"
|
||||||
@click="$emit('set-draw', field)"
|
@click="$emit('set-draw', { field })"
|
||||||
>
|
>
|
||||||
<IconNewSection
|
<IconNewSection
|
||||||
:width="18"
|
:width="18"
|
||||||
@@ -151,11 +151,11 @@
|
|||||||
Page {{ area.page + 1 }}
|
Page {{ area.page + 1 }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li v-if="!field.areas?.length || !['radio', 'multiple'].includes(field.type)">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="text-sm py-1 px-2"
|
class="text-sm py-1 px-2"
|
||||||
@click.prevent="$emit('set-draw', field)"
|
@click.prevent="$emit('set-draw', { field })"
|
||||||
>
|
>
|
||||||
<IconNewSection
|
<IconNewSection
|
||||||
:width="20"
|
:width="20"
|
||||||
@@ -205,16 +205,39 @@
|
|||||||
<span class="text-sm w-3.5">
|
<span class="text-sm w-3.5">
|
||||||
{{ index + 1 }}.
|
{{ index + 1 }}.
|
||||||
</span>
|
</span>
|
||||||
|
<div
|
||||||
|
v-if="['radio', 'multiple'].includes(field.type) && (index > 0 || field.areas.find((a) => a.option_uuid)) && !field.areas.find((a) => a.option_uuid === option.uuid)"
|
||||||
|
class="items-center flex w-full"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-model="option.value"
|
||||||
|
class="w-full input input-primary input-xs text-sm bg-transparent !pr-7 -mr-6"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
@blur="save"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
title="Draw"
|
||||||
|
@click.prevent="$emit('set-draw', { field, option })"
|
||||||
|
>
|
||||||
|
<IconNewSection
|
||||||
|
:width="18"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<input
|
<input
|
||||||
|
v-else
|
||||||
v-model="option.value"
|
v-model="option.value"
|
||||||
class="w-full input input-primary input-xs text-sm bg-transparent"
|
class="w-full input input-primary input-xs text-sm bg-transparent"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
|
@focus="maybeFocusOnOptionArea(option)"
|
||||||
@blur="save"
|
@blur="save"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="text-sm w-3.5"
|
class="text-sm w-3.5"
|
||||||
@click="[field.options.splice(index, 1), save()]"
|
@click="removeOption(option)"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
@@ -248,7 +271,7 @@ export default {
|
|||||||
IconCopy,
|
IconCopy,
|
||||||
FieldType
|
FieldType
|
||||||
},
|
},
|
||||||
inject: ['template', 'save', 'backgroundColor'],
|
inject: ['template', 'save', 'backgroundColor', 'selectedAreaRef'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -306,6 +329,13 @@ export default {
|
|||||||
}, 1)
|
}, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
maybeFocusOnOptionArea (option) {
|
||||||
|
const area = this.field.areas.find((a) => a.option_uuid === option.uuid)
|
||||||
|
|
||||||
|
if (area) {
|
||||||
|
this.selectedAreaRef.value = area
|
||||||
|
}
|
||||||
|
},
|
||||||
scrollToFirstArea () {
|
scrollToFirstArea () {
|
||||||
return this.field.areas?.[0] && this.$emit('scroll-to', this.field.areas[0])
|
return this.field.areas?.[0] && this.$emit('scroll-to', this.field.areas[0])
|
||||||
},
|
},
|
||||||
@@ -317,6 +347,12 @@ export default {
|
|||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
|
removeOption (option) {
|
||||||
|
this.field.options.splice(this.field.options.indexOf(option), 1)
|
||||||
|
this.field.areas.splice(this.field.areas.findIndex((a) => a.option_uuid === option.uuid), 1)
|
||||||
|
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
maybeUpdateOptions () {
|
maybeUpdateOptions () {
|
||||||
delete this.field.default_value
|
delete this.field.default_value
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,16 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% elsif field['type'] == 'checkbox' %>
|
<% elsif field['type'] == 'checkbox' %>
|
||||||
<div class="w-full p-[0.2vw] flex items-center justify-center">
|
<div class="w-full flex items-center justify-center">
|
||||||
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
||||||
</div>
|
</div>
|
||||||
|
<% elsif field['type'].in?(%w[multiple radio]) && area['option_uuid'] %>
|
||||||
|
<% option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] } %>
|
||||||
|
<% if option && Array.wrap(value).include?(option['value']) %>
|
||||||
|
<div class="w-full flex items-center justify-center">
|
||||||
|
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
<% elsif field['type'] == 'cells' %>
|
<% elsif field['type'] == 'cells' %>
|
||||||
<% cell_width = area['cell_w'] / area['w'] * 100 %>
|
<% cell_width = area['cell_w'] / area['w'] * 100 %>
|
||||||
<div class="w-full flex items-center">
|
<div class="w-full flex items-center">
|
||||||
|
|||||||
@@ -124,7 +124,13 @@ module Submissions
|
|||||||
layouter.fit(items, area['w'] * width, height_diff.positive? ? box_height : area['h'] * height)
|
layouter.fit(items, area['w'] * width, height_diff.positive? ? box_height : area['h'] * height)
|
||||||
.draw(canvas, (area['x'] * width) + TEXT_LEFT_MARGIN,
|
.draw(canvas, (area['x'] * width) + TEXT_LEFT_MARGIN,
|
||||||
height - (area['y'] * height) + height_diff - TEXT_TOP_MARGIN)
|
height - (area['y'] * height) + height_diff - TEXT_TOP_MARGIN)
|
||||||
when 'checkbox'
|
when ->(type) { type == 'checkbox' || (type.in?(%w[multiple radio]) && area['option_uuid'].present?) }
|
||||||
|
if field['type'].in?(%w[multiple radio])
|
||||||
|
option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] }
|
||||||
|
|
||||||
|
value = Array.wrap(value).include?(option['value'])
|
||||||
|
end
|
||||||
|
|
||||||
next unless value == true
|
next unless value == true
|
||||||
|
|
||||||
scale = [(area['w'] * width) / PdfIcons::WIDTH, (area['h'] * height) / PdfIcons::HEIGHT].min
|
scale = [(area['w'] * width) / PdfIcons::WIDTH, (area['h'] * height) / PdfIcons::HEIGHT].min
|
||||||
|
|||||||
Reference in New Issue
Block a user