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,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Uploads
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Uploads'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ // =require anjlab/uploads/utils
2
+ // =require anjlab/uploads/handler.base
3
+ // =require anjlab/uploads/handler.form
4
+ // =require anjlab/uploads/handler.xhr
5
+ // =require anjlab/uploads/button
6
+ // =require anjlab/uploads/dnd
7
+ // =require anjlab/uploads/uploader
@@ -0,0 +1,80 @@
1
+ class @AnjLab.Uploads.Button
2
+
3
+ constructor: (element, options) ->
4
+ @options = $.extend(true, {}, $.fn.uploaderButtonDefaults, options)
5
+ @$element = $(@options.element ? element)
6
+
7
+ # make button suitable container for input
8
+ @$element.css
9
+ position: 'relative'
10
+ overflow: 'hidden'
11
+ # Make sure browse button is in the right side
12
+ # in Internet Explorer
13
+ direction: 'ltr'
14
+
15
+ @input = @createInput()
16
+
17
+ getInput: -> @input
18
+
19
+ # cleans/recreates the file input
20
+ reset: ->
21
+ if @input.parentNode
22
+ $(@input).remove()
23
+
24
+ @$element.removeClass(@options.focusClass)
25
+ @input = @createInput()
26
+
27
+ createInput: ->
28
+ input = document.createElement("input")
29
+
30
+ if @options.multiple
31
+ input.setAttribute("multiple", "multiple")
32
+
33
+ if @options.acceptFiles
34
+ input.setAttribute("accept", @options.acceptFiles)
35
+
36
+ input.setAttribute("type", "file")
37
+ input.setAttribute("name", @options.name)
38
+
39
+ $(input).css
40
+ position: 'absolute'
41
+ # in Opera only 'browse' button
42
+ # is clickable and it is located at
43
+ # the right side of the input
44
+ right: 0
45
+ top: 0
46
+ fontFamily: 'Arial'
47
+ # 4 persons reported this, the max values that worked for them were 243, 236, 236, 118
48
+ fontSize: '118px'
49
+ margin: 0
50
+ padding: 0
51
+ cursor: 'pointer'
52
+ opacity: 0
53
+
54
+ @$element.append(input)
55
+
56
+ $(input).on
57
+ change: => @options.onChange(input)
58
+ mouseover: => @$element.addClass(@options.hoverClass)
59
+ mouseout: => @$element.removeClass(@options.hoverClass)
60
+ focus: => @$element.addClass(@options.focusClass)
61
+ blur: => @$element.removeClass(@options.focusClass)
62
+
63
+ # IE and Opera, unfortunately have 2 tab stops on file input
64
+ # which is unacceptable in our case, disable keyboard access
65
+ if window.attachEvent
66
+ # it is IE or Opera
67
+ input.setAttribute('tabIndex', '-1')
68
+
69
+ input
70
+
71
+ $.fn.uploaderButtonDefaults =
72
+ element: null
73
+ # if set to true adds multiple attribute to file input
74
+ multiple: false,
75
+ acceptFiles: null,
76
+ # name attribute of file input
77
+ name: 'file',
78
+ onChange: (input) -> null,
79
+ hoverClass: 'qq-upload-button-hover',
80
+ focusClass: 'qq-upload-button-focus'
@@ -0,0 +1,215 @@
1
+ utils = @AnjLab.Uploads.Utils
2
+
3
+ class @AnjLab.Uploads.DragAndDrop
4
+
5
+ constructor: (zones, options)->
6
+ @droppedFiles = []
7
+ @droppedEntriesCount = 0
8
+ @droppedEntriesParsedCount = 0
9
+ @options = options
10
+ @setupDragDrop(zones)
11
+
12
+ maybeUploadDroppedFiles: ->
13
+ if @droppedEntriesCount == @droppedEntriesParsedCount && !@dirPending
14
+ @options.callbacks.log("Grabbed #{@droppedFiles.length} files after tree traversal.")
15
+ @zones.each -> $(this).data('dropZone').dropDisabled(false)
16
+ @options.callbacks.dropProcessing(false, @droppedFiles)
17
+
18
+ addDroppedFile: (file)->
19
+ @droppedFiles.push(file)
20
+ @droppedEntriesParsedCount += 1
21
+ @maybeUploadDroppedFiles()
22
+
23
+ traverseFileTree: (entry)->
24
+ # var dirReader, i;
25
+ dirPending = false
26
+ @droppedEntriesCount+=1
27
+
28
+ if entry.isFile
29
+ entry.file (file) => @addDroppedFile(file)
30
+ else if entry.isDirectory
31
+ dirPending = true
32
+ dirReader = entry.createReader();
33
+ dirReader.readEntries (entries) =>
34
+ @droppedEntriesParsedCount+=1;
35
+ for e in entries
36
+ @traverseFileTree(e)
37
+
38
+ dirPending = false;
39
+
40
+ if !entries.length
41
+ @maybeUploadDroppedFiles()
42
+
43
+ isFileDrag: (dragEvent) ->
44
+ for own key, val of dragEvent.dataTransfer.types
45
+ return true if val == 'Files'
46
+
47
+ false
48
+
49
+ handleDataTransfer: (dataTransfer) ->
50
+ @options.callbacks.dropProcessing(true)
51
+ @zones.each -> $(this).data('dropZone').dropDisabled(true)
52
+
53
+ if dataTransfer.files.length > 1 && !@options.multiple
54
+ @options.callbacks.dropProcessing(false)
55
+ @options.callbacks.error('tooManyFilesError', "")
56
+ @zones.each -> $(this).data('dropZone').dropDisabled(false)
57
+ else
58
+ @droppedFiles = [];
59
+ @droppedEntriesCount = 0
60
+ @droppedEntriesParsedCount = 0
61
+
62
+ if utils.isFolderDropSupported(dataTransfer)
63
+ items = dataTransfer.items
64
+
65
+ i = 0
66
+ for item in items
67
+ entry = item.webkitGetAsEntry()
68
+ if entry
69
+ # due to a bug in Chrome's File System API impl - #149735
70
+ if entry.isFile
71
+ @droppedFiles.push(items[i].getAsFile());
72
+ if (i == items.length - 1)
73
+ @maybeUploadDroppedFiles()
74
+ else
75
+ @traverseFileTree(entry)
76
+ i += 1
77
+ else
78
+ @options.callbacks.dropProcessing(false, dataTransfer.files)
79
+ @zones.each -> $(this).data('dropZone').dropDisabled(false)
80
+
81
+ setupDragDrop: (zones)->
82
+ dnd = this
83
+ @zones = $(zones).each ->
84
+ $zone = $(this)
85
+ zoneOpts = $.extend(true, {}, {
86
+ onEnter: (e) =>
87
+ $zone.toggleClass(dnd.options.classes.dropActive, true)
88
+ e.stopPropagation()
89
+
90
+ onLeaveNotDescendants: (e) =>
91
+ $zone.toggleClass(dnd.options.classes.dropActive, false)
92
+
93
+ onDrop: (e) =>
94
+ $zone.toggleClass(dnd.options.classes.dropActive, false)
95
+
96
+ dnd.handleDataTransfer(e.originalEvent.dataTransfer)
97
+ }, dnd.options)
98
+
99
+ $zone.data('dropZone', new AnjLab.Uploads.UploadDropZone(this, zoneOpts))
100
+
101
+ $(document).on 'drop', (e) -> e.preventDefault()
102
+
103
+ _dropOutsideDisabled = false
104
+ _collection = $()
105
+
106
+ class @AnjLab.Uploads.UploadDropZone
107
+
108
+ constructor: (element, options)->
109
+ @$element = $(element)
110
+
111
+ defaultOptions =
112
+ onEnter: (e) -> null
113
+ onLeave: (e) -> null
114
+ # is not fired when leaving element by hovering descendants
115
+ onLeaveNotDescendants: (e) -> null,
116
+ onDrop: (e) -> null
117
+
118
+ @options = $.extend(true, {}, defaultOptions, options)
119
+
120
+ @disableDropOutside()
121
+ @attachEvents()
122
+
123
+ docDragEnter:(e)->
124
+ if (_collection.size() == 0)
125
+ $('body').toggleClass(@options.classes.bodyDragover, true)
126
+ _collection = _collection.add(e.target)
127
+
128
+ docDragLeave:(e)->
129
+ #timeout is needed because Firefox 3.6 fires the dragleave event on
130
+ # the previous element before firing dragenter on the next one
131
+ setTimeout( =>
132
+ # remove 'left' element from the collection
133
+ _collection = _collection.not(e.target)
134
+
135
+ # if collection is empty we have left the original element
136
+ # (dragleave has fired on all 'entered' elements)
137
+ if _collection.size() == 0
138
+ $('body').toggleClass(@options.classes.bodyDragover, false)
139
+ , 1)
140
+
141
+ disableDropOutside: (e) ->
142
+ # run only once for all instances
143
+ if !_dropOutsideDisabled
144
+
145
+ $(document).on 'dragover', (e)->
146
+ if e.originalEvent.dataTransfer
147
+ e.originalEvent.dataTransfer.dropEffect = 'none'
148
+ e.preventDefault()
149
+ false
150
+
151
+ $(document).on 'dragenter', (e) => @docDragEnter(e)
152
+
153
+ $(document).on 'dragleave drop', (e)=> @docDragLeave(e)
154
+
155
+ _dropOutsideDisabled = true
156
+
157
+ isValidFileDrag: (e)->
158
+ # e.dataTransfer currently causing IE errors
159
+ # IE9 does NOT support file API, so drag-and-drop is not possible
160
+ return false if utils.ie() && !utils.ie10()
161
+
162
+ dt = e.originalEvent.dataTransfer
163
+ # do not check dt.types.contains in webkit, because it crashes safari 4
164
+ isSafari = utils.safari()
165
+
166
+ # dt.effectAllowed is none in Safari 5
167
+ # dt.types.contains check is for firefox
168
+ effectTest = if utils.ie10() then true else dt.effectAllowed != 'none'
169
+ dt && effectTest && (dt.files || (!isSafari && dt.types.contains && dt.types.contains('Files')))
170
+
171
+ isOrSetDropDisabled: (isDisabled)->
172
+ @preventDrop = isDisabled if isDisabled != undefined
173
+ @preventDrop
174
+
175
+ attachEvents: ->
176
+ @$element.on 'dragover', (e) =>
177
+ return if !@isValidFileDrag(e)
178
+
179
+ effect = if utils.ie() ? null else e.originalEvent.dataTransfer.effectAllowed
180
+ if effect == 'move' || effect == 'linkMove'
181
+ e.originalEvent.dataTransfer.dropEffect = 'move' # for FF (only move allowed)
182
+ else
183
+ e.originalEvent.dataTransfer.dropEffect = 'copy' # for Chrome
184
+
185
+ e.stopPropagation()
186
+ e.preventDefault()
187
+ false
188
+
189
+ @$element.on 'dragenter', (e) =>
190
+ @docDragEnter(e)
191
+ if !@isOrSetDropDisabled()
192
+ return if !@isValidFileDrag(e)
193
+ @options.onEnter(e)
194
+
195
+ @$element.on 'dragleave', (e) =>
196
+ @docDragLeave(e)
197
+ return if !@isValidFileDrag(e)
198
+
199
+ @options.onLeave(e)
200
+
201
+ relatedTarget = document.elementFromPoint(e.clientX, e.clientY)
202
+ # do not fire when moving a mouse over a descendant
203
+ return if $.contains(this, relatedTarget)
204
+
205
+ @options.onLeaveNotDescendants(e)
206
+
207
+ @$element.on 'drop', (e) =>
208
+ @docDragLeave(e)
209
+ if !@isOrSetDropDisabled()
210
+ return if !@isValidFileDrag(e)
211
+ e.preventDefault()
212
+ @options.onDrop(e)
213
+ false
214
+
215
+ dropDisabled: (isDisabled) -> @isOrSetDropDisabled(isDisabled)
@@ -0,0 +1,101 @@
1
+ utils = @AnjLab.Uploads.Utils
2
+
3
+ class @AnjLab.Uploads.UploadHandler
4
+ constructor: (options)->
5
+ @options = options
6
+ @queue = []
7
+ @log = options.log
8
+
9
+ @create: (options) ->
10
+ opts = $.extend(true, {}, $.fn.uploadHandlerDefaults, options)
11
+ if utils.isXhrUploadSupported()
12
+ new AnjLab.Uploads.UploadHandlerXhr(opts)
13
+ else
14
+ new AnjLab.Uploads.UploadHandlerForm(opts)
15
+
16
+ # Removes element from queue, starts upload of next
17
+ dequeue: (id) ->
18
+ i = $.inArray(id, @queue)
19
+ max = @options.maxConnections
20
+
21
+ @queue.splice(i, 1)
22
+
23
+ if @queue.length >= max && i < max
24
+ nextId = @queue[max-1]
25
+ @uploadFile(nextId)
26
+
27
+ upload: (id) ->
28
+ # if too many active uploads, wait...
29
+ @uploadFile(id) if @queue.push(id) <= @options.maxConnections
30
+
31
+ retry: (id) ->
32
+ if $.inArray(id, @queue) >= 0
33
+ @uploadFile(id, true)
34
+ else
35
+ @upload(id)
36
+
37
+ cancel: (id) ->
38
+ @log("Cancelling #{id}")
39
+ @options.paramsStore.remove(id)
40
+ @cancelFile(id)
41
+ @dequeue(id)
42
+
43
+ cancelAll: ->
44
+ for fileId in @queue
45
+ @cancel(fileId)
46
+
47
+ @queue = []
48
+
49
+ getQueue: -> @queue
50
+
51
+ reset: ->
52
+ @log('Resetting upload handler')
53
+ @queue = []
54
+ # all handers should call super in their resets
55
+
56
+ uploadComplete: (id) -> @dequeue(id)
57
+
58
+ # protocol for handlers to implement
59
+
60
+ add: (file) -> @log('Not implemented')
61
+ uploadFile: (id, m) -> @log('Not implemented')
62
+ cancelFile: (id) -> @log('Not implemented')
63
+ getName: (id) -> @log('Not implemented')
64
+ getUuid: (id) -> @log('Not implemented')
65
+ isValid: (id) -> @log('Not implemented')
66
+ getSize: (id) -> null
67
+ getFile: (id) -> null
68
+ getResumableFilesData: -> []
69
+
70
+ $.fn.uploadHandlerDefaults =
71
+ debug: false
72
+ forceMultipart: true
73
+ paramsStore: {}
74
+ endpointStore: {}
75
+ maxConnections: 3 # maximum number of concurrent uploads
76
+ uuidParamName: 'qquuid'
77
+ totalFileSizeParamName: 'qqtotalfilesize'
78
+ chunking:
79
+ enabled: false
80
+ partSize: 2000000 # bytes
81
+ paramNames:
82
+ partIndex: 'qqpartindex'
83
+ partByteOffset: 'qqpartbyteoffset'
84
+ chunkSize: 'qqchunksize'
85
+ totalParts: 'qqtotalparts'
86
+ filename: 'qqfilename'
87
+ resume:
88
+ enabled: false
89
+ id: null
90
+ cookiesExpireIn: 7 #days
91
+ paramNames:
92
+ resuming: "qqresume"
93
+
94
+ log: (str, level) -> null
95
+ onProgress: (id, fileName, loaded, total) -> null
96
+ onComplete: (id, fileName, response, xhr) -> null
97
+ onCancel: (id, fileName) -> null
98
+ onUpload: (id, fileName) -> null
99
+ onUploadChunk: (id, fileName, chunkData) -> null
100
+ onAutoRetry: (id, fileName, response, xhr) -> null
101
+ onResume: (id, fileName, chunkData) -> null