comfortable_media_surfer 3.0.0 → 3.1.2

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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.github/dependabot.yml +7 -0
  4. data/.github/workflows/coveralls.yml +13 -1
  5. data/.github/workflows/rubyonrails.yml +15 -3
  6. data/.gitignore +4 -0
  7. data/.rubocop.yml +4 -1
  8. data/CHANGELOG.md +86 -0
  9. data/CONTRIBUTING.md +5 -2
  10. data/Gemfile +10 -6
  11. data/README.md +64 -27
  12. data/app/assets/builds/.keep +0 -0
  13. data/app/assets/config/manifest.js +1 -0
  14. data/app/assets/javascripts/comfy/admin/cms/application.js +21 -36
  15. data/app/assets/javascripts/comfy/admin/cms/base.js +6 -5
  16. data/app/assets/javascripts/comfy/admin/cms/codemirror.js +22 -10
  17. data/app/assets/javascripts/comfy/admin/cms/diff.js +7 -5
  18. data/app/assets/javascripts/comfy/admin/cms/file_link.js +17 -11
  19. data/app/assets/javascripts/comfy/admin/cms/file_upload.js +67 -41
  20. data/app/assets/javascripts/comfy/admin/cms/files_modal.js +20 -13
  21. data/app/assets/javascripts/comfy/admin/cms/sortable_list.js +28 -19
  22. data/app/assets/javascripts/comfy/admin/cms/timepicker.js +20 -12
  23. data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +39 -20
  24. data/app/assets/javascripts/comfy/vendor/diff/pretty_text_diff.js +30 -18
  25. data/app/assets/javascripts/comfy/vendor/redactor/definedlinks.js +31 -34
  26. data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +77 -62
  27. data/app/assets/javascripts/comfy/vendor/redactor/i18n/hr.js +78 -76
  28. data/app/assets/javascripts/comfy/vendor/redactor/i18n/nb.js +76 -74
  29. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pl.js +77 -75
  30. data/app/assets/javascripts/comfy/vendor/redactor/imagemanager.js +66 -55
  31. data/app/assets/javascripts/comfy/vendor/redactor/table.js +346 -335
  32. data/app/assets/javascripts/comfy/vendor/redactor/video.js +69 -64
  33. data/app/assets/javascripts/comfy/vendor/redactor.js +2 -0
  34. data/app/assets/stylesheets/comfy/admin/cms/application.sass +2 -2
  35. data/app/assets/stylesheets/comfy/admin/cms/codemirror_overrides.sass +1 -1
  36. data/app/helpers/comfy/admin/cms_helper.rb +2 -2
  37. data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +14 -8
  38. data/comfortable_media_surfer.gemspec +8 -9
  39. data/config/application.rb +4 -1
  40. data/config/environments/development.rb +11 -10
  41. data/config/environments/production.rb +0 -6
  42. data/config/puma.rb +43 -0
  43. data/db/migrate/01_create_cms.rb +0 -1
  44. data/db/migrate/02_add_markdown_to_snippets.rb +5 -0
  45. data/gemfiles/7.1.gemfile +3 -2
  46. data/gemfiles/7.2.gemfile +3 -2
  47. data/gemfiles/{6.1.gemfile → 8.0.gemfile} +3 -2
  48. data/lib/comfortable_media_surfer/content/tags/audio.rb +1 -1
  49. data/lib/comfortable_media_surfer/content/tags/breadcrumbs.rb +1 -1
  50. data/lib/comfortable_media_surfer/content/tags/children.rb +1 -1
  51. data/lib/comfortable_media_surfer/content/tags/siblings.rb +1 -1
  52. data/lib/comfortable_media_surfer/engine.rb +3 -8
  53. data/lib/comfortable_media_surfer/extensions/has_revisions.rb +1 -1
  54. data/lib/comfortable_media_surfer/render_methods.rb +7 -7
  55. data/lib/comfortable_media_surfer/version.rb +1 -1
  56. data/lib/generators/comfy/cms/README +2 -9
  57. data/lib/generators/comfy/cms/cms_generator.rb +9 -7
  58. data/lib/generators/comfy/scaffold/scaffold_generator.rb +1 -1
  59. data/lib/tasks/cms_assets.rake +19 -0
  60. data/package-lock.json +379 -0
  61. data/package.json +23 -0
  62. data/rakelib/create_release.rake +17 -17
  63. metadata +24 -146
  64. data/app/assets/javascripts/comfy/vendor/Moxie.swf +0 -0
  65. data/app/assets/javascripts/comfy/vendor/Moxie.xap +0 -0
  66. data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js +0 -7
  67. data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js.map +0 -1
  68. data/app/assets/javascripts/comfy/vendor/codemirror/addon/edit/closetag.js +0 -169
  69. data/app/assets/javascripts/comfy/vendor/codemirror/mode/css/css.js +0 -832
  70. data/app/assets/javascripts/comfy/vendor/codemirror/mode/htmlmixed/htmlmixed.js +0 -152
  71. data/app/assets/javascripts/comfy/vendor/codemirror/mode/javascript/javascript.js +0 -875
  72. data/app/assets/javascripts/comfy/vendor/codemirror/mode/markdown/markdown.js +0 -861
  73. data/app/assets/javascripts/comfy/vendor/codemirror/mode/xml/xml.js +0 -394
  74. data/app/assets/javascripts/comfy/vendor/codemirror.js +0 -9653
  75. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ar.js +0 -52
  76. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bg.js +0 -65
  77. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bn.js +0 -65
  78. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ca.js +0 -83
  79. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cs.js +0 -70
  80. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cy.js +0 -92
  81. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/da.js +0 -71
  82. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/de.js +0 -70
  83. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/default.js +0 -80
  84. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/eo.js +0 -73
  85. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/es.js +0 -69
  86. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/et.js +0 -73
  87. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fa.js +0 -68
  88. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fi.js +0 -69
  89. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fr.js +0 -75
  90. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/gr.js +0 -74
  91. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/he.js +0 -57
  92. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hi.js +0 -65
  93. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hr.js +0 -66
  94. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hu.js +0 -72
  95. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/id.js +0 -61
  96. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/it.js +0 -70
  97. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ja.js +0 -57
  98. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ko.js +0 -60
  99. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lt.js +0 -72
  100. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lv.js +0 -67
  101. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mk.js +0 -69
  102. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mn.js +0 -67
  103. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ms.js +0 -68
  104. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/my.js +0 -69
  105. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/nl.js +0 -75
  106. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/no.js +0 -73
  107. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pa.js +0 -65
  108. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pl.js +0 -68
  109. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt-BR.js +0 -66
  110. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt.js +0 -66
  111. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ro.js +0 -69
  112. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ru.js +0 -66
  113. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/si.js +0 -65
  114. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sk.js +0 -70
  115. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sl.js +0 -70
  116. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sq.js +0 -65
  117. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sr.js +0 -69
  118. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sv.js +0 -70
  119. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/th.js +0 -72
  120. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/tr.js +0 -66
  121. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/uk.js +0 -66
  122. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/vn.js +0 -66
  123. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-CN.js +0 -61
  124. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-TW.js +0 -61
  125. data/app/assets/javascripts/comfy/vendor/moxie.min.js +0 -16
  126. data/app/assets/javascripts/comfy/vendor/plupload.dev.js +0 -2497
  127. data/app/assets/javascripts/comfy/vendor/sortable.min.js +0 -5
  128. data/app/assets/stylesheets/comfy/vendor/codemirror.css +0 -346
  129. data/app/assets/stylesheets/comfy/vendor/flatpickr.min.css +0 -13
  130. data/config/initializers/assets.rb +0 -14
  131. data/gemfiles/7.0.gemfile +0 -31
