PageSourceSearch

https://www.adi-design.org/include/javascript/Swiff.Uploader.js

js adi-design.org collected 2026-10-02 02:54:06 UTC 11,774 bytes, 488 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.