PluginProbe
The Innovative Form Builder – IvyForms / 0.7
The Innovative Form Builder – IvyForms v0.7
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / admin / entries / entry-page / section / EntryPageSectionContent.vue

EntryPageSectionContent.vue in The Innovative Form Builder – IvyForms 0.7, at frontend/src/views/admin/entries/entry-page/section/EntryPageSectionContent.vue

170 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template class="ivyforms-pr-20">
2 <div class="ivyforms-entry-page-section-title">
3 <span class="medium-18">
4 {{ getLabel('user_information') }}
5 </span>
6
7 <IvyCheckbox v-model="showEmptyFields" priority="secondary" type="checkmark">
8 {{ getLabel('show_empty_fields') }}
9 </IvyCheckbox>
10 </div>
11
12 <div class="ivyforms-entry-page-section-content ivyforms-mt-24">
13 <table class="ivyforms-entry-table">
14 <tbody>
15 <tr v-for="field in filteredFields" :key="field.id">
16 <td class="ivyforms-key-column medium-14">
17 {{ getFieldLabel(field) || '' }}
18 </td>
19 <!-- HTML fields with DOMPurify sanitization -->
20 <td v-if="shouldRenderAsHtml(field)" class="ivyforms-value-column regular-14">
21 <SafeHTML :html="getFieldDisplayValue(field)" :field-type="getFormField(field)?.type" />
22 </td>
23 <!-- Regular text fields -->
24 <td v-else class="ivyforms-value-column regular-14">{{ getFieldDisplayValue(field) }}</td>
25 </tr>
26 </tbody>
27 </table>
28 </div>
29 </template>
30
31 <script setup lang="ts">
32 import { ref, computed, watch } from 'vue'
33 import { useEntry } from '@/stores/useEntry.ts'
34 import { useLabels } from '@/composables/useLabels.ts'
35 import { useFormBuilder } from '@/stores/useFormBuilder.ts'
36 import api from '@/composables/IvyFormAPI.ts'
37 import SafeHTML from '@/views/_components/SafeHTML.vue'
38
39 const formBuilderStore = useFormBuilder()
40 const showEmptyFields = ref(false)
41 const entryStore = useEntry()
42 const { getLabel } = useLabels()
43
44 const fieldsLoading = ref(false)
45
46 const filteredFields = computed(() => {
47 // Only include fields whose corresponding form field does not have a parentId
48 return entryStore.entryFields.filter((field) => {
49 const fieldId =
50 typeof field === 'object' && field !== null ? (field.fieldId ?? field.id) : field
51 const formField = formBuilderStore.fields?.find((f) => f.id == fieldId)
52 if (!formField || formField.parentId) return false
53 // If showEmptyFields is off, omit empty values (null or empty string)
54 if (!showEmptyFields.value && (field.fieldValue === null || field.fieldValue === ''))
55 return false
56 return true
57 })
58 })
59
60 // Watch for entry to load and load form fields
61 watch(
62 () => entryStore.entry,
63 async (entry) => {
64 if (
65 entry &&
66 entry.formId &&
67 (!formBuilderStore.fields || formBuilderStore.fields.length === 0)
68 ) {
69 fieldsLoading.value = true
70 await formBuilderStore.loadForm(entry.formId.toString())
71 fieldsLoading.value = false
72 }
73 },
74 { immediate: true },
75 )
76
77 const getFieldLabel = (field) => {
78 const fieldId = typeof field === 'object' && field !== null ? (field.fieldId ?? field.id) : field
79 const formField = formBuilderStore.fields?.find((f) => f.id == fieldId)
80 return formField ? formField.label : ''
81 }
82
83 const getFormField = (field) => {
84 const fieldId = typeof field === 'object' && field !== null ? (field.fieldId ?? field.id) : field
85 return formBuilderStore.fields?.find((f) => f.id == fieldId)
86 }
87
88 const shouldRenderAsHtml = (field) => {
89 const fieldId = typeof field === 'object' && field !== null ? (field.fieldId ?? field.id) : field
90 const formField = formBuilderStore.fields?.find((f) => f.id == fieldId)
91
92 if (!formField) return false
93
94 // Allow extensions to register field types that should render as HTML
95 // This is useful for Pro fields like signature that return sanitized HTML
96 const htmlFieldTypes = api.hooks.applyFilters<string[]>(
97 'ivyforms/entry/html_field_types',
98 [],
99 formField,
100 )
101
102 return htmlFieldTypes.includes(formField.type)
103 }
104
105 const getFieldDisplayValue = (field) => {
106 const fieldId = typeof field === 'object' && field !== null ? (field.fieldId ?? field.id) : field
107 const formField = formBuilderStore.fields?.find((f) => f.id == fieldId)
108
109 if (
110 formField &&
111 (formField.type === 'checkbox' || formField.type === 'multi-select') &&
112 Array.isArray(formField.fieldOptions)
113 ) {
114 const values = (field.fieldValue || '')
115 .split(',')
116 .map((v) => v.trim())
117 .filter((v) => v)
118 const labels = values.map((val) => {
119 const opt = formField.fieldOptions.find((opt) => opt.value == val)
120 return opt ? opt.label : val
121 })
122 return labels.join(', ')
123 }
124 if (
125 formField &&
126 (formField.type === 'radio' || formField.type === 'select') &&
127 Array.isArray(formField.fieldOptions)
128 ) {
129 const opt = formField.fieldOptions.find((opt) => opt.value == field.fieldValue)
130 return opt ? opt.label : field.fieldValue
131 }
132 return field.fieldValue
133 }
134 </script>
135
136 <style lang="scss">
137 .ivyforms-entry-page-section-title {
138 display: flex;
139 align-items: center;
140 justify-content: space-between;
141 color: var(--map-base-text-0);
142 }
143
144 .ivyforms-entry-page-section-content {
145 width: 100%;
146
147 .ivyforms-entry-table {
148 width: 100%;
149
150 td {
151 text-align: left;
152 border-bottom: 1px solid var(--map-divider);
153 height: 48px;
154 color: var(--map-base-text-0);
155 }
156
157 .ivyforms-key-column {
158 width: 50%;
159 }
160
161 .ivyforms-value-column {
162 width: 50%;
163 white-space: pre-wrap;
164 word-break: break-all;
165 overflow-wrap: anywhere;
166 }
167 }
168 }
169 </style>
170