UNPKG

4.9 kBJavaScriptView Raw
1import {addClass, ajax, matches, noop, on, removeClass, trigger} from 'uikit-util';
2
3export 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
183function match(pattern, path) {
184 return path.match(new RegExp(`^${pattern.replace(/\//g, '\\/').replace(/\*\*/g, '(\\/[^\\/]+)*').replace(/\*/g, '[^\\/]+').replace(/((?!\\))\?/g, '$1.')}$`, 'i'));
185}
186
187function 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
199function stop(e) {
200 e.preventDefault();
201 e.stopPropagation();
202}