uploads 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +38 -0
  4. data/app/assets/javascripts/anjlab/uploads.js +7 -0
  5. data/app/assets/javascripts/anjlab/uploads/button.js.coffee +80 -0
  6. data/app/assets/javascripts/anjlab/uploads/dnd.js.coffee +215 -0
  7. data/app/assets/javascripts/anjlab/uploads/handler.base.js.coffee +101 -0
  8. data/app/assets/javascripts/anjlab/uploads/handler.form.js.coffee +173 -0
  9. data/app/assets/javascripts/anjlab/uploads/handler.xhr.js.coffee +393 -0
  10. data/app/assets/javascripts/anjlab/uploads/uploader.js.coffee +487 -0
  11. data/app/assets/javascripts/anjlab/uploads/utils.js.coffee +116 -0
  12. data/lib/tasks/uploads_tasks.rake +4 -0
  13. data/lib/uploads.rb +10 -0
  14. data/lib/uploads/engine.rb +6 -0
  15. data/lib/uploads/version.rb +3 -0
  16. data/test/dummy/README.rdoc +261 -0
  17. data/test/dummy/Rakefile +7 -0
  18. data/test/dummy/app/assets/javascripts/application.js +16 -0
  19. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  20. data/test/dummy/app/controllers/application_controller.rb +3 -0
  21. data/test/dummy/app/controllers/uploads_controller.rb +15 -0
  22. data/test/dummy/app/controllers/welcome_controller.rb +4 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/test/dummy/app/views/welcome/index.html.slim +53 -0
  26. data/test/dummy/config.ru +4 -0
  27. data/test/dummy/config/application.rb +59 -0
  28. data/test/dummy/config/boot.rb +10 -0
  29. data/test/dummy/config/database.yml +25 -0
  30. data/test/dummy/config/environment.rb +5 -0
  31. data/test/dummy/config/environments/development.rb +37 -0
  32. data/test/dummy/config/environments/production.rb +67 -0
  33. data/test/dummy/config/environments/test.rb +37 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/inflections.rb +15 -0
  36. data/test/dummy/config/initializers/mime_types.rb +5 -0
  37. data/test/dummy/config/initializers/secret_token.rb +7 -0
  38. data/test/dummy/config/initializers/session_store.rb +8 -0
  39. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  40. data/test/dummy/config/locales/en.yml +5 -0
  41. data/test/dummy/config/routes.rb +59 -0
  42. data/test/dummy/db/development.sqlite3 +0 -0
  43. data/test/dummy/log/development.log +23847 -0
  44. data/test/dummy/public/404.html +26 -0
  45. data/test/dummy/public/422.html +26 -0
  46. data/test/dummy/public/500.html +25 -0
  47. data/test/dummy/public/favicon.ico +0 -0
  48. data/test/dummy/script/rails +6 -0
  49. data/test/dummy/tmp/cache/assets/C79/790/sprockets%2Fde97a756642791010533233b267b1afe +0 -0
  50. data/test/dummy/tmp/cache/assets/C99/300/sprockets%2F3bd289b286c074ad66220ad20181b135 +0 -0
  51. data/test/dummy/tmp/cache/assets/C9E/CA0/sprockets%2F1252e234767209f94d0a41a0bc19e33c +0 -0
  52. data/test/dummy/tmp/cache/assets/CA1/9E0/sprockets%2F4c40d59c233952767c150cb8234cab22 +0 -0
  53. data/test/dummy/tmp/cache/assets/CA5/AC0/sprockets%2Fcc77204615926b95033b4fa044d7c61b +0 -0
  54. data/test/dummy/tmp/cache/assets/CAA/860/sprockets%2F6b1d0c998769132cda15f7c5d1283300 +0 -0
  55. data/test/dummy/tmp/cache/assets/CCD/830/sprockets%2F962b2259b044ca05005c14fd83ba982a +0 -0
  56. data/test/dummy/tmp/cache/assets/CD2/7B0/sprockets%2Fe9a64cf98e26a4719e64d747d7912893 +0 -0
  57. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  58. data/test/dummy/tmp/cache/assets/CE4/A00/sprockets%2Fe589f936724000ba0e7f077a63b75d4e +0 -0
  59. data/test/dummy/tmp/cache/assets/CE7/D40/sprockets%2F888fd320a7c0125218313f1ef9d6d99d +0 -0
  60. data/test/dummy/tmp/cache/assets/CFD/650/sprockets%2F73de09397391979f4dcd67ce32a7816f +0 -0
  61. data/test/dummy/tmp/cache/assets/D07/710/sprockets%2F56976babbbfe475040b22885733ca41a +0 -0
  62. data/test/dummy/tmp/cache/assets/D0B/D70/sprockets%2F6c298d94014122a613afbebce90590f8 +0 -0
  63. data/test/dummy/tmp/cache/assets/D0F/6A0/sprockets%2F18414faf9678c2ab6d1d60891c6f06a1 +0 -0
  64. data/test/dummy/tmp/cache/assets/D15/C40/sprockets%2F5516d9e4e25aaefc72a78fc641962512 +0 -0
  65. data/test/dummy/tmp/cache/assets/D24/CD0/sprockets%2Fd0cd795c6f0b6074de96706e8bf70975 +0 -0
  66. data/test/dummy/tmp/cache/assets/D2E/980/sprockets%2Fded84d1bb4c31404691d106f4b8e120f +0 -0
  67. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  68. data/test/dummy/tmp/cache/assets/D33/120/sprockets%2F70d8b84b628400ffbf410b17b845bae2 +0 -0
  69. data/test/dummy/tmp/cache/assets/D35/8C0/sprockets%2F20424272a569797e71dbae1bdb33c2fc +0 -0
  70. data/test/dummy/tmp/cache/assets/D3F/FE0/sprockets%2Fbfc6e8a285039670d3ca0399bd3e633b +0 -0
  71. data/test/dummy/tmp/cache/assets/D44/E50/sprockets%2F5767c31d95e72a26ffb3c0092dc3cf94 +0 -0
  72. data/test/dummy/tmp/cache/assets/D48/8B0/sprockets%2F795b331f7ff4a59f0604c531e71af9de +0 -0
  73. data/test/dummy/tmp/cache/assets/D4D/420/sprockets%2Fab27b88913d73cdabe65891eeb884444 +0 -0
  74. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  75. data/test/dummy/tmp/cache/assets/D5A/2A0/sprockets%2Fc379b9f699c8f614cefea762d376d224 +0 -0
  76. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  77. data/test/dummy/tmp/cache/assets/D5D/330/sprockets%2Fce164ed2c0f3e91b338035376ad41bac +0 -0
  78. data/test/dummy/tmp/cache/assets/D6D/350/sprockets%2Fdac0344fd04f6fe00bce8983177635ea +0 -0
  79. data/test/dummy/tmp/cache/assets/D71/6E0/sprockets%2F07996d57b5cfca8a92b02613fdaae735 +0 -0
  80. data/test/dummy/tmp/cache/assets/D7C/210/sprockets%2Ff98c0ec43e4406aa3cec29837d9f618e +0 -0
  81. data/test/dummy/tmp/cache/assets/D7E/AF0/sprockets%2F1d4ffb9a3d536682ff7d185668dc2d4b +0 -0
  82. data/test/dummy/tmp/cache/assets/D96/9A0/sprockets%2Ff1caf4ea19ee66a13841eaf6f40a6433 +0 -0
  83. data/test/dummy/tmp/cache/assets/D97/760/sprockets%2Fd1c9a476956a0ccae81fa57dad53135a +0 -0
  84. data/test/dummy/tmp/cache/assets/DBB/F20/sprockets%2F03e6ee44546ae1ea1bfd3e0801b7ca7a +0 -0
  85. data/test/dummy/tmp/cache/assets/DC3/810/sprockets%2Fc86e769b165de4f9d49745ab9fee7b5f +0 -0
  86. data/test/dummy/tmp/cache/assets/DC5/3C0/sprockets%2Fc21f1ad7fdce18f5b7a5a581b1351fd6 +0 -0
  87. data/test/dummy/tmp/cache/assets/DCA/4A0/sprockets%2Fbdfe27f0efa249de171cbfb2970661c2 +0 -0
  88. data/test/dummy/tmp/cache/assets/DD3/AF0/sprockets%2Fb090f4fd52cbc2e5ccc815aa8999f2f3 +0 -0
  89. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  90. data/test/dummy/tmp/cache/assets/DE7/920/sprockets%2Feea789b2f9e87ceaffa7757e32fd1192 +0 -0
  91. data/test/dummy/tmp/cache/assets/E02/FE0/sprockets%2F68a4afe37ab83b2d9fa1cf5e084fec81 +0 -0
  92. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  93. data/test/dummy/tmp/cache/assets/E2B/C80/sprockets%2Ff6f179d2c6207aabbc3cec5c260eee9e +0 -0
  94. data/test/dummy/tmp/cache/assets/E47/5F0/sprockets%2Fef5f1e3bcbc9baa50e54a15ba0e5ca91 +0 -0
  95. data/test/test_helper.rb +15 -0
  96. data/test/uploads_test.rb +7 -0
  97. metadata +276 -0
