@processmaker/screen-builder 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vue-form-builder.css +1 -1
- package/dist/vue-form-builder.es.js +5974 -5614
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +51 -51
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/assets/Shape.svg +3 -0
- package/src/assets/pencil-square.svg +3 -0
- package/src/components/ScreenTemplateCard.vue +125 -73
- package/src/components/ScreenTemplates.vue +138 -110
- package/src/components/accordions.js +1 -1
- package/src/components/inspector/collection-data-source.vue +0 -1
- package/src/components/inspector/collection-designer-mode.vue +65 -0
- package/src/components/inspector/color-select-modern.vue +101 -0
- package/src/components/inspector/index.js +3 -0
- package/src/components/renderer/file-upload.vue +29 -12
- package/src/components/renderer/form-record-list.vue +200 -23
- package/src/components/sortable/tableStyles.scss +42 -0
- package/src/components/task.vue +1 -0
- package/src/components/vue-form-builder.vue +50 -7
- package/src/form-builder-controls.js +14 -2
- package/src/form-control-common-properties.js +115 -2
- package/src/mixins/Clipboard.js +11 -5
- package/src/mixins/HasColorProperty.js +5 -0
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="screen-templates-container"
|
|
4
|
-
data-cy="screen-templates-section"
|
|
5
|
-
>
|
|
2
|
+
<div class="screen-templates-container" data-cy="screen-templates-section">
|
|
6
3
|
<div class="d-flex justify-content-between">
|
|
7
4
|
<h6 class="pt-2">{{ $t("Select a Template") }}</h6>
|
|
8
5
|
<button
|
|
9
6
|
class="panel-close-btn"
|
|
10
|
-
@click="$emit('close-templates-panel')"
|
|
11
7
|
data-cy="close-templates-section"
|
|
8
|
+
@click="$emit('close-templates-panel')"
|
|
12
9
|
>
|
|
13
10
|
<i class="fas fa-times"></i>
|
|
14
11
|
</button>
|
|
15
12
|
</div>
|
|
16
13
|
<div class="d-flex template-tabs justify-content-center">
|
|
17
14
|
<b-button
|
|
18
|
-
@click="showMyTemplates"
|
|
19
15
|
class="d-inline default-template-btn px-1"
|
|
20
16
|
:class="{ 'my-templates-selected': myTemplatesSelected }"
|
|
21
17
|
data-cy="my-templates-tab"
|
|
18
|
+
@click="showMyTemplates"
|
|
22
19
|
>
|
|
23
20
|
{{ $t("My Templates") }}
|
|
24
21
|
</b-button>
|
|
25
22
|
<b-button
|
|
26
|
-
@click="showSharedTemplates"
|
|
27
23
|
class="d-inline default-template-btn"
|
|
28
24
|
:class="{ 'shared-templates-selected': sharedTemplatesSelected }"
|
|
29
25
|
data-cy="shared-templates-tab"
|
|
26
|
+
@click="showSharedTemplates"
|
|
30
27
|
>
|
|
31
28
|
{{ $t("Shared Templates") }}
|
|
32
29
|
</b-button>
|
|
@@ -38,6 +35,9 @@
|
|
|
38
35
|
data-cy="my-templates-list"
|
|
39
36
|
>
|
|
40
37
|
<b-card-group>
|
|
38
|
+
<b-card-body v-if="loading" class="d-flex justify-content-center">
|
|
39
|
+
<b-spinner variant="primary" label="Spinning"></b-spinner>
|
|
40
|
+
</b-card-body>
|
|
41
41
|
<b-card-body
|
|
42
42
|
v-if="noMyTemplatesFound"
|
|
43
43
|
class="p-2 h-100 overflow-auto"
|
|
@@ -45,12 +45,14 @@
|
|
|
45
45
|
<h5>{{ $t("No templates found.") }}</h5>
|
|
46
46
|
</b-card-body>
|
|
47
47
|
<screen-template-card
|
|
48
|
-
v-else
|
|
49
48
|
v-for="template in myTemplatesData"
|
|
49
|
+
v-else
|
|
50
50
|
:key="template.id"
|
|
51
51
|
:template="template"
|
|
52
52
|
:screen-id="screenId"
|
|
53
|
-
:
|
|
53
|
+
:current-screen-page="currentScreenPage"
|
|
54
|
+
:active-template-id="activeTemplateId"
|
|
55
|
+
@toggle-active="setActiveTemplate"
|
|
54
56
|
/>
|
|
55
57
|
</b-card-group>
|
|
56
58
|
</div>
|
|
@@ -60,6 +62,9 @@
|
|
|
60
62
|
data-cy="shared-templates-list"
|
|
61
63
|
>
|
|
62
64
|
<b-card-group>
|
|
65
|
+
<b-card-body v-if="loading" class="d-flex justify-content-center">
|
|
66
|
+
<b-spinner variant="primary" label="Spinning"></b-spinner>
|
|
67
|
+
</b-card-body>
|
|
63
68
|
<b-card-body
|
|
64
69
|
v-if="noSharedTemplatesFound"
|
|
65
70
|
class="p-2 h-100 overflow-auto"
|
|
@@ -67,96 +72,116 @@
|
|
|
67
72
|
<h5>{{ $t("No templates found.") }}</h5>
|
|
68
73
|
</b-card-body>
|
|
69
74
|
<screen-template-card
|
|
70
|
-
v-else
|
|
71
75
|
v-for="template in sharedTemplatesData"
|
|
76
|
+
v-else
|
|
72
77
|
:key="template.id"
|
|
73
78
|
:template="template"
|
|
74
79
|
:screen-id="screenId"
|
|
75
|
-
:
|
|
80
|
+
:current-screen-page="currentScreenPage"
|
|
81
|
+
:active-template-id="activeTemplateId"
|
|
82
|
+
@toggle-active="setActiveTemplate"
|
|
76
83
|
/>
|
|
77
84
|
</b-card-group>
|
|
78
85
|
</div>
|
|
79
86
|
</div>
|
|
80
87
|
</div>
|
|
81
88
|
</template>
|
|
82
|
-
|
|
89
|
+
|
|
83
90
|
<script>
|
|
84
|
-
|
|
91
|
+
import ScreenTemplateCard from "./ScreenTemplateCard.vue";
|
|
85
92
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
export default {
|
|
94
|
+
components: {
|
|
95
|
+
ScreenTemplateCard
|
|
96
|
+
},
|
|
97
|
+
props: {
|
|
98
|
+
screenId: {
|
|
99
|
+
type: Number,
|
|
100
|
+
required: true
|
|
101
|
+
},
|
|
102
|
+
currentScreenPage: {
|
|
103
|
+
type: Number,
|
|
104
|
+
default: 0
|
|
89
105
|
},
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
screenType: {
|
|
107
|
+
type: String,
|
|
108
|
+
default: "FORM"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
data() {
|
|
112
|
+
return {
|
|
113
|
+
myTemplatesData: null,
|
|
114
|
+
sharedTemplatesData: null,
|
|
115
|
+
myTemplatesSelected: true,
|
|
116
|
+
sharedTemplatesSelected: false,
|
|
117
|
+
noMyTemplatesFound: false,
|
|
118
|
+
noSharedTemplatesFound: false,
|
|
119
|
+
activeTemplateId: null,
|
|
120
|
+
loading: false
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
mounted() {
|
|
124
|
+
this.showMyTemplates();
|
|
125
|
+
},
|
|
126
|
+
methods: {
|
|
127
|
+
setActiveTemplate(id) {
|
|
128
|
+
// If the same template that is already active is clicked, it deactivates it.
|
|
129
|
+
this.activeTemplateId = this.activeTemplateId === id ? null : id;
|
|
103
130
|
},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
sharedTemplatesSelected: false,
|
|
110
|
-
noMyTemplatesFound: false,
|
|
111
|
-
noSharedTemplatesFound: false,
|
|
112
|
-
};
|
|
131
|
+
showMyTemplates() {
|
|
132
|
+
this.myTemplatesSelected = true;
|
|
133
|
+
this.sharedTemplatesSelected = false;
|
|
134
|
+
this.activeTemplateId = null;
|
|
135
|
+
this.fetchMyTemplates();
|
|
113
136
|
},
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
this.fetchMyTemplates();
|
|
119
|
-
},
|
|
120
|
-
fetchMyTemplates() {
|
|
121
|
-
ProcessMaker.apiClient
|
|
122
|
-
.get(
|
|
123
|
-
`templates/screen?is_public=0&screen_type=${this.screenType}`,
|
|
124
|
-
)
|
|
137
|
+
fetchMyTemplates() {
|
|
138
|
+
this.loading = true;
|
|
139
|
+
ProcessMaker.apiClient
|
|
140
|
+
.get(`templates/screen?is_public=0&screen_type=${this.screenType}`)
|
|
125
141
|
.then((response) => {
|
|
126
142
|
this.myTemplatesData = response.data.data;
|
|
127
|
-
if (
|
|
143
|
+
if (
|
|
144
|
+
this.myTemplatesData.length === 0 ||
|
|
145
|
+
this.myTemplatesData === undefined
|
|
146
|
+
) {
|
|
128
147
|
this.noMyTemplatesFound = true;
|
|
129
148
|
}
|
|
130
149
|
})
|
|
131
150
|
.catch((error) => {
|
|
132
151
|
console.error(error);
|
|
152
|
+
})
|
|
153
|
+
.finally(() => {
|
|
154
|
+
this.loading = false;
|
|
133
155
|
});
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
},
|
|
157
|
+
fetchSharedTemplates() {
|
|
158
|
+
this.loading = true;
|
|
136
159
|
ProcessMaker.apiClient
|
|
137
|
-
.get(
|
|
138
|
-
`templates/screen?is_public=1&screen_type=${this.screenType}`,
|
|
139
|
-
)
|
|
160
|
+
.get(`templates/screen?is_public=1&screen_type=${this.screenType}`)
|
|
140
161
|
.then((response) => {
|
|
141
162
|
this.sharedTemplatesData = response.data.data;
|
|
142
|
-
if (
|
|
163
|
+
if (
|
|
164
|
+
this.sharedTemplatesData.length === 0 ||
|
|
165
|
+
this.sharedTemplatesData === undefined
|
|
166
|
+
) {
|
|
143
167
|
this.noSharedTemplatesFound = true;
|
|
144
168
|
}
|
|
145
169
|
})
|
|
146
170
|
.catch((error) => {
|
|
147
171
|
console.error(error);
|
|
172
|
+
})
|
|
173
|
+
.finally(() => {
|
|
174
|
+
this.loading = false;
|
|
148
175
|
});
|
|
149
|
-
},
|
|
150
|
-
showSharedTemplates() {
|
|
151
|
-
this.myTemplatesSelected = false;
|
|
152
|
-
this.sharedTemplatesSelected = true;
|
|
153
|
-
this.fetchSharedTemplates();
|
|
154
|
-
},
|
|
155
176
|
},
|
|
156
|
-
|
|
157
|
-
this.
|
|
177
|
+
showSharedTemplates() {
|
|
178
|
+
this.myTemplatesSelected = false;
|
|
179
|
+
this.sharedTemplatesSelected = true;
|
|
180
|
+
this.activeTemplateId = null;
|
|
181
|
+
this.fetchSharedTemplates();
|
|
158
182
|
}
|
|
159
|
-
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
160
185
|
</script>
|
|
161
186
|
|
|
162
187
|
<style lang="scss" scoped>
|
|
@@ -164,53 +189,56 @@
|
|
|
164
189
|
height: 100%;
|
|
165
190
|
}
|
|
166
191
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
.template-tabs {
|
|
174
|
-
padding: 4px;
|
|
175
|
-
background-color: #E9ECF1;
|
|
176
|
-
border-radius: 8px;
|
|
177
|
-
margin-top: 0.5rem;
|
|
178
|
-
margin-bottom: 0.5rem;
|
|
179
|
-
}
|
|
192
|
+
.panel-close-btn {
|
|
193
|
+
background-color: transparent;
|
|
194
|
+
border: none;
|
|
195
|
+
color: #596372;
|
|
196
|
+
}
|
|
180
197
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
padding-right: 0px;
|
|
189
|
-
text-transform: none;
|
|
190
|
-
}
|
|
198
|
+
.template-tabs {
|
|
199
|
+
padding: 4px;
|
|
200
|
+
background-color: #e9ecf1;
|
|
201
|
+
border-radius: 8px;
|
|
202
|
+
margin-top: 0.5rem;
|
|
203
|
+
margin-bottom: 0.5rem;
|
|
204
|
+
}
|
|
191
205
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
206
|
+
.default-template-btn {
|
|
207
|
+
width: 50%;
|
|
208
|
+
background-color: transparent;
|
|
209
|
+
border: none;
|
|
210
|
+
color: #596372;
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
padding-left: 0px;
|
|
213
|
+
padding-right: 0px;
|
|
214
|
+
text-transform: none;
|
|
215
|
+
}
|
|
203
216
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
.my-templates-selected {
|
|
218
|
+
background-color: #ffffff;
|
|
219
|
+
color: #20242a;
|
|
220
|
+
border-radius: 8px;
|
|
221
|
+
border: none;
|
|
222
|
+
font-weight: 600;
|
|
223
|
+
font-size: 12px;
|
|
224
|
+
padding-left: 0px;
|
|
225
|
+
padding-right: 0px;
|
|
226
|
+
box-shadow: 0px 3px 6px -3px rgb(0, 0, 0, 0.05),
|
|
227
|
+
0px 2px 4px -2px rgba(0, 0, 0, 0.05), 0px 1px 2px -1px rgb(0, 0, 0, 0.05),
|
|
228
|
+
0px 1px 0px -1px rgb(0, 0, 0, 0.05);
|
|
229
|
+
}
|
|
215
230
|
|
|
231
|
+
.shared-templates-selected {
|
|
232
|
+
background-color: #ffffff;
|
|
233
|
+
color: #20242a;
|
|
234
|
+
border-radius: 8px;
|
|
235
|
+
border: none;
|
|
236
|
+
font-weight: 600;
|
|
237
|
+
font-size: 12px;
|
|
238
|
+
padding-left: 0px;
|
|
239
|
+
padding-right: 0px;
|
|
240
|
+
box-shadow: 0px 3px 6px -3px rgb(0, 0, 0, 0.05),
|
|
241
|
+
0px 2px 4px -2px rgba(0, 0, 0, 0.05), 0px 1px 2px -1px rgb(0, 0, 0, 0.05),
|
|
242
|
+
0px 1px 0px -1px rgb(0, 0, 0, 0.05);
|
|
243
|
+
}
|
|
216
244
|
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div>
|
|
4
|
+
<label for="collectiondesigner">{{ $t("Table Style") }}</label>
|
|
5
|
+
<b-form-select
|
|
6
|
+
id="collectiondesigner"
|
|
7
|
+
v-model="designerOptions"
|
|
8
|
+
:options="designerListOptions"
|
|
9
|
+
data-cy="inspector-collection-designer-model"
|
|
10
|
+
/>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
<script>
|
|
15
|
+
|
|
16
|
+
import { cloneDeep } from "lodash";
|
|
17
|
+
|
|
18
|
+
const CONFIG_FIELDS = [
|
|
19
|
+
"designerOptions"
|
|
20
|
+
];
|
|
21
|
+
export default {
|
|
22
|
+
props: ["value", "screenType"],
|
|
23
|
+
data() {
|
|
24
|
+
return {
|
|
25
|
+
fields: [],
|
|
26
|
+
designerOptions: "Classic",
|
|
27
|
+
designerListOptions: [
|
|
28
|
+
{
|
|
29
|
+
text: this.$t('Classic'),
|
|
30
|
+
value: 'Classic',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
text: this.$t('Modern'),
|
|
34
|
+
value: 'Modern',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
computed: {
|
|
40
|
+
options() {
|
|
41
|
+
return Object.fromEntries(
|
|
42
|
+
CONFIG_FIELDS.map((field) => [field, this[field]])
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
watch: {
|
|
47
|
+
value: {
|
|
48
|
+
handler(value) {
|
|
49
|
+
if (!value) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
CONFIG_FIELDS.forEach((field) => (this[field] = value[field]));
|
|
53
|
+
},
|
|
54
|
+
immediate: true
|
|
55
|
+
},
|
|
56
|
+
options: {
|
|
57
|
+
handler() {
|
|
58
|
+
this.$emit("input", this.options);
|
|
59
|
+
this.$root.$emit("style-mode", this.options.designerOptions);
|
|
60
|
+
},
|
|
61
|
+
deep: true
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
</script>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="form-group">
|
|
3
|
+
<div>
|
|
4
|
+
<b-button-toolbar>
|
|
5
|
+
<b-button-group size="lg">
|
|
6
|
+
<b-button
|
|
7
|
+
v-for="option in options"
|
|
8
|
+
:key="option.value"
|
|
9
|
+
size="sm"
|
|
10
|
+
variant="outline-light"
|
|
11
|
+
class="color-option"
|
|
12
|
+
:class="['bg-' + parsedColor(option.value)]"
|
|
13
|
+
:title="option.content"
|
|
14
|
+
>
|
|
15
|
+
<i
|
|
16
|
+
class="fas fa-check"
|
|
17
|
+
:class="[
|
|
18
|
+
option.value === value
|
|
19
|
+
? 'text-light'
|
|
20
|
+
: 'text-' + parsedColor(option.value)
|
|
21
|
+
]"
|
|
22
|
+
@click="selectColor(option.value)"
|
|
23
|
+
/>
|
|
24
|
+
</b-button>
|
|
25
|
+
</b-button-group>
|
|
26
|
+
</b-button-toolbar>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script>
|
|
32
|
+
export default {
|
|
33
|
+
components: {},
|
|
34
|
+
props: {
|
|
35
|
+
/**
|
|
36
|
+
* The label for the color select
|
|
37
|
+
*/
|
|
38
|
+
label: {},
|
|
39
|
+
/**
|
|
40
|
+
* The value of the color select. eg. `alert alert-success`
|
|
41
|
+
*/
|
|
42
|
+
value: {},
|
|
43
|
+
/**
|
|
44
|
+
* The helper text for the color select (not visible yet)
|
|
45
|
+
*/
|
|
46
|
+
helper: {},
|
|
47
|
+
/**
|
|
48
|
+
* The options for the color select
|
|
49
|
+
*/
|
|
50
|
+
options: {},
|
|
51
|
+
},
|
|
52
|
+
data() {
|
|
53
|
+
return {
|
|
54
|
+
newColor: ""
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
computed: {
|
|
58
|
+
hasColor() {
|
|
59
|
+
return Boolean(this.value);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
methods: {
|
|
63
|
+
emitChanges(value) {
|
|
64
|
+
this.$emit("input", value);
|
|
65
|
+
this.$emit("update-state");
|
|
66
|
+
},
|
|
67
|
+
checkColor() {
|
|
68
|
+
if (this.hasColor) {
|
|
69
|
+
this.emitChanges("");
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
selectColor(color) {
|
|
73
|
+
this.emitChanges(color);
|
|
74
|
+
},
|
|
75
|
+
parsedColor(color) {
|
|
76
|
+
return color.split("-")[1];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style lang="scss" scoped>
|
|
83
|
+
.image-preview {
|
|
84
|
+
border: 1px solid #ced4da;
|
|
85
|
+
border-radius: 4px;
|
|
86
|
+
height: 4em;
|
|
87
|
+
text-align: center;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
}
|
|
90
|
+
.color-option {
|
|
91
|
+
left: -8px;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
width: 48px;
|
|
94
|
+
height: 48px;
|
|
95
|
+
margin-right: 15px;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
position: relative;
|
|
100
|
+
}
|
|
101
|
+
</style>
|
|
@@ -2,7 +2,10 @@ export { default as CollectionSelectList } from "./collection-select-list.vue";
|
|
|
2
2
|
export { default as CollectionRecordsList } from "./collection-records-list.vue";
|
|
3
3
|
export { default as collectionDataSource } from "./collection-data-source.vue";
|
|
4
4
|
export { default as CollectionDisplayMode } from "./collection-display-mode.vue";
|
|
5
|
+
export { default as CollectionDesignerMode } from "./collection-designer-mode.vue";
|
|
5
6
|
export { default as ColorSelect } from "./color-select.vue";
|
|
7
|
+
export { default as ColorSelectRecord } from "./color-select.vue";
|
|
8
|
+
export { default as ColorSelectModern } from "./color-select-modern.vue";
|
|
6
9
|
export { default as ColumnSetup } from "./column-setup.vue";
|
|
7
10
|
export { default as ContainerColumns } from "./container-columns.vue";
|
|
8
11
|
export { default as DataMapping } from "./data-mapping.vue";
|
|
@@ -61,32 +61,34 @@
|
|
|
61
61
|
</ul>
|
|
62
62
|
</template>
|
|
63
63
|
</uploader-list>
|
|
64
|
-
<uploader-drop v-if="uploaderLoaded && isConversationalForm" class="form-control-file"
|
|
64
|
+
<uploader-drop v-if="uploaderLoaded && isConversationalForm" class="form-control-file"
|
|
65
|
+
:class="this.files.length > 0 && !this.multipleUpload ? 'cf-single-file-upload' : ''"
|
|
66
|
+
>
|
|
65
67
|
<b-button
|
|
66
68
|
v-if="!required"
|
|
67
69
|
@click="cfSkipFileUpload"
|
|
68
|
-
class="btn cf-skip-btn
|
|
70
|
+
class="btn cf-skip-btn"
|
|
71
|
+
:class="showMultiUploadButton ? 'mb-3' : ''"
|
|
69
72
|
>
|
|
70
73
|
<i class="fas fa-arrow-left mr-2"></i> {{ $t('Skip Uploading') }}
|
|
71
74
|
</b-button>
|
|
72
|
-
|
|
73
75
|
<uploader-btn
|
|
74
76
|
:attrs="nativeButtonAttrs"
|
|
75
77
|
:class="[
|
|
76
78
|
{ disabled: disabled },
|
|
77
79
|
'btn',
|
|
78
|
-
showSingleUploadButton ? 'cf-single-upload-btn' : (showMultiUploadButton ? 'cf-multi-upload-btn' : '')
|
|
80
|
+
showSingleUploadButton || files.length === 0 && !showMultiUploadButton ? 'cf-single-upload-btn mt-3' : (showMultiUploadButton ? 'cf-multi-upload-btn' : '')
|
|
79
81
|
]"
|
|
80
82
|
tabindex="0"
|
|
81
83
|
v-on:keyup.native="browse"
|
|
82
84
|
:aria-label="$attrs['aria-label']"
|
|
83
85
|
>
|
|
84
|
-
<span v-if="showSingleUploadButton"><i class="far fa-image mr-2"></i> {{ $t('Add File/Photo') }}</span>
|
|
86
|
+
<span v-if="showSingleUploadButton || files.length === 0 && !showMultiUploadButton"><i class="far fa-image mr-2"></i> {{ $t('Add File/Photo') }}</span>
|
|
85
87
|
<span v-else-if="showMultiUploadButton"><i class="fas fa-plus mr-2"></i> {{ $t('Add another') }}</span>
|
|
86
88
|
</uploader-btn>
|
|
87
89
|
|
|
88
|
-
<b-button v-if="files.length !== 0" class="cf-file-upload-submit" variant="primary" @click="emitConversationalFormSubmit" :aria-label="$t('Submit')">
|
|
89
|
-
<i class="fas fa-paper-plane"></i> <span v-if="
|
|
90
|
+
<b-button v-if="files.length !== 0" class="cf-file-upload-submit" :class="!showMultiUploadButton ? 'w-100 mt-3' : ''" variant="primary" @click="emitConversationalFormSubmit" :aria-label="$t('Submit')">
|
|
91
|
+
<i class="fas fa-paper-plane"></i> <span v-if="showMultiUploadButton">{{ $t('Send All') }}</span> <span v-else>{{ $t('Submit File/Photo') }}</span>
|
|
90
92
|
</b-button>
|
|
91
93
|
</uploader-drop>
|
|
92
94
|
|
|
@@ -270,7 +272,7 @@ export default {
|
|
|
270
272
|
return this.screenType === 'conversational-forms';
|
|
271
273
|
},
|
|
272
274
|
showSingleUploadButton() {
|
|
273
|
-
return this.files.length === 0
|
|
275
|
+
return this.files.length === 0 && !this.multipleUpload;
|
|
274
276
|
},
|
|
275
277
|
showMultiUploadButton() {
|
|
276
278
|
return this.files.length !== 0 && this.multipleUpload;
|
|
@@ -402,7 +404,6 @@ export default {
|
|
|
402
404
|
},
|
|
403
405
|
setRequestFiles() {
|
|
404
406
|
_.set(window, `PM4ConfigOverrides.requestFiles["${this.fileDataName}"]`, this.files);
|
|
405
|
-
console.log("!!!!!! SET REQUEST FILES", this.valueToSend());
|
|
406
407
|
this.$emit('input', this.valueToSend());
|
|
407
408
|
},
|
|
408
409
|
valueToSend() {
|
|
@@ -491,7 +492,7 @@ export default {
|
|
|
491
492
|
}
|
|
492
493
|
this.$delete(this.nativeFiles, id);
|
|
493
494
|
}
|
|
494
|
-
|
|
495
|
+
this.$emit('file-deleted', this.files);
|
|
495
496
|
},
|
|
496
497
|
addToFiles(fileInfo) {
|
|
497
498
|
if (this.multipleUpload) {
|
|
@@ -528,6 +529,19 @@ export default {
|
|
|
528
529
|
this.prefix = parent.loopContext + '.';
|
|
529
530
|
}
|
|
530
531
|
},
|
|
532
|
+
validateFile(file, acceptFiles){
|
|
533
|
+
const extensions = acceptFiles.filter(item => item.startsWith('.'));
|
|
534
|
+
const mimeTypes = acceptFiles.filter(item => !item.startsWith('.'));
|
|
535
|
+
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
|
536
|
+
const fileType = file.fileType;
|
|
537
|
+
const isExtensionValid = extensions.includes(fileExtension);
|
|
538
|
+
const isMimeTypeValid = mimeTypes.includes(fileType);
|
|
539
|
+
|
|
540
|
+
if (!isExtensionValid && !isMimeTypeValid) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
return true;
|
|
544
|
+
},
|
|
531
545
|
addFile(file) {
|
|
532
546
|
if (this.disabled) {
|
|
533
547
|
file.ignored = true;
|
|
@@ -544,7 +558,7 @@ export default {
|
|
|
544
558
|
|
|
545
559
|
if (this.filesAccept) {
|
|
546
560
|
file.ignored = true;
|
|
547
|
-
if (this.
|
|
561
|
+
if (this.validateFile(file, this.filesAccept)) {
|
|
548
562
|
file.ignored = false;
|
|
549
563
|
}
|
|
550
564
|
if (file.ignored) {
|
|
@@ -612,7 +626,6 @@ export default {
|
|
|
612
626
|
this.$set(this.nativeFiles, id, rootFile);
|
|
613
627
|
this.addToFiles(fileInfo);
|
|
614
628
|
} else {
|
|
615
|
-
console.log("!!!!!! FILE UPLOADED", name);
|
|
616
629
|
this.$emit('input', name);
|
|
617
630
|
}
|
|
618
631
|
},
|
|
@@ -750,4 +763,8 @@ export default {
|
|
|
750
763
|
box-shadow: 0px 12px 24px -12px #0000001F;
|
|
751
764
|
}
|
|
752
765
|
|
|
766
|
+
.form-control-file.cf-single-file-upload label {
|
|
767
|
+
display: none;
|
|
768
|
+
}
|
|
769
|
+
|
|
753
770
|
</style>
|