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.
Files changed (80) hide show
  1. package/LICENSE +0 -0
  2. package/actions/auth/restart.js +0 -0
  3. package/actions/commands/copy.js +0 -0
  4. package/actions/dialogs/notification.js +0 -0
  5. package/actions/dialogs/oauth.js +0 -0
  6. package/actions/dialogs/reload.js +0 -0
  7. package/actions/http/delete.js +0 -0
  8. package/actions/sheets/select.js +0 -0
  9. package/actions/snackbars/select.js +0 -0
  10. package/actions/windows/openWeb.js +0 -0
  11. package/actions/windows/print.js +0 -0
  12. package/app.scss +172 -0
  13. package/components/_message.vue +0 -0
  14. package/components/component.vue +2 -0
  15. package/components/composable/parser.js +41 -0
  16. package/components/fields/multiUpload.vue +3 -191
  17. package/components/fields/phone/countries.js +0 -0
  18. package/components/fields/phone/sprite.css +0 -0
  19. package/components/h1.vue +0 -0
  20. package/components/h2.vue +0 -0
  21. package/components/h3.vue +0 -0
  22. package/components/h5.vue +0 -0
  23. package/components/h6.vue +0 -0
  24. package/components/hr.vue +0 -0
  25. package/components/html.vue +0 -0
  26. package/components/icon.vue +0 -0
  27. package/components/mixins/extension.js +0 -0
  28. package/components/mixins/longClick.js +0 -0
  29. package/components/mixins/scrolling.js +0 -0
  30. package/components/mixins/table/export.js +0 -0
  31. package/components/mixins/text.js +0 -0
  32. package/components/multimedia/video.vue +0 -0
  33. package/components/panels/bulkEdit.vue +17 -15
  34. package/components/panels/bulkEdit2.vue +197 -0
  35. package/index.js +2 -0
  36. package/keys.js +0 -0
  37. package/package.json +1 -1
  38. package/plugins/updatableComponent.js +11 -12
  39. package/plugins/vuetify.js +3 -3
  40. package/static/plugins/alignment/alignment.js +0 -0
  41. package/static/plugins/alignment/alignment.min.js +0 -0
  42. package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
  43. package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
  44. package/static/plugins/blockcode/blockcode.js +0 -0
  45. package/static/plugins/blockcode/blockcode.min.js +0 -0
  46. package/static/plugins/clips/clips.js +0 -0
  47. package/static/plugins/clips/clips.min.js +0 -0
  48. package/static/plugins/counter/counter.js +0 -0
  49. package/static/plugins/counter/counter.min.js +0 -0
  50. package/static/plugins/definedlinks/definedlinks.js +0 -0
  51. package/static/plugins/definedlinks/definedlinks.min.js +0 -0
  52. package/static/plugins/handle/handle.js +0 -0
  53. package/static/plugins/handle/handle.min.js +0 -0
  54. package/static/plugins/icons/icons.js +0 -0
  55. package/static/plugins/icons/icons.min.js +0 -0
  56. package/static/plugins/imageposition/imageposition.js +0 -0
  57. package/static/plugins/imageposition/imageposition.min.js +0 -0
  58. package/static/plugins/inlineformat/inlineformat.js +0 -0
  59. package/static/plugins/inlineformat/inlineformat.min.js +0 -0
  60. package/static/plugins/removeformat/removeformat.js +0 -0
  61. package/static/plugins/removeformat/removeformat.min.js +0 -0
  62. package/static/plugins/selector/selector.js +0 -0
  63. package/static/plugins/selector/selector.min.js +0 -0
  64. package/static/plugins/specialchars/specialchars.js +0 -0
  65. package/static/plugins/specialchars/specialchars.min.js +0 -0
  66. package/static/plugins/textdirection/textdirection.js +0 -0
  67. package/static/plugins/textdirection/textdirection.min.js +0 -0
  68. package/static/plugins/textexpander/textexpander.js +0 -0
  69. package/static/plugins/textexpander/textexpander.min.js +0 -0
  70. package/static/plugins/underline/underline.js +0 -0
  71. package/static/plugins/underline/underline.min.js +0 -0
  72. package/static/redactorx.css +0 -0
  73. package/static/redactorx.min.css +0 -0
  74. package/static/redactorx.min.js +0 -0
  75. package/static/redactorx.usm.min.js +0 -0
  76. package/styles/test.sass +0 -0
  77. package/styles/test.scss +0 -0
  78. package/templates/unsupported.vue +0 -0
  79. package/utils/dom.js +0 -0
  80. package/utils/helper.js +0 -0
package/LICENSE CHANGED
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/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
+ }
File without changes
@@ -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
File without changes
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" @change="loadFile($event, section)" />
74
- <div style="cursor: pointer; border: 1px solid rgba(0, 0, 0, 0.12); text-align: center; padding: 20px; margin: 20px;" @click="triggerImport(sectionIndex)">
75
- Drag your CSV file here<br />
76
- or click to browse
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
- // name: `${id}-name`, // This works with "select all" (see above)
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
@@ -5,6 +5,8 @@ import { settings } from "./utils/settings";
5
5
  import { useTheme } from "vuetify";
6
6
  import { jsonView, vueApp } from "./store";
7
7
 
8
+ import './app.scss';
9
+
8
10
  // lib for deep merge
9
11
  import merge from 'lodash.merge';
10
12
 
package/keys.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "4.8.1",
3
+ "version": "4.8.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -24,20 +24,19 @@ export default {
24
24
 
25
25
  const id = this.viewId;
26
26
 
27
- // const id = spec.id;
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
- // if (existingComponent) {
32
- // console.warn(
33
- // "Duplicate component ID:",
34
- // id,
35
- // "Existing:",
36
- // GLib.component.vueName(existingComponent),
37
- // "New:",
38
- // GLib.component.vueName(this)
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
  }
@@ -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/lib/styles/main.sass';
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
File without changes
File without changes
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