@@ -0,0 +1,487 @@
1
+ utils = @AnjLab.Uploads.Utils
2
+
3
+ class @AnjLab.Uploads.Uploader
4
+
5
+ constructor: (element, options)->
6
+ @$element = $(element)
7
+ @options = $.extend(true, {}, $.fn.uploaderDefaults, @$element.data(), options)
8
+ # number of files being uploaded
9
+ @filesInProgress = []
10
+ @storedFileIds = []
11
+ @autoRetries = []
12
+ @retryTimeouts = []
13
+ @preventRetries = []
14
+
15
+ @paramsStore = @createParamsStore()
16
+ @endpointStore = @createEndpointStore()
17
+
18
+ @handler = @createUploadHandler()
19
+ @dnd = @createDragAndDrop()
20
+
21
+ if @options.button
22
+ @button = new AnjLab.Uploads.Button(@options.button, {
23
+ multiple: @options.multiple && utils.isXhrUploadSupported()
24
+ acceptFiles: @options.validation.acceptFiles
25
+ onChange: (input)=>
26
+ @onInputChange(input)
27
+ hoverClass: @options.classes.buttonHover
28
+ focusClass: @options.classes.buttonFocus
29
+ })
30
+
31
+ log: (str, level) ->
32
+ if @options.debug && (!level || level == 'info')
33
+ utils.log('[FineUploader] ' + str)
34
+ else if level && level != 'info'
35
+ utils.log('[FineUploader] ' + str, level)
36
+ true
37
+
38
+ setParams: (params, fileId) ->
39
+ if fileId?
40
+ @paramsStore.setParams(params, fileId)
41
+ else
42
+ @options.request.params = params
43
+
44
+ setEndpoint: (endpoint, fileId) ->
45
+ if fileId?
46
+ @endpointStore.setEndpoint(endpoint, fileId)
47
+ else
48
+ @options.request.endpoint = endpoint
49
+
50
+ getInProgress: -> @filesInProgress.length
51
+
52
+ createDragAndDrop: ->
53
+ new AnjLab.Uploads.DragAndDrop(@options.dropzones,
54
+ {
55
+ multiple: @options.multiple
56
+ classes:
57
+ dropActive: @options.classes.dropActive
58
+ bodyDragover: @options.classes.bodyDragover
59
+ callbacks:
60
+ dropProcessing: (isProcessing, files) =>
61
+ if files
62
+ @addFiles(files)
63
+ error: (code, filename) =>
64
+ @error(code, filename)
65
+ log: (message, level) =>
66
+ @log(message, level)
67
+ })
68
+
69
+ uploadStoredFiles: ->
70
+ while @storedFileIds.length
71
+ idToUpload = @storedFileIds.shift()
72
+ @filesInProgress.push(idToUpload)
73
+ @handler.upload(idToUpload)
74
+
75
+ clearStoredFiles: -> @storedFileIds = []
76
+
77
+ retry: (id) ->
78
+ if @onBeforeManualRetry(id)
79
+ @handler.retry(id)
80
+ true
81
+ else
82
+ false
83
+
84
+ cancel: (fileId) ->
85
+ @handler.cancel(fileId)
86
+
87
+ reset: ->
88
+ @log("Resetting uploader...")
89
+ @handler.reset()
90
+ @filesInProgress = []
91
+ @storedFileIds = []
92
+ @autoRetries = []
93
+ @retryTimeouts = []
94
+ @preventRetries = []
95
+ @button.reset()
96
+ @paramsStore.reset()
97
+ @endpointStore.reset()
98
+
99
+
100
+ addFiles: (filesOrInputs)->
101
+ verifiedFilesOrInputs = []
102
+
103
+ return if !filesOrInputs
104
+
105
+ if !window.FileList || !(filesOrInputs instanceof FileList)
106
+ filesOrInputs = [].concat(filesOrInputs)
107
+
108
+ for fileOrInput in filesOrInputs
109
+ if utils.isFileOrInput(fileOrInput)
110
+ verifiedFilesOrInputs.push(fileOrInput);
111
+ else
112
+ @log("#{fileOrInput} is not a File or INPUT element! Ignoring!", 'warn')
113
+ @log("Processing #{verifiedFilesOrInputs.length} files or inputs...")
114
+ @uploadFileList(verifiedFilesOrInputs)
115
+
116
+ getUuid: (fileId) -> @handler.getUuid(fileId)
117
+ getResumableFilesData: -> @handler.getResumableFilesData()
118
+ getSize: (fileId) -> @handler.getSize(fileId)
119
+ getFile: (fileId) -> @handler.getFile(fileId)
120
+
121
+ createParamsStore: ->
122
+ paramsStore = {}
123
+ self = this
124
+
125
+ {
126
+ setParams: (params, fileId)->
127
+ paramsStore[fileId] = $.extend(true, {}, params)
128
+ getParams: (fileId) ->
129
+ if fileId? && paramsStore[fileId]
130
+ $.extend(true, {}, paramsStore[fileId])
131
+ else
132
+ $.extend(true, {}, self.options.request.params)
133
+ remove: (fileId) -> delete paramsStore[fileId]
134
+ reset: -> paramsStore = {}
135
+ }
136
+
137
+ createEndpointStore: () ->
138
+ endpointStore = {}
139
+ self = this
140
+
141
+ {
142
+ setEndpoint: (endpoint, fileId) ->
143
+ endpointStore[fileId] = endpoint
144
+
145
+ getEndpoint: (fileId) ->
146
+ if fileId? && endpointStore[fileId]
147
+ return endpointStore[fileId]
148
+
149
+ self.options.request.endpoint;
150
+
151
+ remove: (fileId) -> delete endpointStore[fileId]
152
+
153
+ reset: -> endpointStore = {}
154
+ }
155
+
156
+ preventLeaveInProgress: ->
157
+ $(window).on 'beforeunload', (e)=>
158
+ return if !@filesInProgress.length
159
+
160
+ e.returnValue = @options.messages.onLeave
161
+ onSubmit: (id, fileName) ->
162
+ if @options.autoUpload
163
+ @filesInProgress.push(id)
164
+
165
+ onProgress: (id, fileName, loaded, total) -> false
166
+
167
+ onComplete: (id, fileName, result, xhr) ->
168
+ @removeFromFilesInProgress(id)
169
+ @maybeParseAndSendUploadError(id, fileName, result, xhr)
170
+
171
+ onCancel: (id, fileName) ->
172
+ @removeFromFilesInProgress(id)
173
+
174
+ clearTimeout(@retryTimeouts[id])
175
+
176
+ storedFileIndex = $.inArray(id, @storedFileIds)
177
+ if !@options.autoUpload && storedFileIndex >= 0
178
+ @storedFileIds.splice(storedFileIndex, 1)
179
+
180
+ removeFromFilesInProgress: (id) ->
181
+ index = $.inArray(id, @filesInProgress)
182
+ if index >= 0
183
+ @filesInProgress.splice(index, 1)
184
+
185
+ onUpload: (id, fileName) -> null
186
+
187
+ onInputChange: (input) ->
188
+ if utils.isXhrUploadSupported()
189
+ @addFiles(input.files)
190
+ else
191
+ @addFiles(input)
192
+ @button.reset()
193
+
194
+ onBeforeAutoRetry: (id, fileName) ->
195
+ @log("Waiting #{@options.retry.autoAttemptDelay} seconds before retrying #{fileName}...")
196
+
197
+ onAutoRetry: (id, fileName, responseJSON) ->
198
+ @log("Retrying #{fileName}...")
199
+ @autoRetries[id]++
200
+ @handler.retry(id)
201
+
202
+ shouldAutoRetry: (id, fileName, responseJSON) ->
203
+ if !@preventRetries[id] && @options.retry.enableAuto
204
+ if !@autoRetries[id]?
205
+ @autoRetries[id] = 0
206
+
207
+ return @autoRetries[id] < @options.retry.maxAutoAttempts
208
+
209
+ false
210
+
211
+ uploadFile: (fileContainer) ->
212
+ id = @handler.add(fileContainer)
213
+ fileName = @handler.getName(id)
214
+
215
+ if @options.callbacks.onSubmit(id, fileName) != false
216
+ @onSubmit(id, fileName)
217
+ if @options.autoUpload
218
+ @handler.upload(id)
219
+ else
220
+ @storeFileForLater(id)
221
+
222
+ storeFileForLater: (id) -> @storedFileIds.push(id)
223
+
224
+ parseFileSize: (file) ->
225
+ size = null
226
+ # fix missing properties in Safari 4 and firefox 11.0a2
227
+ size = file.fileSize ? file.size if !file.value
228
+ size
229
+
230
+ formatSize: (bytes) ->
231
+ i = -1;
232
+ while true
233
+ bytes = bytes / 1024
234
+ i++
235
+ break if bytes <= 99
236
+
237
+ Math.max(bytes, 0.1).toFixed(1) + @options.text.sizeSymbols[i]
238
+
239
+ parseFileName: (file) ->
240
+ if file.value
241
+ # it is a file input
242
+ # get input value and remove path to normalize
243
+ file.value.replace(/.*(\/|\\)/, "")
244
+ else
245
+ # fix missing properties in Safari 4 and firefox 11.0a2
246
+ file.fileName ? file.name
247
+
248
+ getValidationDescriptor: (file) ->
249
+ fileDescriptor = {name: @parseFileName(file)}
250
+ size = @parseFileSize(file)
251
+
252
+ fileDescriptor.size = size if size
253
+
254
+ fileDescriptor
255
+
256
+ getValidationDescriptors: (files) ->
257
+ @getValidationDescriptor(file) for file in files
258
+
259
+ isAllowedExtension: (fileName) ->
260
+ allowed = @options.validation.allowedExtensions
261
+
262
+ return true if !allowed.length
263
+
264
+ for allowedExt in allowed
265
+ extRegex = new RegExp('\\.' + allowedExt + "$", 'i')
266
+
267
+ return true if fileName.match(extRegex)?
268
+
269
+ false
270
+
271
+ validateFile: (file) ->
272
+ validationDescriptor = @getValidationDescriptor(file)
273
+ name = validationDescriptor.name
274
+ size = validationDescriptor.size
275
+
276
+ return false if @options.callbacks.onValidate(validationDescriptor) == false
277
+
278
+ if !@isAllowedExtension(name)
279
+ @error('typeError', name)
280
+ false
281
+ else if size == 0
282
+ @error('emptyError', name)
283
+ false
284
+ else if size && @options.validation.sizeLimit && size > @options.validation.sizeLimit
285
+ @error('sizeError', name)
286
+ false
287
+ else if (size && size < @options.validation.minSizeLimit)
288
+ @error('minSizeError', name)
289
+ false
290
+ else
291
+ true
292
+
293
+ error: (code, fileName) ->
294
+ message = @options.messages[code]
295
+ r = (name, replacement) -> message = message.replace(name, replacement)
296
+
297
+ extensions = @options.validation.allowedExtensions.join(', ').toLowerCase()
298
+
299
+ r('{file}', @options.formatFileName(fileName))
300
+ r('{extensions}', extensions)
301
+ r('{sizeLimit}', @formatSize(@options.validation.sizeLimit))
302
+ r('{minSizeLimit}', @formatSize(@options.validation.minSizeLimit))
303
+
304
+ @options.callbacks.onError(null, fileName, message)
305
+
306
+ message
307
+
308
+ # return false if we should not attempt the requested retry
309
+ onBeforeManualRetry: (id) ->
310
+ if @preventRetries[id]
311
+ @log("Retries are forbidden for id #{id}", 'warn')
312
+ false
313
+ else if @handler.isValid(id)
314
+ fileName = @handler.getName(id);
315
+
316
+ return false if @options.callbacks.onManualRetry(id, fileName) == false
317
+
318
+ @log("Retrying upload for '#{fileName}' (id: #{id})...")
319
+ @filesInProgress.push(id)
320
+ true
321
+ else
322
+ @log("'#{id}' is not a valid file ID", 'error')
323
+ false
324
+
325
+ maybeParseAndSendUploadError: (id, fileName, response, xhr) ->
326
+ # assuming no one will actually set the response code to something other than 200 and still set 'success' to true
327
+ if !response.success
328
+ if xhr && xhr.status != 200 && !response.error
329
+ @options.callbacks.onError(id, fileName, "XHR returned response code #{xhr.status}")
330
+ else
331
+ errorReason = if response.error then response.error else "Upload failure reason unknown"
332
+ @options.callbacks.onError(id, fileName, errorReason)
333
+
334
+ uploadFileList: (files) ->
335
+ validationDescriptors = @getValidationDescriptors(files)
336
+ batchInvalid = @options.callbacks.onValidateBatch(validationDescriptors) == false
337
+ if !batchInvalid
338
+ if files.length > 0
339
+ for file in files
340
+ if @validateFile(file)
341
+ @uploadFile(file)
342
+ else
343
+ return if @options.validation.stopOnFirstInvalidFile
344
+ else
345
+ @error('noFilesError', "")
346
+
347
+
348
+ createUploadHandler: ->
349
+ AnjLab.Uploads.UploadHandler.create({
350
+ debug: @options.debug
351
+ forceMultipart: @options.request.forceMultipart
352
+ maxConnections: @options.maxConnections
353
+ customHeaders: @options.request.customHeaders
354
+ inputName: @options.request.inputName
355
+ uuidParamName: @options.request.uuidName
356
+ totalFileSizeParamName: @options.request.totalFileSizeName
357
+ demoMode: @options.demoMode
358
+ paramsStore: @paramsStore
359
+ endpointStore: @endpointStore
360
+ chunking: @options.chunking
361
+ resume: @options.resume
362
+ log: (str, level) => @log(str, level)
363
+
364
+ onProgress: (id, fileName, loaded, total) =>
365
+ @onProgress(id, fileName, loaded, total)
366
+ @options.callbacks.onProgress(id, fileName, loaded, total)
367
+
368
+ onComplete: (id, fileName, result, xhr) =>
369
+ @onComplete(id, fileName, result, xhr)
370
+ @options.callbacks.onComplete(id, fileName, result)
371
+
372
+ onCancel: (id, fileName) =>
373
+ @onCancel(id, fileName)
374
+ @options.callbacks.onCancel(id, fileName)
375
+
376
+ onUpload: (id, fileName) =>
377
+ @onUpload(id, fileName)
378
+ @options.callbacks.onUpload(id, fileName)
379
+
380
+ onUploadChunk: (id, fileName, chunkData) =>
381
+ @options.callbacks.onUploadChunk(id, fileName, chunkData)
382
+
383
+ onResume: (id, fileName, chunkData) =>
384
+ @options.callbacks.onResume(id, fileName, chunkData)
385
+
386
+ onAutoRetry: (id, fileName, responseJSON, xhr) =>
387
+ @preventRetries[id] = responseJSON[@options.retry.preventRetryResponseProperty]
388
+
389
+ if @shouldAutoRetry(id, fileName, responseJSON)
390
+ @maybeParseAndSendUploadError(id, fileName, responseJSON, xhr)
391
+ @options.callbacks.onAutoRetry(id, fileName, self._autoRetries[id] + 1)
392
+ @onBeforeAutoRetry(id, fileName)
393
+
394
+ @retryTimeouts[id] = setTimeout( =>
395
+ @onAutoRetry(id, fileName, responseJSON)
396
+ , @options.retry.autoAttemptDelay * 1000
397
+ )
398
+
399
+ true
400
+ else
401
+ false
402
+ })
403
+
404
+
405
+
406
+ $.fn.uploaderDefaults =
407
+ debug: false
408
+ button: null
409
+ multiple: true
410
+ maxConnections: 3
411
+ disableCancelForFormUploads: false
412
+ autoUpload: true
413
+ request:
414
+ endpoint: '/uploads'
415
+ params: {}
416
+ customHeaders: {}
417
+ forceMultipart: true
418
+ inputName: 'qqfile'
419
+ uuidName: 'qquuid'
420
+ totalFileSizeName: 'qqtotalfilesize'
421
+ validation:
422
+ allowedExtensions: []
423
+ sizeLimit: 0
424
+ minSizeLimit: 0
425
+ stopOnFirstInvalidFile: true
426
+ callbacks:
427
+ onSubmit: (id, fileName) -> null
428
+ onComplete: (id, fileName, responseJSON) -> null
429
+ onCancel: (id, fileName) -> null
430
+ onUpload: (id, fileName) -> null
431
+ onUploadChunk: (id, fileName, chunkData) -> null
432
+ onResume: (id, fileName, chunkData) -> null
433
+ onProgress: (id, fileName, loaded, total) -> null
434
+ onError: (id, fileName, reason) -> null
435
+ onAutoRetry: (id, fileName, attemptNumber) -> null
436
+ onManualRetry: (id, fileName) -> false
437
+ onValidateBatch: (fileData) -> null
438
+ onValidate: (fileData) -> null
439
+ messages:
440
+ typeError: "{file} has an invalid extension. Valid extension(s): {extensions}."
441
+ sizeError: "{file} is too large, maximum file size is {sizeLimit}."
442
+ minSizeError: "{file} is too small, minimum file size is {minSizeLimit}."
443
+ emptyError: "{file} is empty, please select files again without it."
444
+ noFilesError: "No files to upload.",
445
+ onLeave: "The files are being uploaded, if you leave now the upload will be cancelled."
446
+ retry:
447
+ enableAuto: false
448
+ maxAutoAttempts: 3
449
+ autoAttemptDelay: 5
450
+ preventRetryResponseProperty: 'preventRetry'
451
+ classes:
452
+ buttonHover: 'qq-upload-button-hover'
453
+ buttonFocus: 'qq-upload-button-focus'
454
+ bodyDragover: 'qq-upload-dragging'
455
+ chunking:
456
+ enabled: false
457
+ partSize: 2000000
458
+ paramNames:
459
+ partIndex: 'qqpartindex'
460
+ partByteOffset: 'qqpartbyteoffset'
461
+ chunkSize: 'qqchunksize'
462
+ totalFileSize: 'qqtotalfilesize'
463
+ totalParts: 'qqtotalparts'
464
+ filename: 'qqfilename'
465
+ resume:
466
+ enabled: false
467
+ id: null
468
+ cookiesExpireIn: 7 #days
469
+ paramNames:
470
+ resuming: "qqresume"
471
+ text:
472
+ sizeSymbols: ['kB', 'MB', 'GB', 'TB', 'PB', 'EB']
473
+
474
+ formatFileName: (fileName)->
475
+ if fileName.length > 33
476
+ fileName = fileName.slice(0, 19) + '...' + fileName.slice(-14)
477
+ fileName
478
+
479
+ $.fn.uploader = (option) ->
480
+ this.each ->
481
+ $this = $(this)
482
+ data = $this.data('uploader')
483
+ if !data
484
+ options = $.extend(true, {}, typeof option == 'object' && option)
485
+ $this.data('uploader', (data = new AnjLab.Uploads.Uploader(this, options)))
486
+ if (typeof option == 'string')
487
+ data[option]()