<!DOCTYPE html>
<html>
<head>
<title>File Uploader</title>
<link href = "https://file.myfontastic.com/SLzQsLcd7FmmzjBYTcyVW3/icons.css" rel="stylesheet">
<link href = "fileuploader.css" rel = "stylesheet">
<link href = "style.css" rel = "stylesheet">
</head>
<body>
<div id="app">Loading...</div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.17/system.js"></script>
<script type = "text/javascript">
System.config({ transpiler: 'babel' });
System.import('App.js');
</script>
</body>
</html>
/*Demo Styles */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
body {
-webkit-align-items: center;
align-items: center;
background-color: #eee;
display: -webkit-flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
}
button {
display: block;
margin: 2em auto;
}
* Live preview of the image selected
* Drag and drop support
'use strict';
class FileUploader {
cache(selector) {
this.$label = document.querySelector(selector);
this.$fileInput = this.$label.querySelector('input');
this.$img = this.$label.querySelector('img');
}
constructor(selector) {
this.cache(selector);
this.events();
}
events() {
this.$fileInput.addEventListener('change', this._handleInputChange.bind(this));
this.$img.addEventListener('load', this._handleImageLoaded.bind(this));
this.$label.addEventListener('dragenter', this._handleDragEnter.bind(this));
this.$label.addEventListener('dragleave', this._handleDragLeave.bind(this));
this.$label.addEventListener('drop', this._handleDrop.bind(this));
}
_handleDragEnter(e){
e.preventDefault();
if (!this.$label.classList.contains('dragging')) {
this.$label.classList.add('dragging');
}
}
_handleDragLeave(e) {
e.preventDefault();
if (this.$label.classList.contains('dragging')) {
this.$label.classList.remove('dragging');
}
}
_handleDrop(e) {
e.preventDefault();
this.$label.classList.remove('dragging');
this.$img.files = e.dataTransfer.files;
this._handleInputChange();
}
_handleImageLoaded() {
if (!this.$img.classList.contains('loaded')) {
this.$img.classList.add('loaded');
}
}
_handleInputChange(e) {
var file = (undefined !== e)
? e.target.files[0]
: this.$img.files[0];
var pattern = /image-*/;
var reader = new FileReader();
if (!file.type.match(pattern)) {
alert('invalid format');
return;
}
this.$img.src = "";
reader.onload = this._handleReaderLoaded.bind(this);
if (this.$label.classList.contains('loaded')) {
this.$label.classList.remove('loaded');
}
reader.readAsDataURL(file);
}
_handleReaderLoaded(e) {
var reader = e.target;
this.$img.src = reader.result;
this.$label.classList.add('loaded');
}
}
module.exports = FileUploader;
/* File Uploader Styles */
.uploader input {
display: none;
}
.uploader {
-webkit-align-items: center;
align-items: center;
background-color: #efefef;
background-color: rgba(0, 0, 0, 0.02);
display: -webkit-flex;
display: flex;
height: 300px;
-webkit-justify-content: center;
justify-content: center;
outline: 3px dashed #ccc;
outline-offset: 5px;
position: relative;
width: 300px;
}
.uploader img,
.uploader .icon {
pointer-events: none;
}
.uploader,
.uploader .icon {
-webkit-transition: all 100ms ease-in;
-moz-transition: all 100ms ease-in;
-ms-transition: all 100ms ease-in;
-o-transition: all 100ms ease-in;
transition: all 100ms ease-in;
}
.uploader .icon {
color: #eee;
color: rgba(0, 0, 0, 0.2);
font-size: 5em;
}
.uploader.dragging {
outline-color: orangered;
}
.uploader.dragging .icon {
color: orangered;
}
.uploader.loaded .icon {
color: #fff;
color: rgba(255, 255, 255, 0.5);
}
.uploader img {
left: 50%;
opacity: 0;
max-height: 100%;
max-width: 100%;
position: absolute;
top: 50%;
-webkit-transition: all 300ms ease-in;
-moz-transition: all 300ms ease-in;
-ms-transition: all 300ms ease-in;
-o-transition: all 300ms ease-in;
transition: all 300ms ease-in;
-webkit-transform: translate(-50%,-50%);
-moz-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
-o-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
z-index: -1;
}
.uploader img.loaded {
opacity: 1;
}
const propTypes = {
baseColor : React.PropTypes.string,
activeColor : React.PropTypes.string
},
defaultProps = {
baseColor : 'gray',
activeColor : 'green',
overlayColor : 'rgba(255,255,255,0.3)'
};
class FileUploader extends React.Component {
constructor(props) {
super(props);
this.state = {
active : false,
imageSrc : '',
loaded : false
}
this.onDragEnter = this.onDragEnter.bind(this);
this.onDragLeave = this.onDragLeave.bind(this);
this.onDrop = this.onDrop.bind(this);
this.onFileChange = this.onFileChange.bind(this);
}
onDragEnter(e) {
this.setState({ active: true });
}
onDragLeave(e) {
this.setState({ active: false });
}
onDragOver(e) {
e.preventDefault();
}
onDrop(e) {
e.preventDefault();
this.setState({ active: false });
this.onFileChange(e, e.dataTransfer.files[0]);
}
onFileChange(e, fileObject) {
var file = fileObject || e.target.files[0],
pattern = /image-*/,
reader = new FileReader();
if (!file.type.match(pattern)) {
alert('Formato inválido');
return;
}
this.setState({
loaded: false
});
reader.onload = () => {
this.setState({
imageSrc: reader.result,
loaded: true
});
}
reader.readAsDataURL(file);
}
getFileObject() {
return this.refs.input.files[0];
}
getFileString() {
return this.state.imageSrc;
}
render() {
let state = this.state,
props = this.props,
labelClass = `uploader ${state.loaded && 'loaded'}`,
borderColor = state.active ? props.activeColor : props.baseColor,
iconColor = state.active
? props.activeColor
: (state.loaded)
? props.overlayColor
: props.baseColor;
return (
<label
className = { labelClass }
onDragEnter = { this.onDragEnter }
onDragLeave = { this.onDragLeave }
onDragOver = { this.onDragOver }
onDrop = { this.onDrop }
style = { { outlineColor: borderColor }}>
<img
src = { state.imageSrc }
className = { state.loaded && 'loaded' }/>
<i
className = "icon icon-upload"
style = { { color: iconColor } } />
< input
type = "file"
accept = "image/*"
onChange = { this.onFileChange }
ref = "input" />
</label>
);
}
}
FileUploader.propTypes = propTypes;
FileUploader.defaultProps = defaultProps;
export default FileUploader;
import FileUploader from "./FileUploader.js";
class App extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick(e) {
e.preventDefault();
var url = 'http://nowhere.com',
fileObject = this.refs.uploader.getFileObject(),
formData = new FormData(document.getElementById('form'));
if (undefined === fileObject) return;
formData.append('file', fileObject);
fetch(url, {
method : 'POST',
body : formData
});
}
render() {
return (
<div>
<FileUploader ref = "uploader" />
<button onClick = { this.onClick }>Enviar</button>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('#app'));