redditor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +23 -0
  6. data/Guardfile +24 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +16 -0
  9. data/Rakefile +23 -0
  10. data/app/assets/images/redditor/.keep +0 -0
  11. data/app/assets/images/redditor/add_photo.png +0 -0
  12. data/app/assets/images/redditor/add_photo_big.png +0 -0
  13. data/app/assets/images/redditor/add_slider.png +0 -0
  14. data/app/assets/images/redditor/add_slider_big.png +0 -0
  15. data/app/assets/images/redditor/add_txt.png +0 -0
  16. data/app/assets/images/redditor/add_txt_big.png +0 -0
  17. data/app/assets/images/redditor/add_video.png +0 -0
  18. data/app/assets/images/redditor/add_video_big.png +0 -0
  19. data/app/assets/images/redditor/destroy_block_text.png +0 -0
  20. data/app/assets/images/redditor/move_handler.png +0 -0
  21. data/app/assets/images/redditor/no_format_text.png +0 -0
  22. data/app/assets/images/redditor/trash.png +0 -0
  23. data/app/assets/javascripts/fileapi/FileAPI.exif.js +59 -0
  24. data/app/assets/javascripts/fileapi/FileAPI.flash.image.swf +0 -0
  25. data/app/assets/javascripts/fileapi/FileAPI.flash.swf +0 -0
  26. data/app/assets/javascripts/fileapi/FileAPI.id3.js +67 -0
  27. data/app/assets/javascripts/fileapi/FileAPI.min.js +73 -0
  28. data/app/assets/javascripts/fileapi/fileapi.js.coffee.erb +12 -0
  29. data/app/assets/javascripts/fileapi/tmpl.js +35 -0
  30. data/app/assets/javascripts/fileapi/uploader.coffee +139 -0
  31. data/app/assets/javascripts/jquery-ui.min.js +12 -0
  32. data/app/assets/javascripts/redditor/application.js +14 -0
  33. data/app/assets/javascripts/redditor/fileapi/FileAPI.exif.js +59 -0
  34. data/app/assets/javascripts/redditor/fileapi/FileAPI.flash.image.swf +0 -0
  35. data/app/assets/javascripts/redditor/fileapi/FileAPI.flash.swf +0 -0
  36. data/app/assets/javascripts/redditor/fileapi/FileAPI.id3.js +67 -0
  37. data/app/assets/javascripts/redditor/fileapi/FileAPI.min.js +72 -0
  38. data/app/assets/javascripts/redditor/fileapi/README.md +724 -0
  39. data/app/assets/javascripts/redditor/fileapi/config.js.coffee.erb +5 -0
  40. data/app/assets/javascripts/redditor/fileapi/crossdomain.xml +19 -0
  41. data/app/assets/javascripts/redditor/fileapi/example.userpic.html +212 -0
  42. data/app/assets/javascripts/redditor/fileapi/index.html +548 -0
  43. data/app/assets/javascripts/redditor/fileapi/mailru.js +6 -0
  44. data/app/assets/javascripts/redditor/fileapi/mailru_front.js.coffee +143 -0
  45. data/app/assets/javascripts/redditor/fileapi/tmpl.js +35 -0
  46. data/app/assets/javascripts/redditor/fileapi/uploader.coffee +139 -0
  47. data/app/assets/javascripts/redditor/redditor.coffee +148 -0
  48. data/app/assets/stylesheets/redditor/application.css.scss +47 -0
  49. data/app/assets/stylesheets/redditor/fileapi/fileapi.css.scss +174 -0
  50. data/app/assets/stylesheets/redditor/fileapi/fileapi_front.css.scss +175 -0
  51. data/app/assets/stylesheets/redditor/redditor.css.scss +108 -0
  52. data/app/controllers/redditor/admin/base_controller.rb +18 -0
  53. data/app/controllers/redditor/admin/image_blocks_controller.rb +37 -0
  54. data/app/controllers/redditor/admin/images_controller.rb +33 -0
  55. data/app/controllers/redditor/admin/pages_controller.rb +15 -0
  56. data/app/controllers/redditor/admin/slider_blocks_controller.rb +32 -0
  57. data/app/controllers/redditor/admin/text_blocks_controller.rb +31 -0
  58. data/app/controllers/redditor/admin/video_blocks_controller.rb +31 -0
  59. data/app/controllers/redditor/application_controller.rb +4 -0
  60. data/app/helpers/redditor/application_helper.rb +4 -0
  61. data/app/helpers/redditor/fileapi_helper.rb +17 -0
  62. data/app/helpers/redditor/pages_helper.rb +24 -0
  63. data/app/models/redditor/content_block.rb +24 -0
  64. data/app/models/redditor/image.rb +29 -0
  65. data/app/models/redditor/page.rb +28 -0
  66. data/app/models/redditor/slider_block.rb +17 -0
  67. data/app/models/redditor/text_block.rb +20 -0
  68. data/app/models/redditor/video_block.rb +27 -0
  69. data/app/uploaders/redditor_uploader.rb +57 -0
  70. data/app/views/layouts/redditor/application.html.erb +15 -0
  71. data/app/views/redditor/admin/pages/_content_block.haml +16 -0
  72. data/app/views/redditor/admin/pages/_fileapi.erb +199 -0
  73. data/app/views/redditor/admin/pages/_image.haml +18 -0
  74. data/app/views/redditor/admin/pages/_page.haml +13 -0
  75. data/app/views/redditor/admin/pages/_slider_block.haml +16 -0
  76. data/app/views/redditor/admin/pages/_slider_block_image.haml +3 -0
  77. data/app/views/redditor/admin/pages/_text_block.haml +5 -0
  78. data/app/views/redditor/admin/pages/_validate.haml +4 -0
  79. data/app/views/redditor/admin/pages/_video_block.haml +19 -0
  80. data/app/views/redditor/admin/pages/_wrap_dd.haml +1 -0
  81. data/app/views/redditor/admin/pages/_wrapper.haml +3 -0
  82. data/app/views/redditor/admin/pages/new.js.coffee +7 -0
  83. data/app/views/redditor/admin/pages/new.js.erb +7 -0
  84. data/app/views/redditor/admin/pages/slider_block_image.js.coffee +2 -0
  85. data/app/views/redditor/admin/pages/wrapper.js.coffee +6 -0
  86. data/app/views/redditor/pages/_page.html.haml +1 -0
  87. data/app/views/redditor/slider_blocks/_slider_block.html.haml +2 -0
  88. data/app/views/redditor/slider_blocks/_slider_block_image.html.erb +3 -0
  89. data/app/views/redditor/text_blocks/_text_block.html.haml +1 -0
  90. data/app/views/redditor/video_blocks/_video_block.html.haml +2 -0
  91. data/bin/rails +8 -0
  92. data/config/locales/redditor.en.yml +20 -0
  93. data/config/locales/redditor.ru.yml +20 -0
  94. data/config/routes.rb +17 -0
  95. data/db/migrate/20130916155124_create_redditor_images.rb +15 -0
  96. data/db/migrate/20130916155156_create_redditor_pages.rb +12 -0
  97. data/db/migrate/20130916155219_create_redditor_slider_blocks.rb +11 -0
  98. data/db/migrate/20130916155239_create_redditor_text_blocks.rb +12 -0
  99. data/db/migrate/20130916155301_create_redditor_video_blocks.rb +14 -0
  100. data/lib/generators/redditor/views/views_generator.rb +17 -0
  101. data/lib/redditor/engine.rb +12 -0
  102. data/lib/redditor/has_redditor.rb +17 -0
  103. data/lib/redditor/version.rb +3 -0
  104. data/lib/redditor.rb +9 -0
  105. data/lib/tasks/redditor_tasks.rake +4 -0
  106. data/redditor.gemspec +38 -0
  107. data/spec/dummy/.rspec +1 -0
  108. data/spec/dummy/README.rdoc +28 -0
  109. data/spec/dummy/Rakefile +6 -0
  110. data/spec/dummy/app/assets/images/.keep +0 -0
  111. data/spec/dummy/app/assets/javascripts/application.js +17 -0
  112. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  113. data/spec/dummy/app/controllers/admin/articles_controller.rb +23 -0
  114. data/spec/dummy/app/controllers/admin/base_controller.rb +6 -0
  115. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  116. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  117. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  118. data/spec/dummy/app/mailers/.keep +0 -0
  119. data/spec/dummy/app/models/.keep +0 -0
  120. data/spec/dummy/app/models/article.rb +7 -0
  121. data/spec/dummy/app/models/concerns/.keep +0 -0
  122. data/spec/dummy/app/views/admin/articles/edit.html.haml +15 -0
  123. data/spec/dummy/app/views/articles/show.html.haml +2 -0
  124. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  125. data/spec/dummy/bin/bundle +3 -0
  126. data/spec/dummy/bin/rails +4 -0
  127. data/spec/dummy/bin/rake +4 -0
  128. data/spec/dummy/config/application.rb +31 -0
  129. data/spec/dummy/config/boot.rb +5 -0
  130. data/spec/dummy/config/database.yml +25 -0
  131. data/spec/dummy/config/environment.rb +5 -0
  132. data/spec/dummy/config/environments/development.rb +29 -0
  133. data/spec/dummy/config/environments/production.rb +80 -0
  134. data/spec/dummy/config/environments/test.rb +36 -0
  135. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  136. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  137. data/spec/dummy/config/initializers/inflections.rb +16 -0
  138. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  139. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  140. data/spec/dummy/config/initializers/session_store.rb +3 -0
  141. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  142. data/spec/dummy/config/locales/en.yml +23 -0
  143. data/spec/dummy/config/routes.rb +10 -0
  144. data/spec/dummy/config.ru +4 -0
  145. data/spec/dummy/db/migrate/20130908123351_create_articles.rb +9 -0
  146. data/spec/dummy/db/schema.rb +76 -0
  147. data/spec/dummy/lib/assets/.keep +0 -0
  148. data/spec/dummy/log/.keep +0 -0
  149. data/spec/dummy/public/404.html +58 -0
  150. data/spec/dummy/public/422.html +58 -0
  151. data/spec/dummy/public/500.html +57 -0
  152. data/spec/dummy/public/favicon.ico +0 -0
  153. data/spec/factories/articles_factory.rb +27 -0
  154. data/spec/factories/redditor/images_factory.rb +9 -0
  155. data/spec/factories/redditor/pages_factory.rb +37 -0
  156. data/spec/factories/redditor/sliders_factory.rb +9 -0
  157. data/spec/factories/redditor/texts_factory.rb +5 -0
  158. data/spec/factories/redditor/videos_factories.rb +7 -0
  159. data/spec/features/text_spec.rb +52 -0
  160. data/spec/features/video_spec.rb +52 -0
  161. data/spec/fixtures/test.jpg +0 -0
  162. data/spec/generators/views_generator_spec.rb +20 -0
  163. data/spec/models/article_spec.rb +40 -0
  164. data/spec/spec_helper.rb +67 -0
  165. data/spec/views/article/show_spec.rb +22 -0
  166. metadata +480 -0
