File: addon/components/file-chooser/component.js
import Ember from 'ember';
import layout from './template';
/**
* @module ember-osf
* @submodule components
*/
/**
* This component lets the user choose a list of files from their computer, by
* drag-and-drop, a file browser, or whatever method the developer wants.
*
* Exposed to parent context (bindable attributes)
* - `files`: mutable list of chosen File objects
* - `multiple`: boolean (default `true`), when `false`, only keeps the most
* recently chosen File in the list
* - `onChoose`: callback function called each time a file is added, with the
* new File object as the only argument
*
* Exposed to block context
* - `this`: the component object itself, so the block can invoke actions
* example:
* ```handlebars
* {{#file-chooser files=fileList as |component|}}
* {{input type='file'
* change=(action 'onFileInputChange' target=component)}}
* {{/file-chooser}}
* ```
*
* Actions
* - `onFileInputChange`: handle the `change` event on a file input
* - `onChooseFile`: add a file to the chosen list
*
* Styling
* - This component's element has the `drop-zone` class
* - While the user is holding dragged files over this component, it
* has the `drop-zone-ready` class
*
* @class file-chooser component
*/
export default Ember.Component.extend({
layout,
i18n: Ember.inject.service(),
classNames: ['drop-zone'],
classNameBindings: ['dropZoneReady'],
dropZoneReady: false,
multiple: true,
dragOver(event) {
if (event.dataTransfer.types.indexOf('Files') > -1) {
this.set('dropZoneReady', true);
event.dataTransfer.dropEffect = 'move';
return false;
} else {
event.dataTransfer.dropEffect = 'none';
}
},
dragLeave(event) {
this.set('dropZoneReady', false);
event.dataTransfer.dropEffect = '';
},
drop(event) {
event.preventDefault();
this.set('dropZoneReady', false);
for (let i = 0; i < event.dataTransfer.files.length; i++) {
let file = event.dataTransfer.files[i];
this._chooseIfFile(file);
}
},
actions: {
onFileInputChange(event) {
for (let i = 0; i < event.target.files.length; i++) {
let file = event.target.files[i];
this.send('onChooseFile', file);
}
},
onChooseFile(file) {
let files = this.get('files');
if (typeof files === 'undefined') {
this.set('files', Ember.A());
files = this.get('files');
}
if (this.get('multiple')) {
files.pushObject(file);
} else {
this.set('files', Ember.A([file]));
}
let callback = this.get('onChoose');
if (callback) {
callback(file);
}
}
},
_chooseIfFile(file) {
// HACK: There's not a cross-browser way to see the contents of
// dragged-and-dropped directories, but there's also not a good way to
// tell whether a given File object is a directory. Hence, this:
let p = new Ember.RSVP.Promise(function(resolve, reject) {
let reader = new FileReader();
reader.onload = () => resolve(); // it's a file
reader.onerror = () => reject(); // it's a directory or something
reader.readAsText(file.slice(0, 5));
});
p.then(() => this.send('onChooseFile', file));
p.catch(() => this.set('errorMessage',
`Cannot upload directories (${file.name})`));
}
});