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