3 var _
= require('lodash');
5 var context
= require('gitter-web-client-context');
6 var Marionette
= require('backbone.marionette');
7 var appEvents
= require('../../utils/appevents');
8 var apiClient
= require('../../components/api-client');
10 require('transloadit');
12 var PROGRESS_THRESHOLD
= 62.5;
14 function contains(domStringsList
, item
) {
15 if (!domStringsList
) return false;
16 for (var i
= 0; i
< domStringsList
.length
; i
++) {
17 if (domStringsList
[i
] === item
) return true;
22 function ignoreEvent(e
) {
27 var DropTargetView
= Marionette
.ItemView
.extend({
31 progressBar
: '#file-progress-bar',
32 dragOverlay
: '.js-drag-overlay',
33 uploadForm
: '#upload-form'
38 dragenter
: 'onDragEnter',
39 dragleave
: 'onDragLeave',
40 dragover
: 'onDragOver',
45 * IMPORTANT: when dragging moving over child nodes will cause dragenter and dragleave, so we need to keep this count, if it's zero means that we should hide the overlay. WC.
49 updateProgressBar: function(spec
) {
50 var bar
= this.ui
.progressBar
;
51 var value
= spec
.value
&& spec
.value
.toFixed(0) + '%';
52 var timeout
= spec
.timeout
|| 200;
53 setTimeout(function() {
54 bar
.css('width', value
);
58 resetProgressBar: function() {
59 this.ui
.progressBar
.hide();
60 this.updateProgressBar({
66 handleUploadProgress: function(done
, expected
) {
67 this.updateProgressBar({
68 value
: PROGRESS_THRESHOLD
+ (done
/ expected
) * (100 - PROGRESS_THRESHOLD
),
73 handleUploadStart: function() {
74 this.ui
.progressBar
.show();
77 handleUploadSuccess: function(res
) {
78 this.resetProgressBar();
79 var n
= parseInt(res
.fields
.numberOfFiles
, 10);
80 appEvents
.triggerParent('user_notification', {
81 title
: 'Upload complete',
82 text
: (n
> 1 ? n
+ ' files' : 'file') + ' uploaded successfully.'
86 handleUploadError: function(err
) {
87 appEvents
.triggerParent('user_notification', {
88 title
: 'Error Uploading File',
91 this.resetProgressBar();
94 isTextDrag: function(e
) {
95 var dt
= e
.dataTransfer
;
96 if (contains(dt
.types
, 'Files')) return false;
97 if (!dt
.files
&& dt
.files
.length
> 0) {
101 var items
= dt
.items
;
102 if (!items
) return true;
103 for (var i
= 0; i
< items
.length
; i
++) {
104 var kind
= items
[i
].kind
;
105 if (kind
!== 'string') {
113 onDragEnter: function(e
) {
114 if (e
.originalEvent
) e
= e
.originalEvent
;
115 if (this.isTextDrag(e
)) return;
117 this.ui
.dragOverlay
.toggleClass('hide', false);
121 onDragLeave: function(e
) {
122 if (e
.originalEvent
) e
= e
.originalEvent
;
123 if (this.isTextDrag(e
)) return;
126 this.ui
.dragOverlay
.toggleClass('hide', this.dragCounter
=== 0);
130 onDragOver: function(e
) {
131 if (e
.originalEvent
) e
= e
.originalEvent
;
132 if (this.isTextDrag(e
)) return;
136 onDrop: function(e
) {
137 if (e
.originalEvent
) e
= e
.originalEvent
;
138 if (this.isTextDrag(e
)) return;
140 this.dragCounter
= 0; // reset the counter
141 this.ui
.dragOverlay
.toggleClass('hide', true);
144 var files
= e
.dataTransfer
.files
;
148 isImage: function(file
) {
149 var fileType
= file
.type
;
150 // svg causes an INVALID_FILE_META_DATA error from transloadit.
151 // see https://github.com/gitterHQ/gitter/issues/721
152 return fileType
!== 'image/svg+xml' && fileType
.indexOf('image/') >= 0;
156 * handles pasting, image-only for now
158 handlePaste: function(evt
) {
159 evt
= evt
.originalEvent
|| evt
;
160 var clipboard
= evt
.clipboardData
;
163 if (!clipboard
|| !clipboard
.items
) {
164 return; // Safari + FF, don't support pasting images in. Ignore and perform default behaviour. WC.
167 if (clipboard
.items
.length
=== 1) {
168 blob
= clipboard
.items
[0].getAsFile();
169 if (!blob
|| !this.isImage(blob
)) {
172 evt
.preventDefault();
178 // Returns image iff all files are safe for opening in a browser
179 // otherwise returns ''
180 getFileType: function(files
) {
181 if (!files
.length
) return '';
183 for (var i
= 0; i
< files
.length
; i
++) {
185 if (!this.isImage(file
)) {
192 upload: function(files
) {
193 if (!files
.length
) return;
195 this.ui
.progressBar
.show();
197 this.updateProgressBar({
202 this.updateProgressBar({
203 value
: PROGRESS_THRESHOLD
,
207 var DEFAULT_OPTIONS
= {
212 onStart
: this.handleUploadStart
.bind(this),
213 onProgress
: this.handleUploadProgress
.bind(this),
214 onSuccess
: this.handleUploadSuccess
.bind(this),
215 onError
: this.handleUploadError
.bind(this)
218 var formData
= new FormData();
220 for (var i
= 0; i
< files
.length
; i
++) {
222 formData
.append('file', file
);
225 formData
.append('numberOfFiles', files
.length
);
227 .get('/generate-signature', {
228 room_id
: context
.getTroupeId(),
229 type
: this.getFileType(files
)
231 .then(function(res
) {
232 formData
.append('signature', res
.sig
);
234 var form
= self
.ui
.uploadForm
;
235 form
.find('input[name="params"]').attr('value', res
.params
);
236 form
.unbind('submit.transloadit');
237 form
.transloadit(_
.extend(DEFAULT_OPTIONS
, { formData
: formData
}));
243 module
.exports
= DropTargetView
;