@@ -1,2497 +0,0 @@
1
- /**
2
- * Plupload - multi-runtime File Uploader
3
- * v2.3.6
4
- *
5
- * Copyright 2013, Moxiecode Systems AB
6
- * Released under GPL License.
7
- *
8
- * License: http://www.plupload.com/license
9
- * Contributing: http://www.plupload.com/contributing
10
- *
11
- * Date: 2017-11-03
12
- */
13
- ;(function (global, factory) {
14
- var extract = function() {
15
- var ctx = {};
16
- factory.apply(ctx, arguments);
17
- return ctx.plupload;
18
- };
19
-
20
- if (typeof define === "function" && define.amd) {
21
- define("plupload", ['./moxie'], extract);
22
- } else if (typeof module === "object" && module.exports) {
23
- module.exports = extract(require('./moxie'));
24
- } else {
25
- global.plupload = extract(global.moxie);
26
- }
27
- }(this || window, function(moxie) {
28
- /**
29
- * Plupload.js
30
- *
31
- * Copyright 2013, Moxiecode Systems AB
32
- * Released under GPL License.
33
- *
34
- * License: http://www.plupload.com/license
35
- * Contributing: http://www.plupload.com/contributing
36
- */
37
-
38
- ;(function(exports, o, undef) {
39
-
40
- var delay = window.setTimeout;
41
- var fileFilters = {};
42
- var u = o.core.utils;
43
- var Runtime = o.runtime.Runtime;
44
-
45
- // convert plupload features to caps acceptable by mOxie
46
- function normalizeCaps(settings) {
47
- var features = settings.required_features, caps = {};
48
-
49
- function resolve(feature, value, strict) {
50
- // Feature notation is deprecated, use caps (this thing here is required for backward compatibility)
51
- var map = {
52
- chunks: 'slice_blob',
53
- jpgresize: 'send_binary_string',
54
- pngresize: 'send_binary_string',
55
- progress: 'report_upload_progress',
56
- multi_selection: 'select_multiple',
57
- dragdrop: 'drag_and_drop',
58
- drop_element: 'drag_and_drop',
59
- headers: 'send_custom_headers',
60
- urlstream_upload: 'send_binary_string',
61
- canSendBinary: 'send_binary',
62
- triggerDialog: 'summon_file_dialog'
63
- };
64
-
65
- if (map[feature]) {
66
- caps[map[feature]] = value;
67
- } else if (!strict) {
68
- caps[feature] = value;
69
- }
70
- }
71
-
72
- if (typeof(features) === 'string') {
73
- plupload.each(features.split(/\s*,\s*/), function(feature) {
74
- resolve(feature, true);
75
- });
76
- } else if (typeof(features) === 'object') {
77
- plupload.each(features, function(value, feature) {
78
- resolve(feature, value);
79
- });
80
- } else if (features === true) {
81
- // check settings for required features
82
- if (settings.chunk_size && settings.chunk_size > 0) {
83
- caps.slice_blob = true;
84
- }
85
-
86
- if (!plupload.isEmptyObj(settings.resize) || settings.multipart === false) {
87
- caps.send_binary_string = true;
88
- }
89
-
90
- if (settings.http_method) {
91
- caps.use_http_method = settings.http_method;
92
- }
93
-
94
- plupload.each(settings, function(value, feature) {
95
- resolve(feature, !!value, true); // strict check
96
- });
97
- }
98
-
99
- return caps;
100
- }
101
-
102
- /**
103
- * @module plupload
104
- * @static
105
- */
106
- var plupload = {
107
- /**
108
- * Plupload version will be replaced on build.
109
- *
110
- * @property VERSION
111
- * @for Plupload
112
- * @static
113
- * @final
114
- */
115
- VERSION : '2.3.6',
116
-
117
- /**
118
- * The state of the queue before it has started and after it has finished
119
- *
120
- * @property STOPPED
121
- * @static
122
- * @final
123
- */
124
- STOPPED : 1,
125
-
126
- /**
127
- * Upload process is running
128
- *
129
- * @property STARTED
130
- * @static
131
- * @final
132
- */
133
- STARTED : 2,
134
-
135
- /**
136
- * File is queued for upload
137
- *
138
- * @property QUEUED
139
- * @static
140
- * @final
141
- */
142
- QUEUED : 1,
143
-
144
- /**
145
- * File is being uploaded
146
- *
147
- * @property UPLOADING
148
- * @static
149
- * @final
150
- */
151
- UPLOADING : 2,
152
-
153
- /**
154
- * File has failed to be uploaded
155
- *
156
- * @property FAILED
157
- * @static
158
- * @final
159
- */
160
- FAILED : 4,
161
-
162
- /**
163
- * File has been uploaded successfully
164
- *
165
- * @property DONE
166
- * @static
167
- * @final
168
- */
169
- DONE : 5,
170
-
171
- // Error constants used by the Error event
172
-
173
- /**
174
- * Generic error for example if an exception is thrown inside Silverlight.
175
- *
176
- * @property GENERIC_ERROR
177
- * @static
178
- * @final
179
- */
180
- GENERIC_ERROR : -100,
181
-
182
- /**
183
- * HTTP transport error. For example if the server produces a HTTP status other than 200.
184
- *
185
- * @property HTTP_ERROR
186
- * @static
187
- * @final
188
- */
189
- HTTP_ERROR : -200,
190
-
191
- /**
192
- * Generic I/O error. For example if it wasn't possible to open the file stream on local machine.
193
- *
194
- * @property IO_ERROR
195
- * @static
196
- * @final
197
- */
198
- IO_ERROR : -300,
199
-
200
- /**
201
- * @property SECURITY_ERROR
202
- * @static
203
- * @final
204
- */
205
- SECURITY_ERROR : -400,
206
-
207
- /**
208
- * Initialization error. Will be triggered if no runtime was initialized.
209
- *
210
- * @property INIT_ERROR
211
- * @static
212
- * @final
213
- */
214
- INIT_ERROR : -500,
215
-
216
- /**
217
- * File size error. If the user selects a file that is too large or is empty it will be blocked and
218
- * an error of this type will be triggered.
219
- *
220
- * @property FILE_SIZE_ERROR
221
- * @static
222
- * @final
223
- */
224
- FILE_SIZE_ERROR : -600,
225
-
226
- /**
227
- * File extension error. If the user selects a file that isn't valid according to the filters setting.
228
- *
229
- * @property FILE_EXTENSION_ERROR
230
- * @static
231
- * @final
232
- */
233
- FILE_EXTENSION_ERROR : -601,
234
-
235
- /**
236
- * Duplicate file error. If prevent_duplicates is set to true and user selects the same file again.
237
- *
238
- * @property FILE_DUPLICATE_ERROR
239
- * @static
240
- * @final
241
- */
242
- FILE_DUPLICATE_ERROR : -602,
243
-
244
- /**
245
- * Runtime will try to detect if image is proper one. Otherwise will throw this error.
246
- *
247
- * @property IMAGE_FORMAT_ERROR
248
- * @static
249
- * @final
250
- */
251
- IMAGE_FORMAT_ERROR : -700,
252
-
253
- /**
254
- * While working on files runtime may run out of memory and will throw this error.
255
- *
256
- * @since 2.1.2
257
- * @property MEMORY_ERROR
258
- * @static
259
- * @final
260
- */
261
- MEMORY_ERROR : -701,
262
-
263
- /**
264
- * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.
265
- *
266
- * @property IMAGE_DIMENSIONS_ERROR
267
- * @static
268
- * @final
269
- */
270
- IMAGE_DIMENSIONS_ERROR : -702,
271
-
272
- /**
273
- * Expose whole moxie (#1469).
274
- *
275
- * @property moxie
276
- * @type Object
277
- * @final
278
- */
279
- moxie: o,
280
-
281
- /**
282
- * Mime type lookup table.
283
- *
284
- * @property mimeTypes
285
- * @type Object
286
- * @final
287
- */
288
- mimeTypes : u.Mime.mimes,
289
-
290
- /**
291
- * In some cases sniffing is the only way around :(
292
- */
293
- ua: u.Env,
294
-
295
- /**
296
- * Gets the true type of the built-in object (better version of typeof).
297
- * @credits Angus Croll (http://javascriptweblog.wordpress.com/)
298
- *
299
- * @method typeOf
300
- * @static
301
- * @param {Object} o Object to check.
302
- * @return {String} Object [[Class]]
303
- */
304
- typeOf: u.Basic.typeOf,
305
-
306
- /**
307
- * Extends the specified object with another object.
308
- *
309
- * @method extend
310
- * @static
311
- * @param {Object} target Object to extend.
312
- * @param {Object..} obj Multiple objects to extend with.
313
- * @return {Object} Same as target, the extended object.
314
- */
315
- extend : u.Basic.extend,
316
-
317
- /**
318
- * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
319
- * The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages
320
- * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique.
321
- * It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property
322
- * to an user unique key.
323
- *
324
- * @method guid
325
- * @static
326
- * @return {String} Virtually unique id.
327
- */
328
- guid : u.Basic.guid,
329
-
330
- /**
331
- * Get array of DOM Elements by their ids.
332
- *
333
- * @method get
334
- * @param {String} id Identifier of the DOM Element
335
- * @return {Array}
336
- */
337
- getAll : function get(ids) {
338
- var els = [], el;
339
-
340
- if (plupload.typeOf(ids) !== 'array') {
341
- ids = [ids];
342
- }
343
-
344
- var i = ids.length;
345
- while (i--) {
346
- el = plupload.get(ids[i]);
347
- if (el) {
348
- els.push(el);
349
- }
350
- }
351
-
352
- return els.length ? els : null;
353
- },
354
-
355
- /**
356
- Get DOM element by id
357
-
358
- @method get
359
- @param {String} id Identifier of the DOM Element
360
- @return {Node}
361
- */
362
- get: u.Dom.get,
363
-
364
- /**
365
- * Executes the callback function for each item in array/object. If you return false in the
366
- * callback it will break the loop.
367
- *
368
- * @method each
369
- * @static
370
- * @param {Object} obj Object to iterate.
371
- * @param {function} callback Callback function to execute for each item.
372
- */
373
- each : u.Basic.each,
374
-
375
- /**
376
- * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
377
- *
378
- * @method getPos
379
- * @static
380
- * @param {Element} node HTML element or element id to get x, y position from.
381
- * @param {Element} root Optional root element to stop calculations at.
382
- * @return {object} Absolute position of the specified element object with x, y fields.
383
- */
384
- getPos : u.Dom.getPos,
385
-
386
- /**
387
- * Returns the size of the specified node in pixels.
388
- *
389
- * @method getSize
390
- * @static
391
- * @param {Node} node Node to get the size of.
392
- * @return {Object} Object with a w and h property.
393
- */
394
- getSize : u.Dom.getSize,
395
-
396
- /**
397
- * Encodes the specified string.
398
- *
399
- * @method xmlEncode
400
- * @static
401
- * @param {String} s String to encode.
402
- * @return {String} Encoded string.
403
- */
404
- xmlEncode : function(str) {
405
- var xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'}, xmlEncodeRegExp = /[<>&\"\']/g;
406
-
407
- return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) {
408
- return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr;
409
- }) : str;
410
- },
411
-
412
- /**
413
- * Forces anything into an array.
414
- *
415
- * @method toArray
416
- * @static
417
- * @param {Object} obj Object with length field.
418
- * @return {Array} Array object containing all items.
419
- */
420
- toArray : u.Basic.toArray,
421
-
422
- /**
423
- * Find an element in array and return its index if present, otherwise return -1.
424
- *
425
- * @method inArray
426
- * @static
427
- * @param {mixed} needle Element to find
428
- * @param {Array} array
429
- * @return {Int} Index of the element, or -1 if not found
430
- */
431
- inArray : u.Basic.inArray,
432
-
433
- /**
434
- Recieve an array of functions (usually async) to call in sequence, each function
435
- receives a callback as first argument that it should call, when it completes. Finally,
436
- after everything is complete, main callback is called. Passing truthy value to the
437
- callback as a first argument will interrupt the sequence and invoke main callback
438
- immediately.
439
-
440
- @method inSeries
441
- @static
442
- @param {Array} queue Array of functions to call in sequence
443
- @param {Function} cb Main callback that is called in the end, or in case of error
444
- */
445
- inSeries: u.Basic.inSeries,
446
-
447
- /**
448
- * Extends the language pack object with new items.
449
- *
450
- * @method addI18n
451
- * @static
452
- * @param {Object} pack Language pack items to add.
453
- * @return {Object} Extended language pack object.
454
- */
455
- addI18n : o.core.I18n.addI18n,
456
-
457
- /**
458
- * Translates the specified string by checking for the english string in the language pack lookup.
459
- *
460
- * @method translate
461
- * @static
462
- * @param {String} str String to look for.
463
- * @return {String} Translated string or the input string if it wasn't found.
464
- */
465
- translate : o.core.I18n.translate,
466
-
467
- /**
468
- * Pseudo sprintf implementation - simple way to replace tokens with specified values.
469
- *
470
- * @param {String} str String with tokens
471
- * @return {String} String with replaced tokens
472
- */
473
- sprintf : u.Basic.sprintf,
474
-
475
- /**
476
- * Checks if object is empty.
477
- *
478
- * @method isEmptyObj
479
- * @static
480
- * @param {Object} obj Object to check.
481
- * @return {Boolean}
482
- */
483
- isEmptyObj : u.Basic.isEmptyObj,
484
-
485
- /**
486
- * Checks if specified DOM element has specified class.
487
- *
488
- * @method hasClass
489
- * @static
490
- * @param {Object} obj DOM element like object to add handler to.
491
- * @param {String} name Class name
492
- */
493
- hasClass : u.Dom.hasClass,
494
-
495
- /**
496
- * Adds specified className to specified DOM element.
497
- *
498
- * @method addClass
499
- * @static
500
- * @param {Object} obj DOM element like object to add handler to.
501
- * @param {String} name Class name
502
- */
503
- addClass : u.Dom.addClass,
504
-
505
- /**
506
- * Removes specified className from specified DOM element.
507
- *
508
- * @method removeClass
509
- * @static
510
- * @param {Object} obj DOM element like object to add handler to.
511
- * @param {String} name Class name
512
- */
513
- removeClass : u.Dom.removeClass,
514
-
515
- /**
516
- * Returns a given computed style of a DOM element.
517
- *
518
- * @method getStyle
519
- * @static
520
- * @param {Object} obj DOM element like object.
521
- * @param {String} name Style you want to get from the DOM element
522
- */
523
- getStyle : u.Dom.getStyle,
524
-
525
- /**
526
- * Adds an event handler to the specified object and store reference to the handler
527
- * in objects internal Plupload registry (@see removeEvent).
528
- *
529
- * @method addEvent
530
- * @static
531
- * @param {Object} obj DOM element like object to add handler to.
532
- * @param {String} name Name to add event listener to.
533
- * @param {Function} callback Function to call when event occurs.
534
- * @param {String} (optional) key that might be used to add specifity to the event record.
535
- */
536
- addEvent : u.Events.addEvent,
537
-
538
- /**
539
- * Remove event handler from the specified object. If third argument (callback)
540
- * is not specified remove all events with the specified name.
541
- *
542
- * @method removeEvent
543
- * @static
544
- * @param {Object} obj DOM element to remove event listener(s) from.
545
- * @param {String} name Name of event listener to remove.
546
- * @param {Function|String} (optional) might be a callback or unique key to match.
547
- */
548
- removeEvent: u.Events.removeEvent,
549
-
550
- /**
551
- * Remove all kind of events from the specified object
552
- *
553
- * @method removeAllEvents
554
- * @static
555
- * @param {Object} obj DOM element to remove event listeners from.
556
- * @param {String} (optional) unique key to match, when removing events.
557
- */
558
- removeAllEvents: u.Events.removeAllEvents,
559
-
560
- /**
561
- * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _.
562
- *
563
- * @method cleanName
564
- * @static
565
- * @param {String} s String to clean up.
566
- * @return {String} Cleaned string.
567
- */
568
- cleanName : function(name) {
569
- var i, lookup;
570
-
571
- // Replace diacritics
572
- lookup = [
573
- /[\300-\306]/g, 'A', /[\340-\346]/g, 'a',
574
- /\307/g, 'C', /\347/g, 'c',
575
- /[\310-\313]/g, 'E', /[\350-\353]/g, 'e',
576
- /[\314-\317]/g, 'I', /[\354-\357]/g, 'i',
577
- /\321/g, 'N', /\361/g, 'n',
578
- /[\322-\330]/g, 'O', /[\362-\370]/g, 'o',
579
- /[\331-\334]/g, 'U', /[\371-\374]/g, 'u'
580
- ];
581
-
582
- for (i = 0; i < lookup.length; i += 2) {
583
- name = name.replace(lookup[i], lookup[i + 1]);
584
- }
585
-
586
- // Replace whitespace
587
- name = name.replace(/\s+/g, '_');
588
-
589
- // Remove anything else
590
- name = name.replace(/[^a-z0-9_\-\.]+/gi, '');
591
-
592
- return name;
593
- },
594
-
595
- /**
596
- * Builds a full url out of a base URL and an object with items to append as query string items.
597
- *
598
- * @method buildUrl
599
- * @static
600
- * @param {String} url Base URL to append query string items to.
601
- * @param {Object} items Name/value object to serialize as a querystring.
602
- * @return {String} String with url + serialized query string items.
603
- */
604
- buildUrl: function(url, items) {
605
- var query = '';
606
-
607
- plupload.each(items, function(value, name) {
608
- query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value);
609
- });
610
-
611
- if (query) {
612
- url += (url.indexOf('?') > 0 ? '&' : '?') + query;
613
- }
614
-
615
- return url;
616
- },
617
-
618
- /**
619
- * Formats the specified number as a size string for example 1024 becomes 1 KB.
620
- *
621
- * @method formatSize
622
- * @static
623
- * @param {Number} size Size to format as string.
624
- * @return {String} Formatted size string.
625
- */
626
- formatSize : function(size) {
627
-
628
- if (size === undef || /\D/.test(size)) {
629
- return plupload.translate('N/A');
630
- }
631
-
632
- function round(num, precision) {
633
- return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
634
- }
635
-
636
- var boundary = Math.pow(1024, 4);
637
-
638
- // TB
639
- if (size > boundary) {
640
- return round(size / boundary, 1) + " " + plupload.translate('tb');
641
- }
642
-
643
- // GB
644
- if (size > (boundary/=1024)) {
645
- return round(size / boundary, 1) + " " + plupload.translate('gb');
646
- }
647
-
648
- // MB
649
- if (size > (boundary/=1024)) {
650
- return round(size / boundary, 1) + " " + plupload.translate('mb');
651
- }
652
-
653
- // KB
654
- if (size > 1024) {
655
- return Math.round(size / 1024) + " " + plupload.translate('kb');
656
- }
657
-
658
- return size + " " + plupload.translate('b');
659
- },
660
-
661
-
662
- /**
663
- * Parses the specified size string into a byte value. For example 10kb becomes 10240.
664
- *
665
- * @method parseSize
666
- * @static
667
- * @param {String|Number} size String to parse or number to just pass through.
668
- * @return {Number} Size in bytes.
669
- */
670
- parseSize : u.Basic.parseSizeStr,
671
-
672
-
673
- /**
674
- * A way to predict what runtime will be choosen in the current environment with the
675
- * specified settings.
676
- *
677
- * @method predictRuntime
678
- * @static
679
- * @param {Object|String} config Plupload settings to check
680
- * @param {String} [runtimes] Comma-separated list of runtimes to check against
681
- * @return {String} Type of compatible runtime
682
- */
683
- predictRuntime : function(config, runtimes) {
684
- var up, runtime;
685
-
686
- up = new plupload.Uploader(config);
687
- runtime = Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes);
688
- up.destroy();
689
- return runtime;
690
- },
691
-
692
- /**
693
- * Registers a filter that will be executed for each file added to the queue.
694
- * If callback returns false, file will not be added.
695
- *
696
- * Callback receives two arguments: a value for the filter as it was specified in settings.filters
697
- * and a file to be filtered. Callback is executed in the context of uploader instance.
698
- *
699
- * @method addFileFilter
700
- * @static
701
- * @param {String} name Name of the filter by which it can be referenced in settings.filters
702
- * @param {String} cb Callback - the actual routine that every added file must pass
703
- */
704
- addFileFilter: function(name, cb) {
705
- fileFilters[name] = cb;
706
- }
707
- };
708
-
709
-
710
- plupload.addFileFilter('mime_types', function(filters, file, cb) {
711
- if (filters.length && !filters.regexp.test(file.name)) {
712
- this.trigger('Error', {
713
- code : plupload.FILE_EXTENSION_ERROR,
714
- message : plupload.translate('File extension error.'),
715
- file : file
716
- });
717
- cb(false);
718
- } else {
719
- cb(true);
720
- }
721
- });
722
-
723
-
724
- plupload.addFileFilter('max_file_size', function(maxSize, file, cb) {
725
- var undef;
726
-
727
- maxSize = plupload.parseSize(maxSize);
728
-
729
- // Invalid file size
730
- if (file.size !== undef && maxSize && file.size > maxSize) {
731
- this.trigger('Error', {
732
- code : plupload.FILE_SIZE_ERROR,
733
- message : plupload.translate('File size error.'),
734
- file : file
735
- });
736
- cb(false);
737
- } else {
738
- cb(true);
739
- }
740
- });
741
-
742
-
743
- plupload.addFileFilter('prevent_duplicates', function(value, file, cb) {
744
- if (value) {
745
- var ii = this.files.length;
746
- while (ii--) {
747
- // Compare by name and size (size might be 0 or undefined, but still equivalent for both)
748
- if (file.name === this.files[ii].name && file.size === this.files[ii].size) {
749
- this.trigger('Error', {
750
- code : plupload.FILE_DUPLICATE_ERROR,
751
- message : plupload.translate('Duplicate file error.'),
752
- file : file
753
- });
754
- cb(false);
755
- return;
756
- }
757
- }
758
- }
759
- cb(true);
760
- });
761
-
762
- plupload.addFileFilter('prevent_empty', function(value, file, cb) {
763
- if (value && !file.size && file.size !== undef) {
764
- this.trigger('Error', {
765
- code : plupload.FILE_SIZE_ERROR,
766
- message : plupload.translate('File size error.'),
767
- file : file
768
- });
769
- cb(false);
770
- } else {
771
- cb(true);
772
- }
773
- });
774
-
775
-
776
- /**
777
- @class Uploader
778
- @constructor
779
-
780
- @param {Object} settings For detailed information about each option check documentation.
781
- @param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger.
782
- @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
783
- @param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element.
784
- @param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop.
785
- @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
786
- @param {Object} [settings.filters={}] Set of file type filters.
787
- @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
788
- @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
789
- @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
790
- @param {Boolean} [settings.filters.prevent_empty=true] Do not let empty files into the queue (IE10 is known to hang for example when trying to upload such). Dispatches `plupload.FILE_SIZE_ERROR`.
791
- @param {String} [settings.flash_swf_url] URL of the Flash swf.
792
- @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
793
- @param {String} [settings.http_method="POST"] HTTP method to use during upload (only PUT or POST allowed).
794
- @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
795
- @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
796
- @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
797
- @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
798
- @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
799
- @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
800
- @param {Number} [settings.resize.width] If image is bigger, it will be resized.
801
- @param {Number} [settings.resize.height] If image is bigger, it will be resized.
802
- @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
803
- @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
804
- @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
805
- @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
806
- @param {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes.
807
- @param {Boolean} [settings.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways).
808
- @param {String} settings.url URL of the server-side upload handler.
809
- @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
810
-
811
- */
812
- plupload.Uploader = function(options) {
813
- /**
814
- Fires when the current RunTime has been initialized.
815
-
816
- @event Init
817
- @param {plupload.Uploader} uploader Uploader instance sending the event.
818
- */
819
-
820
- /**
821
- Fires after the init event incase you need to perform actions there.
822
-
823
- @event PostInit
824
- @param {plupload.Uploader} uploader Uploader instance sending the event.
825
- */
826
-
827
- /**
828
- Fires when the option is changed in via uploader.setOption().
829
-
830
- @event OptionChanged
831
- @since 2.1
832
- @param {plupload.Uploader} uploader Uploader instance sending the event.
833
- @param {String} name Name of the option that was changed
834
- @param {Mixed} value New value for the specified option
835
- @param {Mixed} oldValue Previous value of the option
836
- */
837
-
838
- /**
839
- Fires when the silverlight/flash or other shim needs to move.
840
-
841
- @event Refresh
842
- @param {plupload.Uploader} uploader Uploader instance sending the event.
843
- */
844
-
845
- /**
846
- Fires when the overall state is being changed for the upload queue.
847
-
848
- @event StateChanged
849
- @param {plupload.Uploader} uploader Uploader instance sending the event.
850
- */
851
-
852
- /**
853
- Fires when browse_button is clicked and browse dialog shows.
854
-
855
- @event Browse
856
- @since 2.1.2
857
- @param {plupload.Uploader} uploader Uploader instance sending the event.
858
- */
859
-
860
- /**
861
- Fires for every filtered file before it is added to the queue.
862
-
863
- @event FileFiltered
864
- @since 2.1
865
- @param {plupload.Uploader} uploader Uploader instance sending the event.
866
- @param {plupload.File} file Another file that has to be added to the queue.
867
- */
868
-
869
- /**
870
- Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance.
871
-
872
- @event QueueChanged
873
- @param {plupload.Uploader} uploader Uploader instance sending the event.
874
- */
875
-
876
- /**
877
- Fires after files were filtered and added to the queue.
878
-
879
- @event FilesAdded
880
- @param {plupload.Uploader} uploader Uploader instance sending the event.
881
- @param {Array} files Array of file objects that were added to queue by the user.
882
- */
883
-
884
- /**
885
- Fires when file is removed from the queue.
886
-
887
- @event FilesRemoved
888
- @param {plupload.Uploader} uploader Uploader instance sending the event.
889
- @param {Array} files Array of files that got removed.
890
- */
891
-
892
- /**
893
- Fires just before a file is uploaded. Can be used to cancel the upload for the specified file
894
- by returning false from the handler.
895
-
896
- @event BeforeUpload
897
- @param {plupload.Uploader} uploader Uploader instance sending the event.
898
- @param {plupload.File} file File to be uploaded.
899
- */
900
-
901
- /**
902
- Fires when a file is to be uploaded by the runtime.
903
-
904
- @event UploadFile
905
- @param {plupload.Uploader} uploader Uploader instance sending the event.
906
- @param {plupload.File} file File to be uploaded.
907
- */
908
-
909
- /**
910
- Fires while a file is being uploaded. Use this event to update the current file upload progress.
911
-
912
- @event UploadProgress
913
- @param {plupload.Uploader} uploader Uploader instance sending the event.
914
- @param {plupload.File} file File that is currently being uploaded.
915
- */
916
-
917
- /**
918
- * Fires just before a chunk is uploaded. This event enables you to override settings
919
- * on the uploader instance before the chunk is uploaded.
920
- *
921
- * @event BeforeChunkUpload
922
- * @param {plupload.Uploader} uploader Uploader instance sending the event.
923
- * @param {plupload.File} file File to be uploaded.
924
- * @param {Object} args POST params to be sent.
925
- * @param {Blob} chunkBlob Current blob.
926
- * @param {offset} offset Current offset.
927
- */
928
-
929
- /**
930
- Fires when file chunk is uploaded.
931
-
932
- @event ChunkUploaded
933
- @param {plupload.Uploader} uploader Uploader instance sending the event.
934
- @param {plupload.File} file File that the chunk was uploaded for.
935
- @param {Object} result Object with response properties.
936
- @param {Number} result.offset The amount of bytes the server has received so far, including this chunk.
937
- @param {Number} result.total The size of the file.
938
- @param {String} result.response The response body sent by the server.
939
- @param {Number} result.status The HTTP status code sent by the server.
940
- @param {String} result.responseHeaders All the response headers as a single string.
941
- */
942
-
943
- /**
944
- Fires when a file is successfully uploaded.
945
-
946
- @event FileUploaded
947
- @param {plupload.Uploader} uploader Uploader instance sending the event.
948
- @param {plupload.File} file File that was uploaded.
949
- @param {Object} result Object with response properties.
950
- @param {String} result.response The response body sent by the server.
951
- @param {Number} result.status The HTTP status code sent by the server.
952
- @param {String} result.responseHeaders All the response headers as a single string.
953
- */
954
-
955
- /**
956
- Fires when all files in a queue are uploaded.
957
-
958
- @event UploadComplete
959
- @param {plupload.Uploader} uploader Uploader instance sending the event.
960
- @param {Array} files Array of file objects that was added to queue/selected by the user.
961
- */
962
-
963
- /**
964
- Fires when a error occurs.
965
-
966
- @event Error
967
- @param {plupload.Uploader} uploader Uploader instance sending the event.
968
- @param {Object} error Contains code, message and sometimes file and other details.
969
- @param {Number} error.code The plupload error code.
970
- @param {String} error.message Description of the error (uses i18n).
971
- */
972
-
973
- /**
974
- Fires when destroy method is called.
975
-
976
- @event Destroy
977
- @param {plupload.Uploader} uploader Uploader instance sending the event.
978
- */
979
- var uid = plupload.guid()
980
- , settings
981
- , files = []
982
- , preferred_caps = {}
983
- , fileInputs = []
984
- , fileDrops = []
985
- , startTime
986
- , total
987
- , disabled = false
988
- , xhr
989
- ;
990
-
991
-
992
- // Private methods
993
- function uploadNext() {
994
- var file, count = 0, i;
995
-
996
- if (this.state == plupload.STARTED) {
997
- // Find first QUEUED file
998
- for (i = 0; i < files.length; i++) {
999
- if (!file && files[i].status == plupload.QUEUED) {
1000
- file = files[i];
1001
- if (this.trigger("BeforeUpload", file)) {
1002
- file.status = plupload.UPLOADING;
1003
- this.trigger("UploadFile", file);
1004
- }
1005
- } else {
1006
- count++;
1007
- }
1008
- }
1009
-
1010
- // All files are DONE or FAILED
1011
- if (count == files.length) {
1012
- if (this.state !== plupload.STOPPED) {
1013
- this.state = plupload.STOPPED;
1014
- this.trigger("StateChanged");
1015
- }
1016
- this.trigger("UploadComplete", files);
1017
- }
1018
- }
1019
- }
1020
-
1021
-
1022
- function calcFile(file) {
1023
- file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;
1024
- calc();
1025
- }
1026
-
1027
-
1028
- function calc() {
1029
- var i, file;
1030
- var loaded;
1031
- var loadedDuringCurrentSession = 0;
1032
-
1033
- // Reset stats
1034
- total.reset();
1035
-
1036
- // Check status, size, loaded etc on all files
1037
- for (i = 0; i < files.length; i++) {
1038
- file = files[i];
1039
-
1040
- if (file.size !== undef) {
1041
- // We calculate totals based on original file size
1042
- total.size += file.origSize;
1043
-
1044
- // Since we cannot predict file size after resize, we do opposite and
1045
- // interpolate loaded amount to match magnitude of total
1046
- loaded = file.loaded * file.origSize / file.size;
1047
-
1048
- if (!file.completeTimestamp || file.completeTimestamp > startTime) {
1049
- loadedDuringCurrentSession += loaded;
1050
- }
1051
-
1052
- total.loaded += loaded;
1053
- } else {
1054
- total.size = undef;
1055
- }
1056
-
1057
- if (file.status == plupload.DONE) {
1058
- total.uploaded++;
1059
- } else if (file.status == plupload.FAILED) {
1060
- total.failed++;
1061
- } else {
1062
- total.queued++;
1063
- }
1064
- }
1065
-
1066
- // If we couldn't calculate a total file size then use the number of files to calc percent
1067
- if (total.size === undef) {
1068
- total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;
1069
- } else {
1070
- total.bytesPerSec = Math.ceil(loadedDuringCurrentSession / ((+new Date() - startTime || 1) / 1000.0));
1071
- total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;
1072
- }
1073
- }
1074
-
1075
-
1076
- function getRUID() {
1077
- var ctrl = fileInputs[0] || fileDrops[0];
1078
- if (ctrl) {
1079
- return ctrl.getRuntime().uid;
1080
- }
1081
- return false;
1082
- }
1083
-
1084
-
1085
- function bindEventListeners() {
1086
- this.bind('FilesAdded FilesRemoved', function(up) {
1087
- up.trigger('QueueChanged');
1088
- up.refresh();
1089
- });
1090
-
1091
- this.bind('CancelUpload', onCancelUpload);
1092
-
1093
- this.bind('BeforeUpload', onBeforeUpload);
1094
-
1095
- this.bind('UploadFile', onUploadFile);
1096
-
1097
- this.bind('UploadProgress', onUploadProgress);
1098
-
1099
- this.bind('StateChanged', onStateChanged);
1100
-
1101
- this.bind('QueueChanged', calc);
1102
-
1103
- this.bind('Error', onError);
1104
-
1105
- this.bind('FileUploaded', onFileUploaded);
1106
-
1107
- this.bind('Destroy', onDestroy);
1108
- }
1109
-
1110
-
1111
- function initControls(settings, cb) {
1112
- var self = this, inited = 0, queue = [];
1113
-
1114
- // common settings
1115
- var options = {
1116
- runtime_order: settings.runtimes,
1117
- required_caps: settings.required_features,
1118
- preferred_caps: preferred_caps,
1119
- swf_url: settings.flash_swf_url,
1120
- xap_url: settings.silverlight_xap_url
1121
- };
1122
-
1123
- // add runtime specific options if any
1124
- plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) {
1125
- if (settings[runtime]) {
1126
- options[runtime] = settings[runtime];
1127
- }
1128
- });
1129
-
1130
- // initialize file pickers - there can be many
1131
- if (settings.browse_button) {
1132
- plupload.each(settings.browse_button, function(el) {
1133
- queue.push(function(cb) {
1134
- var fileInput = new o.file.FileInput(plupload.extend({}, options, {
1135
- accept: settings.filters.mime_types,
1136
- name: settings.file_data_name,
1137
- multiple: settings.multi_selection,
1138
- container: settings.container,
1139
- browse_button: el
1140
- }));
1141
-
1142
- fileInput.onready = function() {
1143
- var info = Runtime.getInfo(this.ruid);
1144
-
1145
- // for backward compatibility
1146
- plupload.extend(self.features, {
1147
- chunks: info.can('slice_blob'),
1148
- multipart: info.can('send_multipart'),
1149
- multi_selection: info.can('select_multiple')
1150
- });
1151
-
1152
- inited++;
1153
- fileInputs.push(this);
1154
- cb();
1155
- };
1156
-
1157
- fileInput.onchange = function() {
1158
- self.addFile(this.files);
1159
- };
1160
-
1161
- fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) {
1162
- if (!disabled) {
1163
- if (settings.browse_button_hover) {
1164
- if ('mouseenter' === e.type) {
1165
- plupload.addClass(el, settings.browse_button_hover);
1166
- } else if ('mouseleave' === e.type) {
1167
- plupload.removeClass(el, settings.browse_button_hover);
1168
- }
1169
- }
1170
-
1171
- if (settings.browse_button_active) {
1172
- if ('mousedown' === e.type) {
1173
- plupload.addClass(el, settings.browse_button_active);
1174
- } else if ('mouseup' === e.type) {
1175
- plupload.removeClass(el, settings.browse_button_active);
1176
- }
1177
- }
1178
- }
1179
- });
1180
-
1181
- fileInput.bind('mousedown', function() {
1182
- self.trigger('Browse');
1183
- });
1184
-
1185
- fileInput.bind('error runtimeerror', function() {
1186
- fileInput = null;
1187
- cb();
1188
- });
1189
-
1190
- fileInput.init();
1191
- });
1192
- });
1193
- }
1194
-
1195
- // initialize drop zones
1196
- if (settings.drop_element) {
1197
- plupload.each(settings.drop_element, function(el) {
1198
- queue.push(function(cb) {
1199
- var fileDrop = new o.file.FileDrop(plupload.extend({}, options, {
1200
- drop_zone: el
1201
- }));
1202
-
1203
- fileDrop.onready = function() {
1204
- var info = Runtime.getInfo(this.ruid);
1205
-
1206
- // for backward compatibility
1207
- plupload.extend(self.features, {
1208
- chunks: info.can('slice_blob'),
1209
- multipart: info.can('send_multipart'),
1210
- dragdrop: info.can('drag_and_drop')
1211
- });
1212
-
1213
- inited++;
1214
- fileDrops.push(this);
1215
- cb();
1216
- };
1217
-
1218
- fileDrop.ondrop = function() {
1219
- self.addFile(this.files);
1220
- };
1221
-
1222
- fileDrop.bind('error runtimeerror', function() {
1223
- fileDrop = null;
1224
- cb();
1225
- });
1226
-
1227
- fileDrop.init();
1228
- });
1229
- });
1230
- }
1231
-
1232
-
1233
- plupload.inSeries(queue, function() {
1234
- if (typeof(cb) === 'function') {
1235
- cb(inited);
1236
- }
1237
- });
1238
- }
1239
-
1240
-
1241
- function resizeImage(blob, params, runtimeOptions, cb) {
1242
- var img = new o.image.Image();
1243
-
1244
- try {
1245
- img.onload = function() {
1246
- // no manipulation required if...
1247
- if (params.width > this.width &&
1248
- params.height > this.height &&
1249
- params.quality === undef &&
1250
- params.preserve_headers &&
1251
- !params.crop
1252
- ) {
1253
- this.destroy();
1254
- cb(blob);
1255
- } else {
1256
- // otherwise downsize
1257
- img.downsize(params.width, params.height, params.crop, params.preserve_headers);
1258
- }
1259
- };
1260
-
1261
- img.onresize = function() {
1262
- var resizedBlob = this.getAsBlob(blob.type, params.quality);
1263
- this.destroy();
1264
- cb(resizedBlob);
1265
- };
1266
-
1267
- img.bind('error runtimeerror', function() {
1268
- this.destroy();
1269
- cb(blob);
1270
- });
1271
-
1272
- img.load(blob, runtimeOptions);
1273
- } catch(ex) {
1274
- cb(blob);
1275
- }
1276
- }
1277
-
1278
-
1279
- function setOption(option, value, init) {
1280
- var self = this, reinitRequired = false;
1281
-
1282
- function _setOption(option, value, init) {
1283
- var oldValue = settings[option];
1284
-
1285
- switch (option) {
1286
- case 'max_file_size':
1287
- if (option === 'max_file_size') {
1288
- settings.max_file_size = settings.filters.max_file_size = value;
1289
- }
1290
- break;
1291
-
1292
- case 'chunk_size':
1293
- if (value = plupload.parseSize(value)) {
1294
- settings[option] = value;
1295
- settings.send_file_name = true;
1296
- }
1297
- break;
1298
-
1299
- case 'multipart':
1300
- settings[option] = value;
1301
- if (!value) {
1302
- settings.send_file_name = true;
1303
- }
1304
- break;
1305
-
1306
- case 'http_method':
1307
- settings[option] = value.toUpperCase() === 'PUT' ? 'PUT' : 'POST';
1308
- break;
1309
-
1310
- case 'unique_names':
1311
- settings[option] = value;
1312
- if (value) {
1313
- settings.send_file_name = true;
1314
- }
1315
- break;
1316
-
1317
- case 'filters':
1318
- // for sake of backward compatibility
1319
- if (plupload.typeOf(value) === 'array') {
1320
- value = {
1321
- mime_types: value
1322
- };
1323
- }
1324
-
1325
- if (init) {
1326
- plupload.extend(settings.filters, value);
1327
- } else {
1328
- settings.filters = value;
1329
- }
1330
-
1331
- // if file format filters are being updated, regenerate the matching expressions
1332
- if (value.mime_types) {
1333
- if (plupload.typeOf(value.mime_types) === 'string') {
1334
- value.mime_types = o.core.utils.Mime.mimes2extList(value.mime_types);
1335
- }
1336
-
1337
- value.mime_types.regexp = (function(filters) {
1338
- var extensionsRegExp = [];
1339
-
1340
- plupload.each(filters, function(filter) {
1341
- plupload.each(filter.extensions.split(/,/), function(ext) {
1342
- if (/^\s*\*\s*$/.test(ext)) {
1343
- extensionsRegExp.push('\\.*');
1344
- } else {
1345
- extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));
1346
- }
1347
- });
1348
- });
1349
-
1350
- return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i');
1351
- }(value.mime_types));
1352
-
1353
- settings.filters.mime_types = value.mime_types;
1354
- }
1355
- break;
1356
-
1357
- case 'resize':
1358
- if (value) {
1359
- settings.resize = plupload.extend({
1360
- preserve_headers: true,
1361
- crop: false
1362
- }, value);
1363
- } else {
1364
- settings.resize = false;
1365
- }
1366
- break;
1367
-
1368
- case 'prevent_duplicates':
1369
- settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value;
1370
- break;
1371
-
1372
- // options that require reinitialisation
1373
- case 'container':
1374
- case 'browse_button':
1375
- case 'drop_element':
1376
- value = 'container' === option
1377
- ? plupload.get(value)
1378
- : plupload.getAll(value)
1379
- ;
1380
-
1381
- case 'runtimes':
1382
- case 'multi_selection':
1383
- case 'flash_swf_url':
1384
- case 'silverlight_xap_url':
1385
- settings[option] = value;
1386
- if (!init) {
1387
- reinitRequired = true;
1388
- }
1389
- break;
1390
-
1391
- default:
1392
- settings[option] = value;
1393
- }
1394
-
1395
- if (!init) {
1396
- self.trigger('OptionChanged', option, value, oldValue);
1397
- }
1398
- }
1399
-
1400
- if (typeof(option) === 'object') {
1401
- plupload.each(option, function(value, option) {
1402
- _setOption(option, value, init);
1403
- });
1404
- } else {
1405
- _setOption(option, value, init);
1406
- }
1407
-
1408
- if (init) {
1409
- // Normalize the list of required capabilities
1410
- settings.required_features = normalizeCaps(plupload.extend({}, settings));
1411
-
1412
- // Come up with the list of capabilities that can affect default mode in a multi-mode runtimes
1413
- preferred_caps = normalizeCaps(plupload.extend({}, settings, {
1414
- required_features: true
1415
- }));
1416
- } else if (reinitRequired) {
1417
- self.trigger('Destroy');
1418
-
1419
- initControls.call(self, settings, function(inited) {
1420
- if (inited) {
1421
- self.runtime = Runtime.getInfo(getRUID()).type;
1422
- self.trigger('Init', { runtime: self.runtime });
1423
- self.trigger('PostInit');
1424
- } else {
1425
- self.trigger('Error', {
1426
- code : plupload.INIT_ERROR,
1427
- message : plupload.translate('Init error.')
1428
- });
1429
- }
1430
- });
1431
- }
1432
- }
1433
-
1434
-
1435
- // Internal event handlers
1436
- function onBeforeUpload(up, file) {
1437
- // Generate unique target filenames
1438
- if (up.settings.unique_names) {
1439
- var matches = file.name.match(/\.([^.]+)$/), ext = "part";
1440
- if (matches) {
1441
- ext = matches[1];
1442
- }
1443
- file.target_name = file.id + '.' + ext;
1444
- }
1445
- }
1446
-
1447
-
1448
- function onUploadFile(up, file) {
1449
- var url = up.settings.url;
1450
- var chunkSize = up.settings.chunk_size;
1451
- var retries = up.settings.max_retries;
1452
- var features = up.features;
1453
- var offset = 0;
1454
- var blob;
1455
-
1456
- var runtimeOptions = {
1457
- runtime_order: up.settings.runtimes,
1458
- required_caps: up.settings.required_features,
1459
- preferred_caps: preferred_caps,
1460
- swf_url: up.settings.flash_swf_url,
1461
- xap_url: up.settings.silverlight_xap_url
1462
- };
1463
-
1464
- // make sure we start at a predictable offset
1465
- if (file.loaded) {
1466
- offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0;
1467
- }
1468
-
1469
- function handleError() {
1470
- if (retries-- > 0) {
1471
- delay(uploadNextChunk, 1000);
1472
- } else {
1473
- file.loaded = offset; // reset all progress
1474
-
1475
- up.trigger('Error', {
1476
- code : plupload.HTTP_ERROR,
1477
- message : plupload.translate('HTTP Error.'),
1478
- file : file,
1479
- response : xhr.responseText,
1480
- status : xhr.status,
1481
- responseHeaders: xhr.getAllResponseHeaders()
1482
- });
1483
- }
1484
- }
1485
-
1486
- function uploadNextChunk() {
1487
- var chunkBlob, args = {}, curChunkSize;
1488
-
1489
- // make sure that file wasn't cancelled and upload is not stopped in general
1490
- if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) {
1491
- return;
1492
- }
1493
-
1494
- // send additional 'name' parameter only if required
1495
- if (up.settings.send_file_name) {
1496
- args.name = file.target_name || file.name;
1497
- }
1498
-
1499
- if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory
1500
- curChunkSize = Math.min(chunkSize, blob.size - offset);
1501
- chunkBlob = blob.slice(offset, offset + curChunkSize);
1502
- } else {
1503
- curChunkSize = blob.size;
1504
- chunkBlob = blob;
1505
- }
1506
-
1507
- // If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller
1508
- if (chunkSize && features.chunks) {
1509
- // Setup query string arguments
1510
- if (up.settings.send_chunk_number) {
1511
- args.chunk = Math.ceil(offset / chunkSize);
1512
- args.chunks = Math.ceil(blob.size / chunkSize);
1513
- } else { // keep support for experimental chunk format, just in case
1514
- args.offset = offset;
1515
- args.total = blob.size;
1516
- }
1517
- }
1518
-
1519
- if (up.trigger('BeforeChunkUpload', file, args, chunkBlob, offset)) {
1520
- uploadChunk(args, chunkBlob, curChunkSize);
1521
- }
1522
- }
1523
-
1524
- function uploadChunk(args, chunkBlob, curChunkSize) {
1525
- var formData;
1526
-
1527
- xhr = new o.xhr.XMLHttpRequest();
1528
-
1529
- // Do we have upload progress support
1530
- if (xhr.upload) {
1531
- xhr.upload.onprogress = function(e) {
1532
- file.loaded = Math.min(file.size, offset + e.loaded);
1533
- up.trigger('UploadProgress', file);
1534
- };
1535
- }
1536
-
1537
- xhr.onload = function() {
1538
- // check if upload made itself through
1539
- if (xhr.status < 200 || xhr.status >= 400) {
1540
- handleError();
1541
- return;
1542
- }
1543
-
1544
- retries = up.settings.max_retries; // reset the counter
1545
-
1546
- // Handle chunk response
1547
- if (curChunkSize < blob.size) {
1548
- chunkBlob.destroy();
1549
-
1550
- offset += curChunkSize;
1551
- file.loaded = Math.min(offset, blob.size);
1552
-
1553
- up.trigger('ChunkUploaded', file, {
1554
- offset : file.loaded,
1555
- total : blob.size,
1556
- response : xhr.responseText,
1557
- status : xhr.status,
1558
- responseHeaders: xhr.getAllResponseHeaders()
1559
- });
1560
-
1561
- // stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them
1562
- if (plupload.ua.browser === 'Android Browser') {
1563
- // doesn't harm in general, but is not required anywhere else
1564
- up.trigger('UploadProgress', file);
1565
- }
1566
- } else {
1567
- file.loaded = file.size;
1568
- }
1569
-
1570
- chunkBlob = formData = null; // Free memory
1571
-
1572
- // Check if file is uploaded
1573
- if (!offset || offset >= blob.size) {
1574
- // If file was modified, destory the copy
1575
- if (file.size != file.origSize) {
1576
- blob.destroy();
1577
- blob = null;
1578
- }
1579
-
1580
- up.trigger('UploadProgress', file);
1581
-
1582
- file.status = plupload.DONE;
1583
- file.completeTimestamp = +new Date();
1584
-
1585
- up.trigger('FileUploaded', file, {
1586
- response : xhr.responseText,
1587
- status : xhr.status,
1588
- responseHeaders: xhr.getAllResponseHeaders()
1589
- });
1590
- } else {
1591
- // Still chunks left
1592
- delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere
1593
- }
1594
- };
1595
-
1596
- xhr.onerror = function() {
1597
- handleError();
1598
- };
1599
-
1600
- xhr.onloadend = function() {
1601
- this.destroy();
1602
- };
1603
-
1604
- // Build multipart request
1605
- if (up.settings.multipart && features.multipart) {
1606
- xhr.open(up.settings.http_method, url, true);
1607
-
1608
- // Set custom headers
1609
- plupload.each(up.settings.headers, function(value, name) {
1610
- xhr.setRequestHeader(name, value);
1611
- });
1612
-
1613
- formData = new o.xhr.FormData();
1614
-
1615
- // Add multipart params
1616
- plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
1617
- formData.append(name, value);
1618
- });
1619
-
1620
- // Add file and send it
1621
- formData.append(up.settings.file_data_name, chunkBlob);
1622
- xhr.send(formData, runtimeOptions);
1623
- } else {
1624
- // if no multipart, send as binary stream
1625
- url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params));
1626
-
1627
- xhr.open(up.settings.http_method, url, true);
1628
-
1629
- // Set custom headers
1630
- plupload.each(up.settings.headers, function(value, name) {
1631
- xhr.setRequestHeader(name, value);
1632
- });
1633
-
1634
- // do not set Content-Type, if it was defined previously (see #1203)
1635
- if (!xhr.hasRequestHeader('Content-Type')) {
1636
- xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header
1637
- }
1638
-
1639
- xhr.send(chunkBlob, runtimeOptions);
1640
- }
1641
- }
1642
-
1643
-
1644
- blob = file.getSource();
1645
-
1646
- // Start uploading chunks
1647
- if (!plupload.isEmptyObj(up.settings.resize) && plupload.inArray(blob.type, ['image/jpeg', 'image/png']) !== -1) {
1648
- // Resize if required
1649
- resizeImage(blob, up.settings.resize, runtimeOptions, function(resizedBlob) {
1650
- blob = resizedBlob;
1651
- file.size = resizedBlob.size;
1652
- uploadNextChunk();
1653
- });
1654
- } else {
1655
- uploadNextChunk();
1656
- }
1657
- }
1658
-
1659
-
1660
- function onUploadProgress(up, file) {
1661
- calcFile(file);
1662
- }
1663
-
1664
-
1665
- function onStateChanged(up) {
1666
- if (up.state == plupload.STARTED) {
1667
- // Get start time to calculate bps
1668
- startTime = (+new Date());
1669
- } else if (up.state == plupload.STOPPED) {
1670
- // Reset currently uploading files
1671
- for (var i = up.files.length - 1; i >= 0; i--) {
1672
- if (up.files[i].status == plupload.UPLOADING) {
1673
- up.files[i].status = plupload.QUEUED;
1674
- calc();
1675
- }
1676
- }
1677
- }
1678
- }
1679
-
1680
-
1681
- function onCancelUpload() {
1682
- if (xhr) {
1683
- xhr.abort();
1684
- }
1685
- }
1686
-
1687
-
1688
- function onFileUploaded(up) {
1689
- calc();
1690
-
1691
- // Upload next file but detach it from the error event
1692
- // since other custom listeners might want to stop the queue
1693
- delay(function() {
1694
- uploadNext.call(up);
1695
- }, 1);
1696
- }
1697
-
1698
-
1699
- function onError(up, err) {
1700
- if (err.code === plupload.INIT_ERROR) {
1701
- up.destroy();
1702
- }
1703
- // Set failed status if an error occured on a file
1704
- else if (err.code === plupload.HTTP_ERROR) {
1705
- err.file.status = plupload.FAILED;
1706
- err.file.completeTimestamp = +new Date();
1707
- calcFile(err.file);
1708
-
1709
- // Upload next file but detach it from the error event
1710
- // since other custom listeners might want to stop the queue
1711
- if (up.state == plupload.STARTED) { // upload in progress
1712
- up.trigger('CancelUpload');
1713
- delay(function() {
1714
- uploadNext.call(up);
1715
- }, 1);
1716
- }
1717
- }
1718
- }
1719
-
1720
-
1721
- function onDestroy(up) {
1722
- up.stop();
1723
-
1724
- // Purge the queue
1725
- plupload.each(files, function(file) {
1726
- file.destroy();
1727
- });
1728
- files = [];
1729
-
1730
- if (fileInputs.length) {
1731
- plupload.each(fileInputs, function(fileInput) {
1732
- fileInput.destroy();
1733
- });
1734
- fileInputs = [];
1735
- }
1736
-
1737
- if (fileDrops.length) {
1738
- plupload.each(fileDrops, function(fileDrop) {
1739
- fileDrop.destroy();
1740
- });
1741
- fileDrops = [];
1742
- }
1743
-
1744
- preferred_caps = {};
1745
- disabled = false;
1746
- startTime = xhr = null;
1747
- total.reset();
1748
- }
1749
-
1750
-
1751
- // Default settings
1752
- settings = {
1753
- chunk_size: 0,
1754
- file_data_name: 'file',
1755
- filters: {
1756
- mime_types: [],
1757
- max_file_size: 0,
1758
- prevent_duplicates: false,
1759
- prevent_empty: true
1760
- },
1761
- flash_swf_url: 'js/Moxie.swf',
1762
- http_method: 'POST',
1763
- max_retries: 0,
1764
- multipart: true,
1765
- multi_selection: true,
1766
- resize: false,
1767
- runtimes: Runtime.order,
1768
- send_file_name: true,
1769
- send_chunk_number: true,
1770
- silverlight_xap_url: 'js/Moxie.xap'
1771
- };
1772
-
1773
-
1774
- setOption.call(this, options, null, true);
1775
-
1776
- // Inital total state
1777
- total = new plupload.QueueProgress();
1778
-
1779
- // Add public methods
1780
- plupload.extend(this, {
1781
-
1782
- /**
1783
- * Unique id for the Uploader instance.
1784
- *
1785
- * @property id
1786
- * @type String
1787
- */
1788
- id : uid,
1789
- uid : uid, // mOxie uses this to differentiate between event targets
1790
-
1791
- /**
1792
- * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED.
1793
- * These states are controlled by the stop/start methods. The default value is STOPPED.
1794
- *
1795
- * @property state
1796
- * @type Number
1797
- */
1798
- state : plupload.STOPPED,
1799
-
1800
- /**
1801
- * Map of features that are available for the uploader runtime. Features will be filled
1802
- * before the init event is called, these features can then be used to alter the UI for the end user.
1803
- * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize.
1804
- *
1805
- * @property features
1806
- * @type Object
1807
- */
1808
- features : {},
1809
-
1810
- /**
1811
- * Current runtime name.
1812
- *
1813
- * @property runtime
1814
- * @type String
1815
- */
1816
- runtime : null,
1817
-
1818
- /**
1819
- * Current upload queue, an array of File instances.
1820
- *
1821
- * @property files
1822
- * @type Array
1823
- * @see plupload.File
1824
- */
1825
- files : files,
1826
-
1827
- /**
1828
- * Object with name/value settings.
1829
- *
1830
- * @property settings
1831
- * @type Object
1832
- */
1833
- settings : settings,
1834
-
1835
- /**
1836
- * Total progess information. How many files has been uploaded, total percent etc.
1837
- *
1838
- * @property total
1839
- * @type plupload.QueueProgress
1840
- */
1841
- total : total,
1842
-
1843
-
1844
- /**
1845
- * Initializes the Uploader instance and adds internal event listeners.
1846
- *
1847
- * @method init
1848
- */
1849
- init : function() {
1850
- var self = this, opt, preinitOpt, err;
1851
-
1852
- preinitOpt = self.getOption('preinit');
1853
- if (typeof(preinitOpt) == "function") {
1854
- preinitOpt(self);
1855
- } else {
1856
- plupload.each(preinitOpt, function(func, name) {
1857
- self.bind(name, func);
1858
- });
1859
- }
1860
-
1861
- bindEventListeners.call(self);
1862
-
1863
- // Check for required options
1864
- plupload.each(['container', 'browse_button', 'drop_element'], function(el) {
1865
- if (self.getOption(el) === null) {
1866
- err = {
1867
- code : plupload.INIT_ERROR,
1868
- message : plupload.sprintf(plupload.translate("%s specified, but cannot be found."), el)
1869
- }
1870
- return false;
1871
- }
1872
- });
1873
-
1874
- if (err) {
1875
- return self.trigger('Error', err);
1876
- }
1877
-
1878
-
1879
- if (!settings.browse_button && !settings.drop_element) {
1880
- return self.trigger('Error', {
1881
- code : plupload.INIT_ERROR,
1882
- message : plupload.translate("You must specify either browse_button or drop_element.")
1883
- });
1884
- }
1885
-
1886
-
1887
- initControls.call(self, settings, function(inited) {
1888
- var initOpt = self.getOption('init');
1889
- if (typeof(initOpt) == "function") {
1890
- initOpt(self);
1891
- } else {
1892
- plupload.each(initOpt, function(func, name) {
1893
- self.bind(name, func);
1894
- });
1895
- }
1896
-
1897
- if (inited) {
1898
- self.runtime = Runtime.getInfo(getRUID()).type;
1899
- self.trigger('Init', { runtime: self.runtime });
1900
- self.trigger('PostInit');
1901
- } else {
1902
- self.trigger('Error', {
1903
- code : plupload.INIT_ERROR,
1904
- message : plupload.translate('Init error.')
1905
- });
1906
- }
1907
- });
1908
- },
1909
-
1910
- /**
1911
- * Set the value for the specified option(s).
1912
- *
1913
- * @method setOption
1914
- * @since 2.1
1915
- * @param {String|Object} option Name of the option to change or the set of key/value pairs
1916
- * @param {Mixed} [value] Value for the option (is ignored, if first argument is object)
1917
- */
1918
- setOption: function(option, value) {
1919
- setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize
1920
- },
1921
-
1922
- /**
1923
- * Get the value for the specified option or the whole configuration, if not specified.
1924
- *
1925
- * @method getOption
1926
- * @since 2.1
1927
- * @param {String} [option] Name of the option to get
1928
- * @return {Mixed} Value for the option or the whole set
1929
- */
1930
- getOption: function(option) {
1931
- if (!option) {
1932
- return settings;
1933
- }
1934
- return settings[option];
1935
- },
1936
-
1937
- /**
1938
- * Refreshes the upload instance by dispatching out a refresh event to all runtimes.
1939
- * This would for example reposition flash/silverlight shims on the page.
1940
- *
1941
- * @method refresh
1942
- */
1943
- refresh : function() {
1944
- if (fileInputs.length) {
1945
- plupload.each(fileInputs, function(fileInput) {
1946
- fileInput.trigger('Refresh');
1947
- });
1948
- }
1949
- this.trigger('Refresh');
1950
- },
1951
-
1952
- /**
1953
- * Starts uploading the queued files.
1954
- *
1955
- * @method start
1956
- */
1957
- start : function() {
1958
- if (this.state != plupload.STARTED) {
1959
- this.state = plupload.STARTED;
1960
- this.trigger('StateChanged');
1961
-
1962
- uploadNext.call(this);
1963
- }
1964
- },
1965
-
1966
- /**
1967
- * Stops the upload of the queued files.
1968
- *
1969
- * @method stop
1970
- */
1971
- stop : function() {
1972
- if (this.state != plupload.STOPPED) {
1973
- this.state = plupload.STOPPED;
1974
- this.trigger('StateChanged');
1975
- this.trigger('CancelUpload');
1976
- }
1977
- },
1978
-
1979
-
1980
- /**
1981
- * Disables/enables browse button on request.
1982
- *
1983
- * @method disableBrowse
1984
- * @param {Boolean} disable Whether to disable or enable (default: true)
1985
- */
1986
- disableBrowse : function() {
1987
- disabled = arguments[0] !== undef ? arguments[0] : true;
1988
-
1989
- if (fileInputs.length) {
1990
- plupload.each(fileInputs, function(fileInput) {
1991
- fileInput.disable(disabled);
1992
- });
1993
- }
1994
-
1995
- this.trigger('DisableBrowse', disabled);
1996
- },
1997
-
1998
- /**
1999
- * Returns the specified file object by id.
2000
- *
2001
- * @method getFile
2002
- * @param {String} id File id to look for.
2003
- * @return {plupload.File} File object or undefined if it wasn't found;
2004
- */
2005
- getFile : function(id) {
2006
- var i;
2007
- for (i = files.length - 1; i >= 0; i--) {
2008
- if (files[i].id === id) {
2009
- return files[i];
2010
- }
2011
- }
2012
- },
2013
-
2014
- /**
2015
- * Adds file to the queue programmatically. Can be native file, instance of Plupload.File,
2016
- * instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded,
2017
- * if any files were added to the queue. Otherwise nothing happens.
2018
- *
2019
- * @method addFile
2020
- * @since 2.0
2021
- * @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue.
2022
- * @param {String} [fileName] If specified, will be used as a name for the file
2023
- */
2024
- addFile : function(file, fileName) {
2025
- var self = this
2026
- , queue = []
2027
- , filesAdded = []
2028
- , ruid
2029
- ;
2030
-
2031
- function filterFile(file, cb) {
2032
- var queue = [];
2033
- plupload.each(self.settings.filters, function(rule, name) {
2034
- if (fileFilters[name]) {
2035
- queue.push(function(cb) {
2036
- fileFilters[name].call(self, rule, file, function(res) {
2037
- cb(!res);
2038
- });
2039
- });
2040
- }
2041
- });
2042
- plupload.inSeries(queue, cb);
2043
- }
2044
-
2045
- /**
2046
- * @method resolveFile
2047
- * @private
2048
- * @param {moxie.file.File|moxie.file.Blob|plupload.File|File|Blob|input[type="file"]} file
2049
- */
2050
- function resolveFile(file) {
2051
- var type = plupload.typeOf(file);
2052
-
2053
- // moxie.file.File
2054
- if (file instanceof o.file.File) {
2055
- if (!file.ruid && !file.isDetached()) {
2056
- if (!ruid) { // weird case
2057
- return false;
2058
- }
2059
- file.ruid = ruid;
2060
- file.connectRuntime(ruid);
2061
- }
2062
- resolveFile(new plupload.File(file));
2063
- }
2064
- // moxie.file.Blob
2065
- else if (file instanceof o.file.Blob) {
2066
- resolveFile(file.getSource());
2067
- file.destroy();
2068
- }
2069
- // plupload.File - final step for other branches
2070
- else if (file instanceof plupload.File) {
2071
- if (fileName) {
2072
- file.name = fileName;
2073
- }
2074
-
2075
- queue.push(function(cb) {
2076
- // run through the internal and user-defined filters, if any
2077
- filterFile(file, function(err) {
2078
- if (!err) {
2079
- // make files available for the filters by updating the main queue directly
2080
- files.push(file);
2081
- // collect the files that will be passed to FilesAdded event
2082
- filesAdded.push(file);
2083
-
2084
- self.trigger("FileFiltered", file);
2085
- }
2086
- delay(cb, 1); // do not build up recursions or eventually we might hit the limits
2087
- });
2088
- });
2089
- }
2090
- // native File or blob
2091
- else if (plupload.inArray(type, ['file', 'blob']) !== -1) {
2092
- resolveFile(new o.file.File(null, file));
2093
- }
2094
- // input[type="file"]
2095
- else if (type === 'node' && plupload.typeOf(file.files) === 'filelist') {
2096
- // if we are dealing with input[type="file"]
2097
- plupload.each(file.files, resolveFile);
2098
- }
2099
- // mixed array of any supported types (see above)
2100
- else if (type === 'array') {
2101
- fileName = null; // should never happen, but unset anyway to avoid funny situations
2102
- plupload.each(file, resolveFile);
2103
- }
2104
- }
2105
-
2106
- ruid = getRUID();
2107
-
2108
- resolveFile(file);
2109
-
2110
- if (queue.length) {
2111
- plupload.inSeries(queue, function() {
2112
- // if any files left after filtration, trigger FilesAdded
2113
- if (filesAdded.length) {
2114
- self.trigger("FilesAdded", filesAdded);
2115
- }
2116
- });
2117
- }
2118
- },
2119
-
2120
- /**
2121
- * Removes a specific file.
2122
- *
2123
- * @method removeFile
2124
- * @param {plupload.File|String} file File to remove from queue.
2125
- */
2126
- removeFile : function(file) {
2127
- var id = typeof(file) === 'string' ? file : file.id;
2128
-
2129
- for (var i = files.length - 1; i >= 0; i--) {
2130
- if (files[i].id === id) {
2131
- return this.splice(i, 1)[0];
2132
- }
2133
- }
2134
- },
2135
-
2136
- /**
2137
- * Removes part of the queue and returns the files removed. This will also trigger the
2138
- * FilesRemoved and QueueChanged events.
2139
- *
2140
- * @method splice
2141
- * @param {Number} [start=0] Start index to remove from.
2142
- * @param {Number} [length] Number of files to remove (defaults to number of files in the queue).
2143
- * @return {Array} Array of files that was removed.
2144
- */
2145
- splice : function(start, length) {
2146
- // Splice and trigger events
2147
- var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length);
2148
-
2149
- // if upload is in progress we need to stop it and restart after files are removed
2150
- var restartRequired = false;
2151
- if (this.state == plupload.STARTED) { // upload in progress
2152
- plupload.each(removed, function(file) {
2153
- if (file.status === plupload.UPLOADING) {
2154
- restartRequired = true; // do not restart, unless file that is being removed is uploading
2155
- return false;
2156
- }
2157
- });
2158
-
2159
- if (restartRequired) {
2160
- this.stop();
2161
- }
2162
- }
2163
-
2164
- this.trigger("FilesRemoved", removed);
2165
-
2166
- // Dispose any resources allocated by those files
2167
- plupload.each(removed, function(file) {
2168
- file.destroy();
2169
- });
2170
-
2171
- if (restartRequired) {
2172
- this.start();
2173
- }
2174
-
2175
- return removed;
2176
- },
2177
-
2178
- /**
2179
- Dispatches the specified event name and its arguments to all listeners.
2180
-
2181
- @method trigger
2182
- @param {String} name Event name to fire.
2183
- @param {Object..} Multiple arguments to pass along to the listener functions.
2184
- */
2185
-
2186
- // override the parent method to match Plupload-like event logic
2187
- dispatchEvent: function(type) {
2188
- var list, args, result;
2189
-
2190
- type = type.toLowerCase();
2191
-
2192
- list = this.hasEventListener(type);
2193
-
2194
- if (list) {
2195
- // sort event list by priority
2196
- list.sort(function(a, b) { return b.priority - a.priority; });
2197
-
2198
- // first argument should be current plupload.Uploader instance
2199
- args = [].slice.call(arguments);
2200
- args.shift();
2201
- args.unshift(this);
2202
-
2203
- for (var i = 0; i < list.length; i++) {
2204
- // Fire event, break chain if false is returned
2205
- if (list[i].fn.apply(list[i].scope, args) === false) {
2206
- return false;
2207
- }
2208
- }
2209
- }
2210
- return true;
2211
- },
2212
-
2213
- /**
2214
- Check whether uploader has any listeners to the specified event.
2215
-
2216
- @method hasEventListener
2217
- @param {String} name Event name to check for.
2218
- */
2219
-
2220
-
2221
- /**
2222
- Adds an event listener by name.
2223
-
2224
- @method bind
2225
- @param {String} name Event name to listen for.
2226
- @param {function} fn Function to call ones the event gets fired.
2227
- @param {Object} [scope] Optional scope to execute the specified function in.
2228
- @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
2229
- */
2230
- bind: function(name, fn, scope, priority) {
2231
- // adapt moxie EventTarget style to Plupload-like
2232
- plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope);
2233
- },
2234
-
2235
- /**
2236
- Removes the specified event listener.
2237
-
2238
- @method unbind
2239
- @param {String} name Name of event to remove.
2240
- @param {function} fn Function to remove from listener.
2241
- */
2242
-
2243
- /**
2244
- Removes all event listeners.
2245
-
2246
- @method unbindAll
2247
- */
2248
-
2249
-
2250
- /**
2251
- * Destroys Plupload instance and cleans after itself.
2252
- *
2253
- * @method destroy
2254
- */
2255
- destroy : function() {
2256
- this.trigger('Destroy');
2257
- settings = total = null; // purge these exclusively
2258
- this.unbindAll();
2259
- }
2260
- });
2261
- };
2262
-
2263
- plupload.Uploader.prototype = o.core.EventTarget.instance;
2264
-
2265
- /**
2266
- * Constructs a new file instance.
2267
- *
2268
- * @class File
2269
- * @constructor
2270
- *
2271
- * @param {Object} file Object containing file properties
2272
- * @param {String} file.name Name of the file.
2273
- * @param {Number} file.size File size.
2274
- */
2275
- plupload.File = (function() {
2276
- var filepool = {};
2277
-
2278
- function PluploadFile(file) {
2279
-
2280
- plupload.extend(this, {
2281
-
2282
- /**
2283
- * File id this is a globally unique id for the specific file.
2284
- *
2285
- * @property id
2286
- * @type String
2287
- */
2288
- id: plupload.guid(),
2289
-
2290
- /**
2291
- * File name for example "myfile.gif".
2292
- *
2293
- * @property name
2294
- * @type String
2295
- */
2296
- name: file.name || file.fileName,
2297
-
2298
- /**
2299
- * File type, `e.g image/jpeg`
2300
- *
2301
- * @property type
2302
- * @type String
2303
- */
2304
- type: file.type || '',
2305
-
2306
- /**
2307
- * Relative path to the file inside a directory
2308
- *
2309
- * @property relativePath
2310
- * @type String
2311
- * @default ''
2312
- */
2313
- relativePath: file.relativePath || '',
2314
-
2315
- /**
2316
- * File size in bytes (may change after client-side manupilation).
2317
- *
2318
- * @property size
2319
- * @type Number
2320
- */
2321
- size: file.fileSize || file.size,
2322
-
2323
- /**
2324
- * Original file size in bytes.
2325
- *
2326
- * @property origSize
2327
- * @type Number
2328
- */
2329
- origSize: file.fileSize || file.size,
2330
-
2331
- /**
2332
- * Number of bytes uploaded of the files total size.
2333
- *
2334
- * @property loaded
2335
- * @type Number
2336
- */
2337
- loaded: 0,
2338
-
2339
- /**
2340
- * Number of percentage uploaded of the file.
2341
- *
2342
- * @property percent
2343
- * @type Number
2344
- */
2345
- percent: 0,
2346
-
2347
- /**
2348
- * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
2349
- *
2350
- * @property status
2351
- * @type Number
2352
- * @see plupload
2353
- */
2354
- status: plupload.QUEUED,
2355
-
2356
- /**
2357
- * Date of last modification.
2358
- *
2359
- * @property lastModifiedDate
2360
- * @type {String}
2361
- */
2362
- lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
2363
-
2364
-
2365
- /**
2366
- * Set when file becomes plupload.DONE or plupload.FAILED. Is used to calculate proper plupload.QueueProgress.bytesPerSec.
2367
- * @private
2368
- * @property completeTimestamp
2369
- * @type {Number}
2370
- */
2371
- completeTimestamp: 0,
2372
-
2373
- /**
2374
- * Returns native window.File object, when it's available.
2375
- *
2376
- * @method getNative
2377
- * @return {window.File} or null, if plupload.File is of different origin
2378
- */
2379
- getNative: function() {
2380
- var file = this.getSource().getSource();
2381
- return plupload.inArray(plupload.typeOf(file), ['blob', 'file']) !== -1 ? file : null;
2382
- },
2383
-
2384
- /**
2385
- * Returns mOxie.File - unified wrapper object that can be used across runtimes.
2386
- *
2387
- * @method getSource
2388
- * @return {mOxie.File} or null
2389
- */
2390
- getSource: function() {
2391
- if (!filepool[this.id]) {
2392
- return null;
2393
- }
2394
- return filepool[this.id];
2395
- },
2396
-
2397
- /**
2398
- * Destroys plupload.File object.
2399
- *
2400
- * @method destroy
2401
- */
2402
- destroy: function() {
2403
- var src = this.getSource();
2404
- if (src) {
2405
- src.destroy();
2406
- delete filepool[this.id];
2407
- }
2408
- }
2409
- });
2410
-
2411
- filepool[this.id] = file;
2412
- }
2413
-
2414
- return PluploadFile;
2415
- }());
2416
-
2417
-
2418
- /**
2419
- * Constructs a queue progress.
2420
- *
2421
- * @class QueueProgress
2422
- * @constructor
2423
- */
2424
- plupload.QueueProgress = function() {
2425
- var self = this; // Setup alias for self to reduce code size when it's compressed
2426
-
2427
- /**
2428
- * Total queue file size.
2429
- *
2430
- * @property size
2431
- * @type Number
2432
- */
2433
- self.size = 0;
2434
-
2435
- /**
2436
- * Total bytes uploaded.
2437
- *
2438
- * @property loaded
2439
- * @type Number
2440
- */
2441
- self.loaded = 0;
2442
-
2443
- /**
2444
- * Number of files uploaded.
2445
- *
2446
- * @property uploaded
2447
- * @type Number
2448
- */
2449
- self.uploaded = 0;
2450
-
2451
- /**
2452
- * Number of files failed to upload.
2453
- *
2454
- * @property failed
2455
- * @type Number
2456
- */
2457
- self.failed = 0;
2458
-
2459
- /**
2460
- * Number of files yet to be uploaded.
2461
- *
2462
- * @property queued
2463
- * @type Number
2464
- */
2465
- self.queued = 0;
2466
-
2467
- /**
2468
- * Total percent of the uploaded bytes.
2469
- *
2470
- * @property percent
2471
- * @type Number
2472
- */
2473
- self.percent = 0;
2474
-
2475
- /**
2476
- * Bytes uploaded per second.
2477
- *
2478
- * @property bytesPerSec
2479
- * @type Number
2480
- */
2481
- self.bytesPerSec = 0;
2482
-
2483
- /**
2484
- * Resets the progress to its initial values.
2485
- *
2486
- * @method reset
2487
- */
2488
- self.reset = function() {
2489
- self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0;
2490
- };
2491
- };
2492
-
2493
- exports.plupload = plupload;
2494
-
2495
- }(this, moxie));
2496
-
2497
- }));