define(['jquery', 'underscore', 'gettext', 'js/views/modals/base_modal', 'jquery.form'], function($, _, gettext, BaseModal) { var UploadDialog = BaseModal.extend({ events: _.extend({}, BaseModal.prototype.events, { 'change input[type=file]': 'selectFile', 'click .action-upload': 'upload' }), options: $.extend({}, BaseModal.prototype.options, { modalName: 'assetupload', modalSize: 'med', successMessageTimeout: 2000, // 2 seconds viewSpecificClasses: 'confirm' }), initialize: function() { BaseModal.prototype.initialize.call(this); this.template = this.loadTemplate('upload-dialog'); this.listenTo(this.model, 'change', this.renderContents); this.options.title = this.model.get('title'); }, addActionButtons: function() { this.addActionButton('upload', gettext('Upload'), true); BaseModal.prototype.addActionButtons.call(this); }, renderContents: function() { var isValid = this.model.isValid(), selectedFile = this.model.get('selectedFile'), oldInput = this.$('input[type=file]').get(0); BaseModal.prototype.renderContents.call(this); // Ideally, we'd like to tell the browser to pre-populate the // <input type="file"> with the selectedFile if we have one -- but // browser security prohibits that. So instead, we'll swap out the // new input (that has no file selected) with the old input (that // already has the selectedFile selected). However, we only want to do // this if the selected file is valid: if it isn't, we want to render // a blank input to prompt the user to upload a different (valid) file. if (selectedFile && isValid) { $(oldInput).removeClass('error'); this.$('input[type=file]').replaceWith(oldInput); this.$('.action-upload').removeClass('disabled'); } else { this.$('.action-upload').addClass('disabled'); } return this; }, getContentHtml: function() { return this.template({ url: this.options.url || CMS.URL.UPLOAD_ASSET, message: this.model.escape('message'), selectedFile: this.model.get('selectedFile'), uploading: this.model.get('uploading'), uploadedBytes: this.model.get('uploadedBytes'), totalBytes: this.model.get('totalBytes'), finished: this.model.get('finished'), error: this.model.validationError }); }, selectFile: function(e) { var selectedFile = e.target.files[0] || null; this.model.set({ selectedFile: selectedFile }); // This change event triggering necessary for FireFox, because the browser don't // consider change of File object (file input field) as a change in model. if (selectedFile && $.isEmptyObject(this.model.changed)) { this.model.trigger('change'); } }, upload: function(e) { if (e && e.preventDefault) { e.preventDefault(); } this.model.set('uploading', true); this.$('form').ajaxSubmit({ success: _.bind(this.success, this), error: _.bind(this.error, this), uploadProgress: _.bind(this.progress, this), data: { // don't show the generic error notification; we're in a modal, // and we're better off modifying it instead. notifyOnError: false } }); }, progress: function(event, position, total) { this.model.set({ uploadedBytes: position, totalBytes: total }); }, success: function(response, statusText, xhr, form) { this.model.set({ uploading: false, finished: true }); if (this.options.onSuccess) { this.options.onSuccess(response, statusText, xhr, form); } var that = this; this.removalTimeout = setTimeout(function() { that.hide(); }, this.options.successMessageTimeout); }, error: function() { this.model.set({ uploading: false, uploadedBytes: 0, title: gettext("We're sorry, there was an error") }); } }); return UploadDialog; }); // end define()