Dotclear

source: admin/js/jquery/jquery.candyUpload.js @ 3:cf375f1e7b0f

Revision 3:cf375f1e7b0f, 18.6 KB checked in by Dsls <dsls@…>, 14 years ago (diff)

Ported Franck & Kozlika updates for user prefs, dedicated branch

Line 
1(function($) {
2     // We need to create a global SWFUpload object to store instances
3     window.SWFUpload = {
4          instances: new Array(),
5          movieCount: 0,
6          version: "2.2.0 Beta 2",
7          QUEUE_ERROR: {
8               QUEUE_LIMIT_EXCEEDED:    -100,
9               FILE_EXCEEDS_SIZE_LIMIT: -110,
10               ZERO_BYTE_FILE:          -120,
11               INVALID_FILETYPE:        -130
12          },
13          UPLOAD_ERROR: {
14               HTTP_ERROR:                   -200,
15               MISSING_UPLOAD_URL:           -210,
16               IO_ERROR:                     -220,
17               SECURITY_ERROR:               -230,
18               UPLOAD_LIMIT_EXCEEDED:        -240,
19               UPLOAD_FAILED:                -250,
20               SPECIFIED_FILE_ID_NOT_FOUND:  -260,
21               FILE_VALIDATION_FAILED:       -270,
22               FILE_CANCELLED:               -280,
23               UPLOAD_STOPPED:               -290
24          },
25          FILE_STATUS: {
26               QUEUED:        -1,
27               IN_PROGRESS:   -2,
28               ERROR:         -3,
29               COMPLETE:      -4,
30               CANCELLED:     -5
31          },
32          BUTTON_ACTION: {
33               SELECT_FILE:   -100,
34               SELECT_FILES:  -110,
35               START_UPLOAD:  -120
36          },
37          CURSOR: {
38               ARROW:    -1,
39               HAND:     -2
40          },
41          WINDOW_MODE: {
42               WINDOW:        'window',
43               TRANSPARENT:   'transparent',
44               OPAQUE:        'opaque'
45          }
46     };
47     
48     $.uploader = function(settings,callbacks) {
49          return new $._uploader(settings,callbacks);
50     };
51     
52     $._uploader = function(settings,callbacks) {
53          var defaults = {
54               debug: false,
55               upload_url: '',
56               flash_movie: '',
57               movie_name: null,
58               params: null,
59               use_query_string: null,
60               requeue_on_error: false,
61               file_types: '*.*',
62               file_types_description: 'All files',
63               file_size_limit: 0,
64               file_upload_limit: 0,
65               file_queue_limit: -1,
66               target_element: null
67          };
68          this.params = $.extend(defaults,settings);
69         
70          var default_callbacks = {
71               flashReady: function() {},
72               fileDialogComplete: function() {},
73               fileDialogStart: function() {},
74               fileQueued: function() {},
75               fileQueueError: function() {},
76               uploadStart: function() {},
77               uploadProgress: function() {},
78               uploadError: function() {},
79               uploadSuccess: function() {},
80               uploadComplete: function() {},
81               debug: function() {}
82          };
83          this.callbacks = $.extend(default_callbacks,callbacks);
84         
85          return this.build();
86     };
87     
88     $._uploader.prototype = {
89          log: function(msg) {
90               if (!this.params.debug) { return; }
91               try {
92                    console.log(msg);
93               } catch(e) {}
94          },
95         
96          /* Constructor */
97          build: function(settings) {
98               if (!this.params.upload_url || !this.params.movie_name) {
99                    throw('Configuration error. Please make sure you specified movie_name and upload_url options.');
100               }
101               
102               if ($.browser.opera) {
103                    return this;
104               }
105               
106               // Get a real bytes size limit (if we want to reuse it somewhere)
107               this.params.file_size_limit = this.getFileSizeLimit(this.params.file_size_limit);
108               
109               // Flash vars
110               var fv = new Array();
111               this.addFlashVar(fv,'debugEnabled',this.params.debug);
112               this.addFlashVar(fv,'movieName',this.params.movie_name);
113               this.addFlashVar(fv,'uploadURL',this.params.upload_url);
114               this.addFlashVar(fv,'fileTypes',this.params.file_types);
115               this.addFlashVar(fv,'fileTypesDescription',this.params.file_types_description);
116               this.addFlashVar(fv,'params',this.params.params);
117               this.addFlashVar(fv,'fileSizeLimit',this.params.file_size_limit + 'b');
118               this.addFlashVar(fv,'fileUploadLimit',this.params.file_upload_limit);
119               this.addFlashVar(fv,'fileQueueLimit',this.params.file_queue_limit);
120               this.addFlashVar(fv,'requeueOnError',this.params.requeue_on_error);
121               this.addFlashVar(fv,'buttonImageURL','');
122               this.addFlashVar(fv,'buttonWidth',500);
123               this.addFlashVar(fv,'buttonHeight',500);
124               this.addFlashVar(fv,'buttonText','');
125               this.addFlashVar(fv,'buttonTextTopPadding',0);
126               this.addFlashVar(fv,'buttonTextLeftPadding',0);
127               this.addFlashVar(fv,'buttonTextStyle','');
128               this.addFlashVar(fv,'buttonAction',this.params.upload_limit == 1 ? -100 : -110);
129               this.addFlashVar(fv,'buttonDisabled',false);
130               this.addFlashVar(fv,'buttonCursor',-2);
131               this.addFlashVar(fv,'button_window_mode','window');
132               
133               // Create SWFUpload Instance
134               this.flashBind();
135               
136               // Flash object
137               var flash =
138               '<object id="' + this.params.movie_name + '" data="' + this.params.flash_movie + '" ' +
139               'type="application/x-shockwave-flash" width="10" height="10">' +
140               '<param name="movie" value="' + this.params.flash_movie + '" />'+
141               '<param name="wmode" value="transparent" />'+
142               '<param name="menu" value="false" />'+
143               '<param name="allowScriptAccess" value="always" />'+
144               '<param name="flashvars" value="' + fv.join('&amp;') + '" />'+
145               '</object>';
146               
147               // Flash container
148               this.container = $('<span></span>');
149               if (this.params.target_element == null) {
150                    this.container.css({
151                         display: 'block',
152                         position: 'absolute',
153                         left: $(document).scrollLeft()+'px',
154                         top: $(document).scrollTop()+'px',
155                         width: '30px',
156                         height: '30px',
157                         background: '#f00'
158                    });
159                   
160                    $('body').append(this.container);
161               } else {
162                    $(this.params.target_element).append(this.container);
163                    this.container.css({
164                         display: 'block',
165                         position: 'absolute',
166                         top: 0,
167                         left: 0,
168                         zIndex: 1
169                    });
170               }
171               this.container[0].innerHTML = flash;
172               this.movie = document.getElementById(this.params.movie_name);
173               
174               return this;
175          },
176         
177          addFlashVar: function(fv,n,v) {
178               if (v != null) {
179                    fv.push(n + '=' + encodeURIComponent(v));
180               }
181          },
182         
183          // Bind flash events to callbacks.events
184          flashBind: function() {
185               _this = this;
186               var events = {
187                    flashReady: function() {
188                         if (window[_this.params.movie_name] == undefined) {
189                              window[_this.params.movie_name] = _this.movie;
190                         }
191                         _this.flashBindEvent('flashReady',arguments);
192                    },
193                    fileDialogComplete: function() { _this.flashBindEvent('fileDialogComplete',arguments); },
194                    fileDialogStart: function() { _this.flashBindEvent('fileDialogStart',arguments); },
195                    fileQueued: function(file_object) { _this.flashBindEvent('fileQueued',arguments); },
196                    fileQueueError: function(file_object,error_code,error_msg) { _this.flashBindEvent('fileQueueError',arguments); },
197                    uploadStart: function() { _this.flashBindEvent('uploadStart',arguments); },
198                    uploadProgress: function() { _this.flashBindEvent('uploadProgress',arguments); },
199                    uploadError: function() { _this.flashBindEvent('uploadError',arguments); },
200                    uploadSuccess: function() { _this.flashBindEvent('uploadSuccess',arguments); },
201                    uploadComplete: function() { _this.flashBindEvent('uploadComplete',arguments); },
202                    debug: function() { _this.flashBindEvent('debug',arguments); }
203               };
204               window.SWFUpload.instances[this.params.movie_name] = events;
205               window.SWFUpload.movieCount++;
206          },
207         
208          // Each flash event is called as callbacks.events([arg],...) with this = uploader object
209          flashEventQueue: [],
210          flashBindEvent: function(evt,a) {
211               a = a || new Array();
212               
213               var _this = this;
214               if ($.isFunction(this.callbacks[evt])) {
215                    // Queue the event
216                    this.flashEventQueue.push(function () {
217                              this.callbacks[evt].apply(this,a);
218                    });
219                   
220                    // Execute the next queued event
221                    setTimeout(function () {
222                         _this.flashExecuteNextEvent();
223                    },0);
224               } else if (this.callbacks[evt] !== null) {
225                    throw 'Event handler ' + evt + ' is unknown or is not a function';
226               }
227
228          },
229          flashExecuteNextEvent: function() {
230               var f = this.flashEventQueue ? this.flashEventQueue.shift() : null;
231               if ($.isFunction(f)) {
232                    f.apply(this);
233               }
234          },
235         
236          destroy: function() {
237               try {
238                    this.StopUpload();
239                    $(this.movie).remove();
240                    SWFUpload.instances[this.params.movie_name] = null;
241                    SWFUpload.movieCount--;
242                    delete SWFUpload.instances[this.movieName];
243                    delete window[this.movieName];
244                   
245                    return true;
246               } catch(e) {
247                    return false;
248               }
249          },
250         
251          // Flash uploader functions
252          StartUpload: function(file_id) {
253               return this.movie.StartUpload(file_id);
254          },
255          ReturnUploadStart: function(value) {
256               return this.movie.ReturnUploadStart(value);
257          },
258          StopUpload: function() {
259               return this.movie.StopUpload();
260          },
261          CancelUpload: function(file_id) {
262               return this.movie.CancelUpload(file_id);
263          },
264          GetStats: function() {
265               return this.movie.GetStats();
266          },
267          SetStats: function(stats) {
268               return this.movie.SetStats(stats);
269          },
270          GetFile: function(file_id) {
271               return this.movie.GetFile(file_id);
272          },
273          GetFileByIndex: function(file_index) {
274               return this.movie.GetFileByIndex(file_index);
275          },
276         
277          // Size formater, that's better
278          getFileSizeLimit: function(size) {
279               var value = 0;
280               var unit = 'kb';
281               
282               size = $.trim(size.toLowerCase());
283               
284               var values = size.match(/^\d+/);
285               if (values != null && values.length > 0) {
286                    value = parseInt(values[0]);
287               }
288               
289               var units = size.match(/(b|kb|mb|gb)/);
290               if (units != null && units.length > 0) {
291                    unit = units[0];
292               }
293               
294               var multiplier = 1024;
295               if (unit === "b") {
296                    multiplier = 1;
297               } else if (unit === "mb") {
298                    multiplier = 1048576;
299               } else if (unit === "gb") {
300                    multiplier = 1073741824;
301               }
302               
303               return value * multiplier;
304          }
305     };
306})(jQuery);
307
308(function($) {
309     $.fn.candyUpload = function(settings,callbacks) {
310          new $._candyUpload(this,settings,callbacks);
311          return this;
312     };
313     
314     $._candyUpload = function(target,settings,callbacks) {
315          var defaults = {
316               debug: false,
317               upload_url: '',
318               params: null,
319               flash_movie: '',
320               file_types: '*.*',
321               file_types_description: 'All files',
322               file_size_limit: 0,
323               file_upload_limit: 0,
324               file_queue_limit: -1,
325               
326               callbacks: {} // Put here all callbacks you want, named as in $.uploader events
327          };
328          this.params = $.extend(defaults,settings);
329          this.params.movie_name = 'SWFU-' + (window.SWFUpload.instances.length + 1);
330          this.target = target;
331         
332          // Create controls
333          this.createControls();
334         
335          this.target.hide().after(this.ctrl.block).hide();
336          this.params.target_element = this.ctrl.btn_browse.parent().get(0);
337         
338          // Uploader init
339          var _this = this;
340          this.upldr = $.uploader(this.params,{
341               debug: function(msg) {
342                    $('body').append('<pre class="debug">' + msg + '</pre>');
343                    _this.bindEvent('debug',arguments);
344               },
345               flashReady: function() {
346                    _this.initControls(this);
347                    _this.bindEvent('flashReady',arguments);
348                   
349                    this.movie.style.width = _this.ctrl.btn_browse.width()+'px';
350                    this.movie.style.height = _this.ctrl.btn_browse.height()+'px';
351               },
352               fileDialogComplete: function(num_ref_files,num_queue_files) {
353                    _this.bindEvent('fileDialogComplete',arguments);
354               },
355               fileDialogStart: function() {
356                    _this.bindEvent('fileQueued',arguments);
357               },
358               fileQueued: function(o) {
359                    _this.appendFile(this,o);
360                    _this.refreshControls(this);
361                    _this.bindEvent('fileQueued',arguments);
362               },
363               fileQueueError: function(o,code,msg) {
364                    var codes = window.SWFUpload.QUEUE_ERROR;
365                    switch (code) {
366                         case codes.QUEUE_LIMIT_EXCEEDED:
367                              _this.queueErrorMsg(_this.locales.limit_exceeded);
368                              break;
369                         case codes.FILE_EXCEEDS_SIZE_LIMIT:
370                              _this.queueErrorMsg(_this.locales.size_limit_exceeded);
371                              break;
372                         case codes.ZERO_BYTE_FILE:
373                         case codes.INVALID_FILETYPE:
374                              _this.queueErrorMsg(msg);
375                              break;
376                    }
377                    _this.bindEvent('fileQueueError',arguments);
378               },
379               uploadStart: function() {
380                    this.ReturnUploadStart(true);
381                    _this.bindEvent('uploadStart',arguments);
382               },
383               uploadProgress: function(o,bytes,total) {
384                    _this.fileProgressBar(o.id,bytes,total);
385                    _this.bindEvent('uploadProgress',arguments);
386               },
387               uploadError: function(o,code,msg) {
388                    var codes = window.SWFUpload.UPLOAD_ERROR;
389                    switch (code) {
390                         case codes.FILE_CANCELLED:
391                              _this.fileErrorMsg(o.id,_this.locales.canceled);
392                              break;
393                         case codes.HTTP_ERROR:
394                              _this.fileErrorMsg(o.id,_this.locales.http_error + ' ' + msg);
395                              break;
396                         case codes.MISSING_UPLOAD_URL:
397                         case codes.IO_ERROR:
398                         case codes.SECURITY_ERROR:
399                         case codes.UPLOAD_LIMIT_EXCEEDED:
400                         case codes.UPLOAD_FAILED:
401                         case codes.SPECIFIED_FILE_ID_NOT_FOUND:
402                         case codes.FILE_VALIDATION_FAILED:
403                         case codes.FILE_CANCELLED:
404                         case codes.UPLOAD_STOPPED:
405                              _this.fileErrorMsg(o.id,_this.locales.error + ' ' + msg);
406                              break;
407                    }
408                    _this.refreshControls(this);
409                    _this.removeFileCancel(o);
410                    _this.bindEvent('uploadError',arguments);
411               },
412               uploadSuccess: function(o,data) {
413                    _this.fileProgressBar(o.id,1,1);
414                    _this.refreshControls(this);
415                    _this.removeFileCancel(o);
416                    _this.bindEvent('uploadSuccess',arguments);
417               },
418               uploadComplete: function(o) {
419                    // Once completed, start next queued upload
420                    this.StartUpload();
421                    _this.refreshControls(this);
422                    _this.bindEvent('uploadComplete',arguments);
423               }
424          });
425     };
426     
427     $._candyUpload.prototype = {
428          locales: {
429               max_file_size: 'Maximum file size allowed:',
430               limit_exceeded: 'Limit exceeded.',
431               size_limit_exceeded: 'File size exceeds allowed limit.',
432               canceled: 'Canceled.',
433               http_error: 'HTTP Error:',
434               error: 'Error:',
435               choose_file: 'Choose file',
436               choose_files: 'Choose files',
437               cancel: 'Cancel',
438               clean: 'Clean',
439               upload: 'Upload',
440               no_file_in_queue: 'No file in queue.',
441               file_in_queue: '1 file in queue.',
442               files_in_queue: '%d files in queue.',
443               queue_error: 'Queue error:'
444          },
445          ctrl: {
446               block: $('<div class="cu-ctrl"></div>'),
447               files: null
448          },
449         
450          createControls: function() {
451               this.ctrl.btn_browse = $('<a href="#" class="button">&nbsp;</a>').click(function() {
452                    return false;
453               });
454               
455               this.ctrl.btn_cancel = $('<a href="#" class="button">' + this.locales.cancel + '</a>').click(function() {
456                    return false;
457               });
458               
459               this.ctrl.btn_clean = $('<a href="#" class="button">' + this.locales.clean + '</a>').click(function() {
460                    return false;
461               });
462               
463               this.ctrl.btn_upload = $('<a href="#" class="button">' + this.locales.upload + '</a>').click(function() {
464                    return false;
465               });
466               
467               this.ctrl.msg = $('<div class="cu-msg">' + this.locales.no_file_in_queue + '</div>').appendTo(this.ctrl.block);
468               
469               var btn = $('<div class="cu-btn"></div>').appendTo(this.ctrl.block);
470               var brw = $('<span class="cu-btn-browse"></span>').append(this.ctrl.btn_browse).appendTo(btn);
471               $('<span class="cu-btn-upload"></span>').append(this.ctrl.btn_upload).appendTo(btn).hide();
472               $('<span class="cu-btn-cancel"></span>').append(this.ctrl.btn_cancel).appendTo(btn).hide();
473               $('<span class="cu-btn-clean"></span>').append(this.ctrl.btn_clean).appendTo(btn).hide();
474               
475               this.bindEvent('createControls');
476          },
477         
478          initControls: function(upldr) {
479               if (this.params.file_queue_limit == 1) {
480                    this.ctrl.btn_browse.text(this.locales.choose_file);
481               } else {
482                    this.ctrl.btn_browse.text(this.locales.choose_files);
483               }
484               
485               var _this = this;
486               
487               this.ctrl.btn_cancel.click(function() {
488                    _this.cancelQueue(upldr);
489                    return false;
490               });
491               
492               this.ctrl.btn_clean.click(function() {
493                    _this.cleanQueue(upldr);
494                    return false;
495               });
496               
497               this.ctrl.btn_upload.click(function() {
498                    _this.uploadQueue(upldr);
499                    return false;
500               });
501               
502               var size = this.formatSize(upldr.params.file_size_limit);
503               $('<div class="cu-maxsize">' + this.locales.max_file_size + ' ' + size + '</div>').appendTo(this.ctrl.block);
504          },
505         
506          refreshControls: function(upldr) {
507               if (!this.ctrl.files || this.ctrl.files.length == 0) {
508                    return;
509               }
510               
511               var stats = upldr.GetStats();
512               
513               if (stats.files_queued > 0) {
514                    this.ctrl.btn_cancel.parent().show();
515                    this.ctrl.btn_upload.parent().show();
516                    if (this.params.file_queue_limit > 0 && this.params.file_queue_limit == stats.files_queued) {
517                         this.ctrl.btn_browse.hide();
518                    } else {
519                         this.ctrl.btn_browse.show();
520                    }
521                    if (stats.files_queued > 1) {
522                         var msg = this.locales.files_in_queue.replace(/%d/,stats.files_queued);
523                    } else {
524                         var msg = this.locales.file_in_queue;
525                    }
526               } else {
527                    this.ctrl.btn_browse.show();
528                    this.ctrl.btn_cancel.parent().hide();
529                    this.ctrl.btn_upload.parent().hide();
530                    var msg = this.locales.no_file_in_queue;
531               }
532               
533               this.ctrl.msg.removeClass('cu-error').text(msg);
534               
535               if (stats.successful_uploads > 0 || stats.upload_errors > 0 || stats.upload_cancelled > 0) {
536                    this.ctrl.btn_clean.parent().show();
537               } else {
538                    this.ctrl.btn_clean.parent().hide();
539               }
540          },
541         
542          removeFileCancel: function(o) {
543               $('#' + o.id + ' span.cu-filecancel',this.ctrl.files).remove();
544          },
545         
546          appendFile: function(upldr,o) {
547               if (!this.ctrl.files) {
548                    this.ctrl.files = $('<div class="cu-files"></div>');
549                    this.ctrl.msg.after(this.ctrl.files);
550               }
551               
552               var fileblock = $('<div class="cu-file" id="' + o.id + '">' +
553                         '<div class="cu-fileinfo"><span class="cu-filename">' + o.name + '</span> ' + 
554                         '<span class="cu-filesize">(' + this.formatSize(o.size) + ')</span> ' +
555                         '<span class="cu-filecancel"><a href="#">cancel</a></span> ' +
556                         '<span class="cu-filemsg"></span>' +
557                         '</div>');
558               
559               $('span.cu-filecancel a',fileblock).click(function() {
560                    upldr.CancelUpload(o.id);
561                    return false;
562               });
563               this.ctrl.files.append(fileblock);
564          },
565         
566          fileProgressBar: function(file_id,bytes,total) {
567               var bar = $('#' + file_id + ' div.cu-progress>div',this.ctrl.files);
568               if (bar.length == 0) {
569                    $('#' + file_id,this.ctrl.files).append('<div class="cu-progress"><div>&nbsp;</div></div>');
570                    bar = $('#' + file_id + ' div.cu-progress>div',this.ctrl.files);
571               }
572               
573               var percent = Math.round((bytes * 100) / total);
574               bar.css('width',percent+'%').text(percent + '%');
575          },
576         
577          fileMsg: function(file_id,msg,error) {
578               error = error || false;
579               var span = $('#' + file_id + ' span.cu-filemsg',this.ctrl.files).attr('class','cu-filemsg');
580               if (error) {
581                    span.addClass('cu-error');
582               }
583               span.text(msg);
584          },
585         
586          fileErrorMsg: function(file_id,msg) {
587               this.fileMsg(file_id,msg,true);
588          },
589         
590          cancelQueue: function(upldr) {
591               if (!this.ctrl.files || this.ctrl.files.length == 0) {
592                    return;
593               }
594               
595               this.ctrl.files.children('div').each(function() {
596                    upldr.CancelUpload(this.id);
597               });
598          },
599         
600          uploadQueue: function(upldr) {
601               if (!this.ctrl.files || this.ctrl.files.length == 0) {
602                    return;
603               }
604               
605               upldr.StartUpload();
606          },
607         
608          cleanQueue: function(upldr) {
609               var _this = this;
610               var e = $('div.cu-file',this.ctrl.files).not(':has(span.cu-filecancel a)');
611               
612               e.filter(':last').slideUp(200,function() {
613                    $(this).remove();
614                    if (e.length == 1) {
615                         upldr.SetStats({successful_uploads:0, upload_errors:0, upload_cancelled:0});
616                         _this.refreshControls(upldr);
617                    } else if (e.length > 1) {
618                         _this.cleanQueue(upldr);
619                    }
620               });
621          },
622         
623          queueErrorMsg: function(msg) {
624               this.ctrl.msg.addClass('cu-error').text(this.locales.queue_error + ' ' + msg);
625          },
626         
627          formatSize: function(s) {
628               var a_size = Array('B', 'KB', 'MB', 'GB', 'TB');
629               var i_index = 0;
630               while (s > 1024) {
631                    i_index++;
632                    s/=1024;
633               }
634               return (Math.round(s * 100) /100) + ' ' + a_size[i_index];
635          },
636         
637          bindEvent: function(evt,a) {
638               if (this.params.callbacks[evt] != undefined && $.isFunction(this.params.callbacks[evt])) {
639                    a = a || new Array();
640                    this.params.callbacks[evt].apply(this,a);
641               }
642          }
643     };
644})(jQuery);
Note: See TracBrowser for help on using the repository browser.

Sites map