quasar-ui-danx 0.0.9 → 0.0.11
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/package.json +3 -2
- package/src/components/ActionTable/ActionTable.vue +135 -0
- package/src/components/ActionTable/BatchActionMenu.vue +60 -0
- package/src/components/ActionTable/EmptyTableState.vue +33 -0
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +36 -0
- package/src/components/ActionTable/Filters/FilterGroupItem.vue +28 -0
- package/src/components/ActionTable/Filters/FilterGroupList.vue +76 -0
- package/src/components/ActionTable/Filters/FilterListToggle.vue +50 -0
- package/src/components/ActionTable/Filters/FilterableField.vue +141 -0
- package/src/components/ActionTable/Form/Fields/BooleanField.vue +37 -0
- package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/DateField.vue +59 -0
- package/src/components/ActionTable/Form/Fields/DateRangeField.vue +110 -0
- package/src/components/ActionTable/Form/Fields/DateTimeField.vue +50 -0
- package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +59 -0
- package/src/components/ActionTable/Form/Fields/EditableDiv.vue +39 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +32 -0
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +78 -0
- package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +44 -0
- package/src/components/ActionTable/Form/Fields/IntegerField.vue +26 -0
- package/src/components/ActionTable/Form/Fields/LabeledInput.vue +63 -0
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +91 -0
- package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +57 -0
- package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +39 -0
- package/src/components/ActionTable/Form/Fields/NumberField.vue +94 -0
- package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +140 -0
- package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +136 -0
- package/src/components/ActionTable/Form/Fields/SelectField.vue +318 -0
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +81 -0
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +78 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +82 -0
- package/src/components/ActionTable/Form/Fields/WysiwygField.vue +46 -0
- package/src/components/ActionTable/Form/Fields/index.ts +23 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +74 -0
- package/src/components/ActionTable/RenderComponentColumn.vue +22 -0
- package/src/components/ActionTable/TableSummaryRow.vue +95 -0
- package/src/components/ActionTable/index.ts +15 -0
- package/src/components/ActionTable/listActions.ts +361 -0
- package/src/components/ActionTable/tableColumns.ts +72 -0
- package/src/components/ActionTable/tableHelpers.ts +83 -0
- package/src/components/DragAndDrop/listDragAndDrop.ts +210 -210
- package/src/components/Utility/CollapsableSidebar.vue +119 -0
- package/src/components/Utility/ContentDrawer.vue +70 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +132 -0
- package/src/components/Utility/Dialogs/FullScreenDialog.vue +46 -0
- package/src/components/Utility/Dialogs/InfoDialog.vue +92 -0
- package/src/components/Utility/Dialogs/InputDialog.vue +35 -0
- package/src/components/Utility/SvgImg.vue +10 -5
- package/src/components/Utility/Transitions/ListTransition.vue +50 -0
- package/src/components/Utility/Transitions/SlideTransition.vue +63 -0
- package/src/components/Utility/Transitions/StaggeredListTransition.vue +97 -0
- package/src/components/Utility/index.ts +9 -0
- package/src/components/index.ts +3 -0
- package/src/helpers/FileUpload.ts +294 -0
- package/src/helpers/FlashMessages.ts +79 -0
- package/src/helpers/array.ts +37 -0
- package/src/helpers/compatibility.ts +64 -0
- package/src/helpers/date.ts +5 -0
- package/src/helpers/download.ts +192 -0
- package/src/helpers/downloadPdf.ts +92 -0
- package/src/helpers/files.ts +52 -0
- package/src/helpers/formats.ts +183 -0
- package/src/helpers/http.ts +62 -0
- package/src/helpers/index.ts +10 -1
- package/src/helpers/multiFileUpload.ts +68 -0
- package/src/helpers/singleFileUpload.ts +54 -0
- package/src/helpers/storage.ts +8 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
import { download } from "danx/src/helpers/download";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Asynchronously load a file from the URL and trigger a download in the browser
|
5
|
+
*
|
6
|
+
* @param url
|
7
|
+
* @param filename
|
8
|
+
* @param postParams
|
9
|
+
* @returns {Promise<void>}
|
10
|
+
*/
|
11
|
+
export async function downloadFile(url, filename = "", postParams = null) {
|
12
|
+
let fetchOptions = undefined;
|
13
|
+
|
14
|
+
if (postParams) {
|
15
|
+
fetchOptions = {
|
16
|
+
method: "POST",
|
17
|
+
"Content-Type": "application/json",
|
18
|
+
body: JSON.stringify(postParams)
|
19
|
+
};
|
20
|
+
}
|
21
|
+
|
22
|
+
const response = await fetch(url, fetchOptions);
|
23
|
+
|
24
|
+
if (!response.ok) {
|
25
|
+
throw Error("File download failed: invalid response from server");
|
26
|
+
}
|
27
|
+
|
28
|
+
let errorMessage;
|
29
|
+
|
30
|
+
// Handle a JSON response (which indicates an error occurred)
|
31
|
+
try {
|
32
|
+
// @ts-expect-error data is defined on response
|
33
|
+
const jsonResponse = JSON.parse(new TextDecoder().decode(response.data));
|
34
|
+
console.error("Error downloading file:", jsonResponse);
|
35
|
+
errorMessage = jsonResponse.message;
|
36
|
+
if (jsonResponse.errors) {
|
37
|
+
errorMessage = jsonResponse.errors[0].message;
|
38
|
+
}
|
39
|
+
} catch (e) {
|
40
|
+
// we expect an error thrown for invalid JSON when the response is a file
|
41
|
+
}
|
42
|
+
|
43
|
+
if (errorMessage) {
|
44
|
+
throw new Error("Failed to download file: " + errorMessage);
|
45
|
+
}
|
46
|
+
|
47
|
+
await downloadFileResponse(response, filename);
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Downloads a file from a response object w/ a file attachment
|
52
|
+
*
|
53
|
+
* @param response
|
54
|
+
* @param filename
|
55
|
+
*/
|
56
|
+
export async function downloadFileResponse(response, filename = "") {
|
57
|
+
const contentDisposition = getResponseHeader(
|
58
|
+
response,
|
59
|
+
"content-disposition",
|
60
|
+
""
|
61
|
+
);
|
62
|
+
|
63
|
+
const contentType = getResponseHeader(response, "content-type", "");
|
64
|
+
|
65
|
+
const match = contentDisposition.match(/filename="([^"]+)"/);
|
66
|
+
|
67
|
+
filename = filename || (match && match[1]) || "download.pdf";
|
68
|
+
|
69
|
+
let data = response.data;
|
70
|
+
if (!data) {
|
71
|
+
data = await response.blob();
|
72
|
+
}
|
73
|
+
|
74
|
+
download(data, filename, contentType);
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Get a header from a response object
|
79
|
+
* @param response
|
80
|
+
* @param header
|
81
|
+
* @param defaultValue
|
82
|
+
* @returns {*}
|
83
|
+
*/
|
84
|
+
export function getResponseHeader(response, header, defaultValue) {
|
85
|
+
if (response.headers) {
|
86
|
+
if (typeof response.headers.get === "function") {
|
87
|
+
return response.headers.get(header) || defaultValue;
|
88
|
+
} else {
|
89
|
+
return response.headers[header] || defaultValue;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { FlashMessages, useCompatibility } from "danx/src/helpers";
|
2
|
+
import ExifReader from "exifreader";
|
3
|
+
|
4
|
+
export async function resolveFileLocation(file, waitMessage = null) {
|
5
|
+
if (file.location) {
|
6
|
+
return file.location;
|
7
|
+
}
|
8
|
+
|
9
|
+
try {
|
10
|
+
const tags = await ExifReader.load(file.blobUrl || file.url, {
|
11
|
+
expanded: true
|
12
|
+
});
|
13
|
+
if (tags.gps) {
|
14
|
+
return {
|
15
|
+
latitude: tags.gps.Latitude,
|
16
|
+
longitude: tags.gps.Longitude
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
const { waitForLocation, location } = useCompatibility();
|
21
|
+
|
22
|
+
// Show a waiting for location message if we have not returned within 1 second
|
23
|
+
if (waitMessage) {
|
24
|
+
setTimeout(() => {
|
25
|
+
if (!location.value && waitMessage) {
|
26
|
+
FlashMessages.warning(waitMessage);
|
27
|
+
}
|
28
|
+
}, 1000);
|
29
|
+
}
|
30
|
+
|
31
|
+
// Wait for the browser to return the location (https only as http will not return a location)
|
32
|
+
if (window.location.protocol === "https:") {
|
33
|
+
await waitForLocation();
|
34
|
+
}
|
35
|
+
// Ignore the wait message if we already returned
|
36
|
+
waitMessage = false;
|
37
|
+
if (!location.value) {
|
38
|
+
return null;
|
39
|
+
}
|
40
|
+
|
41
|
+
return {
|
42
|
+
latitude: location.value.latitude,
|
43
|
+
longitude: location.value.longitude,
|
44
|
+
accuracy: location.value.accuracy,
|
45
|
+
altitude: location.value.altitude,
|
46
|
+
altitudeAccuracy: location.value.altitudeAccuracy
|
47
|
+
};
|
48
|
+
} catch (error) {
|
49
|
+
console.error(error);
|
50
|
+
return null;
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,183 @@
|
|
1
|
+
import { DateTime, IANAZone } from "luxon";
|
2
|
+
|
3
|
+
const SERVER_TZ = new IANAZone("America/Chicago");
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Converts a date string from the server's time zone to the user's time zone.
|
7
|
+
* @param {String} dateTimeString
|
8
|
+
* @returns {DateTime}
|
9
|
+
*/
|
10
|
+
export function localizedDateTime(dateTimeString) {
|
11
|
+
dateTimeString = dateTimeString?.replace("T", " ");
|
12
|
+
// noinspection JSCheckFunctionSignatures
|
13
|
+
return DateTime.fromSQL(dateTimeString, { zone: SERVER_TZ }).setZone("local");
|
14
|
+
}
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Converts a date string from the user's time zone to the server's time zone.
|
18
|
+
* @param dateTimeString
|
19
|
+
* @returns {DateTime}
|
20
|
+
*/
|
21
|
+
export function remoteDateTime(dateTimeString) {
|
22
|
+
dateTimeString = dateTimeString?.replace("T", " ");
|
23
|
+
// noinspection JSCheckFunctionSignatures
|
24
|
+
return DateTime.fromSQL(dateTimeString, { zone: "local" }).setZone(SERVER_TZ);
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @param {DateTime|String} dateTime
|
29
|
+
* @returns {DateTime|*}
|
30
|
+
*/
|
31
|
+
export function parseDateTime(dateTime) {
|
32
|
+
if (typeof dateTime === "string") {
|
33
|
+
dateTime = dateTime.replace("T", " ").replace(/\//g, "-");
|
34
|
+
return DateTime.fromSQL(dateTime);
|
35
|
+
}
|
36
|
+
return dateTime || DateTime.fromSQL("0000-00-00 00:00:00");
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Parses a Quasar formatted date string into a Luxon DateTime object
|
41
|
+
* @param date
|
42
|
+
* @param format
|
43
|
+
* @returns {DateTime}
|
44
|
+
*/
|
45
|
+
export function parseQDate(date, format = "yyyy/MM/dd") {
|
46
|
+
return DateTime.fromFormat(date, format);
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* Parses a Quasar formatted date/time string into a Luxon DateTime object
|
51
|
+
* @param date
|
52
|
+
* @param format
|
53
|
+
* @returns {DateTime}
|
54
|
+
*/
|
55
|
+
export function parseQDateTime(date, format = "yyyy/MM/dd HH:mm:ss") {
|
56
|
+
return DateTime.fromFormat(date, format);
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Formats a Luxon DateTime object into a Quasar formatted date string
|
61
|
+
* @param date
|
62
|
+
* @returns {string}
|
63
|
+
*/
|
64
|
+
export function fQDate(date) {
|
65
|
+
return fDate(date, { format: "yyyy/MM/dd" });
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
*
|
70
|
+
* @param {String} dateTimeString
|
71
|
+
* @param options
|
72
|
+
* @returns {string}
|
73
|
+
*/
|
74
|
+
export function fLocalizedDateTime(dateTimeString, options = {}) {
|
75
|
+
return fDateTime(localizedDateTime(dateTimeString), options);
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Formats a date/time object or string into a human-readable format
|
80
|
+
*
|
81
|
+
* @param {String|Object} dateTime
|
82
|
+
* @param format
|
83
|
+
* @param {String|null} empty
|
84
|
+
* @returns {string}
|
85
|
+
*/
|
86
|
+
export function fDateTime(
|
87
|
+
dateTime = null,
|
88
|
+
{ format = "M/d/yy h:mma", empty = "- -" } = {}
|
89
|
+
) {
|
90
|
+
const formatted = (dateTime ? parseDateTime(dateTime) : DateTime.now()).toFormat(format).toLowerCase();
|
91
|
+
return formatted === "invalid datetime" ? empty : formatted;
|
92
|
+
}
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Formats a date/time object or string into the best format for DB input
|
96
|
+
* @param dateTime
|
97
|
+
* @returns {string}
|
98
|
+
*/
|
99
|
+
export function dbDateTime(dateTime = null) {
|
100
|
+
return fDateTime(dateTime, { format: "yyyy-MM-dd HH:mm:ss", empty: null });
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Formats a date object or string into a human-readable format
|
105
|
+
* @param {String|Object} dateTime
|
106
|
+
* @param {String|null} empty
|
107
|
+
* @param format
|
108
|
+
* @returns {string}
|
109
|
+
*/
|
110
|
+
export function fDate(dateTime, { empty = "--", format = "M/d/yy" } = {}) {
|
111
|
+
const formatted = parseDateTime(dateTime).toFormat(format);
|
112
|
+
return ["Invalid DateTime", "invalid datetime"].includes(formatted) ? empty : formatted;
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Formats a number of seconds into Hours / Minutes / Seconds or just Minutes and Seconds
|
117
|
+
*
|
118
|
+
* @param second
|
119
|
+
* @returns {string}
|
120
|
+
*/
|
121
|
+
export function fSecondsToTime(second) {
|
122
|
+
const time = DateTime.now().setZone("UTC").startOf("year").set({ second });
|
123
|
+
const hours = Math.floor(second / 3600);
|
124
|
+
return (hours ? hours + ":" : "") + time.toFormat("mm:ss");
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Formats an amount into USD currency format
|
129
|
+
* @param amount
|
130
|
+
* @returns {string}
|
131
|
+
*/
|
132
|
+
export function fCurrency(amount) {
|
133
|
+
return new Intl.NumberFormat("en-US", {
|
134
|
+
style: "currency",
|
135
|
+
currency: "USD"
|
136
|
+
}).format(amount);
|
137
|
+
}
|
138
|
+
|
139
|
+
/**
|
140
|
+
* Formats a number into a human-readable format
|
141
|
+
* @param number
|
142
|
+
* @param options
|
143
|
+
* @returns {string}
|
144
|
+
*/
|
145
|
+
export function fNumber(number, options = {}) {
|
146
|
+
return new Intl.NumberFormat("en-US", options).format(number);
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Truncates the string by removing chars from the middle of the string
|
151
|
+
* @param str
|
152
|
+
* @param maxLength
|
153
|
+
* @returns {string|*}
|
154
|
+
*/
|
155
|
+
export function centerTruncate(str, maxLength) {
|
156
|
+
if (str.length > maxLength) {
|
157
|
+
const frontCharCount = Math.floor((maxLength - 3) / 2);
|
158
|
+
const backCharCount = maxLength - frontCharCount - 3;
|
159
|
+
return (
|
160
|
+
str.substring(0, frontCharCount) +
|
161
|
+
"..." +
|
162
|
+
str.substring(str.length - backCharCount)
|
163
|
+
);
|
164
|
+
} else {
|
165
|
+
return str;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Formats a number into a percentage
|
171
|
+
* @param num
|
172
|
+
* @param options
|
173
|
+
* @returns {string}
|
174
|
+
*/
|
175
|
+
export function fPercent(num, options = { multiplier: 100, maximumFractionDigits: 1, NaN: "N/A" }) {
|
176
|
+
num = parseFloat(num);
|
177
|
+
|
178
|
+
if (isNaN(num)) {
|
179
|
+
return options.NaN;
|
180
|
+
}
|
181
|
+
|
182
|
+
return fNumber(num * options.multiplier, options) + "%";
|
183
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
export const request = {
|
2
|
+
async get(url, options = {}) {
|
3
|
+
return fetch(url, {
|
4
|
+
method: "get",
|
5
|
+
headers: {
|
6
|
+
Accept: "application/json",
|
7
|
+
"Content-Type": "application/json"
|
8
|
+
},
|
9
|
+
...options
|
10
|
+
});
|
11
|
+
},
|
12
|
+
|
13
|
+
async post(url, data = {}, options = {}) {
|
14
|
+
return fetch(url, {
|
15
|
+
method: "post",
|
16
|
+
body: JSON.stringify(data),
|
17
|
+
headers: {
|
18
|
+
Accept: "application/json",
|
19
|
+
"Content-Type": "application/json"
|
20
|
+
},
|
21
|
+
...options
|
22
|
+
}).then((r) => r.json());
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Fetches a resource list applying the filter. If there is a selected resource,
|
28
|
+
* stores that resource from the already populated list. If that resource does not exist
|
29
|
+
* also fetches that resource record from the endpoint, then adds it to the list if it
|
30
|
+
* does not exist in the filtered list
|
31
|
+
*
|
32
|
+
* @param fetchFn
|
33
|
+
* @param list
|
34
|
+
* @param id
|
35
|
+
* @param filter
|
36
|
+
* @returns {Promise<void>}
|
37
|
+
*/
|
38
|
+
export async function fetchResourceListWithSelected(fetchFn, list, id, filter) {
|
39
|
+
// First make sure we have the selected record, so we can always add it to the list
|
40
|
+
let selectedResource;
|
41
|
+
if (id) {
|
42
|
+
selectedResource = list.value.find((c) => c.id === id) || (await fetchFn({ id }))[0];
|
43
|
+
}
|
44
|
+
|
45
|
+
// Get the filtered campaign list
|
46
|
+
list.value = await fetchFn(filter);
|
47
|
+
|
48
|
+
// If our selected campaign is not in the filtered list, add it
|
49
|
+
if (selectedResource && !list.value.find((c) => c.id === id)) {
|
50
|
+
list.value.push(selectedResource);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Returns the value of the URL parameter (if it is set)
|
56
|
+
* @param key
|
57
|
+
* @param url
|
58
|
+
*/
|
59
|
+
export function getUrlParam(key, url = undefined) {
|
60
|
+
const params = new URLSearchParams(url?.replace(/.*\?/, "") || window.location.search);
|
61
|
+
return params.get(key);
|
62
|
+
}
|
package/src/helpers/index.ts
CHANGED
@@ -1 +1,10 @@
|
|
1
|
-
export * from
|
1
|
+
export * from "./array";
|
2
|
+
export * from "./compatibility";
|
3
|
+
export * from "./files";
|
4
|
+
export * from "./FileUpload";
|
5
|
+
export * from "./FlashMessages";
|
6
|
+
export * from "./http";
|
7
|
+
export * from "./multiFileUpload";
|
8
|
+
export * from "./singleFileUpload";
|
9
|
+
export * from "./storage";
|
10
|
+
export * from "./utils";
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import { FileUpload, FileUploadOptions } from "danx/src/helpers/FileUpload";
|
2
|
+
import { ref } from "vue";
|
3
|
+
|
4
|
+
export function useMultiFileUpload(options: FileUploadOptions) {
|
5
|
+
const uploadedFiles = ref([]);
|
6
|
+
const onCompleteCb = ref(null);
|
7
|
+
const onFilesChangeCb = ref(null);
|
8
|
+
const onFilesSelected = (e) => {
|
9
|
+
uploadedFiles.value = [...uploadedFiles.value, ...e.target.files];
|
10
|
+
new FileUpload(e.target.files, options)
|
11
|
+
.onProgress(({ file }) => {
|
12
|
+
updateFileInList(file);
|
13
|
+
})
|
14
|
+
.onComplete(({ file, uploadedFile }) => {
|
15
|
+
updateFileInList(file, uploadedFile);
|
16
|
+
})
|
17
|
+
.onAllComplete(() => {
|
18
|
+
onCompleteCb.value && onCompleteCb.value();
|
19
|
+
onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
|
20
|
+
})
|
21
|
+
.upload();
|
22
|
+
};
|
23
|
+
|
24
|
+
function updateFileInList(file, replace = null) {
|
25
|
+
const index = uploadedFiles.value.findIndex(f => f.id === file.id);
|
26
|
+
if (index !== -1) {
|
27
|
+
uploadedFiles.value.splice(index, 1, replace || file);
|
28
|
+
}
|
29
|
+
onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
|
30
|
+
}
|
31
|
+
|
32
|
+
const onDrop = (e) => {
|
33
|
+
onFilesSelected({ target: { files: e.dataTransfer.files } });
|
34
|
+
};
|
35
|
+
|
36
|
+
const onFilesChange = (cb) => {
|
37
|
+
onFilesChangeCb.value = cb;
|
38
|
+
};
|
39
|
+
|
40
|
+
const onComplete = (cb) => {
|
41
|
+
onCompleteCb.value = cb;
|
42
|
+
};
|
43
|
+
|
44
|
+
const onClear = () => {
|
45
|
+
uploadedFiles.value = [];
|
46
|
+
onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
|
47
|
+
onCompleteCb.value && onCompleteCb.value();
|
48
|
+
};
|
49
|
+
|
50
|
+
const onRemove = (file) => {
|
51
|
+
const index = uploadedFiles.value.findIndex(f => f.id === file.id);
|
52
|
+
if (index !== -1) {
|
53
|
+
uploadedFiles.value.splice(index, 1);
|
54
|
+
}
|
55
|
+
onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
|
56
|
+
onCompleteCb.value && onCompleteCb.value();
|
57
|
+
};
|
58
|
+
|
59
|
+
return {
|
60
|
+
onClear,
|
61
|
+
onRemove,
|
62
|
+
onComplete,
|
63
|
+
onFilesChange,
|
64
|
+
onDrop,
|
65
|
+
onFilesSelected,
|
66
|
+
uploadedFiles
|
67
|
+
};
|
68
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { FileUpload, FileUploadOptions } from "danx/src/helpers";
|
2
|
+
import { computed, ref } from "vue";
|
3
|
+
|
4
|
+
export function useSingleFileUpload(options: FileUploadOptions) {
|
5
|
+
const uploadedFile = ref(null);
|
6
|
+
const onCompleteCb = ref(null);
|
7
|
+
const onFileChangeCb = ref(null);
|
8
|
+
|
9
|
+
const onFileSelected = (e) => {
|
10
|
+
uploadedFile.value = null;
|
11
|
+
new FileUpload(e.target.files[0], options)
|
12
|
+
.onProgress(({ file }) => {
|
13
|
+
uploadedFile.value = file;
|
14
|
+
onFileChangeCb.value && onFileChangeCb.value(uploadedFile.value);
|
15
|
+
})
|
16
|
+
.onComplete(({ uploadedFile: completedFile }) => {
|
17
|
+
uploadedFile.value = completedFile;
|
18
|
+
onCompleteCb.value && onCompleteCb.value(uploadedFile.value);
|
19
|
+
onFileChangeCb.value && onFileChangeCb.value(uploadedFile.value);
|
20
|
+
})
|
21
|
+
.upload();
|
22
|
+
};
|
23
|
+
|
24
|
+
const onDrop = (e) => {
|
25
|
+
onFileSelected({ target: { files: e.dataTransfer.files } });
|
26
|
+
};
|
27
|
+
|
28
|
+
const isFileUploaded = computed(() => {
|
29
|
+
return uploadedFile.value && uploadedFile.value.url;
|
30
|
+
});
|
31
|
+
|
32
|
+
const onFileChange = (cb) => {
|
33
|
+
onFileChangeCb.value = cb;
|
34
|
+
};
|
35
|
+
|
36
|
+
const onComplete = (cb) => {
|
37
|
+
onCompleteCb.value = cb;
|
38
|
+
};
|
39
|
+
|
40
|
+
const onClear = () => {
|
41
|
+
uploadedFile.value = null;
|
42
|
+
onFileChangeCb.value && onFileChangeCb.value(uploadedFile.value);
|
43
|
+
};
|
44
|
+
|
45
|
+
return {
|
46
|
+
isFileUploaded,
|
47
|
+
onClear,
|
48
|
+
onComplete,
|
49
|
+
onFileChange,
|
50
|
+
onDrop,
|
51
|
+
onFileSelected,
|
52
|
+
uploadedFile
|
53
|
+
};
|
54
|
+
}
|