@@ -0,0 +1,724 @@
1
+ # FileAPI — a set of tools for working with files.
2
+
3
+
4
+ <p align="center">
5
+ ~~~ <a href="http://mailru.github.com/FileAPI/">DEMO</a>
6
+ ~~~ <a href="http://mailru.github.com/FileAPI/example.userpic.html">user pic</a>
7
+ ~~~
8
+ </p>
9
+
10
+
11
+ ## Support
12
+ * Multiupload: all browsers that support HTML5 or [Flash](#flash-settings)
13
+ * Drag'n'Drop upload: files (HTML5) & directories (Chrome 21+)
14
+ * [Chunked](#chunked) file upload (HTML5)
15
+ * Upload one file: all browsers
16
+ * Working with [Images](#images): IE6+, FF 3.6+, Chrome 10+, Opera 11.1+, Safari 5.4+
17
+ + crop, resize, preview & rotate (HTML5 or Flash)
18
+ + auto orientation by exif (HTML5, if include FileAPI.exif.js or Flash)
19
+
20
+
21
+
22
+
23
+ ## Example
24
+ ```html
25
+ <span class="js-fileapi-wrapper" style="position: relative;">
26
+ <input id="user-files" type="file" multiple />
27
+ </span>
28
+
29
+ <div id="preview-list">
30
+ </div>
31
+ ```
32
+ ```js
33
+ var input = document.getElementById('user-files');
34
+ var previewNode = document.getElementById('preview-list');
35
+
36
+ // Drag'n'Drop
37
+ FileAPI.event.dnd(previewNode, function (over){
38
+ $(this).css('background', over ? 'red' : '');
39
+ }, function (files){
40
+ // ..
41
+ });
42
+
43
+
44
+
45
+ FileAPI.event.on(input, 'change', function (evt){
46
+ var files = FileAPI.getFiles(evt.target); // or FileAPI.getFiles(evt)
47
+
48
+ // filtering
49
+ FileAPI.filterFiles(files, function (file, info){
50
+ if( /image/.test(file.type) && info ){
51
+ return info.width >= 320 && info.height >= 240;
52
+ }
53
+ else {
54
+ return file.size > 128;
55
+ }
56
+ }, function (fileList, ignor){
57
+ if( ignor.length ){
58
+ // ...
59
+ }
60
+
61
+ if( !fileList.length ){
62
+ // empty file list
63
+ return;
64
+ }
65
+
66
+
67
+ // do preview
68
+ var imageList = FileAPI.filter(fileList, function (file){ return /image/.test(file.type); });
69
+ FileAPI.each(imageList, function (imageFile){
70
+ FileAPI.Image(imageFile)
71
+ .preview(100, 120)
72
+ .get(function (err, image){
73
+ if( err ){
74
+ // ...
75
+ }
76
+ else {
77
+ previewNode.appendChild(image);
78
+ }
79
+ })
80
+ ;
81
+ });
82
+
83
+
84
+ // upload on server
85
+ var xhr = FileAPI.upload({
86
+ url: '...',
87
+ data: { foo: 'bar' }, // POST-data (iframe, flash, html5)
88
+ headers: { 'x-header': '...' }, // request headers (html5)
89
+ files: {
90
+ files: FileAPI.filter(fileList, function (file){ return !/image/.test(file.type); }),
91
+ pictures: imageList
92
+ },
93
+ imageTransform: {
94
+ maxWidth: 1024,
95
+ maxHeight: 768
96
+ },
97
+ imageAutoOrientation: true,
98
+ fileprogress: function (evt){ // (flash, html5)
99
+ var percent = evt.loaded/evt.total*100;
100
+ // ...
101
+ },
102
+ progress: function (evt){ // (flash, html5)
103
+ var percent = evt.loaded/evt.total*100;
104
+ // ...
105
+ },
106
+ complete: function (err, xhr){
107
+ // ...
108
+ }
109
+ });
110
+ });
111
+ });
112
+ ```
113
+
114
+ ### HTML structure (templates)
115
+ * [Default](#html-default)
116
+ * [Button](#html-button)
117
+ * [Link](#html-link)
118
+
119
+
120
+ ### API
121
+ * FileAPI.[getFiles](#getFiles)(`source:HTMLInput|Event`)`:Array`
122
+ * FileAPI.[getDropFiles](#getDropFiles)(`files:Array`, `callback:Function`)
123
+ * FileAPI.[filterFiles](#filterFiles)(`files:Array`, `iterator:Function`, `complete:Function`)
124
+ * FileAPI.[upload](#upload)(`options:Object`)`:XMLHttpRequest`
125
+ * FileAPI.[getInfo](#getInfo)(`file:File`, `callback:Function`)
126
+ * FileAPI.[readAsImage](#readAs)(`file:File`, `callback:function`)
127
+ * FileAPI.[readAsDataURL](#readAs)(`file:File`, `callback:function`)
128
+ * FileAPI.[readAsBinaryString](#readAs)(`file:File`, `callback:function`)
129
+ * FileAPI.[readAsArrayBuffer](#readAs)(`file:File`, `callback:function`)
130
+ * FileAPI.[readAsText](#readAs)(`file:File`, `callback:function`)
131
+ * FileAPI.[readAsText](#readAs)(`file:File`, `encoding:String`, `callback:function`)
132
+
133
+
134
+ ### Events
135
+ * FileAPI.event.on(`el:HTMLElement`, `eventType:String`, `fn:Function`)
136
+ * FileAPI.event.off(`el:HTMLElement`, `eventType:String`, `fn:Function`)
137
+ * FileAPI.event.one(`el:HTMLElement`, `eventType:String`, `fn:Function`)
138
+ * FileAPI.event.dnd(`el:HTMLElement`, `onHover:Function`, `onDrop:Function`)
139
+ * jQuery('#el').dnd(onHover, onDrop)
140
+
141
+
142
+ <a name="images"></a>
143
+ ### FileAPI.Image
144
+ * .crop(width[, height])
145
+ * .crop(x, y, width[, height])
146
+ * .resize(width[, height])
147
+ * .resize(width, height, `type:Enum(min,max,preview)`)
148
+ * .preview(width[, height])
149
+ * .rotate(deg)
150
+ * .get(`fn:Function`)
151
+
152
+
153
+
154
+ ### Utils
155
+ * FileAPI.KB
156
+ * FileAPI.MB
157
+ * FileAPI.GB
158
+ * FileAPI.TB
159
+ * FileAPI.support.`html5:Boolean`
160
+ * FileAPI.support.`cors:Boolean`
161
+ * FileAPI.support.`dnd:Boolean`
162
+ * FileAPI.support.`flash:Boolean`
163
+ * FileAPI.support.`canvas:Boolean`
164
+ * FileAPI.support.`dataURI:Boolean`
165
+ * FileAPI.support.`chunked:Boolean`
166
+ * FileAPI.each(`obj:Object|Array`, `fn:function`, `context:Mixed`)
167
+ * FileAPI.extend(`dst:Object`, `src:Object`)`:Object`
168
+ * FileAPI.filter(`list:Array`, `iterator:Function`)`:Array`
169
+ * FileAPI.isFile(`file:Mixed`)`:Boolean`
170
+ * FileAPI.toBinaryString(`str:Base64`)`:String`
171
+
172
+
173
+
174
+ ---------------------------------------
175
+
176
+
177
+ <a name="getFiles"></a>
178
+ ### FileAPI.getFiles
179
+ ```js
180
+ FileAPI.event.on('#my-file-1', 'change', onSelect);
181
+
182
+ // or jQuery
183
+ $('#my-file-2').on('change', onSelect);
184
+
185
+ function onSelect(evt/**Event*/){
186
+ // (1) extract fileList from event
187
+ var files = FileAPI.getFiles(evt);
188
+
189
+ // (2) or so
190
+ var files = FileAPI.getFiles(evt.target);
191
+ }
192
+ ```
193
+
194
+
195
+ <a name="getDropFiles"></a>
196
+ ### FileAPI.getDropFiles
197
+ ```js
198
+ function onDrop(evt){
199
+ FileAPI.getDropFiles(evt, function (files){
200
+ if( files.length ){
201
+ // ...
202
+ }
203
+ });
204
+ }
205
+
206
+ // OR
207
+
208
+ var el = document.getElementById('el');
209
+ FileAPI.event.dnd(el, function (over/**Boolean*/, evt/**Event*/){
210
+ el.style.background = over ? 'red' : '';
211
+ }, function (files/**Array*/, evt/**Event*/){
212
+ // ...
213
+ });
214
+ ```
215
+
216
+
217
+ <a name="getInfo"></a>
218
+ ### FileAPI.getInfo
219
+ ```js
220
+ FileAPI.getInfo(imageFile/**File*/, function (err/**Boolean*/, info/**Object*/){
221
+ if( !err ){
222
+ switch( info.exif.Orientation ){
223
+ // ...
224
+ }
225
+ }
226
+ });
227
+
228
+ // ...
229
+
230
+ FileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){
231
+ // http://www.nihilogic.dk/labs/exif/exif.js
232
+ // http://www.nihilogic.dk/labs/binaryajax/binaryajax.js
233
+ FileAPI.readAsBinaryString(file, function (evt){
234
+ if( evt.type == 'load' ){
235
+ var binaryString = evt.result;
236
+ var oFile = new BinaryFile(binaryString, 0, file.size);
237
+ var exif = EXIF.readFromBinaryFile(oFile);
238
+ callback(false, { 'exif': exif || {} });
239
+ }
240
+ else if( evt.type == 'error' ){
241
+ callback('read_as_binary_string');
242
+ }
243
+ else if( evt.type == 'progress' ){
244
+ // ...
245
+ }
246
+ });
247
+ });
248
+ ```
249
+
250
+
251
+ <a name="filterFiles"></a>
252
+ ### FileAPI.filterFiles
253
+ ```js
254
+ FileAPI.filterFiles(files, function (file, info){
255
+ if( /image/.test(file.type) && info ){
256
+ return info.width > 320 && info.height > 240;
257
+ }
258
+ return file.size < 10 * FileAPI.MB;
259
+ }, function (result, ignor){
260
+ // ...
261
+ });
262
+ ```
263
+
264
+
265
+ <a name="readAs"></a>
266
+ ### FileAPI.readAsImage, FileAPI.readAsDataURL (FileAPI.readAsBinaryString)
267
+ ```js
268
+ FileAPI.readAsImage(file, function (evt){
269
+ if( evt.type == 'load' ){
270
+ var images = document.getElementById('images');
271
+ images.appendChild(evt.result);
272
+ }
273
+ else {
274
+ // ...
275
+ }
276
+ });
277
+
278
+
279
+ FileAPI.readAsDataURL(file, function (evt){
280
+ if( evt.type == 'load' ){
281
+ // success
282
+ var result = evt.result;
283
+ }
284
+ else if( evt.type == 'progress' ){
285
+ var pr = evt.loaded/evt.total * 100;
286
+ }
287
+ else {
288
+ // error
289
+ }
290
+ });
291
+ ```
292
+
293
+
294
+ <a name="upload"></a>
295
+ ### FileAPI.upload
296
+ ```js
297
+ var xhr = FileAPI.upload({
298
+ url: '...',
299
+ data: { foo: 'bar' },
300
+ headers: { 'x-header': '...' },
301
+ files: {
302
+ images: FileAPI.filter(files, function (file){ return /image/.test(file.type); }),
303
+ customFile: { file: 'generate.txt', blob: customFileBlob }
304
+ },
305
+
306
+ chunkSize: 0, // or chunk size in bytes, eg: FileAPI.MB*.5 (html5)
307
+ chunkUploadRetry: 0, // number of retries during upload chunks (html5)
308
+
309
+ imageTransform: {
310
+ maxWidth: 1024,
311
+ maxHeight: 768
312
+ },
313
+ imageAutoOrientation: true,
314
+ prepare: function (file, options){
315
+ // prepare options for current file
316
+ options.data.filename = file.name;
317
+ },
318
+ upload: function (xhr, options){
319
+ // start uploading
320
+ },
321
+ fileupload: function (xhr, options){
322
+ // start file uploading
323
+ },
324
+ fileprogress: function (evt){
325
+ // progress file uploading
326
+ var filePercent = evt.loaded/evt.total*100;
327
+ },
328
+ filecomplete: function (err, xhr){
329
+ if( !err ){
330
+ var response = xhr.responseText;
331
+ }
332
+ },
333
+ progress: function (evt){
334
+ // total progress uploading
335
+ var totalPercent = evt.loaded/evt.total*100;
336
+ },
337
+ complete: function (err, xhr){
338
+ if( !err ){
339
+ // Congratulations, the uploading was successful!
340
+ }
341
+ }
342
+ });
343
+ ```
344
+
345
+
346
+ <a href="imageTransform"></a>
347
+ ### imageTransform
348
+ * width`:Number`
349
+ * height`:Number`
350
+ * preview`:Boolean`
351
+ * maxWidth`:Number`
352
+ * maxHeight`:Number`
353
+ * rotate`:Number`
354
+ ```js
355
+ FileAPI.upload({
356
+ // ..
357
+ imageOriginal: false, // don't send original on server
358
+
359
+ imageTransform: {
360
+ // (1) Resize to 120x200
361
+ resize: { width: 120, height: 200 }
362
+
363
+ // (2) create preview 320x240
364
+ thumb: { width: 320, height: 240, preview: true }
365
+
366
+ // (3) Resize by max side
367
+ max: { maxWidth: 800, maxHeight: 600 }
368
+
369
+ // (4) Custom resize
370
+ custom: function (info, transform){
371
+ return transform
372
+ .crop(100, 100, 300, 200)
373
+ .resize(100, 50)
374
+ ;
375
+ }
376
+ }
377
+ });
378
+ ```
379
+
380
+
381
+ <a name="imageAutoOrientation"></a>
382
+ ### imageAutoOrientation
383
+ ```js
384
+ // (1) all images
385
+ FileAPI.upload({
386
+ // ..
387
+ imageAutoOrientation: true
388
+ });
389
+
390
+ // (2) or so
391
+ FileAPI.upload({
392
+ // ..
393
+ imageAutoOrientation: true,
394
+ imageTransform: { width: .., height: .. }
395
+ });
396
+
397
+ // (3) or so
398
+ FileAPI.upload({
399
+ // ..
400
+ imageTransform: { rotate: 'auto' }
401
+ });
402
+
403
+ // (4) only "800x600", original not modified
404
+ FileAPI.upload({
405
+ // ..
406
+ imageTransform: {
407
+ "800x600": { width: 800, height: 600, rotate: 'auto' }
408
+ }
409
+ });
410
+ ```
411
+
412
+
413
+ -----
414
+
415
+
416
+ <a name="flash-settings"></a>
417
+ ### Flash settings
418
+ ```html
419
+ <script>
420
+ var FileAPI = {
421
+ // @required
422
+ staticPath: '/js/' // @default: "./"
423
+
424
+ // @optional
425
+ , flashUrl: '/js/FileAPI.flash.swf' // @default: FileAPI.staticPath + "FileAPI.flash.swf"
426
+ , flashImageUrl: '/js/FileAPI.flash.image.swf' // @default: FileAPI.staticPath + "FileAPI.flash.image.swf"
427
+ };
428
+ </script>
429
+ <script src="/js/FileAPI.min.js"></script>
430
+ ```
431
+
432
+ #### Flash-request ([FileReference](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/FileReference.html))
433
+ The following sample HTTP POST request is sent from Flash Player to a server-side script if no parameters are specified:
434
+ ```
435
+ POST /handler.cfm HTTP/1.1
436
+ Accept: text/*
437
+ Content-Type: multipart/form-data;
438
+ boundary=----------Ij5ae0ae0KM7GI3KM7
439
+ User-Agent: Shockwave Flash
440
+ Host: www.example.com
441
+ Content-Length: 421
442
+ Connection: Keep-Alive
443
+ Cache-Control: no-cache
444
+
445
+ ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
446
+ Content-Disposition: form-data; name="Filename"
447
+
448
+ MyFile.jpg
449
+ ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
450
+ Content-Disposition: form-data; name="Filedata"; filename="MyFile.jpg"
451
+ Content-Type: application/octet-stream
452
+
453
+ FileDataHere
454
+ ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
455
+ Content-Disposition: form-data; name="Upload"
456
+
457
+ Submit Query
458
+ ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--
459
+ ```
460
+
461
+
462
+
463
+ -----
464
+
465
+
466
+
467
+ <a name="chunked"></a>
468
+ ### Chunked file upload (html5)
469
+ ```js
470
+ FileAPI.upload({
471
+ url: '...'
472
+ , files: fileList
473
+ , chunkSize: .5 * FileAPI.MB // 512KB
474
+ , chunkUploadRetry: 1
475
+ , complete: function (err, xhr){}
476
+ });
477
+ ```
478
+
479
+ Client and server communicate to each other using the following HTTP headers and status codes.
480
+
481
+ Client explicitly sets the following headers:
482
+ * [Content-Range](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16): bytes \<start-offset\>-\<end-offset\>/\<total\>
483
+ * [Content-Disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1): attachment; filename=\<file-name\>
484
+
485
+ Any other headers are set by a target browser and are not used by client.
486
+ Library does not provide any facilities to track a file uniqueness across requests, it's left on developer's consideration.
487
+
488
+ Client recognizes the following response codes:
489
+ * 200, 201 - chunk is successfully saved
490
+ * 416, 500 - recoverable error, library tries to resend chunk 'chunkUploadRetry' times then fails
491
+
492
+ All the other codes - fatal error, user's involvement is recommend.
493
+
494
+
495
+ -----
496
+
497
+
498
+
499
+ ### File object (https://developer.mozilla.org/en/DOM/File)
500
+ ```js
501
+ {
502
+ name: 'fileName',
503
+ type: 'mime-type',
504
+ size: 'fileSize'
505
+ }
506
+ ```
507
+
508
+
509
+ ### XMLHttpRequest
510
+ ```js
511
+ {
512
+ status: Number,
513
+ statusText: Number,
514
+ readyState: Number,
515
+ response: Blob,
516
+ responseXML: XML,
517
+ responseText: String,
518
+ responseBody: String,
519
+ getResponseHeader: function (name/**String*/)/**String*/{},
520
+ getAllResponseHeaders: function ()/**Object*/{},
521
+ abort: function (){}
522
+ }
523
+ ```
524
+
525
+
526
+ ### Cross-Domain upload-controller headers
527
+ ```php
528
+ <?
529
+ header('Access-Control-Allow-Methods: POST, OPTIONS');
530
+ header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type'); // and other custom headers
531
+ header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); // a comma-separated list of domains
532
+
533
+ if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){
534
+ exit;
535
+ }
536
+
537
+ if( $_SERVER['REQUEST_METHOD'] == 'POST' ){
538
+ // ...
539
+ }
540
+ ?>
541
+ ```
542
+
543
+
544
+ ### iframe
545
+ #### POST-query
546
+ ```
547
+ /controller.php
548
+ ?foo=bar
549
+ &images=...
550
+ &callback=...
551
+ ```
552
+
553
+
554
+ #### POST-response
555
+ ```php
556
+ <script type="text/javascript">
557
+ (function (ctx, jsonp){
558
+ if( ctx && ctx[jsonp] ){
559
+ ctx[jsonp](<?=$statusCode/*200 — OK*/?>, "<?=addslashes($statusText)?>", "<?=addslashes($response)?>");
560
+ }
561
+ })(this.parent, "<?=htmlspecialchars($_POST['callback'])?>");
562
+ </script>
563
+ ```
564
+
565
+
566
+
567
+ ---
568
+
569
+
570
+
571
+ ### HTML structure (templates)
572
+
573
+ <a name="html-default"></a>
574
+ ### Default
575
+ ```html
576
+ <span class="js-fileapi-wrapper" style="position: relative; display: inline-block;">
577
+ <input name="files" type="file" multiple />
578
+ </span>
579
+ ```
580
+
581
+
582
+ <a name="html-button"></a>
583
+ ### Button
584
+ ```html
585
+ <style>
586
+ .upload-btn {
587
+ width: 130px;
588
+ height: 25px;
589
+ overflow: hidden;
590
+ position: relative;
591
+ border: 3px solid #06c;
592
+ border-radius: 5px;
593
+ background: #0cf;
594
+
595
+ }
596
+ .upload-btn:hover {
597
+ background: #09f;
598
+ }
599
+ .upload-btn__txt {
600
+ z-index: 1;
601
+ position: relative;
602
+ color: #fff;
603
+ font-size: 18px;
604
+ font-family: "Helvetica Neue";
605
+ line-height: 24px;
606
+ text-align: center;
607
+ text-shadow: 0 1px 1px #000;
608
+ }
609
+ .upload-btn__inp {
610
+ top: -10px;
611
+ right: -40px;
612
+ z-index: 2;
613
+ position: absolute;
614
+ cursor: pointer;
615
+ opacity: 0;
616
+ filter: alpha(opacity=0);
617
+ font-size: 50px;
618
+ }
619
+ </style>
620
+ <div class="upload-btn js-fileapi-wrapper">
621
+ <div class="upload-btn__txt">Upload files</div>
622
+ <input class="upload-btn__inp" name="files" type="file" multiple />
623
+ </div>
624
+ ```
625
+
626
+
627
+ <a name="html-link"></a>
628
+ ### Link
629
+ ```html
630
+ <style>
631
+ .upload-link {
632
+ color: #36c;
633
+ display: inline-block;
634
+ *zoom: 1;
635
+ *display: inline;
636
+ overflow: hidden;
637
+ position: relative;
638
+ padding-bottom: 2px;
639
+ text-decoration: none;
640
+ }
641
+ .upload-link__txt {
642
+ z-index: 1;
643
+ position: relative;
644
+ border-bottom: 1px dotted #36c;
645
+ }
646
+ .upload-link:hover .upload-link__txt {
647
+ color: #f00;
648
+ border-bottom-color: #f00;
649
+ }
650
+
651
+ .upload-link__inp {
652
+ top: -10px;
653
+ right: -40px;
654
+ z-index: 2;
655
+ position: absolute;
656
+ cursor: pointer;
657
+ opacity: 0;
658
+ filter: alpha(opacity=0);
659
+ font-size: 50px;
660
+ }
661
+ </style>
662
+ <a class="upload-link js-fileapi-wrapper">
663
+ <span class="upload-link__txt">Upload photo</span>
664
+ <input class="upload-link__inp" name="photo" type="file" accept=".jpg,.jpeg,.gif" />
665
+ </a>
666
+ ```
667
+
668
+
669
+ ---
670
+
671
+
672
+ ## Changelog
673
+ ### 1.2.5
674
+ * [#86](https://github.com/mailru/FileAPI/issues/86): Smarter upload recovery
675
+ * [#87](https://github.com/mailru/FileAPI/issues/87): Fixed upload files into browsers that do not support FormData
676
+ * Fixed support "accept" attribute for Flash.
677
+ * Fixed detection of HTML5 support for FireFox 3.6
678
+ * + FileAPI.html5 option, default "true"
679
+
680
+
681
+ ### 1.2.4
682
+ * Fixed auto orientation image by EXIF (Flash)
683
+ * Fixed image dimensions after rotate (Flash)
684
+ * [#82](https://github.com/mailru/FileAPI/issues/82): "undefined" data-fields cause exceptions
685
+ * [#83](https://github.com/mailru/FileAPI/issues/83): Allow requests without files
686
+ * [#84](https://github.com/mailru/FileAPI/pull/84): Fixed connection abort when waiting for connection recovery
687
+
688
+
689
+ ### 1.2.3
690
+ * [#77](https://github.com/mailru/FileAPI/pull/77): Fixed flash.abort(), [#75](https://github.com/mailru/FileAPI/issues/75)
691
+ * - `FileAPI.addMime`
692
+ * + `FileAPI.accept` — fallback for flash.
693
+
694
+
695
+ ### 1.2.2
696
+ * [#67](https://github.com/mailru/FileAPI/pull/67): Added correct httpStatus for upload fail, [#62](https://github.com/mailru/FileAPI/pull/68)
697
+ * [#68](https://github.com/mailru/FileAPI/pull/68) Added "Content-Type" for chunked upload, [#65](https://github.com/mailru/FileAPI/pull/65)
698
+ * [#69](https://github.com/mailru/FileAPI/issues/69): Fixed network down recovery
699
+ * Fixed progress event, [#66](https://github.com/mailru/FileAPI/issues/66)
700
+ * Increase flash stage size, [#73](https://github.com/mailru/FileAPI/pull/73)
701
+ * - array index from POST-param "name", [#72](https://github.com/mailru/FileAPI/issues/72)
702
+ * - dependency on FileAPI.Image for FileAPI.Flash
703
+
704
+
705
+ ### 1.2.1
706
+ * [#64](https://github.com/mailru/FileAPI/issues/64): Bufixed for [#63](https://github.com/mailru/FileAPI/issues/63)
707
+
708
+
709
+
710
+ ### 1.2.0
711
+ * [#57](https://github.com/mailru/FileAPI/issues/57): Chunked file upload
712
+
713
+
714
+ ### 1.1.0
715
+ * [#54](https://github.com/mailru/FileAPI/issues/54): added `FileAPI.flashUrl` and `FileAPI.flashImageUrl`
716
+
717
+
718
+ ### 1.0.1
719
+ * [#51](https://github.com/mailru/FileAPI/issues/51): remove circular references from `file-objects` (Flash transport)
720
+ * added `changelog`
721
+
722
+
723
+ ### 1.0.0
724
+ * first release