API Docs for: 0.25.0
Show:

File: addon/components/dropzone-widget/component.js

/* global Dropzone */

import Ember from 'ember';
import config from 'ember-get-config';
import diffAttrs from 'ember-diff-attrs';

import layout from './template';

/**
 * @module ember-osf
 * @submodule components
 */

/**
 * Support file uploads via dropzone.
 * Accepts dropzone event listeners as parameters (e.g. success, error, addedfile)
 *
 * Sample usage:
 * ```handlebars
 * {{dropzone-widget
 *   preUpload=attrs.preUpload
 *   buildUrl=buildUrl
 *   success=attrs.success
 *   defaultMessage=defaultMessage
 *   options=dropzoneOptions
 *   clickable=clickable}}
 * ```
 *
 * @class dropzone-widget
 */
export default Ember.Component.extend({
    layout,
    session: Ember.inject.service(),
    currentUser: Ember.inject.service('current-user'),

    classNameBindings: ['dropzone'],
    dropzone: true,
    enable: true,
    clickable: true,
    dropzoneElement: null,
    loadDropzone() {
        let preUpload = this.get('preUpload');
        let dropzoneOptions = this.get('options') || {};

        function CustomDropzone() {
            Dropzone.call(this, ...arguments);
        }
        CustomDropzone.prototype = Object.create(Dropzone.prototype);
        CustomDropzone.prototype.drop = function(e) {
            if (this.options.preventMultipleFiles && e.dataTransfer) {
                if (e.dataTransfer.items && e.dataTransfer.items.length > 1 || e.dataTransfer.files.length > 1) {
                    this.emit("drop", e);
                    this.emit('error', 'None', 'Cannot upload multiple files');
                    return;
                }
                if (e.dataTransfer.files.length === 0) {
                    this.emit("drop", e);
                    this.emit('error', 'None', 'Cannot upload directories, applications, or packages');
                    return;
                }
            }
            return Dropzone.prototype.drop.call(this, e);
        };
        CustomDropzone.prototype._addFilesFromDirectory  = function(directory, path) {
            if (!this.options.acceptDirectories) {
                directory.status = Dropzone.ERROR;
                this.emit("error", directory, "Cannot upload directories, applications, or packages");
                return;
            }
            return Dropzone.prototype._addFilesFromDirectory.call(directory, path);
        };

        const currentUser = this.get('currentUser');
        const authorizeXHR = currentUser.authorizeXHR.bind(currentUser);

        let drop = new CustomDropzone(`#${this.elementId}`, {
            url: file => typeof this.get('buildUrl') === 'function' ? this.get('buildUrl')(file) : this.get('buildUrl'),
            autoProcessQueue: false,
            autoQueue: false,
            clickable: this.get('clickable'),
            dictDefaultMessage: this.get('defaultMessage') || 'Drop files here to upload',
            sending(file, xhr) {
                authorizeXHR(xhr)
                // Monkey patch to send the raw file instead of formData
                xhr.send = xhr.send.bind(xhr, file);
            }
        });

        // Dropzone.js does not have an option for disabling selecting multiple files when clicking the "upload" button.
        // Therefore, we remove the "multiple" attribute for the hidden file input element, so that users cannot select
        // multiple files for upload in the first place.
        if (this.get('options.preventMultipleFiles') && this.get('clickable')){
            Ember.$('.dz-hidden-input').removeAttr('multiple');
        }

        this.set('dropzoneElement', drop);

        // Set osf session header
        let headers = {};

        let authType = config['ember-simple-auth'].authorizer;
        this.get('session').authorize(authType, (headerName, content) => {
            headers[headerName] = content;
        });
        dropzoneOptions.headers = headers;
        dropzoneOptions.withCredentials = (config.authorizationType === 'cookie');

        // Attach preUpload to addedfile event
        drop.on('addedfile', file => {
            if (preUpload) {
                preUpload(this, drop, file).then(() => drop.processFile(file));
            } else {
                drop.processFile(file);
            }
        });

        // Set dropzone options
        drop.options = Ember.assign(drop.options, dropzoneOptions);

        // Attach dropzone event listeners: http://www.dropzonejs.com/#events
        drop.events.forEach(event => {
            if (typeof this.get(event) === 'function') {
                drop.on(event, (...args) => this.get(event)(this, drop, ...args));
            }
        });
    },
    destroyDropzone() {
        if (this.get('dropzoneElement')) {
            this.get('dropzoneElement').destroy();
        }
    },
    didReceiveAttrs: diffAttrs('enable', 'clickable', function(changedAttrs, ...args) {
        this._super(...args);
        if (changedAttrs) {
            if (changedAttrs.enable) {
                if (this.get('enable')) {
                    this.loadDropzone();
                } else {
                    this.destroyDropzone();
                }
            } else if (changedAttrs.clickable && this.get('enable')) {
                // Dropzone must be reloaded for clickable changes to take effect.
                this.destroyDropzone();
                this.loadDropzone();
            }
        }
    }),
    didInsertElement() {
        if (this.get('enable')) {
            this.loadDropzone();
        }
    }
});