file_uploader.js 5.56 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/**
 * A view for uploading a file.
 *
 * Currently only single-file upload is supported (to support multiple-file uploads, the HTML
 * input must be changed to specify "multiple" and the notification messaging needs to be changed
 * to support the display of multiple status messages).
 *
 * There is no associated model, but the view supports the following options:
 *
 * @param title, the title to display.
 * @param inputLabel, a label that will be added for the file input field. Note that this label is only shown to
 *     screen readers.
 * @param inputTip, a tooltip linked to the file input field. Can be used to state what sort of file can be uploaded.
 * @param extensions, the allowed file extensions of the uploaded file, as a comma-separated string (ex, ".csv,.txt").
 *     Some browsers will enforce that only files with these extensions can be uploaded, but others
 *     (for instance, Firefox), will not. By default, no extensions are specified and any file can be uploaded.
 * @param submitButtonText, text to display on the submit button to upload the file. The default value for this is
 *     "Upload File".
 * @param url, the url for posting the uploaded file.
 * @param successNotification, optional callback that can return a success NotificationModel for display
 *     after a file was successfully uploaded. This method will be passed the uploaded file, event, and data.
 * @param errorNotification, optional callback that can return a success NotificationModel for display
 *     after a file failed to upload. This method will be passed the attempted file, event, and data.
 */
25
(function(Backbone, $, _, gettext, interpolate_text, NotificationModel, NotificationView) {
26 27 28
    // Requires JQuery-File-Upload.
    var FileUploaderView = Backbone.View.extend({

29
        initialize: function(options) {
30 31 32 33
            this.template = _.template($('#file-upload-tpl').text());
            this.options = options;
        },

34
        render: function() {
35 36 37 38 39 40 41 42
            var options = this.options,
                get_option_with_default = function(option, default_value) {
                    var optionVal = options[option];
                    return optionVal ? optionVal : default_value;
                },
                submitButton, resultNotification;

            this.$el.html(this.template({
43 44 45 46 47 48
                title: get_option_with_default('title', ''),
                inputLabel: get_option_with_default('inputLabel', ''),
                inputTip: get_option_with_default('inputTip', ''),
                extensions: get_option_with_default('extensions', ''),
                submitButtonText: get_option_with_default('submitButtonText', gettext('Upload File')),
                url: get_option_with_default('url', '')
49 50 51 52 53 54 55 56 57 58 59 60
            }));

            submitButton = this.$el.find('.submit-file-button');
            resultNotification = this.$el.find('.result'),

            this.$el.find('#file-upload-form').fileupload({
                dataType: 'json',
                type: 'POST',
                done: this.successHandler.bind(this),
                fail: this.errorHandler.bind(this),
                autoUpload: false,
                replaceFileInput: false,
61
                add: function(e, data) {
62
                    var file = data.files[0];
63
                    submitButton.removeClass('is-disabled').attr('aria-disabled', false);
64
                    submitButton.unbind('click');
65
                    submitButton.click(function(event) {
66 67 68
                        event.preventDefault();
                        data.submit();
                    });
69
                    resultNotification.html('');
70 71 72 73 74 75
                }
            });

            return this;
        },

76
        successHandler: function(event, data) {
77 78 79 80 81 82 83
            var file = data.files[0].name;
            var notificationModel;
            if (this.options.successNotification) {
                notificationModel = this.options.successNotification(file, event, data);
            }
            else {
                notificationModel = new NotificationModel({
84
                    type: 'confirmation',
85 86 87 88 89 90 91 92 93 94
                    title: interpolate_text(gettext("Your upload of '{file}' succeeded."), {file: file})
                });
            }
            var notification = new NotificationView({
                el: this.$('.result'),
                model: notificationModel
            });
            notification.render();
        },

95
        errorHandler: function(event, data) {
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
            var file = data.files[0].name, message = null, jqXHR = data.response().jqXHR;
            var notificationModel;
            if (this.options.errorNotification) {
                notificationModel = this.options.errorNotification(file, event, data);
            }
            else {
                if (jqXHR.responseText) {
                    try {
                        message = JSON.parse(jqXHR.responseText).error;
                    }
                    catch (err) {
                    }
                }
                if (!message) {
                    message = interpolate_text(gettext("Your upload of '{file}' failed."), {file: file});
                }
                notificationModel = new NotificationModel({
113
                    type: 'error',
114 115 116 117 118 119 120 121 122 123 124 125 126
                    title: message
                });
            }
            var notification = new NotificationView({
                el: this.$('.result'),
                model: notificationModel
            });
            notification.render();
        }
    });

    this.FileUploaderView = FileUploaderView;
}).call(this, Backbone, $, _, gettext, interpolate_text, NotificationModel, NotificationView);