glib-web 4.8.1 → 4.8.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/LICENSE +0 -0
- package/actions/auth/restart.js +0 -0
- package/actions/commands/copy.js +0 -0
- package/actions/dialogs/notification.js +0 -0
- package/actions/dialogs/oauth.js +0 -0
- package/actions/dialogs/reload.js +0 -0
- package/actions/http/delete.js +0 -0
- package/actions/sheets/select.js +0 -0
- package/actions/snackbars/select.js +0 -0
- package/actions/windows/openWeb.js +0 -0
- package/actions/windows/print.js +0 -0
- package/app.scss +172 -0
- package/components/_message.vue +0 -0
- package/components/component.vue +2 -0
- package/components/composable/parser.js +41 -0
- package/components/fields/multiUpload.vue +3 -191
- package/components/fields/phone/countries.js +0 -0
- package/components/fields/phone/sprite.css +0 -0
- package/components/h1.vue +0 -0
- package/components/h2.vue +0 -0
- package/components/h3.vue +0 -0
- package/components/h5.vue +0 -0
- package/components/h6.vue +0 -0
- package/components/hr.vue +0 -0
- package/components/html.vue +0 -0
- package/components/icon.vue +0 -0
- package/components/mixins/extension.js +0 -0
- package/components/mixins/longClick.js +0 -0
- package/components/mixins/scrolling.js +0 -0
- package/components/mixins/table/export.js +0 -0
- package/components/mixins/text.js +0 -0
- package/components/multimedia/video.vue +0 -0
- package/components/panels/bulkEdit.vue +17 -15
- package/components/panels/bulkEdit2.vue +197 -0
- package/index.js +2 -0
- package/keys.js +0 -0
- package/package.json +1 -1
- package/plugins/updatableComponent.js +11 -12
- package/plugins/vuetify.js +3 -3
- package/static/plugins/alignment/alignment.js +0 -0
- package/static/plugins/alignment/alignment.min.js +0 -0
- package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
- package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
- package/static/plugins/blockcode/blockcode.js +0 -0
- package/static/plugins/blockcode/blockcode.min.js +0 -0
- package/static/plugins/clips/clips.js +0 -0
- package/static/plugins/clips/clips.min.js +0 -0
- package/static/plugins/counter/counter.js +0 -0
- package/static/plugins/counter/counter.min.js +0 -0
- package/static/plugins/definedlinks/definedlinks.js +0 -0
- package/static/plugins/definedlinks/definedlinks.min.js +0 -0
- package/static/plugins/handle/handle.js +0 -0
- package/static/plugins/handle/handle.min.js +0 -0
- package/static/plugins/icons/icons.js +0 -0
- package/static/plugins/icons/icons.min.js +0 -0
- package/static/plugins/imageposition/imageposition.js +0 -0
- package/static/plugins/imageposition/imageposition.min.js +0 -0
- package/static/plugins/inlineformat/inlineformat.js +0 -0
- package/static/plugins/inlineformat/inlineformat.min.js +0 -0
- package/static/plugins/removeformat/removeformat.js +0 -0
- package/static/plugins/removeformat/removeformat.min.js +0 -0
- package/static/plugins/selector/selector.js +0 -0
- package/static/plugins/selector/selector.min.js +0 -0
- package/static/plugins/specialchars/specialchars.js +0 -0
- package/static/plugins/specialchars/specialchars.min.js +0 -0
- package/static/plugins/textdirection/textdirection.js +0 -0
- package/static/plugins/textdirection/textdirection.min.js +0 -0
- package/static/plugins/textexpander/textexpander.js +0 -0
- package/static/plugins/textexpander/textexpander.min.js +0 -0
- package/static/plugins/underline/underline.js +0 -0
- package/static/plugins/underline/underline.min.js +0 -0
- package/static/redactorx.css +0 -0
- package/static/redactorx.min.css +0 -0
- package/static/redactorx.min.js +0 -0
- package/static/redactorx.usm.min.js +0 -0
- package/styles/test.sass +0 -0
- package/styles/test.scss +0 -0
- package/templates/unsupported.vue +0 -0
- package/utils/dom.js +0 -0
- package/utils/helper.js +0 -0
package/LICENSE
CHANGED
|
File without changes
|
package/actions/auth/restart.js
CHANGED
|
File without changes
|
package/actions/commands/copy.js
CHANGED
|
File without changes
|
|
File without changes
|
package/actions/dialogs/oauth.js
CHANGED
|
File without changes
|
|
File without changes
|
package/actions/http/delete.js
CHANGED
|
File without changes
|
package/actions/sheets/select.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/actions/windows/print.js
CHANGED
|
File without changes
|
package/app.scss
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
.border-\[2px\] {
|
|
2
|
+
border-width: 2px;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.border-\[4px\] {
|
|
6
|
+
border-width: 4px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.\!font-semibold {
|
|
10
|
+
font-weight: 600px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.opacity-50 {
|
|
14
|
+
opacity: 0.5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.guploaded-file {
|
|
18
|
+
/* pt-6 w-full */
|
|
19
|
+
padding-top: 24px;
|
|
20
|
+
width: 100%;
|
|
21
|
+
|
|
22
|
+
.title {
|
|
23
|
+
color: #6b7280;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
margin-bottom: 8px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.file-container {
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
border-radius: 6px;
|
|
33
|
+
background-color: #f3f4f6;
|
|
34
|
+
width: 100%;
|
|
35
|
+
padding: 16px;
|
|
36
|
+
margin-bottom: 16px;
|
|
37
|
+
min-height: 72px;
|
|
38
|
+
gap: 8px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.file {
|
|
42
|
+
display: flex;
|
|
43
|
+
width: 100%;
|
|
44
|
+
position: relative;
|
|
45
|
+
|
|
46
|
+
.status {
|
|
47
|
+
display: flex;
|
|
48
|
+
width: 100%;
|
|
49
|
+
gap: 8px;
|
|
50
|
+
align-items: center;
|
|
51
|
+
|
|
52
|
+
.image-icon {
|
|
53
|
+
width: 40px;
|
|
54
|
+
height: 40px;
|
|
55
|
+
background-color: #fff;
|
|
56
|
+
border-radius: 5px;
|
|
57
|
+
display: flex;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
align-items: center;
|
|
60
|
+
|
|
61
|
+
img {
|
|
62
|
+
width: 20px;
|
|
63
|
+
height: 20px;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.icon {
|
|
68
|
+
margin-right: 8px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.progress {
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-grow: 1;
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
|
|
77
|
+
.label {
|
|
78
|
+
/* mb-1 */
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
margin-bottom: 4px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.label a {
|
|
85
|
+
color: #47495F;
|
|
86
|
+
font-weight: 600;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.label a:hover {
|
|
90
|
+
text-decoration: underline;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.label a[href=""],
|
|
94
|
+
.label a[href="#"],
|
|
95
|
+
.label a:not([href]) {
|
|
96
|
+
text-decoration: none !important;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.close-btn {
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.background {
|
|
108
|
+
width: 100%;
|
|
109
|
+
background-color: #e6e6e6;
|
|
110
|
+
border-radius: 9999px;
|
|
111
|
+
height: 8px;
|
|
112
|
+
display: flex;
|
|
113
|
+
|
|
114
|
+
.value {
|
|
115
|
+
background-color: #0A2A9E;
|
|
116
|
+
height: inherit;
|
|
117
|
+
border-radius: inherit;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.percentage-wrapper {
|
|
122
|
+
width: 100%;
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: center;
|
|
126
|
+
gap: 8px;
|
|
127
|
+
|
|
128
|
+
.percentage {
|
|
129
|
+
font-size: 14px;
|
|
130
|
+
font-weight: 600;
|
|
131
|
+
margin-bottom: 2px;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.gdrop-file {
|
|
137
|
+
/* px-6 py-10 border-[2px] border-dashed border-gray-400 w-full rounded-2xl cursor-pointer */
|
|
138
|
+
padding: 40px 24px;
|
|
139
|
+
border-style: dashed;
|
|
140
|
+
border-color: #9ca3af;
|
|
141
|
+
width: 100%;
|
|
142
|
+
border-radius: 16px;
|
|
143
|
+
cursor: pointer;
|
|
144
|
+
|
|
145
|
+
.cloud {
|
|
146
|
+
/* w-full flex flex-col justify-center items-center */
|
|
147
|
+
width: 100%;
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
align-items: center;
|
|
152
|
+
|
|
153
|
+
.icon {
|
|
154
|
+
/* mb-3 text-gray-400 */
|
|
155
|
+
margin-bottom: 12px;
|
|
156
|
+
color: #9ca3af;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.title {
|
|
160
|
+
/* text-center mb-2 */
|
|
161
|
+
text-align: center;
|
|
162
|
+
margin-bottom: 8px;
|
|
163
|
+
color: #47495F;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.subtitle {
|
|
167
|
+
/* text-color-light text-center */
|
|
168
|
+
color: #A7ADB5;
|
|
169
|
+
text-align: center;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
package/components/_message.vue
CHANGED
|
File without changes
|
package/components/component.vue
CHANGED
|
@@ -104,6 +104,7 @@ import ListPanel from "./panels/list.vue";
|
|
|
104
104
|
import CarouselPanel from "./panels/carousel.vue";
|
|
105
105
|
import TablePanel from "./panels/table.vue";
|
|
106
106
|
import BulkEditPanel from "./panels/bulkEdit.vue";
|
|
107
|
+
import BulkEditPanel2 from "./panels/bulkEdit2.vue";
|
|
107
108
|
import CustomPanel from "./panels/custom.vue";
|
|
108
109
|
import ColumnPanel from "./panels/column.vue";
|
|
109
110
|
import ResponsivePanel from "./panels/responsive.vue";
|
|
@@ -200,6 +201,7 @@ export default {
|
|
|
200
201
|
"panels-carousel": CarouselPanel,
|
|
201
202
|
"panels-table": TablePanel,
|
|
202
203
|
"panels-bulkEdit": BulkEditPanel,
|
|
204
|
+
"panels-bulkEdit2": BulkEditPanel2,
|
|
203
205
|
"panels-custom": CustomPanel,
|
|
204
206
|
"panels-responsive": ResponsivePanel,
|
|
205
207
|
"panels-column": ColumnPanel,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function parseCsv(csvString) {
|
|
2
|
+
// https://stackoverflow.com/a/41563966/9970813
|
|
3
|
+
let prevLetter = "",
|
|
4
|
+
row = [""],
|
|
5
|
+
result = [row],
|
|
6
|
+
columnIndex = 0,
|
|
7
|
+
rowIndex = 0,
|
|
8
|
+
canSplit = true,
|
|
9
|
+
letter;
|
|
10
|
+
for (let i = 0; i <= csvString.length; ++i) {
|
|
11
|
+
letter = csvString[i];
|
|
12
|
+
|
|
13
|
+
if ('"' === letter) {
|
|
14
|
+
if (canSplit && letter === prevLetter) {
|
|
15
|
+
row[columnIndex] += letter;
|
|
16
|
+
}
|
|
17
|
+
canSplit = !canSplit;
|
|
18
|
+
} else if ("," === letter && canSplit) {
|
|
19
|
+
letter = row[++columnIndex] = "";
|
|
20
|
+
} else if ("\n" === letter && canSplit) {
|
|
21
|
+
if ("\r" === prevLetter) {
|
|
22
|
+
row[columnIndex] = row[columnIndex].slice(0, -1);
|
|
23
|
+
}
|
|
24
|
+
row = result[++rowIndex] = [(letter = "")];
|
|
25
|
+
columnIndex = 0;
|
|
26
|
+
} else if (Utils.type.isString(letter)) {
|
|
27
|
+
row[columnIndex] += letter;
|
|
28
|
+
}
|
|
29
|
+
prevLetter = letter;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Remove any blank rows
|
|
33
|
+
result = result.filter(r => {
|
|
34
|
+
return r[0] !== "";
|
|
35
|
+
});
|
|
36
|
+
// result = result.filter(r => {
|
|
37
|
+
// return r[0] !== "undefined"
|
|
38
|
+
// });
|
|
39
|
+
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
@@ -53,194 +53,6 @@
|
|
|
53
53
|
</div>
|
|
54
54
|
</template>
|
|
55
55
|
|
|
56
|
-
<style>
|
|
57
|
-
.slide-fade-enter-active {
|
|
58
|
-
transition: all 0.3s ease-out;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.slide-fade-leave-active {
|
|
62
|
-
transition: all 1s cubic-bezier(1, 0.5, 0.8, 1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.slide-fade-enter-from,
|
|
66
|
-
.slide-fade-leave-to {
|
|
67
|
-
opacity: 0;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.border-\[2px\] {
|
|
71
|
-
border-width: 2px;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.border-\[4px\] {
|
|
75
|
-
border-width: 4px;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.\!font-semibold {
|
|
79
|
-
font-weight: 600px;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.opacity-50 {
|
|
83
|
-
opacity: 0.5;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.guploaded-file {
|
|
87
|
-
/* pt-6 w-full */
|
|
88
|
-
padding-top: 24px;
|
|
89
|
-
width: 100%;
|
|
90
|
-
|
|
91
|
-
.title {
|
|
92
|
-
color: #6b7280;
|
|
93
|
-
font-weight: 600;
|
|
94
|
-
margin-bottom: 8px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.file-container {
|
|
98
|
-
display: flex;
|
|
99
|
-
align-items: center;
|
|
100
|
-
flex-direction: column;
|
|
101
|
-
border-radius: 6px;
|
|
102
|
-
background-color: #f3f4f6;
|
|
103
|
-
width: 100%;
|
|
104
|
-
padding: 16px;
|
|
105
|
-
margin-bottom: 16px;
|
|
106
|
-
min-height: 72px;
|
|
107
|
-
gap: 8px;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.file {
|
|
111
|
-
display: flex;
|
|
112
|
-
width: 100%;
|
|
113
|
-
position: relative;
|
|
114
|
-
|
|
115
|
-
.status {
|
|
116
|
-
display: flex;
|
|
117
|
-
width: 100%;
|
|
118
|
-
gap: 8px;
|
|
119
|
-
align-items: center;
|
|
120
|
-
|
|
121
|
-
.image-icon {
|
|
122
|
-
width: 40px;
|
|
123
|
-
height: 40px;
|
|
124
|
-
background-color: #fff;
|
|
125
|
-
border-radius: 5px;
|
|
126
|
-
display: flex;
|
|
127
|
-
justify-content: center;
|
|
128
|
-
align-items: center;
|
|
129
|
-
|
|
130
|
-
img {
|
|
131
|
-
width: 20px;
|
|
132
|
-
height: 20px;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.icon {
|
|
137
|
-
margin-right: 8px;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.progress {
|
|
141
|
-
display: flex;
|
|
142
|
-
flex-grow: 1;
|
|
143
|
-
flex-direction: column;
|
|
144
|
-
justify-content: space-between;
|
|
145
|
-
|
|
146
|
-
.label {
|
|
147
|
-
/* mb-1 */
|
|
148
|
-
display: flex;
|
|
149
|
-
flex-direction: column;
|
|
150
|
-
margin-bottom: 4px;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.label a {
|
|
154
|
-
color: #47495F;
|
|
155
|
-
font-weight: 600;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.label a:hover {
|
|
159
|
-
text-decoration: underline;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.label a[href=""],
|
|
163
|
-
.label a[href="#"],
|
|
164
|
-
.label a:not([href]) {
|
|
165
|
-
text-decoration: none !important;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.close-btn {
|
|
172
|
-
cursor: pointer;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.background {
|
|
177
|
-
width: 100%;
|
|
178
|
-
background-color: #e6e6e6;
|
|
179
|
-
border-radius: 9999px;
|
|
180
|
-
height: 8px;
|
|
181
|
-
display: flex;
|
|
182
|
-
|
|
183
|
-
.value {
|
|
184
|
-
background-color: #0A2A9E;
|
|
185
|
-
height: inherit;
|
|
186
|
-
border-radius: inherit;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.percentage-wrapper {
|
|
191
|
-
width: 100%;
|
|
192
|
-
display: flex;
|
|
193
|
-
align-items: center;
|
|
194
|
-
justify-content: center;
|
|
195
|
-
gap: 8px;
|
|
196
|
-
|
|
197
|
-
.percentage {
|
|
198
|
-
font-size: 14px;
|
|
199
|
-
font-weight: 600;
|
|
200
|
-
margin-bottom: 2px;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.gdrop-file {
|
|
206
|
-
/* px-6 py-10 border-[2px] border-dashed border-gray-400 w-full rounded-2xl cursor-pointer */
|
|
207
|
-
padding: 40px 24px;
|
|
208
|
-
border-style: dashed;
|
|
209
|
-
border-color: #9ca3af;
|
|
210
|
-
width: 100%;
|
|
211
|
-
border-radius: 16px;
|
|
212
|
-
cursor: pointer;
|
|
213
|
-
|
|
214
|
-
.cloud {
|
|
215
|
-
/* w-full flex flex-col justify-center items-center */
|
|
216
|
-
width: 100%;
|
|
217
|
-
display: flex;
|
|
218
|
-
flex-direction: column;
|
|
219
|
-
justify-content: center;
|
|
220
|
-
align-items: center;
|
|
221
|
-
|
|
222
|
-
.icon {
|
|
223
|
-
/* mb-3 text-gray-400 */
|
|
224
|
-
margin-bottom: 12px;
|
|
225
|
-
color: #9ca3af;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.title {
|
|
229
|
-
/* text-center mb-2 */
|
|
230
|
-
text-align: center;
|
|
231
|
-
margin-bottom: 8px;
|
|
232
|
-
color: #47495F;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.subtitle {
|
|
236
|
-
/* text-color-light text-center */
|
|
237
|
-
color: #A7ADB5;
|
|
238
|
-
text-align: center;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
</style>
|
|
243
|
-
|
|
244
56
|
<script>
|
|
245
57
|
import { ref, computed, defineComponent, watch, getCurrentInstance } from 'vue';
|
|
246
58
|
import { VIcon } from 'vuetify/components';
|
|
@@ -249,9 +61,9 @@ import * as delegateUploader from "../composable/upload_delegator";
|
|
|
249
61
|
import { triggerOnChange } from "../composable/form";
|
|
250
62
|
import { nextTick } from "vue";
|
|
251
63
|
import { useFilesState, useFileUtils } from "../composable/file";
|
|
252
|
-
import doc from "./selectAsset/doc-1.png"
|
|
253
|
-
import pic from "./selectAsset/pic-1.png"
|
|
254
|
-
import pdf from "./selectAsset/pdf-1.png"
|
|
64
|
+
import doc from "./selectAsset/doc-1.png";
|
|
65
|
+
import pic from "./selectAsset/pic-1.png";
|
|
66
|
+
import pdf from "./selectAsset/pdf-1.png";
|
|
255
67
|
const { makeKey, Item, signedIds } = useFileUtils();
|
|
256
68
|
|
|
257
69
|
export default defineComponent({
|
|
File without changes
|
|
File without changes
|
package/components/h1.vue
CHANGED
|
File without changes
|
package/components/h2.vue
CHANGED
|
File without changes
|
package/components/h3.vue
CHANGED
|
File without changes
|
package/components/h5.vue
CHANGED
|
File without changes
|
package/components/h6.vue
CHANGED
|
File without changes
|
package/components/hr.vue
CHANGED
|
File without changes
|
package/components/html.vue
CHANGED
|
File without changes
|
package/components/icon.vue
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -70,10 +70,13 @@
|
|
|
70
70
|
<tr v-if="importable && section.dataRows.length <= 0">
|
|
71
71
|
<td colspan="20">
|
|
72
72
|
<!-- TODO: Reuse code from multiUpload so it supports drag-and-drop too -->
|
|
73
|
-
<input ref="fileInput" style="display: none;" type="file" accept=".csv"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
<input ref="fileInput" style="display: none;" type="file" accept=".csv"
|
|
74
|
+
@change="loadFile($event, section)" />
|
|
75
|
+
<div
|
|
76
|
+
style="cursor: pointer; border: 1px solid rgba(0, 0, 0, 0.12); text-align: center; padding: 20px; margin: 20px;"
|
|
77
|
+
@click="triggerImport(sectionIndex)">
|
|
78
|
+
Drag your CSV file here<br />
|
|
79
|
+
or click to browse
|
|
77
80
|
</div>
|
|
78
81
|
</td>
|
|
79
82
|
</tr>
|
|
@@ -142,10 +145,10 @@ export default {
|
|
|
142
145
|
this.sections = this.spec.sections;
|
|
143
146
|
this.sections.forEach((section, sectionIndex) => {
|
|
144
147
|
section.header = section.header || {};
|
|
145
|
-
section.index = sectionIndex
|
|
148
|
+
section.index = sectionIndex;
|
|
146
149
|
// Use Object.assign() to bind the nested property
|
|
147
150
|
Object.assign(section, { dataRows: [] });
|
|
148
|
-
})
|
|
151
|
+
});
|
|
149
152
|
this.autoloadAll(this.spec.nextPage);
|
|
150
153
|
this.initCsvExport();
|
|
151
154
|
this.initCsvImport();
|
|
@@ -168,7 +171,7 @@ export default {
|
|
|
168
171
|
tooltip: {
|
|
169
172
|
text: "Review before submitting"
|
|
170
173
|
}
|
|
171
|
-
}
|
|
174
|
+
};
|
|
172
175
|
},
|
|
173
176
|
headerCheckSpec(section) {
|
|
174
177
|
const sectionIndex = section.index;
|
|
@@ -185,25 +188,22 @@ export default {
|
|
|
185
188
|
value: { "var": "check_all" }
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
|
-
}
|
|
191
|
+
};
|
|
189
192
|
return result;
|
|
190
193
|
},
|
|
191
194
|
rowCheckSpec(sectionIndex, rowIndex) {
|
|
192
195
|
const id = this.rowCheckId(sectionIndex, rowIndex);
|
|
193
|
-
// TODO: Right now, there is a bug where when the "select all" checkbox is checked, the individual
|
|
194
|
-
// checkboxes do not get checked. BUT, it works if we change the `name: id` to a different name (see below).
|
|
195
|
-
// It looks like there is a bug where the `id` and `name` cannot be the same.
|
|
196
196
|
return {
|
|
197
197
|
view: 'fields/check',
|
|
198
198
|
checkValue: true,
|
|
199
|
-
|
|
200
|
-
name: id,
|
|
199
|
+
name: `${id}-name`, // For some unknown reason, equating the id and name values causes this function to be executed causing the component to be reset.
|
|
200
|
+
// name: id,
|
|
201
201
|
id: id
|
|
202
|
-
}
|
|
202
|
+
};
|
|
203
203
|
},
|
|
204
204
|
rowCheckId(sectionIndex, rowIndex) {
|
|
205
205
|
// Use underscore to prevent conflict with server-defined IDs, e.g. for pendingIconSpec()
|
|
206
|
-
return `_check_row_${sectionIndex}_${rowIndex}
|
|
206
|
+
return `_check_row_${sectionIndex}_${rowIndex}`;
|
|
207
207
|
},
|
|
208
208
|
colSpan(row, index) {
|
|
209
209
|
const spans = row.colSpans || [];
|
|
@@ -245,12 +245,14 @@ thead {
|
|
|
245
245
|
&.fixed-width {
|
|
246
246
|
min-width: 200px; // TODO: Make this configurable
|
|
247
247
|
}
|
|
248
|
+
|
|
248
249
|
&.status {
|
|
249
250
|
min-width: 80px;
|
|
250
251
|
}
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
}
|
|
255
|
+
|
|
254
256
|
tbody {
|
|
255
257
|
// tr.clickable {
|
|
256
258
|
// td>a {
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :style="$styles()" :class="$classes()" v-if="loadIf">
|
|
3
|
+
<div>Rows: {{ loadedRowCount }} Selected: {{ selectedRowCount }}</div>
|
|
4
|
+
<input ref="fileInput" style="display: none;" type="file" accept=".csv" @change="handleClick" />
|
|
5
|
+
<div class="scrollable">
|
|
6
|
+
<table>
|
|
7
|
+
<thead v-if="props.spec.viewHeaders">
|
|
8
|
+
<tr>
|
|
9
|
+
<th v-if="rowLoaded"><v-checkbox v-model="checkbox" color="primary" @change="checkAll"></v-checkbox></th>
|
|
10
|
+
<th v-for="cell in props.spec.viewHeaders" :key="cell.id"
|
|
11
|
+
:style="{ minWidth: `${cell.minWidth || 100}px` }">
|
|
12
|
+
<span>{{ cell.text }}</span>
|
|
13
|
+
</th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
|
|
17
|
+
<tbody>
|
|
18
|
+
<template v-if="rowLoaded">
|
|
19
|
+
<template v-for="(section, sectionIndex) in sections" :key="`head_${sectionIndex}`">
|
|
20
|
+
<tr v-for="(row, rowIndex) in section.rows" :key="`row_${rowIndex}`">
|
|
21
|
+
<td><v-checkbox v-model="row.selected" color="primary"></v-checkbox></td>
|
|
22
|
+
<td v-for="(cell, cellIndex) in row.columns" :key="`cell_${cellIndex}`"
|
|
23
|
+
@change="(e) => handleCellChange(e, cell)">
|
|
24
|
+
<glib-component :spec="cell.view"></glib-component>
|
|
25
|
+
</td>
|
|
26
|
+
</tr>
|
|
27
|
+
</template>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<tr v-else>
|
|
31
|
+
<td colspan="100%" style="padding-top: 8px">
|
|
32
|
+
<div class="gdrop-file border-[2px]" @dragover="(e) => e.preventDefault()" @drop="handleDrop"
|
|
33
|
+
@click="fileInput.click()">
|
|
34
|
+
|
|
35
|
+
<div class="cloud" style="pointer-events: none;">
|
|
36
|
+
<v-icon ref="icon" size="48" class="icon">cloud_upload</v-icon>
|
|
37
|
+
<h4 class="title">Drag your CSV file here</h4>
|
|
38
|
+
<p class="subtitle">or click to browse</p>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</td>
|
|
42
|
+
</tr>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<style lang="scss" scoped>
|
|
50
|
+
table thead th {
|
|
51
|
+
position: sticky;
|
|
52
|
+
top: 0px;
|
|
53
|
+
z-index: 1005;
|
|
54
|
+
background-color: white;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
57
|
+
|
|
58
|
+
<script setup>
|
|
59
|
+
import { computed, getCurrentInstance, ref, watch } from "vue";
|
|
60
|
+
import { parseCsv } from "../composable/parser";
|
|
61
|
+
import Action from "../../action";
|
|
62
|
+
|
|
63
|
+
class Cell {
|
|
64
|
+
constructor({ viewHeaders, cellIndex, rowId, view, value }) {
|
|
65
|
+
this.viewHeaders = viewHeaders;
|
|
66
|
+
this.cellIndex = cellIndex;
|
|
67
|
+
this.rowId = rowId;
|
|
68
|
+
this.view = view;
|
|
69
|
+
this.value = value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get cellId() {
|
|
73
|
+
return this.viewHeaders[this.cellIndex].id;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function handleClick(e) {
|
|
78
|
+
loadFile(e.target.files);
|
|
79
|
+
e.target.value = '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleDrop(e) {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
loadFile(e.dataTransfer.files);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function makeSection(section) {
|
|
88
|
+
const rows = section.dataRows.map((dataRow) => {
|
|
89
|
+
const selected = false;
|
|
90
|
+
const rowId = dataRow.rowId;
|
|
91
|
+
const columns = props.spec.viewColumns.map((viewColumn, viewColumnIndex) => {
|
|
92
|
+
const view = Object.assign({}, viewColumn, dataRow.columns[viewColumnIndex]);
|
|
93
|
+
const cellIndex = viewColumnIndex;
|
|
94
|
+
const viewHeaders = props.spec.viewHeaders;
|
|
95
|
+
const value = dataRow.columns[viewColumnIndex].value;
|
|
96
|
+
return new Cell({ rowId, view, cellIndex, viewHeaders, value });
|
|
97
|
+
});
|
|
98
|
+
return { selected, columns, rowId };
|
|
99
|
+
});
|
|
100
|
+
return Object.assign({}, section, { rows });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const props = defineProps(['spec']);
|
|
104
|
+
const fileInput = ref(null);
|
|
105
|
+
const checkbox = ref(false);
|
|
106
|
+
const instance = getCurrentInstance();
|
|
107
|
+
|
|
108
|
+
const fillableColumnIndexes = props.spec.viewHeaders.reduce((prev, curr, index) => {
|
|
109
|
+
if (curr.importable) prev.push(index);
|
|
110
|
+
return prev;
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
const sections = ref(props.spec.sections.map((section) => makeSection(section)));
|
|
114
|
+
|
|
115
|
+
watch(props, (value) => {
|
|
116
|
+
sections.value = value.spec.sections.map((section) => makeSection(section));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const selectedRows = computed(() => {
|
|
120
|
+
const rows = [];
|
|
121
|
+
sections.value.forEach((section) => section.rows.filter((row) => row.selected).forEach((row) => rows.push(row)));
|
|
122
|
+
return rows;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
watch(selectedRows, (value) => {
|
|
126
|
+
const rows = value.map((row) => {
|
|
127
|
+
const rowId = row.rowId;
|
|
128
|
+
const columns = row.columns.map((col) => ({ cellId: col.cellId, value: col.value }));
|
|
129
|
+
|
|
130
|
+
return { rowId, columns };
|
|
131
|
+
});
|
|
132
|
+
const data = Object.assign(
|
|
133
|
+
{},
|
|
134
|
+
props.spec.onRowSelected,
|
|
135
|
+
{ [props.spec.paramNameForFormData || 'formData']: rows }
|
|
136
|
+
);
|
|
137
|
+
Action.execute(data, instance.ctx);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const loadedRowCount = computed(() => sections.value.reduce((prev, curr) => prev + curr.dataRows.length, 0));
|
|
141
|
+
const selectedRowCount = computed(() => selectedRows.value.length);
|
|
142
|
+
const rowLoaded = computed(() => !!(sections.value[0] && sections.value[0].rows));
|
|
143
|
+
|
|
144
|
+
function checkAll() {
|
|
145
|
+
sections.value.forEach((section) => section.rows.forEach((row) => row.selected = checkbox.value));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function handleCellChange(e, cell) {
|
|
149
|
+
const rowId = cell.rowId;
|
|
150
|
+
const columnId = cell.cellId;
|
|
151
|
+
|
|
152
|
+
let value = null;
|
|
153
|
+
if (e.target instanceof HTMLInputElement) {
|
|
154
|
+
value = e.target.value;
|
|
155
|
+
} else {
|
|
156
|
+
value = e.target.querySelector('input').value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
cell.value = value;
|
|
160
|
+
|
|
161
|
+
const data = Object.assign(
|
|
162
|
+
{},
|
|
163
|
+
props.spec.onCellChange,
|
|
164
|
+
{ [props.spec.paramNameForFormData || 'formData']: { rowId, columnId, value } }
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
Action.execute(data, instance.ctx);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function loadFile(files) {
|
|
171
|
+
const reader = new FileReader();
|
|
172
|
+
reader.readAsText(files[0]);
|
|
173
|
+
|
|
174
|
+
reader.onload = (ev) => {
|
|
175
|
+
const csvData = parseCsv(ev.target.result);
|
|
176
|
+
const dataRows = csvData.map((columns) => {
|
|
177
|
+
let i = 0;
|
|
178
|
+
const cols = [];
|
|
179
|
+
props.spec.viewColumns.forEach((viewColumn, index) => {
|
|
180
|
+
const obj = {};
|
|
181
|
+
if (fillableColumnIndexes.includes(index)) {
|
|
182
|
+
cols.push(Object.assign(obj, viewColumn, { value: columns[i] }));
|
|
183
|
+
i++;
|
|
184
|
+
} else {
|
|
185
|
+
cols.push(Object.assign(obj, viewColumn));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
return { rowId: null, columns: cols };
|
|
189
|
+
});
|
|
190
|
+
const newSections = makeSection({ dataRows });
|
|
191
|
+
sections.value.push(newSections);
|
|
192
|
+
|
|
193
|
+
Action.execute(props.spec.onLoadRows, instance.ctx);
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
</script>
|
package/index.js
CHANGED
package/keys.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -24,20 +24,19 @@ export default {
|
|
|
24
24
|
|
|
25
25
|
const id = this.viewId;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
// const existingComponent = GLib.component.findById(id, false);
|
|
27
|
+
const existingComponent = GLib.component.findById(id);
|
|
29
28
|
// A component with the same ID in a different page shouldn't be considered a
|
|
30
29
|
// duplicate. See `utils/components#deregister` for more details.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
if (existingComponent) {
|
|
31
|
+
console.warn(
|
|
32
|
+
"Duplicate component ID:",
|
|
33
|
+
id,
|
|
34
|
+
"Existing:",
|
|
35
|
+
GLib.component.vueName(existingComponent),
|
|
36
|
+
"New:",
|
|
37
|
+
GLib.component.vueName(this)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
41
40
|
const newComponent = this;
|
|
42
41
|
GLib.component.register(id, newComponent);
|
|
43
42
|
}
|
package/plugins/vuetify.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createVuetify } from "vuetify";
|
|
2
2
|
// import 'material-design-icons-iconfont/dist/material-design-icons.css';
|
|
3
3
|
import { aliases, md } from 'vuetify/iconsets/md';
|
|
4
|
-
import 'vuetify/
|
|
4
|
+
import 'vuetify/styles';
|
|
5
5
|
import * as components from 'vuetify/components';
|
|
6
6
|
import { jsonView } from "../store";
|
|
7
7
|
// import * as directives from 'vuetify/directives'
|
|
8
|
-
import { md3 } from 'vuetify/blueprints';
|
|
8
|
+
// import { md3 } from 'vuetify/blueprints';
|
|
9
9
|
|
|
10
10
|
const opts = {
|
|
11
|
-
blueprint: md3,
|
|
11
|
+
// blueprint: md3,
|
|
12
12
|
components,
|
|
13
13
|
// directives,
|
|
14
14
|
icons: {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/static/redactorx.css
CHANGED
|
File without changes
|
package/static/redactorx.min.css
CHANGED
|
File without changes
|
package/static/redactorx.min.js
CHANGED
|
File without changes
|
|
File without changes
|
package/styles/test.sass
CHANGED
|
File without changes
|
package/styles/test.scss
CHANGED
|
File without changes
|
|
File without changes
|
package/utils/dom.js
CHANGED
|
File without changes
|
package/utils/helper.js
CHANGED
|
File without changes
|