uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
203 lines (154 loc) • 4.9 kB
JavaScript
import {addClass, ajax, matches, noop, on, removeClass, trigger} from 'uikit-util';
export default {
props: {
allow: String,
clsDragover: String,
concurrent: Number,
maxSize: Number,
method: String,
mime: String,
msgInvalidMime: String,
msgInvalidName: String,
msgInvalidSize: String,
multiple: Boolean,
name: String,
params: Object,
type: String,
url: String
},
data: {
allow: false,
clsDragover: 'uk-dragover',
concurrent: 1,
maxSize: 0,
method: 'POST',
mime: false,
msgInvalidMime: 'Invalid File Type: %s',
msgInvalidName: 'Invalid File Name: %s',
msgInvalidSize: 'Invalid File Size: %s Kilobytes Max',
multiple: false,
name: 'files[]',
params: {},
type: '',
url: '',
abort: noop,
beforeAll: noop,
beforeSend: noop,
complete: noop,
completeAll: noop,
error: noop,
fail: noop,
load: noop,
loadEnd: noop,
loadStart: noop,
progress: noop
},
events: {
change(e) {
if (!matches(e.target, 'input[type="file"]')) {
return;
}
e.preventDefault();
if (e.target.files) {
this.upload(e.target.files);
}
e.target.value = '';
},
drop(e) {
stop(e);
const transfer = e.dataTransfer;
if (!transfer || !transfer.files) {
return;
}
removeClass(this.$el, this.clsDragover);
this.upload(transfer.files);
},
dragenter(e) {
stop(e);
},
dragover(e) {
stop(e);
addClass(this.$el, this.clsDragover);
},
dragleave(e) {
stop(e);
removeClass(this.$el, this.clsDragover);
}
},
methods: {
upload(files) {
if (!files.length) {
return;
}
trigger(this.$el, 'upload', [files]);
for (let i = 0; i < files.length; i++) {
if (this.maxSize && this.maxSize * 1000 < files[i].size) {
this.fail(this.msgInvalidSize.replace('%s', this.maxSize));
return;
}
if (this.allow && !match(this.allow, files[i].name)) {
this.fail(this.msgInvalidName.replace('%s', this.allow));
return;
}
if (this.mime && !match(this.mime, files[i].type)) {
this.fail(this.msgInvalidMime.replace('%s', this.mime));
return;
}
}
if (!this.multiple) {
files = [files[0]];
}
this.beforeAll(this, files);
const chunks = chunk(files, this.concurrent);
const upload = files => {
const data = new FormData();
files.forEach(file => data.append(this.name, file));
for (const key in this.params) {
data.append(key, this.params[key]);
}
ajax(this.url, {
data,
method: this.method,
responseType: this.type,
beforeSend: env => {
const {xhr} = env;
xhr.upload && on(xhr.upload, 'progress', this.progress);
['loadStart', 'load', 'loadEnd', 'abort'].forEach(type =>
on(xhr, type.toLowerCase(), this[type])
);
return this.beforeSend(env);
}
}).then(
xhr => {
this.complete(xhr);
if (chunks.length) {
upload(chunks.shift());
} else {
this.completeAll(xhr);
}
},
e => this.error(e)
);
};
upload(chunks.shift());
}
}
};
function match(pattern, path) {
return path.match(new RegExp(`^${pattern.replace(/\//g, '\\/').replace(/\*\*/g, '(\\/[^\\/]+)*').replace(/\*/g, '[^\\/]+').replace(/((?!\\))\?/g, '$1.')}$`, 'i'));
}
function chunk(files, size) {
const chunks = [];
for (let i = 0; i < files.length; i += size) {
const chunk = [];
for (let j = 0; j < size; j++) {
chunk.push(files[i + j]);
}
chunks.push(chunk);
}
return chunks;
}
function stop(e) {
e.preventDefault();
e.stopPropagation();
}