rlm@3
|
1 /**
|
rlm@3
|
2 * Swiff.Uploader - Flash FileReference Control
|
rlm@3
|
3 *
|
rlm@3
|
4 * @version 3.0 rc1
|
rlm@3
|
5 *
|
rlm@3
|
6 * @license MIT License
|
rlm@3
|
7 *
|
rlm@3
|
8 * @author Harald Kirschner <mail [at] digitarald [dot] de>
|
rlm@3
|
9 * @copyright Authors
|
rlm@3
|
10 */
|
rlm@3
|
11
|
rlm@3
|
12 Swiff.Uploader = new Class({
|
rlm@3
|
13
|
rlm@3
|
14 Extends: Swiff,
|
rlm@3
|
15
|
rlm@3
|
16 Implements: Events,
|
rlm@3
|
17
|
rlm@3
|
18 options: {
|
rlm@3
|
19 path: 'Swiff.Uploader.swf',
|
rlm@3
|
20
|
rlm@3
|
21 target: null,
|
rlm@3
|
22 zIndex: 9999,
|
rlm@3
|
23
|
rlm@3
|
24 height: 30,
|
rlm@3
|
25 width: 100,
|
rlm@3
|
26 callBacks: null,
|
rlm@3
|
27 params: {
|
rlm@3
|
28 wMode: 'opaque',
|
rlm@3
|
29 menu: 'false',
|
rlm@3
|
30 allowScriptAccess: 'always'
|
rlm@3
|
31 },
|
rlm@3
|
32
|
rlm@3
|
33 typeFilter: null,
|
rlm@3
|
34 multiple: true,
|
rlm@3
|
35 queued: true,
|
rlm@3
|
36 verbose: false,
|
rlm@3
|
37
|
rlm@3
|
38 url: null,
|
rlm@3
|
39 method: null,
|
rlm@3
|
40 data: null,
|
rlm@3
|
41 mergeData: true,
|
rlm@3
|
42 fieldName: null,
|
rlm@3
|
43
|
rlm@3
|
44 fileSizeMin: 1,
|
rlm@3
|
45 fileSizeMax: null, // Official limit is 100 MB for FileReference!
|
rlm@3
|
46 allowDuplicates: false,
|
rlm@3
|
47
|
rlm@3
|
48 buttonImage: null,
|
rlm@3
|
49
|
rlm@3
|
50 fileListMax: 0,
|
rlm@3
|
51 fileListSizeMax: 0,
|
rlm@3
|
52
|
rlm@3
|
53 instantStart: false,
|
rlm@3
|
54 appendCookieData: false,
|
rlm@3
|
55
|
rlm@3
|
56 fileClass: null
|
rlm@3
|
57 /*
|
rlm@3
|
58 onLoad: $empty,
|
rlm@3
|
59 onFail: $empty,
|
rlm@3
|
60 onStart: $empty,
|
rlm@3
|
61 onQueue: $empty,
|
rlm@3
|
62 onComplete: $empty,
|
rlm@3
|
63 onBrowse: $empty,
|
rlm@3
|
64 onDisabledBrowse: $empty,
|
rlm@3
|
65 onCancel: $empty,
|
rlm@3
|
66 onSelect: $empty,
|
rlm@3
|
67 onSelectSuccess: $empty,
|
rlm@3
|
68 onSelectFail: $empty,
|
rlm@3
|
69
|
rlm@3
|
70 onButtonEnter: $empty,
|
rlm@3
|
71 onButtonLeave: $empty,
|
rlm@3
|
72 onButtonDown: $empty,
|
rlm@3
|
73 onButtonDisable: $empty,
|
rlm@3
|
74
|
rlm@3
|
75 onFileStart: $empty,
|
rlm@3
|
76 onFileStop: $empty,
|
rlm@3
|
77 onFileRequeue: $empty,
|
rlm@3
|
78 onFileOpen: $empty,
|
rlm@3
|
79 onFileProgress: $empty,
|
rlm@3
|
80 onFileComplete: $empty,
|
rlm@3
|
81 onFileRemove: $empty
|
rlm@3
|
82 */
|
rlm@3
|
83 },
|
rlm@3
|
84
|
rlm@3
|
85 initialize: function(options) {
|
rlm@3
|
86 // protected events to control the class, added
|
rlm@3
|
87 // before setting options (which adds own events)
|
rlm@3
|
88 this.addEvent('load', this.initializeSwiff, true)
|
rlm@3
|
89 .addEvent('select', this.processFiles, true)
|
rlm@3
|
90 .addEvent('complete', this.update, true)
|
rlm@3
|
91 .addEvent('fileRemove', function(file) {
|
rlm@3
|
92 this.fileList.erase(file);
|
rlm@3
|
93 }.bind(this), true);
|
rlm@3
|
94
|
rlm@3
|
95 this.setOptions(options);
|
rlm@3
|
96
|
rlm@3
|
97 // callbacks are no longer in the options, every callback
|
rlm@3
|
98 // is fired as event, this is just compat
|
rlm@3
|
99 if (this.options.callBacks) {
|
rlm@3
|
100 Hash.each(this.options.callBacks, function(fn, name) {
|
rlm@3
|
101 this.addEvent(name, fn);
|
rlm@3
|
102 }, this);
|
rlm@3
|
103 }
|
rlm@3
|
104
|
rlm@3
|
105 this.options.callBacks = {
|
rlm@3
|
106 fireCallback: this.fireCallback.bind(this)
|
rlm@3
|
107 };
|
rlm@3
|
108
|
rlm@3
|
109 var path = this.options.path;
|
rlm@3
|
110 if (!path.contains('?')) path += '?noCache=' + $time(); // cache in IE
|
rlm@3
|
111
|
rlm@3
|
112 // container options for Swiff class
|
rlm@3
|
113 this.options.container = this.box = new Element('span', {'class': 'swiff-uploader-box'}).inject($(this.options.container) || document.body);
|
rlm@3
|
114
|
rlm@3
|
115 // target
|
rlm@3
|
116 this.target = $(this.options.target);
|
rlm@3
|
117 if (this.target) {
|
rlm@3
|
118 var scroll = window.getScroll();
|
rlm@3
|
119 this.box.setStyles({
|
rlm@3
|
120 position: 'absolute',
|
rlm@3
|
121 visibility: 'visible',
|
rlm@3
|
122 zIndex: this.options.zIndex,
|
rlm@3
|
123 overflow: 'hidden',
|
rlm@3
|
124 height: 1, width: 1,
|
rlm@3
|
125 top: scroll.y, left: scroll.x
|
rlm@3
|
126 });
|
rlm@3
|
127
|
rlm@3
|
128 // we force wMode to transparent for the overlay effect
|
rlm@3
|
129 this.parent(path, {
|
rlm@3
|
130 params: {
|
rlm@3
|
131 wMode: 'transparent'
|
rlm@3
|
132 },
|
rlm@3
|
133 height: '100%',
|
rlm@3
|
134 width: '100%'
|
rlm@3
|
135 });
|
rlm@3
|
136
|
rlm@3
|
137 this.target.addEvent('mouseenter', this.reposition.bind(this, []));
|
rlm@3
|
138
|
rlm@3
|
139 // button interactions, relayed to to the target
|
rlm@3
|
140 this.addEvents({
|
rlm@3
|
141 buttonEnter: this.targetRelay.bind(this, ['mouseenter']),
|
rlm@3
|
142 buttonLeave: this.targetRelay.bind(this, ['mouseleave']),
|
rlm@3
|
143 buttonDown: this.targetRelay.bind(this, ['mousedown']),
|
rlm@3
|
144 buttonDisable: this.targetRelay.bind(this, ['disable'])
|
rlm@3
|
145 });
|
rlm@3
|
146
|
rlm@3
|
147 this.reposition();
|
rlm@3
|
148 window.addEvent('resize', this.reposition.bind(this, []));
|
rlm@3
|
149 } else {
|
rlm@3
|
150 this.parent(path);
|
rlm@3
|
151 }
|
rlm@3
|
152
|
rlm@3
|
153 this.inject(this.box);
|
rlm@3
|
154
|
rlm@3
|
155 this.fileList = [];
|
rlm@3
|
156
|
rlm@3
|
157 this.size = this.uploading = this.bytesLoaded = this.percentLoaded = 0;
|
rlm@3
|
158
|
rlm@3
|
159 if (Browser.Plugins.Flash.version < 9) {
|
rlm@3
|
160 this.fireEvent('fail', ['flash']);
|
rlm@3
|
161 } else {
|
rlm@3
|
162 this.verifyLoad.delay(500, this);
|
rlm@3
|
163 }
|
rlm@3
|
164 },
|
rlm@3
|
165
|
rlm@3
|
166 verifyLoad: function() {
|
rlm@3
|
167 if (this.loaded) return;
|
rlm@3
|
168 if (!this.object.parentNode) {
|
rlm@3
|
169 this.fireEvent('fail', ['disabled']);
|
rlm@3
|
170 } else if (this.object.style.display == 'none') {
|
rlm@3
|
171 this.fireEvent('fail', ['hidden']);
|
rlm@3
|
172 } else if (!this.object.offsetWidth) {
|
rlm@3
|
173 this.fireEvent('fail', ['empty']);
|
rlm@3
|
174 }
|
rlm@3
|
175 },
|
rlm@3
|
176
|
rlm@3
|
177 fireCallback: function(name, args) {
|
rlm@3
|
178 // file* callbacks are relayed to the specific file
|
rlm@3
|
179 if (name.substr(0, 4) == 'file') {
|
rlm@3
|
180 // updated queue data is the second argument
|
rlm@3
|
181 if (args.length > 1) this.update(args[1]);
|
rlm@3
|
182 var data = args[0];
|
rlm@3
|
183
|
rlm@3
|
184 var file = this.findFile(data.id);
|
rlm@3
|
185 this.fireEvent(name, file || data, 5);
|
rlm@3
|
186 if (file) {
|
rlm@3
|
187 var fire = name.replace(/^file([A-Z])/, function($0, $1) {
|
rlm@3
|
188 return $1.toLowerCase();
|
rlm@3
|
189 });
|
rlm@3
|
190 file.update(data).fireEvent(fire, [data], 10);
|
rlm@3
|
191 }
|
rlm@3
|
192 } else {
|
rlm@3
|
193 this.fireEvent(name, args, 5);
|
rlm@3
|
194 }
|
rlm@3
|
195 },
|
rlm@3
|
196
|
rlm@3
|
197 update: function(data) {
|
rlm@3
|
198 // the data is saved right to the instance
|
rlm@3
|
199 $extend(this, data);
|
rlm@3
|
200 this.fireEvent('queue', [this], 10);
|
rlm@3
|
201 return this;
|
rlm@3
|
202 },
|
rlm@3
|
203
|
rlm@3
|
204 findFile: function(id) {
|
rlm@3
|
205 for (var i = 0; i < this.fileList.length; i++) {
|
rlm@3
|
206 if (this.fileList[i].id == id) return this.fileList[i];
|
rlm@3
|
207 }
|
rlm@3
|
208 return null;
|
rlm@3
|
209 },
|
rlm@3
|
210
|
rlm@3
|
211 initializeSwiff: function() {
|
rlm@3
|
212 // extracted options for the swf
|
rlm@3
|
213 this.remote('initialize', {
|
rlm@3
|
214 width: this.options.width,
|
rlm@3
|
215 height: this.options.height,
|
rlm@3
|
216 typeFilter: this.options.typeFilter,
|
rlm@3
|
217 multiple: this.options.multiple,
|
rlm@3
|
218 queued: this.options.queued,
|
rlm@3
|
219 url: this.options.url,
|
rlm@3
|
220 method: this.options.method,
|
rlm@3
|
221 data: this.options.data,
|
rlm@3
|
222 mergeData: this.options.mergeData,
|
rlm@3
|
223 fieldName: this.options.fieldName,
|
rlm@3
|
224 verbose: this.options.verbose,
|
rlm@3
|
225 fileSizeMin: this.options.fileSizeMin,
|
rlm@3
|
226 fileSizeMax: this.options.fileSizeMax,
|
rlm@3
|
227 allowDuplicates: this.options.allowDuplicates,
|
rlm@3
|
228 buttonImage: this.options.buttonImage
|
rlm@3
|
229 });
|
rlm@3
|
230
|
rlm@3
|
231 this.loaded = true;
|
rlm@3
|
232
|
rlm@3
|
233 this.appendCookieData();
|
rlm@3
|
234 },
|
rlm@3
|
235
|
rlm@3
|
236 targetRelay: function(name) {
|
rlm@3
|
237 if (this.target) this.target.fireEvent(name);
|
rlm@3
|
238 },
|
rlm@3
|
239
|
rlm@3
|
240 reposition: function(coords) {
|
rlm@3
|
241 // update coordinates, manual or automatically
|
rlm@3
|
242 coords = coords || (this.target && this.target.offsetHeight)
|
rlm@3
|
243 ? this.target.getCoordinates(this.box.getOffsetParent())
|
rlm@3
|
244 : {top: window.getScrollTop(), left: 0, width: 40, height: 40}
|
rlm@3
|
245 this.box.setStyles(coords);
|
rlm@3
|
246 this.fireEvent('reposition', [coords, this.box, this.target]);
|
rlm@3
|
247 },
|
rlm@3
|
248
|
rlm@3
|
249 setOptions: function(options) {
|
rlm@3
|
250 if (options) {
|
rlm@3
|
251 if (options.url) options.url = Swiff.Uploader.qualifyPath(options.url);
|
rlm@3
|
252 if (options.buttonImage) options.buttonImage = Swiff.Uploader.qualifyPath(options.buttonImage);
|
rlm@3
|
253 this.parent(options);
|
rlm@3
|
254 if (this.loaded) this.remote('setOptions', options);
|
rlm@3
|
255 }
|
rlm@3
|
256 return this;
|
rlm@3
|
257 },
|
rlm@3
|
258
|
rlm@3
|
259 setEnabled: function(status) {
|
rlm@3
|
260 this.remote('setEnabled', status);
|
rlm@3
|
261 },
|
rlm@3
|
262
|
rlm@3
|
263 start: function() {
|
rlm@3
|
264 this.remote('start');
|
rlm@3
|
265 },
|
rlm@3
|
266
|
rlm@3
|
267 stop: function() {
|
rlm@3
|
268 this.remote('stop');
|
rlm@3
|
269 },
|
rlm@3
|
270
|
rlm@3
|
271 remove: function() {
|
rlm@3
|
272 this.remote('remove');
|
rlm@3
|
273 },
|
rlm@3
|
274
|
rlm@3
|
275 fileStart: function(file) {
|
rlm@3
|
276 this.remote('fileStart', file.id);
|
rlm@3
|
277 },
|
rlm@3
|
278
|
rlm@3
|
279 fileStop: function(file) {
|
rlm@3
|
280 this.remote('fileStop', file.id);
|
rlm@3
|
281 },
|
rlm@3
|
282
|
rlm@3
|
283 fileRemove: function(file) {
|
rlm@3
|
284 this.remote('fileRemove', file.id);
|
rlm@3
|
285 },
|
rlm@3
|
286
|
rlm@3
|
287 fileRequeue: function(file) {
|
rlm@3
|
288 this.remote('fileRequeue', file.id);
|
rlm@3
|
289 },
|
rlm@3
|
290
|
rlm@3
|
291 appendCookieData: function() {
|
rlm@3
|
292 var append = this.options.appendCookieData;
|
rlm@3
|
293 if (!append) return;
|
rlm@3
|
294
|
rlm@3
|
295 var hash = {};
|
rlm@3
|
296 document.cookie.split(/;\s*/).each(function(cookie) {
|
rlm@3
|
297 cookie = cookie.split('=');
|
rlm@3
|
298 if (cookie.length == 2) {
|
rlm@3
|
299 hash[decodeURIComponent(cookie[0])] = decodeURIComponent(cookie[1]);
|
rlm@3
|
300 }
|
rlm@3
|
301 });
|
rlm@3
|
302
|
rlm@3
|
303 var data = this.options.data || {};
|
rlm@3
|
304 if ($type(append) == 'string') data[append] = hash;
|
rlm@3
|
305 else $extend(data, hash);
|
rlm@3
|
306
|
rlm@3
|
307 this.setOptions({data: data});
|
rlm@3
|
308 },
|
rlm@3
|
309
|
rlm@3
|
310 processFiles: function(successraw, failraw, queue) {
|
rlm@3
|
311 var cls = this.options.fileClass || Swiff.Uploader.File;
|
rlm@3
|
312
|
rlm@3
|
313 var fail = [], success = [];
|
rlm@3
|
314
|
rlm@3
|
315 if (successraw) {
|
rlm@3
|
316 successraw.each(function(data) {
|
rlm@3
|
317 var ret = new cls(this, data);
|
rlm@3
|
318 if (!ret.validate()) {
|
rlm@3
|
319 ret.remove.delay(10, ret);
|
rlm@3
|
320 fail.push(ret);
|
rlm@3
|
321 } else {
|
rlm@3
|
322 this.size += data.size;
|
rlm@3
|
323 this.fileList.push(ret);
|
rlm@3
|
324 success.push(ret);
|
rlm@3
|
325 ret.render();
|
rlm@3
|
326 }
|
rlm@3
|
327 }, this);
|
rlm@3
|
328
|
rlm@3
|
329 this.fireEvent('selectSuccess', [success], 10);
|
rlm@3
|
330 }
|
rlm@3
|
331
|
rlm@3
|
332 if (failraw || fail.length) {
|
rlm@3
|
333 fail.extend((failraw) ? failraw.map(function(data) {
|
rlm@3
|
334 return new cls(this, data);
|
rlm@3
|
335 }, this) : []).each(function(file) {
|
rlm@3
|
336 file.invalidate().render();
|
rlm@3
|
337 });
|
rlm@3
|
338
|
rlm@3
|
339 this.fireEvent('selectFail', [fail], 10);
|
rlm@3
|
340 }
|
rlm@3
|
341
|
rlm@3
|
342 this.update(queue);
|
rlm@3
|
343
|
rlm@3
|
344 if (this.options.instantStart && success.length) this.start();
|
rlm@3
|
345 }
|
rlm@3
|
346
|
rlm@3
|
347 });
|
rlm@3
|
348
|
rlm@3
|
349 $extend(Swiff.Uploader, {
|
rlm@3
|
350
|
rlm@3
|
351 STATUS_QUEUED: 0,
|
rlm@3
|
352 STATUS_RUNNING: 1,
|
rlm@3
|
353 STATUS_ERROR: 2,
|
rlm@3
|
354 STATUS_COMPLETE: 3,
|
rlm@3
|
355 STATUS_STOPPED: 4,
|
rlm@3
|
356
|
rlm@3
|
357 log: function() {
|
rlm@3
|
358 if (window.console && console.info) console.info.apply(console, arguments);
|
rlm@3
|
359 },
|
rlm@3
|
360
|
rlm@3
|
361 unitLabels: {
|
rlm@3
|
362 b: [{min: 1, unit: 'B'}, {min: 1024, unit: 'kB'}, {min: 1048576, unit: 'MB'}, {min: 1073741824, unit: 'GB'}],
|
rlm@3
|
363 s: [{min: 1, unit: 's'}, {min: 60, unit: 'm'}, {min: 3600, unit: 'h'}, {min: 86400, unit: 'd'}]
|
rlm@3
|
364 },
|
rlm@3
|
365
|
rlm@3
|
366 formatUnit: function(base, type, join) {
|
rlm@3
|
367 var labels = Swiff.Uploader.unitLabels[(type == 'bps') ? 'b' : type];
|
rlm@3
|
368 var append = (type == 'bps') ? '/s' : '';
|
rlm@3
|
369 var i, l = labels.length, value;
|
rlm@3
|
370
|
rlm@3
|
371 if (base < 1) return '0 ' + labels[0].unit + append;
|
rlm@3
|
372
|
rlm@3
|
373 if (type == 's') {
|
rlm@3
|
374 var units = [];
|
rlm@3
|
375
|
rlm@3
|
376 for (i = l - 1; i >= 0; i--) {
|
rlm@3
|
377 value = Math.floor(base / labels[i].min);
|
rlm@3
|
378 if (value) {
|
rlm@3
|
379 units.push(value + ' ' + labels[i].unit);
|
rlm@3
|
380 base -= value * labels[i].min;
|
rlm@3
|
381 if (!base) break;
|
rlm@3
|
382 }
|
rlm@3
|
383 }
|
rlm@3
|
384
|
rlm@3
|
385 return (join === false) ? units : units.join(join || ', ');
|
rlm@3
|
386 }
|
rlm@3
|
387
|
rlm@3
|
388 for (i = l - 1; i >= 0; i--) {
|
rlm@3
|
389 value = labels[i].min;
|
rlm@3
|
390 if (base >= value) break;
|
rlm@3
|
391 }
|
rlm@3
|
392
|
rlm@3
|
393 return (base / value).toFixed(1) + ' ' + labels[i].unit + append;
|
rlm@3
|
394 }
|
rlm@3
|
395
|
rlm@3
|
396 });
|
rlm@3
|
397
|
rlm@3
|
398 Swiff.Uploader.qualifyPath = (function() {
|
rlm@3
|
399
|
rlm@3
|
400 var anchor;
|
rlm@3
|
401
|
rlm@3
|
402 return function(path) {
|
rlm@3
|
403 (anchor || (anchor = new Element('a'))).href = path;
|
rlm@3
|
404 return anchor.href;
|
rlm@3
|
405 };
|
rlm@3
|
406
|
rlm@3
|
407 })();
|
rlm@3
|
408
|
rlm@3
|
409 Swiff.Uploader.File = new Class({
|
rlm@3
|
410
|
rlm@3
|
411 Implements: Events,
|
rlm@3
|
412
|
rlm@3
|
413 initialize: function(base, data) {
|
rlm@3
|
414 this.base = base;
|
rlm@3
|
415 this.update(data);
|
rlm@3
|
416 },
|
rlm@3
|
417
|
rlm@3
|
418 update: function(data) {
|
rlm@3
|
419 return $extend(this, data);
|
rlm@3
|
420 },
|
rlm@3
|
421
|
rlm@3
|
422 validate: function() {
|
rlm@3
|
423 var options = this.base.options;
|
rlm@3
|
424
|
rlm@3
|
425 if (options.fileListMax && this.base.fileList.length >= options.fileListMax) {
|
rlm@3
|
426 this.validationError = 'fileListMax';
|
rlm@3
|
427 return false;
|
rlm@3
|
428 }
|
rlm@3
|
429
|
rlm@3
|
430 if (options.fileListSizeMax && (this.base.size + this.size) > options.fileListSizeMax) {
|
rlm@3
|
431 this.validationError = 'fileListSizeMax';
|
rlm@3
|
432 return false;
|
rlm@3
|
433 }
|
rlm@3
|
434
|
rlm@3
|
435 return true;
|
rlm@3
|
436 },
|
rlm@3
|
437
|
rlm@3
|
438 invalidate: function() {
|
rlm@3
|
439 this.invalid = true;
|
rlm@3
|
440 this.base.fireEvent('fileInvalid', this, 10);
|
rlm@3
|
441 return this.fireEvent('invalid', this, 10);
|
rlm@3
|
442 },
|
rlm@3
|
443
|
rlm@3
|
444 render: function() {
|
rlm@3
|
445 return this;
|
rlm@3
|
446 },
|
rlm@3
|
447
|
rlm@3
|
448 setOptions: function(options) {
|
rlm@3
|
449 if (options) {
|
rlm@3
|
450 if (options.url) options.url = Swiff.Uploader.qualifyPath(options.url);
|
rlm@3
|
451 this.base.remote('fileSetOptions', this.id, options);
|
rlm@3
|
452 this.options = $merge(this.options, options);
|
rlm@3
|
453 }
|
rlm@3
|
454 return this;
|
rlm@3
|
455 },
|
rlm@3
|
456
|
rlm@3
|
457 start: function() {
|
rlm@3
|
458 this.base.fileStart(this);
|
rlm@3
|
459 return this;
|
rlm@3
|
460 },
|
rlm@3
|
461
|
rlm@3
|
462 stop: function() {
|
rlm@3
|
463 this.base.fileStop(this);
|
rlm@3
|
464 return this;
|
rlm@3
|
465 },
|
rlm@3
|
466
|
rlm@3
|
467 remove: function() {
|
rlm@3
|
468 this.base.fileRemove(this);
|
rlm@3
|
469 return this;
|
rlm@3
|
470 },
|
rlm@3
|
471
|
rlm@3
|
472 requeue: function() {
|
rlm@3
|
473 this.base.fileRequeue(this);
|
rlm@3
|
474 }
|
rlm@3
|
475
|
rlm@3
|
476 });
|