@ditojs/admin 3.2.7 → 3.3.0
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/dito-admin.css +1 -1
- package/dist/dito-admin.es.js +6011 -5826
- package/dist/dito-admin.umd.js +3 -7
- package/package.json +18 -17
- package/src/DitoAdmin.js +44 -24
- package/src/DitoContext.js +28 -2
- package/src/DitoTypeComponent.js +1 -0
- package/src/appState.js +6 -3
- package/src/components/DitoAccount.vue +35 -27
- package/src/components/DitoAffixes.vue +9 -2
- package/src/components/DitoClipboard.vue +59 -93
- package/src/components/DitoConfirmMessage.vue +18 -0
- package/src/components/DitoContainer.vue +56 -18
- package/src/components/DitoCreateButton.vue +36 -84
- package/src/components/DitoDialog.vue +20 -15
- package/src/components/DitoDragHandle.vue +44 -0
- package/src/components/DitoDraggable.vue +43 -16
- package/src/components/DitoEditButtons.vue +48 -24
- package/src/components/DitoErrors.vue +9 -56
- package/src/components/DitoForm.vue +82 -42
- package/src/components/DitoInputAffixes.vue +50 -0
- package/src/components/DitoLabel.vue +1 -15
- package/src/components/DitoMenu.vue +45 -52
- package/src/components/DitoNotifications.vue +38 -14
- package/src/components/DitoOptionList.vue +81 -0
- package/src/components/DitoOptionsEditButtons.vue +57 -0
- package/src/components/DitoPagination.vue +1 -8
- package/src/components/DitoPane.vue +51 -39
- package/src/components/DitoPanel.vue +12 -26
- package/src/components/DitoPanels.vue +11 -5
- package/src/components/DitoResizeHandle.vue +47 -0
- package/src/components/DitoRoot.vue +113 -320
- package/src/components/DitoSchema.vue +72 -63
- package/src/components/DitoSchemaInlined.vue +8 -9
- package/src/components/DitoScopes.vue +14 -18
- package/src/components/DitoSidebar.vue +4 -29
- package/src/components/DitoSourceItem.vue +114 -0
- package/src/components/DitoTableCell.vue +4 -0
- package/src/components/DitoTableHead.vue +15 -17
- package/src/components/DitoTabs.vue +25 -0
- package/src/components/DitoTrail.vue +25 -25
- package/src/components/DitoTreeItem.vue +102 -141
- package/src/components/DitoUploadFile.vue +5 -2
- package/src/components/DitoView.vue +33 -24
- package/src/index.js +4 -1
- package/src/mixins/DitoMixin.js +77 -110
- package/src/mixins/DomMixin.js +12 -14
- package/src/mixins/EmitterMixin.js +3 -2
- package/src/mixins/ItemMixin.js +38 -94
- package/src/mixins/OptionsMixin.js +38 -25
- package/src/mixins/ResourceMixin.js +182 -111
- package/src/mixins/RouteMixin.js +61 -44
- package/src/mixins/SchemaParentMixin.js +4 -1
- package/src/mixins/SourceMixin.js +118 -100
- package/src/mixins/TypeMixin.js +42 -40
- package/src/mixins/ValidationMixin.js +16 -4
- package/src/mixins/ValidatorMixin.js +1 -1
- package/src/styles/_settings.scss +4 -0
- package/src/styles/_tippy.scss +0 -11
- package/src/styles/style.scss +0 -1
- package/src/types/DitoTypeButton.vue +11 -14
- package/src/types/DitoTypeCheckboxes.vue +35 -17
- package/src/types/DitoTypeCode.vue +19 -41
- package/src/types/DitoTypeColor.vue +67 -19
- package/src/types/DitoTypeDate.vue +11 -14
- package/src/types/DitoTypeList.vue +50 -62
- package/src/types/DitoTypeMarkup.vue +41 -54
- package/src/types/DitoTypeMultiselect.vue +82 -52
- package/src/types/DitoTypeNumber.vue +12 -15
- package/src/types/DitoTypeObject.vue +4 -38
- package/src/types/DitoTypeRadio.vue +19 -6
- package/src/types/DitoTypeSection.vue +23 -9
- package/src/types/DitoTypeSelect.vue +39 -23
- package/src/types/DitoTypeSlider.vue +9 -1
- package/src/types/DitoTypeSwitch.vue +1 -1
- package/src/types/DitoTypeText.vue +11 -14
- package/src/types/DitoTypeTreeList.vue +46 -8
- package/src/types/DitoTypeUpload.vue +190 -67
- package/src/utils/DataModel.js +368 -146
- package/src/utils/FileDropTargets.js +97 -0
- package/src/utils/ItemStores.js +31 -0
- package/src/utils/ListQuery.js +115 -0
- package/src/utils/LoadingTracker.js +76 -0
- package/src/utils/SchemaGraph.js +3 -2
- package/src/utils/Session.js +151 -0
- package/src/utils/ViewRegistry.js +85 -0
- package/src/utils/accessor.js +12 -4
- package/src/utils/affixes.js +33 -0
- package/src/utils/changeOnceEdited.js +33 -0
- package/src/utils/clipboard.js +55 -0
- package/src/utils/data.js +10 -5
- package/src/utils/dialogs.js +59 -0
- package/src/utils/dragResize.js +61 -0
- package/src/utils/filter.js +36 -2
- package/src/utils/html.js +9 -0
- package/src/utils/list.js +10 -0
- package/src/utils/options.js +4 -0
- package/src/utils/registration.js +18 -0
- package/src/utils/request.js +108 -13
- package/src/utils/route.js +6 -17
- package/src/utils/schema/data.js +24 -2
- package/src/utils/schema/events.js +19 -0
- package/src/utils/schema/item.js +114 -0
- package/src/utils/schema/lookup.js +39 -14
- package/src/utils/schema/setup.js +5 -5
- package/src/utils/schema/validation.js +16 -2
- package/src/utils/uid.js +105 -8
- package/src/validators/_decimals.js +16 -5
- package/types/index.d.ts +168 -41
- package/src/mixins/LoadingMixin.js +0 -23
- package/src/mixins/PulldownMixin.js +0 -72
- package/src/styles/_pulldown.scss +0 -38
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
|
-
.dito-upload
|
|
2
|
+
.dito-upload(
|
|
3
|
+
ref="dropTarget"
|
|
4
|
+
:class="{ 'dito-upload--drop-target': isDropTarget }"
|
|
5
|
+
)
|
|
3
6
|
//- In order to handle upload buttons in multiple possible places, depending
|
|
4
7
|
//- on whether they handle single or multiple uploads, render the upload
|
|
5
8
|
//- component invisibly at the root, and delegate the click events to it from
|
|
@@ -11,11 +14,12 @@
|
|
|
11
14
|
:name="dataPath"
|
|
12
15
|
:disabled="disabled"
|
|
13
16
|
:postAction="uploadPath"
|
|
17
|
+
:headers="uploadOptions?.headers"
|
|
14
18
|
:extensions="extensions"
|
|
15
19
|
:accept="accept"
|
|
16
20
|
:multiple="multiple"
|
|
17
21
|
:size="maxSize"
|
|
18
|
-
:drop="
|
|
22
|
+
:drop="true"
|
|
19
23
|
:dropDirectory="true"
|
|
20
24
|
@input-filter="onInputFilter"
|
|
21
25
|
@input-file="onInputFile"
|
|
@@ -41,9 +45,10 @@
|
|
|
41
45
|
template(
|
|
42
46
|
v-if="multiple || !isUploadActive"
|
|
43
47
|
)
|
|
48
|
+
//- Stored files have unique keys, uploading files unique ids:
|
|
44
49
|
tr(
|
|
45
50
|
v-for="(file, index) in files"
|
|
46
|
-
:key="file.name"
|
|
51
|
+
:key="file.key ?? file.id ?? file.name"
|
|
47
52
|
)
|
|
48
53
|
td(
|
|
49
54
|
v-if="render"
|
|
@@ -60,6 +65,7 @@
|
|
|
60
65
|
)
|
|
61
66
|
DitoUploadFile(
|
|
62
67
|
:file="file"
|
|
68
|
+
:upload="getUpload(file)"
|
|
63
69
|
:thumbnail="thumbnails"
|
|
64
70
|
:thumbnailUrl="thumbnailUrls[index]"
|
|
65
71
|
)
|
|
@@ -68,6 +74,7 @@
|
|
|
68
74
|
)
|
|
69
75
|
DitoUploadFile(
|
|
70
76
|
:file="file"
|
|
77
|
+
:upload="getUpload(file)"
|
|
71
78
|
:thumbnail="thumbnails"
|
|
72
79
|
:thumbnailUrl="thumbnailUrls[index]"
|
|
73
80
|
)
|
|
@@ -77,57 +84,56 @@
|
|
|
77
84
|
v-if="file.upload"
|
|
78
85
|
)
|
|
79
86
|
template(
|
|
80
|
-
v-if="file.upload.
|
|
87
|
+
v-if="file.upload.success"
|
|
81
88
|
)
|
|
82
|
-
|
|
|
89
|
+
| Uploaded
|
|
83
90
|
template(
|
|
84
|
-
v-else-if="file
|
|
91
|
+
v-else-if="getUpload(file)?.error"
|
|
85
92
|
)
|
|
86
|
-
|
|
|
93
|
+
| Error: {{ getUpload(file).error }}
|
|
87
94
|
template(
|
|
88
|
-
v-else-if="file
|
|
95
|
+
v-else-if="getUpload(file)?.active"
|
|
89
96
|
)
|
|
90
|
-
|
|
|
97
|
+
| Uploading...
|
|
91
98
|
template(
|
|
92
99
|
v-else
|
|
93
100
|
)
|
|
94
101
|
| Stored
|
|
95
102
|
td.dito-table__buttons
|
|
96
103
|
.dito-buttons.dito-buttons--round
|
|
97
|
-
|
|
104
|
+
DitoButton.dito-button--upload(
|
|
98
105
|
v-if="!multiple"
|
|
99
106
|
:title="uploadTitle"
|
|
100
107
|
@click="onClickUpload"
|
|
101
108
|
)
|
|
102
|
-
|
|
103
|
-
a.dito-button(
|
|
109
|
+
DitoDragHandle(
|
|
104
110
|
v-if="draggable"
|
|
105
|
-
|
|
111
|
+
:disabled="disabled"
|
|
112
|
+
@move="delta => moveFile(file, delta)"
|
|
106
113
|
)
|
|
107
|
-
|
|
114
|
+
DitoButton(
|
|
108
115
|
v-if="deletable"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
@click="deleteFile(file
|
|
116
|
+
:verb="verbs.delete"
|
|
117
|
+
:disabled="disabled"
|
|
118
|
+
@click="deleteFile(file)"
|
|
112
119
|
)
|
|
113
120
|
tfoot(
|
|
114
121
|
v-if="multiple || isUploadActive || !hasFiles"
|
|
115
122
|
)
|
|
116
123
|
tr
|
|
117
124
|
td(:colspan="4")
|
|
118
|
-
.dito-
|
|
125
|
+
.dito-upload__footer
|
|
119
126
|
progress.dito-progress(
|
|
120
127
|
v-if="isUploadActive"
|
|
121
128
|
:value="uploadProgress"
|
|
122
129
|
max="100"
|
|
123
130
|
)
|
|
124
131
|
.dito-buttons.dito-buttons--round
|
|
125
|
-
|
|
132
|
+
DitoButton(
|
|
126
133
|
v-if="isUploadActive"
|
|
127
|
-
type="button"
|
|
128
134
|
@click.prevent="upload.active = false"
|
|
129
135
|
) Cancel
|
|
130
|
-
|
|
136
|
+
DitoButton.dito-button--upload(
|
|
131
137
|
v-if="multiple || !hasFiles"
|
|
132
138
|
:title="uploadTitle"
|
|
133
139
|
@click="onClickUpload"
|
|
@@ -137,25 +143,49 @@
|
|
|
137
143
|
<script>
|
|
138
144
|
import DitoTypeComponent from '../DitoTypeComponent.js'
|
|
139
145
|
import DitoContext from '../DitoContext.js'
|
|
146
|
+
import DitoDragHandle from '../components/DitoDragHandle.vue'
|
|
147
|
+
import { DitoButton } from '@ditojs/ui/src'
|
|
140
148
|
import SortableMixin from '../mixins/SortableMixin.js'
|
|
141
149
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
142
150
|
import { formatFileSize, parseFileSize } from '../utils/units.js'
|
|
143
151
|
import { appendDataPath } from '../utils/data.js'
|
|
144
|
-
import {
|
|
152
|
+
import {
|
|
153
|
+
fetchBlob,
|
|
154
|
+
getUploadOptions,
|
|
155
|
+
resolveDownloadUrl
|
|
156
|
+
} from '../utils/request.js'
|
|
157
|
+
import { confirmAndRemove } from '../utils/dialogs.js'
|
|
158
|
+
import { getListWithMovedItem } from '../utils/list.js'
|
|
159
|
+
import { isArray, asArray, escapeHtml } from '@ditojs/utils'
|
|
145
160
|
import VueUpload from 'vue-upload-component'
|
|
146
161
|
|
|
147
162
|
// @vue/component
|
|
148
163
|
export default DitoTypeComponent.register('upload', {
|
|
149
164
|
mixins: [SortableMixin],
|
|
150
|
-
components: { VueUpload },
|
|
165
|
+
components: { VueUpload, DitoButton, DitoDragHandle },
|
|
166
|
+
inject: ['$fileDropTargets'],
|
|
151
167
|
|
|
152
168
|
data() {
|
|
153
169
|
return {
|
|
154
|
-
uploads: []
|
|
170
|
+
uploads: [],
|
|
171
|
+
// Removes the upload from the targets of dragged files, see
|
|
172
|
+
// `updateDropTarget()`.
|
|
173
|
+
removeDropTarget: null
|
|
155
174
|
}
|
|
156
175
|
},
|
|
157
176
|
|
|
158
177
|
computed: {
|
|
178
|
+
fileDropTargets() {
|
|
179
|
+
return this.$fileDropTargets()
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
// Whether files are dragged over the admin while the upload is enabled, for
|
|
183
|
+
// which it stands out above the overlay of `DitoRoot`. The dragged files'
|
|
184
|
+
// types can't be read before the drop, so `accept` isn't checked here.
|
|
185
|
+
isDropTarget() {
|
|
186
|
+
return this.fileDropTargets.isDraggingFiles && !this.disabled
|
|
187
|
+
},
|
|
188
|
+
|
|
159
189
|
upload() {
|
|
160
190
|
return this.$refs.upload
|
|
161
191
|
},
|
|
@@ -164,12 +194,24 @@ export default DitoTypeComponent.register('upload', {
|
|
|
164
194
|
return this.multiple ? 'Upload Files' : 'Upload File'
|
|
165
195
|
},
|
|
166
196
|
|
|
167
|
-
files
|
|
168
|
-
|
|
197
|
+
files: {
|
|
198
|
+
get() {
|
|
199
|
+
return asFiles(this.value)
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// Writes the reordered files, see `DitoDraggable` and `moveFile()`.
|
|
203
|
+
set(files) {
|
|
204
|
+
this.value = this.multiple ? files : files[0] ?? null
|
|
205
|
+
}
|
|
169
206
|
},
|
|
170
207
|
|
|
171
208
|
downloadUrls() {
|
|
172
|
-
|
|
209
|
+
// Resolve the URLs like `fetchBlob()` does, so that the links point to
|
|
210
|
+
// the same files that clicking them downloads:
|
|
211
|
+
return this.files.map((file, index) => {
|
|
212
|
+
const url = this.getDownloadUrl(file, index)
|
|
213
|
+
return url ? resolveDownloadUrl(this.api, url) : null
|
|
214
|
+
})
|
|
173
215
|
},
|
|
174
216
|
|
|
175
217
|
thumbnailUrls() {
|
|
@@ -233,6 +275,13 @@ export default DitoTypeComponent.register('upload', {
|
|
|
233
275
|
return this.files.length > 0
|
|
234
276
|
},
|
|
235
277
|
|
|
278
|
+
// The files of the upload component by their ids. It replaces a file's
|
|
279
|
+
// object on each update, so the files in the value only refer to their
|
|
280
|
+
// upload by id, see `onInputFile()` and `getUpload()`.
|
|
281
|
+
uploadsById() {
|
|
282
|
+
return new Map(this.uploads.map(upload => [upload.id, upload]))
|
|
283
|
+
},
|
|
284
|
+
|
|
236
285
|
hasUploads() {
|
|
237
286
|
return this.uploads.length > 0
|
|
238
287
|
},
|
|
@@ -256,15 +305,27 @@ export default DitoTypeComponent.register('upload', {
|
|
|
256
305
|
},
|
|
257
306
|
|
|
258
307
|
uploadPath() {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
308
|
+
// Uploads are posted to the resource of the data, see
|
|
309
|
+
// `api.resources.upload()`, which views without resource don't have.
|
|
310
|
+
return this.dataComponent?.resource
|
|
311
|
+
? this.getResourceUrl({
|
|
312
|
+
type: 'upload',
|
|
313
|
+
method: 'post',
|
|
314
|
+
path: this.api.normalizePath(this.dataPath)
|
|
315
|
+
})
|
|
316
|
+
: null
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
uploadOptions() {
|
|
320
|
+
return this.uploadPath
|
|
321
|
+
? getUploadOptions(this.api, this.uploadPath)
|
|
322
|
+
: null
|
|
264
323
|
}
|
|
265
324
|
},
|
|
266
325
|
|
|
267
326
|
watch: {
|
|
327
|
+
disabled: 'updateDropTarget',
|
|
328
|
+
|
|
268
329
|
isUploadReady(ready) {
|
|
269
330
|
if (ready) {
|
|
270
331
|
// Auto-upload.
|
|
@@ -275,9 +336,27 @@ export default DitoTypeComponent.register('upload', {
|
|
|
275
336
|
}
|
|
276
337
|
},
|
|
277
338
|
|
|
339
|
+
mounted() {
|
|
340
|
+
this.updateDropTarget()
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
unmounted() {
|
|
344
|
+
this.removeDropTarget?.()
|
|
345
|
+
},
|
|
346
|
+
|
|
278
347
|
methods: {
|
|
279
348
|
formatFileSize,
|
|
280
349
|
|
|
350
|
+
// Adds the upload to the targets of dragged files while it's enabled.
|
|
351
|
+
// `VueUpload` handles the files dropped on its parent, which is the same
|
|
352
|
+
// element, see `:drop="true"`.
|
|
353
|
+
updateDropTarget() {
|
|
354
|
+
this.removeDropTarget?.()
|
|
355
|
+
this.removeDropTarget = this.disabled
|
|
356
|
+
? null
|
|
357
|
+
: this.fileDropTargets.add(this.$refs.dropTarget)
|
|
358
|
+
},
|
|
359
|
+
|
|
281
360
|
getFileContext(file, index) {
|
|
282
361
|
return this.multiple
|
|
283
362
|
? new DitoContext(this, {
|
|
@@ -293,12 +372,18 @@ export default DitoTypeComponent.register('upload', {
|
|
|
293
372
|
return this.render(this.getFileContext(file, index))
|
|
294
373
|
},
|
|
295
374
|
|
|
375
|
+
// Returns the current file object of the upload component for a file that
|
|
376
|
+
// was added through it, or `null`.
|
|
377
|
+
getUpload(file) {
|
|
378
|
+
return file.upload ? (this.uploadsById.get(file.upload.id) ?? null) : null
|
|
379
|
+
},
|
|
380
|
+
|
|
296
381
|
getDownloadUrl(file, index) {
|
|
297
382
|
return file.url
|
|
298
383
|
? file.url
|
|
299
384
|
: !file.upload || file.upload.success
|
|
300
385
|
? this.getSchemaValue('downloadUrl', {
|
|
301
|
-
type:
|
|
386
|
+
type: String,
|
|
302
387
|
default: null,
|
|
303
388
|
context: this.getFileContext(file, index)
|
|
304
389
|
})
|
|
@@ -308,7 +393,7 @@ export default DitoTypeComponent.register('upload', {
|
|
|
308
393
|
getThumbnailUrl(file, index) {
|
|
309
394
|
return !file.upload || file.upload.success
|
|
310
395
|
? this.getSchemaValue('thumbnailUrl', {
|
|
311
|
-
type:
|
|
396
|
+
type: String,
|
|
312
397
|
default: null,
|
|
313
398
|
context: this.getFileContext(file, index)
|
|
314
399
|
}) || (
|
|
@@ -319,29 +404,40 @@ export default DitoTypeComponent.register('upload', {
|
|
|
319
404
|
: null
|
|
320
405
|
},
|
|
321
406
|
|
|
322
|
-
deleteFile(file
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
file
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
this.
|
|
407
|
+
async deleteFile(file) {
|
|
408
|
+
if (!file) return
|
|
409
|
+
await confirmAndRemove(this, {
|
|
410
|
+
label: escapeHtml(file.name),
|
|
411
|
+
// The file is only removed from the value, which still needs the form
|
|
412
|
+
// to be saved.
|
|
413
|
+
isTransient: true,
|
|
414
|
+
remove: () => {
|
|
415
|
+
// Look up the file by identity once confirmed, as the files may have
|
|
416
|
+
// changed while the dialog was open. Stored files may not have ids,
|
|
417
|
+
// see `getFileIndex()`.
|
|
418
|
+
const index = this.files.indexOf(file)
|
|
419
|
+
if (index < 0) {
|
|
420
|
+
return false
|
|
421
|
+
}
|
|
422
|
+
if (this.multiple) {
|
|
423
|
+
this.value.splice(index, 1)
|
|
424
|
+
} else {
|
|
425
|
+
this.value = null
|
|
426
|
+
}
|
|
427
|
+
if (file.upload) {
|
|
428
|
+
this.upload.remove(file.upload.id)
|
|
429
|
+
}
|
|
430
|
+
this.onChange()
|
|
338
431
|
}
|
|
432
|
+
})
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
// Moves the file by `delta` positions, see `DitoDragHandle`.
|
|
436
|
+
moveFile(file, delta) {
|
|
437
|
+
const files = getListWithMovedItem(this.files, file, delta)
|
|
438
|
+
if (files) {
|
|
439
|
+
this.files = files
|
|
339
440
|
this.onChange()
|
|
340
|
-
this.notify({
|
|
341
|
-
type: 'info',
|
|
342
|
-
title: 'Successfully Removed',
|
|
343
|
-
text: `${name} was ${this.verbs.deleted}.`
|
|
344
|
-
})
|
|
345
441
|
}
|
|
346
442
|
},
|
|
347
443
|
|
|
@@ -382,10 +478,14 @@ export default DitoTypeComponent.register('upload', {
|
|
|
382
478
|
this.replaceFile(file, null)
|
|
383
479
|
},
|
|
384
480
|
|
|
481
|
+
// Files added through the upload component refer to their upload with
|
|
482
|
+
// `upload: { id, success }` in the value: `success` tells `processValue()`
|
|
483
|
+
// which files were stored, and the upload's state is read through
|
|
484
|
+
// `getUpload()`.
|
|
385
485
|
onInputFile(newFile, oldFile) {
|
|
386
486
|
if (newFile && !oldFile) {
|
|
387
487
|
const { id, name, size } = newFile
|
|
388
|
-
this.addFile({ id, name, size, upload:
|
|
488
|
+
this.addFile({ id, name, size, upload: { id, success: false } })
|
|
389
489
|
}
|
|
390
490
|
if (newFile && oldFile) {
|
|
391
491
|
const { success, error } = newFile
|
|
@@ -393,9 +493,9 @@ export default DitoTypeComponent.register('upload', {
|
|
|
393
493
|
this.onChange()
|
|
394
494
|
const file = newFile.response[0]
|
|
395
495
|
if (file) {
|
|
396
|
-
file.upload = newFile
|
|
397
|
-
// Replace the
|
|
398
|
-
//
|
|
496
|
+
file.upload = { id: newFile.id, success: true }
|
|
497
|
+
// Replace the file added for the upload with the file received
|
|
498
|
+
// in the upload response.
|
|
399
499
|
this.replaceFile(newFile, file)
|
|
400
500
|
} else {
|
|
401
501
|
this.removeFile(newFile)
|
|
@@ -425,22 +525,32 @@ export default DitoTypeComponent.register('upload', {
|
|
|
425
525
|
},
|
|
426
526
|
|
|
427
527
|
onInputFilter(newFile /*, oldFile, prevent */) {
|
|
528
|
+
// `VueUpload` only creates the request when uploading, and has no setting
|
|
529
|
+
// for its credentials:
|
|
428
530
|
const xhr = newFile?.xhr
|
|
429
|
-
if (this.
|
|
531
|
+
if (this.uploadOptions?.withCredentials && xhr && !xhr.withCredentials) {
|
|
430
532
|
xhr.withCredentials = true
|
|
431
533
|
}
|
|
432
534
|
},
|
|
433
535
|
|
|
434
536
|
async onClickDownload(file, index) {
|
|
435
537
|
try {
|
|
436
|
-
const
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
filename: file.name,
|
|
440
|
-
|
|
441
|
-
|
|
538
|
+
const blob = await fetchBlob(this.api, this.downloadUrls[index])
|
|
539
|
+
const url = URL.createObjectURL(blob)
|
|
540
|
+
try {
|
|
541
|
+
this.download({ filename: file.name, url })
|
|
542
|
+
} finally {
|
|
543
|
+
// Release the blob once the browser started the download, which
|
|
544
|
+
// some browsers don't do synchronously when the link is clicked.
|
|
545
|
+
setTimeout(() => URL.revokeObjectURL(url), 1000)
|
|
546
|
+
}
|
|
442
547
|
} catch (error) {
|
|
443
|
-
|
|
548
|
+
this.notify({
|
|
549
|
+
type: 'error',
|
|
550
|
+
error,
|
|
551
|
+
title: 'File Download Error',
|
|
552
|
+
text: `Unable to download ${file.name}: ${error.message}`
|
|
553
|
+
})
|
|
444
554
|
}
|
|
445
555
|
},
|
|
446
556
|
|
|
@@ -470,6 +580,19 @@ function asFiles(value) {
|
|
|
470
580
|
@import '../styles/_imports';
|
|
471
581
|
|
|
472
582
|
.dito-upload {
|
|
583
|
+
// Positioned for `z-index`, to stay above the overlay of `DitoRoot` until it
|
|
584
|
+
// faded out:
|
|
585
|
+
position: relative;
|
|
586
|
+
transition:
|
|
587
|
+
filter $drag-overlay-duration,
|
|
588
|
+
z-index 0s $drag-overlay-duration;
|
|
589
|
+
|
|
590
|
+
&--drop-target {
|
|
591
|
+
z-index: $z-index-drag-overlay + 1;
|
|
592
|
+
filter: drop-shadow(0 4px 8px rgb(0, 0, 0, 0.25));
|
|
593
|
+
transition: filter $drag-overlay-duration;
|
|
594
|
+
}
|
|
595
|
+
|
|
473
596
|
.dito-table {
|
|
474
597
|
tr,
|
|
475
598
|
.dito-table__buttons {
|