framework-entersol-web
Version:
Framework based on bootstrap 5
121 lines (110 loc) • 3.54 kB
JSX
import React from "react";
import Field from "./field";
import bytes from "bytes";
import * as LZMAObj from 'lzma/src/lzma_worker';
import eventHandler from "../../functions/event-handler";
export default class FileField extends Field {
static defaultProps = {
...Field.defaultProps,
multiple: false,
format: 'base64',
zip: false
}
static jsClass = 'FileField';
get type() {
return 'file';
}
isInvalid(value) {
if (this.props.maxSize && this.input.current?.files) {
const files = Array.from(this.input.current.files);
const error = files.some(file => file.size > bytes(this.props.maxSize, { unit: 'B' }));
if (error) {
this.input.current.setCustomValidity(this.props.errorMessage);
return true;
}
}
return super.isInvalid(value);
}
async onChange(e) {
let { value, files } = e.target;
const arrayFiles = Array.from(files);
const newState = {
value,
error: this.isInvalid(value)
}
this.setState(newState);
if (!arrayFiles.length || newState.error) return this.returnData(null);
const p6s = arrayFiles.map(file => this.readAs(file, this.props.format));
const final = await Promise.all(p6s);
if (this.props.multiple) {
this.returnData(final);
} else {
this.returnData(final[0]);
}
}
readAs(file, format = 'base64') {
if (!file) return null;
return new Promise((resolve, reject) => {
const reader = new FileReader();
switch (format) {
case 'base64':
reader.readAsDataURL(file);
break;
case 'text':
reader.readAsText(file);
break;
case 'binaryString':
reader.readAsBinaryString(file);
break;
case 'zip':
reader.readAsArrayBuffer(file);
break;
default:
break;
}
const onFinish = (result, error) => {
eventHandler.dispatch('zipping.' + this.props.name, { [this.props.name]: 'end' });
if (error) return reject(error);
resolve(result);
};
const onPercentage = (percentage) =>
eventHandler.dispatch('zipping.' + this.props.name, { [this.props.name]: percentage });
reader.onload = () => {
if (this.props.format !== 'zip') return resolve(reader.result);
eventHandler.dispatch('zipping.' + this.props.name, { [this.props.name]: 'start' });
const array = new Uint8Array(reader.result);
const mode = this.props.zip || 9;
LZMAObj.LZMA.compress(array, mode, onFinish, onPercentage);
};
reader.onerror = error => reject(error);
});
}
get inputProps() {
const ip = super.inputProps;
ip.required = ip.required && !(this.state.value);
delete ip.value;
return ip;
}
get inputNode() {
const { inline, disabled, readOnly } = this.props;
const { value } = this.state;
const inputNode = (<>
{!(value && (disabled || readOnly)) ?
<input {...this.inputProps} /> :
<p className="form-control mb-1 disabled">
<a href={value} target="_blank">
{value.split(/[\/\\]/).pop().split('?')[0]}
</a>
</p>}
{value && !(disabled || readOnly) &&
<p className="text-end my-1">
<small><a href={value} target="_blank">
{value.split(/[\/\\]/).pop().split('?')[0]}
</a></small>
</p>}
</>);
return (inline ? <div className="col-auto">
{inputNode}
</div> : inputNode);
}
}