1 | import {addClass, ajax, matches, noop, on, removeClass, trigger} from 'uikit-util';
|
2 |
|
3 | export default {
|
4 |
|
5 | props: {
|
6 | allow: String,
|
7 | clsDragover: String,
|
8 | concurrent: Number,
|
9 | maxSize: Number,
|
10 | method: String,
|
11 | mime: String,
|
12 | msgInvalidMime: String,
|
13 | msgInvalidName: String,
|
14 | msgInvalidSize: String,
|
15 | multiple: Boolean,
|
16 | name: String,
|
17 | params: Object,
|
18 | type: String,
|
19 | url: String
|
20 | },
|
21 |
|
22 | data: {
|
23 | allow: false,
|
24 | clsDragover: 'uk-dragover',
|
25 | concurrent: 1,
|
26 | maxSize: 0,
|
27 | method: 'POST',
|
28 | mime: false,
|
29 | msgInvalidMime: 'Invalid File Type: %s',
|
30 | msgInvalidName: 'Invalid File Name: %s',
|
31 | msgInvalidSize: 'Invalid File Size: %s Kilobytes Max',
|
32 | multiple: false,
|
33 | name: 'files[]',
|
34 | params: {},
|
35 | type: '',
|
36 | url: '',
|
37 | abort: noop,
|
38 | beforeAll: noop,
|
39 | beforeSend: noop,
|
40 | complete: noop,
|
41 | completeAll: noop,
|
42 | error: noop,
|
43 | fail: noop,
|
44 | load: noop,
|
45 | loadEnd: noop,
|
46 | loadStart: noop,
|
47 | progress: noop
|
48 | },
|
49 |
|
50 | events: {
|
51 |
|
52 | change(e) {
|
53 |
|
54 | if (!matches(e.target, 'input[type="file"]')) {
|
55 | return;
|
56 | }
|
57 |
|
58 | e.preventDefault();
|
59 |
|
60 | if (e.target.files) {
|
61 | this.upload(e.target.files);
|
62 | }
|
63 |
|
64 | e.target.value = '';
|
65 | },
|
66 |
|
67 | drop(e) {
|
68 | stop(e);
|
69 |
|
70 | const transfer = e.dataTransfer;
|
71 |
|
72 | if (!transfer || !transfer.files) {
|
73 | return;
|
74 | }
|
75 |
|
76 | removeClass(this.$el, this.clsDragover);
|
77 |
|
78 | this.upload(transfer.files);
|
79 | },
|
80 |
|
81 | dragenter(e) {
|
82 | stop(e);
|
83 | },
|
84 |
|
85 | dragover(e) {
|
86 | stop(e);
|
87 | addClass(this.$el, this.clsDragover);
|
88 | },
|
89 |
|
90 | dragleave(e) {
|
91 | stop(e);
|
92 | removeClass(this.$el, this.clsDragover);
|
93 | }
|
94 |
|
95 | },
|
96 |
|
97 | methods: {
|
98 |
|
99 | upload(files) {
|
100 |
|
101 | if (!files.length) {
|
102 | return;
|
103 | }
|
104 |
|
105 | trigger(this.$el, 'upload', [files]);
|
106 |
|
107 | for (let i = 0; i < files.length; i++) {
|
108 |
|
109 | if (this.maxSize && this.maxSize * 1000 < files[i].size) {
|
110 | this.fail(this.msgInvalidSize.replace('%s', this.maxSize));
|
111 | return;
|
112 | }
|
113 |
|
114 | if (this.allow && !match(this.allow, files[i].name)) {
|
115 | this.fail(this.msgInvalidName.replace('%s', this.allow));
|
116 | return;
|
117 | }
|
118 |
|
119 | if (this.mime && !match(this.mime, files[i].type)) {
|
120 | this.fail(this.msgInvalidMime.replace('%s', this.mime));
|
121 | return;
|
122 | }
|
123 |
|
124 | }
|
125 |
|
126 | if (!this.multiple) {
|
127 | files = [files[0]];
|
128 | }
|
129 |
|
130 | this.beforeAll(this, files);
|
131 |
|
132 | const chunks = chunk(files, this.concurrent);
|
133 | const upload = files => {
|
134 |
|
135 | const data = new FormData();
|
136 |
|
137 | files.forEach(file => data.append(this.name, file));
|
138 |
|
139 | for (const key in this.params) {
|
140 | data.append(key, this.params[key]);
|
141 | }
|
142 |
|
143 | ajax(this.url, {
|
144 | data,
|
145 | method: this.method,
|
146 | responseType: this.type,
|
147 | beforeSend: env => {
|
148 |
|
149 | const {xhr} = env;
|
150 | xhr.upload && on(xhr.upload, 'progress', this.progress);
|
151 | ['loadStart', 'load', 'loadEnd', 'abort'].forEach(type =>
|
152 | on(xhr, type.toLowerCase(), this[type])
|
153 | );
|
154 |
|
155 | this.beforeSend(env);
|
156 |
|
157 | }
|
158 | }).then(
|
159 | xhr => {
|
160 |
|
161 | this.complete(xhr);
|
162 |
|
163 | if (chunks.length) {
|
164 | upload(chunks.shift());
|
165 | } else {
|
166 | this.completeAll(xhr);
|
167 | }
|
168 |
|
169 | },
|
170 | e => this.error(e)
|
171 | );
|
172 |
|
173 | };
|
174 |
|
175 | upload(chunks.shift());
|
176 |
|
177 | }
|
178 |
|
179 | }
|
180 |
|
181 | };
|
182 |
|
183 | function match(pattern, path) {
|
184 | return path.match(new RegExp(`^${pattern.replace(/\//g, '\\/').replace(/\*\*/g, '(\\/[^\\/]+)*').replace(/\*/g, '[^\\/]+').replace(/((?!\\))\?/g, '$1.')}$`, 'i'));
|
185 | }
|
186 |
|
187 | function chunk(files, size) {
|
188 | const chunks = [];
|
189 | for (let i = 0; i < files.length; i += size) {
|
190 | const chunk = [];
|
191 | for (let j = 0; j < size; j++) {
|
192 | chunk.push(files[i + j]);
|
193 | }
|
194 | chunks.push(chunk);
|
195 | }
|
196 | return chunks;
|
197 | }
|
198 |
|
199 | function stop(e) {
|
200 | e.preventDefault();
|
201 | e.stopPropagation();
|
202 | }
|