Added javascript upload handler (work in progress)
authorMarcel Werk <burntime@woltlab.com>
Thu, 16 Feb 2012 19:07:54 +0000 (20:07 +0100)
committerMarcel Werk <burntime@woltlab.com>
Thu, 16 Feb 2012 19:07:54 +0000 (20:07 +0100)
wcfsetup/install/files/js/WCF.js

index 7b48e9245fe53c652687b5d2ea183836336345a3..e317eafe7e7eeddd4f15bd9cd39742493d3f8dd3 100644 (file)
@@ -3885,6 +3885,227 @@ WCF.InlineEditor = Class.extend({
        }
 });
 
+/**
+ * Default implementation for ajax file uploads
+ * 
+ * @param      jquery          buttonSelector
+ * @param      jquery          fileListSelector
+ * @param      string          className
+ * @param      jquery          options
+ */
+WCF.Upload = Class.extend({
+       /**
+        * name of the upload field
+        * @var string
+        */
+       _name: '__files[]',
+       
+       /**
+        * button selector
+        * @var jquery
+        */
+       _buttonSelector: null,
+       
+       /**
+        * file list selector
+        * @var jquery
+        */
+       _fileListSelector: null,
+       
+       /**
+        * upload file
+        * @var jquery
+        */
+       _fileUpload: null,
+       
+       /**
+        * class name
+        * @var string
+        */
+       _className: '',
+       
+       /**
+        * additional options
+        * @var jquery
+        */
+       _options: {},
+       
+       /**
+        * upload matrix
+        * @var array
+        */
+       _uploadMatrix: [],
+       
+       /**
+        * True, if your browser supports ajax file uploads. False, if your browser sucks.
+        * @var boolean
+        */
+       _supportsAJAXUpload: true,
+       
+       /**
+        * fallback overlay for stupid browsers
+        * @var jquery
+        */
+       _overlay: null,
+       
+       /**
+        * Initializes a new upload handler.
+        */
+       init: function(buttonSelector, fileListSelector, className, options) {
+               this._buttonSelector = buttonSelector;
+               this._fileListSelector = fileListSelector;
+               this._className = className;
+               this._options = $.extend(true, {
+                       action: 'upload',
+                       multiple: false,
+                       url: 'index.php/AJAXUpload/?t=' + SECURITY_TOKEN + SID_ARG_2ND
+               }, options);
+               
+               // check for ajax upload support
+               var $xhr = new XMLHttpRequest();
+               this._supportsAJAXUpload = ($xhr && ('upload' in $xhr) && ('onprogress' in $xhr.upload));
+               
+               // create upload button
+               this._createButton();
+       },
+       
+       /**
+        * Creates the upload button.
+        */
+       _createButton: function() {
+               if (this._supportsAJAXUpload) {
+                       this._fileUpload = $('<input type="file" name="'+this._name+'" style="opacity: 0" '+(this._options.multiple ? 'multiple="true" ' : '')+'/>');
+                       this._fileUpload.change($.proxy(this._upload, this));
+                       var $button = $('<p class="wcf-button" style="display: inline-block; position: relative; overflow: hidden; width: 100px"><span style="position: absolute; top: 0; left: 0">Upload</span></p>');
+                       $button.append(this._fileUpload);
+               }
+               else {
+                       var $button = $('<p class="wcf-button" style="display: inline-block;"><span>Upload</span></p>');
+                       $button.click($.proxy(this._showOverlay, this));
+               }
+               
+               this._insertButton($button);
+       },
+       
+       /**
+        * Inserts the upload button.
+        */
+       _insertButton: function(button) {
+               this._buttonSelector.append(button);
+       },
+       
+       /**
+        * Callback for file uploads.
+        */
+       _upload: function() {
+               var $files = this._fileUpload.prop('files');
+               
+               if ($files.length > 0) {
+                       var $fd = new FormData();
+                       var self = this;
+                       var $uploadID = this._uploadMatrix.length;
+                       this._uploadMatrix[$uploadID] = [];
+                       
+                       for (var $i = 0; $i < $files.length; $i++) {
+                               this._uploadMatrix[$uploadID].push(this._initFile($files[$i]));
+                               $fd.append('__files[]', $files[$i]);
+                       }
+                       $fd.append('actionName', this._options.action);
+                       $fd.append('className', this._className);
+                       
+                       $.ajax({ 
+                               type: 'POST',
+                               url: this._options.url,
+                               enctype: 'multipart/form-data',
+                               data: $fd,
+                               contentType: false,
+                               processData: false,
+                               success: $.proxy(this._success, this),
+                               error: $.proxy(this._error, this),
+                               xhr: function() {
+                                       var $xhr = $.ajaxSettings.xhr();
+                                       if ($xhr) {
+                                               $xhr.upload.addEventListener('progress', function(event) {
+                                                       self._progress(event, $uploadID);
+                                               }, false);
+                                       }
+                                       return $xhr;
+                               }
+                       });
+               }
+       },
+       
+       /**
+        * Callback for success event
+        */
+       _success: function(data, textStatus, jqXHR) {
+               console.debug(jqXHR.responseText);
+       },
+       
+       /**
+        * Callback for error event
+        */
+       _error: function(jqXHR, textStatus, errorThrown) {
+               console.debug(jqXHR.responseText);
+       },
+       
+       /**
+        * Callback for progress event
+        */
+       _progress: function(event, uploadID) {
+               var $percentComplete = Math.round(event.loaded * 100 / event.total);
+               
+               for (var $i = 0; $i < this._uploadMatrix[uploadID].length; $i++) {
+                       this._uploadMatrix[uploadID][$i].find('progress').attr('value', $percentComplete);
+               }
+       },
+       
+       
+       _initFile: function(file) {
+               var $li = $('<li>'+file.name+' ('+file.size+')<progress max="100"></progress></li>');
+               this._fileListSelector.append($li);
+               
+               return $li;
+       },
+       
+       /**
+        * Shows the fallback overlay (work in progress)
+        */
+       _showOverlay: function() {
+               var $self = this;
+               if (!this._overlay) {
+                       // create overlay
+                       this._overlay = $('<div style="display: none;"><form enctype="multipart/form-data" method="post" action="'+this._options.url+'"><dl><dt><label for="__fileUpload">File</label></dt><dd><input type="file" id="__fileUpload" name="'+this._name+'" '+(this._options.multiple ? 'multiple="true" ' : '')+'/></dd></dl><div class="wcf-formSubmit"><input type="submit" value="Upload" accesskey="s" /></div></form></div>');
+               }
+               
+               // create iframe
+               var $iframe = $('<iframe style="display: none"></iframe>'); // width: 300px; height: 100px; border: 5px solid red
+               $iframe.attr('name', $iframe.wcfIdentify());
+               $('body').append($iframe);
+               this._overlay.find('form').attr('target', $iframe.wcfIdentify());
+               
+               // add events (iframe onload)
+               $iframe.load(function() {
+                       console.debug('iframe ready');
+                       console.debug($iframe.contents());
+               });
+               
+               this._overlay.find('form').submit(function() {
+                       $iframe.data('loading', true);
+                       $self._overlay.wcfDialog('close');
+               });
+               
+               this._overlay.wcfDialog({
+                       title: 'Upload',
+                       onClose: function() {
+                               if (!$iframe.data('loading')) {
+                                       $iframe.remove();
+                               }
+                       }
+               });
+       }
+});
+
 /**
  * Provides a toggleable sidebar.
  */