mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	The first argument to the error callback is *usually* a string code from a list in the filedrop source; but sometimes it was the text the server sent in the HTTP status line, instead. The latter isn't predictable, and so it's not possible to write app code that uses it to handle error consistently. Instead, use that parameter for the numeric HTTP status code. This still isn't totally clean in that sometimes it's internal filedrop errors, as strings, and sometimes it's HTTP status codes, as numbers; but at least both of those are things we can sanely handle with a `switch` statement. Also pass through `serverResponse`, which for a nice JSON error from the server will contain meaningful information about the error which the calling code can use for nice error handling. And just drop the HTTP status text, which at best is redundant with the numeric code. In passing, fix one case where for no obvious reason filedrop was passing the file object but not the index. This should be a pure refactor.
		
			
				
	
	
		
			645 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			645 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*global jQuery:false, alert:false */
 | 
						|
 | 
						|
/** @preserve
 | 
						|
 Software from "jQuery Filedrop 0.1.0", a jQuery plugin for html5 dragging files,
 | 
						|
 is Copyright (c) Resopollution and is provided under the following license:
 | 
						|
 --
 | 
						|
 Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
 of this software and associated documentation files (the "Software"), to deal
 | 
						|
 in the Software without restriction, including without limitation the rights
 | 
						|
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
 copies of the Software, and to permit persons to whom the Software is
 | 
						|
 furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
 The above copyright notice and this permission notice shall be included in
 | 
						|
 all copies or substantial portions of the Software.
 | 
						|
 | 
						|
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						|
 THE SOFTWARE.
 | 
						|
 --
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
 * Default text - jQuery plugin for html5 dragging files from desktop to browser
 | 
						|
 *
 | 
						|
 * Author: Weixi Yen
 | 
						|
 *
 | 
						|
 * Email: [Firstname][Lastname]@gmail.com
 | 
						|
 *
 | 
						|
 * Copyright (c) 2010 Resopollution
 | 
						|
 *
 | 
						|
 * Licensed under the MIT license:
 | 
						|
 *   http://www.opensource.org/licenses/mit-license.php
 | 
						|
 *
 | 
						|
 * Project home:
 | 
						|
 *   http://www.github.com/weixiyen/jquery-filedrop
 | 
						|
 *
 | 
						|
 * Version:  0.1.0
 | 
						|
 *
 | 
						|
 * Features:
 | 
						|
 *      Allows sending of extra parameters with file.
 | 
						|
 *      Works with Firefox 3.6+
 | 
						|
 *      Future-compliant with HTML5 spec (will work with Webkit browsers and IE9)
 | 
						|
 * Usage:
 | 
						|
 *  See README at project homepage
 | 
						|
 *
 | 
						|
 */
 | 
						|
;(function($) {
 | 
						|
 | 
						|
  var default_opts = {
 | 
						|
      fallback_id: '',
 | 
						|
      url: '',
 | 
						|
      refresh: 1000,
 | 
						|
      paramname: 'userfile',
 | 
						|
      allowedfiletypes:[],
 | 
						|
      raw_droppable:[],
 | 
						|
      maxfiles: 25,           // Ignored if queuefiles is set > 0
 | 
						|
      maxfilesize: 1,         // MB file size limit
 | 
						|
      queuefiles: 0,          // Max files before queueing (for large volume uploads)
 | 
						|
      queuewait: 200,         // Queue wait time if full
 | 
						|
      data: {},
 | 
						|
      headers: {},
 | 
						|
      drop: empty,
 | 
						|
      rawDrop: empty,
 | 
						|
      dragStart: empty,
 | 
						|
      dragEnter: empty,
 | 
						|
      dragOver: empty,
 | 
						|
      dragLeave: empty,
 | 
						|
      docEnter: empty,
 | 
						|
      docOver: empty,
 | 
						|
      docLeave: empty,
 | 
						|
      beforeEach: empty,
 | 
						|
      afterAll: empty,
 | 
						|
      rename: empty,
 | 
						|
      error: function(err, response, file, i) {
 | 
						|
        alert(err);
 | 
						|
      },
 | 
						|
      uploadStarted: empty,
 | 
						|
      uploadFinished: empty,
 | 
						|
      progressUpdated: empty,
 | 
						|
      globalProgressUpdated: empty,
 | 
						|
      speedUpdated: empty
 | 
						|
      },
 | 
						|
      errors = ["BrowserNotSupported", "TooManyFiles", "FileTooLarge", "FileTypeNotAllowed", "NotFound", "NotReadable", "AbortError", "ReadError"],
 | 
						|
      doc_leave_timer, stop_loop = false,
 | 
						|
      files_count = 0,
 | 
						|
      files;
 | 
						|
 | 
						|
  $.fn.filedrop = function(options) {
 | 
						|
    var opts = $.extend({}, default_opts, options),
 | 
						|
        global_progress = []
 | 
						|
        // Zulip modification: keep a pointer to the object that the function
 | 
						|
        // was invoked on.
 | 
						|
        caller = this;
 | 
						|
 | 
						|
    this.on('drop', drop).on('dragstart', opts.dragStart).on('dragenter', dragEnter).on('dragover', dragOver).on('dragleave', dragLeave);
 | 
						|
    this.on('paste', paste);
 | 
						|
    this.on('imagedata-upload.zulip', uploadRawImageData);
 | 
						|
 | 
						|
    $(document).on('drop', docDrop).on('dragenter', docEnter).on('dragover', docOver).on('dragleave', docLeave);
 | 
						|
 | 
						|
    $('#' + opts.fallback_id).change(function(e) {
 | 
						|
      opts.drop(e);
 | 
						|
      files = e.target.files;
 | 
						|
      files_count = files.length;
 | 
						|
      upload();
 | 
						|
    });
 | 
						|
 | 
						|
    function drop(e) {
 | 
						|
      if (!e.originalEvent.dataTransfer) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      files = e.originalEvent.dataTransfer.files;
 | 
						|
 | 
						|
      function has_type(dom_stringlist, type) {
 | 
						|
        var j;
 | 
						|
        for (j = 0; j < dom_stringlist.length; j++) {
 | 
						|
          if (dom_stringlist[j] === type) {
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      if (files.length === 0) {
 | 
						|
        var i;
 | 
						|
        for (i = 0; i < opts.raw_droppable.length; i++) {
 | 
						|
          var type = opts.raw_droppable[i];
 | 
						|
          if (has_type(e.originalEvent.dataTransfer.types, type)) {
 | 
						|
            opts.rawDrop(e.originalEvent.dataTransfer.getData(type));
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if( opts.drop.call(this, e) === false ) return false;
 | 
						|
      if (files === null || files === undefined || files.length === 0) {
 | 
						|
        opts.error(errors[0]);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      files_count = files.length;
 | 
						|
      upload();
 | 
						|
      e.preventDefault();
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function sendRawImageData(event, image) {
 | 
						|
      function finished_callback(serverResponse, timeDiff, xhr) {
 | 
						|
        return opts.uploadFinished(-1, undefined, serverResponse, timeDiff, xhr);
 | 
						|
      }
 | 
						|
 | 
						|
      var url_params = "?mimetype=" + encodeURIComponent(image.type);
 | 
						|
      do_xhr("pasted_image", image.data, image.type, {}, url_params, finished_callback, function () {});
 | 
						|
    }
 | 
						|
 | 
						|
    function uploadRawImageData(event, image) {
 | 
						|
      // Call the user callback to initialize the drop event
 | 
						|
      if( opts.drop.call(this, undefined) === false ) return false;
 | 
						|
      sendRawImageData(event, image);
 | 
						|
    }
 | 
						|
 | 
						|
    function paste(event) {
 | 
						|
      if (event.originalEvent.clipboardData === undefined ||
 | 
						|
          event.originalEvent.clipboardData.items === undefined) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // Check if any of the items are strings, and if they are,
 | 
						|
      // then return, since we want the default browser behavior
 | 
						|
      // to deal with those.
 | 
						|
 | 
						|
      var itemsLength = event.originalEvent.clipboardData.items.length;
 | 
						|
 | 
						|
      for (var i = 0; i <  itemsLength; i++) {
 | 
						|
        if (event.originalEvent.clipboardData.items[i].kind === "string") {
 | 
						|
          return;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // Take the first image pasted in the clipboard
 | 
						|
      var match_re = /image.*/;
 | 
						|
      var item;
 | 
						|
      $.each(event.originalEvent.clipboardData.items, function (idx, this_event) {
 | 
						|
        if (this_event.type.match(match_re)) {
 | 
						|
          item = this_event;
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      });
 | 
						|
 | 
						|
      if (item === undefined) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // Call the user callback to initialize the drop event
 | 
						|
      if( opts.drop.call(this, event) === false ) return false;
 | 
						|
 | 
						|
      // Read the data of the drop in as binary data, and send it to the server
 | 
						|
      var data = item.getAsFile();
 | 
						|
      var reader = new FileReader();
 | 
						|
      reader.onload = function(event) {
 | 
						|
        sendRawImageData(event, {type: data.type, data: event.target.result});
 | 
						|
      };
 | 
						|
      reader.readAsBinaryString(data);
 | 
						|
    }
 | 
						|
 | 
						|
    function getBuilder(filename, filedata, mime, boundary) {
 | 
						|
      var dashdash = '--',
 | 
						|
          crlf = '\r\n',
 | 
						|
          builder = '';
 | 
						|
 | 
						|
      if (opts.data) {
 | 
						|
        var params = $.param(opts.data).replace(/\+/g, '%20').split(/&/);
 | 
						|
 | 
						|
        $.each(params, function() {
 | 
						|
          var pair = this.split("=", 2),
 | 
						|
              name = decodeURIComponent(pair[0]),
 | 
						|
              val  = decodeURIComponent(pair[1]);
 | 
						|
 | 
						|
          builder += dashdash;
 | 
						|
          builder += boundary;
 | 
						|
          builder += crlf;
 | 
						|
          builder += 'Content-Disposition: form-data; name="' + name + '"';
 | 
						|
          builder += crlf;
 | 
						|
          builder += crlf;
 | 
						|
          builder += val;
 | 
						|
          builder += crlf;
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      builder += dashdash;
 | 
						|
      builder += boundary;
 | 
						|
      builder += crlf;
 | 
						|
      builder += 'Content-Disposition: form-data; name="' + opts.paramname + '"';
 | 
						|
      builder += '; filename="' + encodeURIComponent(filename) + '"';
 | 
						|
      builder += crlf;
 | 
						|
 | 
						|
      builder += 'Content-Type: ' + mime;
 | 
						|
      builder += crlf;
 | 
						|
      builder += crlf;
 | 
						|
 | 
						|
      builder += filedata;
 | 
						|
      builder += crlf;
 | 
						|
 | 
						|
      builder += dashdash;
 | 
						|
      builder += boundary;
 | 
						|
      builder += dashdash;
 | 
						|
      builder += crlf;
 | 
						|
      return builder;
 | 
						|
    }
 | 
						|
 | 
						|
    function progress(e) {
 | 
						|
      if (e.lengthComputable) {
 | 
						|
        var percentage = Math.round((e.loaded * 100) / e.total);
 | 
						|
        if (this.currentProgress !== percentage) {
 | 
						|
 | 
						|
          this.currentProgress = percentage;
 | 
						|
          opts.progressUpdated(this.index, this.file, this.currentProgress);
 | 
						|
 | 
						|
          global_progress[this.global_progress_index] = this.currentProgress;
 | 
						|
          globalProgress();
 | 
						|
 | 
						|
          var elapsed = new Date().getTime();
 | 
						|
          var diffTime = elapsed - this.currentStart;
 | 
						|
          if (diffTime >= opts.refresh) {
 | 
						|
            var diffData = e.loaded - this.startData;
 | 
						|
            var speed = diffData / diffTime; // KB per second
 | 
						|
            opts.speedUpdated(this.index, this.file, speed);
 | 
						|
            this.startData = e.loaded;
 | 
						|
            this.currentStart = elapsed;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    function globalProgress() {
 | 
						|
      if (global_progress.length === 0) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      var total = 0, index;
 | 
						|
      for (index in global_progress) {
 | 
						|
        if(global_progress.hasOwnProperty(index)) {
 | 
						|
          total = total + global_progress[index];
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      opts.globalProgressUpdated(Math.round(total / global_progress.length));
 | 
						|
    }
 | 
						|
 | 
						|
    function do_xhr(filename, filedata, mime, upload_args, extra_url_args, finished_callback, on_error) {
 | 
						|
      var xhr                   = new XMLHttpRequest(),
 | 
						|
          start_time            = new Date().getTime(),
 | 
						|
          global_progress_index = global_progress.length,
 | 
						|
          boundary              = '------multipartformboundary' + (new Date()).getTime(),
 | 
						|
          upload                = xhr.upload;
 | 
						|
 | 
						|
      // Zulip modification: Shunt the XHR into the parent object so we
 | 
						|
      // can interrupt it later.
 | 
						|
      caller.data("filedrop_xhr", xhr);
 | 
						|
 | 
						|
      if (opts.withCredentials) {
 | 
						|
        xhr.withCredentials = opts.withCredentials;
 | 
						|
      }
 | 
						|
 | 
						|
      var builder = builder = getBuilder(filename, filedata, mime, boundary);
 | 
						|
 | 
						|
      upload = $.extend(upload, upload_args);
 | 
						|
      upload.downloadStartTime = start_time;
 | 
						|
      upload.currentStart = start_time;
 | 
						|
      upload.currentProgress = 0;
 | 
						|
      upload.global_progress_index = global_progress_index;
 | 
						|
      upload.startData = 0;
 | 
						|
      upload.addEventListener("progress", progress, false);
 | 
						|
 | 
						|
      // Allow url to be a method
 | 
						|
      if (jQuery.isFunction(opts.url)) {
 | 
						|
        xhr.open("POST", opts.url() + extra_url_args, true);
 | 
						|
      } else {
 | 
						|
        xhr.open("POST", opts.url + extra_url_args, true);
 | 
						|
      }
 | 
						|
 | 
						|
      xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary);
 | 
						|
 | 
						|
      // Add headers
 | 
						|
      $.each(opts.headers, function(k, v) {
 | 
						|
        xhr.setRequestHeader(k, v);
 | 
						|
      });
 | 
						|
 | 
						|
      xhr.sendAsBinary(builder);
 | 
						|
 | 
						|
      global_progress[global_progress_index] = 0;
 | 
						|
      globalProgress();
 | 
						|
 | 
						|
      xhr.onload = function() {
 | 
						|
        var serverResponse = null;
 | 
						|
 | 
						|
        if (xhr.responseText) {
 | 
						|
          try {
 | 
						|
            serverResponse = JSON.parse(xhr.responseText);
 | 
						|
          }
 | 
						|
          catch (e) {
 | 
						|
            serverResponse = xhr.responseText;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        var now = new Date().getTime(),
 | 
						|
            timeDiff = now - start_time,
 | 
						|
            result = finished_callback(serverResponse, timeDiff, xhr);
 | 
						|
 | 
						|
          // Make sure the global progress is updated
 | 
						|
          global_progress[global_progress_index] = 100;
 | 
						|
          globalProgress();
 | 
						|
 | 
						|
          if (result === false) {
 | 
						|
            stop_loop = true;
 | 
						|
          }
 | 
						|
 | 
						|
        // Pass any errors to the error option
 | 
						|
        if (xhr.status < 200 || xhr.status > 299) {
 | 
						|
          on_error(xhr.status, serverResponse);
 | 
						|
        }
 | 
						|
      };
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    // Respond to an upload
 | 
						|
    function upload() {
 | 
						|
      stop_loop = false;
 | 
						|
 | 
						|
      if (!files) {
 | 
						|
        opts.error(errors[0]);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      if (opts.allowedfiletypes.push && opts.allowedfiletypes.length) {
 | 
						|
        for(var fileIndex = files.length;fileIndex--;) {
 | 
						|
          if(!files[fileIndex].type || $.inArray(files[fileIndex].type, opts.allowedfiletypes) < 0) {
 | 
						|
            opts.error(errors[3], null, files[fileIndex], fileIndex);
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      var filesDone = 0,
 | 
						|
          filesRejected = 0;
 | 
						|
 | 
						|
      if (files_count > opts.maxfiles && opts.queuefiles === 0) {
 | 
						|
        opts.error(errors[1]);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      // Define queues to manage upload process
 | 
						|
      var workQueue = [];
 | 
						|
      var processingQueue = [];
 | 
						|
      var doneQueue = [];
 | 
						|
 | 
						|
      // Add everything to the workQueue
 | 
						|
      for (var i = 0; i < files_count; i++) {
 | 
						|
        workQueue.push(i);
 | 
						|
      }
 | 
						|
 | 
						|
      // Helper function to enable pause of processing to wait
 | 
						|
      // for in process queue to complete
 | 
						|
      var pause = function(timeout) {
 | 
						|
        setTimeout(process, timeout);
 | 
						|
        return;
 | 
						|
      };
 | 
						|
 | 
						|
      // Process an upload, recursive
 | 
						|
      var process = function() {
 | 
						|
 | 
						|
        var fileIndex;
 | 
						|
 | 
						|
        if (stop_loop) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Check to see if are in queue mode
 | 
						|
        if (opts.queuefiles > 0 && processingQueue.length >= opts.queuefiles) {
 | 
						|
          return pause(opts.queuewait);
 | 
						|
        } else {
 | 
						|
          // Take first thing off work queue
 | 
						|
          fileIndex = workQueue[0];
 | 
						|
          workQueue.splice(0, 1);
 | 
						|
 | 
						|
          // Add to processing queue
 | 
						|
          processingQueue.push(fileIndex);
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
          if (beforeEach(files[fileIndex]) !== false) {
 | 
						|
            if (fileIndex === files_count) {
 | 
						|
              return;
 | 
						|
            }
 | 
						|
            var reader = new FileReader(),
 | 
						|
                max_file_size = 1048576 * opts.maxfilesize;
 | 
						|
 | 
						|
            reader.index = fileIndex;
 | 
						|
            if (files[fileIndex].size > max_file_size) {
 | 
						|
              opts.error(errors[2], null, files[fileIndex], fileIndex);
 | 
						|
              // Remove from queue
 | 
						|
              processingQueue.forEach(function(value, key) {
 | 
						|
                if (value === fileIndex) {
 | 
						|
                  processingQueue.splice(key, 1);
 | 
						|
                }
 | 
						|
              });
 | 
						|
              filesRejected++;
 | 
						|
              return true;
 | 
						|
            }
 | 
						|
 | 
						|
            reader.onerror = function(e) {
 | 
						|
                switch(e.target.error.code) {
 | 
						|
                    case e.target.error.NOT_FOUND_ERR:
 | 
						|
                        opts.error(errors[4]);
 | 
						|
                        return false;
 | 
						|
                    case e.target.error.NOT_READABLE_ERR:
 | 
						|
                        opts.error(errors[5]);
 | 
						|
                        return false;
 | 
						|
                    case e.target.error.ABORT_ERR:
 | 
						|
                        opts.error(errors[6]);
 | 
						|
                        return false;
 | 
						|
                    default:
 | 
						|
                        opts.error(errors[7]);
 | 
						|
                        return false;
 | 
						|
                };
 | 
						|
            };
 | 
						|
 | 
						|
            reader.onloadend = !opts.beforeSend ? send : function (e) {
 | 
						|
              opts.beforeSend(files[fileIndex], fileIndex, function () { send(e); });
 | 
						|
            };
 | 
						|
 | 
						|
            reader.readAsBinaryString(files[fileIndex]);
 | 
						|
 | 
						|
          } else {
 | 
						|
            filesRejected++;
 | 
						|
          }
 | 
						|
        } catch (err) {
 | 
						|
          // Remove from queue
 | 
						|
          processingQueue.forEach(function(value, key) {
 | 
						|
            if (value === fileIndex) {
 | 
						|
              processingQueue.splice(key, 1);
 | 
						|
            }
 | 
						|
          });
 | 
						|
          opts.error(errors[0]);
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // If we still have work to do,
 | 
						|
        if (workQueue.length > 0) {
 | 
						|
          process();
 | 
						|
        }
 | 
						|
      };
 | 
						|
 | 
						|
      var send = function(e) {
 | 
						|
 | 
						|
        var fileIndex = ((typeof(e.srcElement) === "undefined") ? e.target : e.srcElement).index;
 | 
						|
 | 
						|
        // Sometimes the index is not attached to the
 | 
						|
        // event object. Find it by size. Hack for sure.
 | 
						|
        if (e.target.index === undefined) {
 | 
						|
          e.target.index = getIndexBySize(e.total);
 | 
						|
        }
 | 
						|
 | 
						|
        var file = files[e.target.index],
 | 
						|
            index = e.target.index;
 | 
						|
 | 
						|
        function finished_callback(serverResponse, timeDiff, xhr) {
 | 
						|
          filesDone++;
 | 
						|
          var result = opts.uploadFinished(index, file, serverResponse, timeDiff, xhr);
 | 
						|
 | 
						|
          if (filesDone === (files_count - filesRejected)) {
 | 
						|
            afterAll();
 | 
						|
          }
 | 
						|
 | 
						|
          // Remove from processing queue
 | 
						|
          processingQueue.forEach(function(value, key) {
 | 
						|
            if (value === fileIndex) {
 | 
						|
              processingQueue.splice(key, 1);
 | 
						|
            }
 | 
						|
          });
 | 
						|
 | 
						|
          // Add to donequeue
 | 
						|
          doneQueue.push(fileIndex);
 | 
						|
 | 
						|
          return result;
 | 
						|
        }
 | 
						|
 | 
						|
        function on_error(status_code, response) {
 | 
						|
          opts.error(status_code, response, file, fileIndex);
 | 
						|
        }
 | 
						|
 | 
						|
        var fileName,
 | 
						|
            fileData = e.target.result;
 | 
						|
        if (typeof newName === "string") {
 | 
						|
          fileName = newName;
 | 
						|
        } else {
 | 
						|
          fileName = file.name;
 | 
						|
        }
 | 
						|
 | 
						|
        var extra_opts = { file: files[e.target.index],
 | 
						|
                           index: e.target.index };
 | 
						|
 | 
						|
        do_xhr(fileName, fileData, file.type, extra_opts, "", finished_callback, on_error);
 | 
						|
 | 
						|
      };
 | 
						|
 | 
						|
      // Initiate the processing loop
 | 
						|
      process();
 | 
						|
    }
 | 
						|
 | 
						|
    function getIndexBySize(size) {
 | 
						|
      for (var i = 0; i < files_count; i++) {
 | 
						|
        if (files[i].size === size) {
 | 
						|
          return i;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      return undefined;
 | 
						|
    }
 | 
						|
 | 
						|
    function rename(name) {
 | 
						|
      return opts.rename(name);
 | 
						|
    }
 | 
						|
 | 
						|
    function beforeEach(file) {
 | 
						|
      return opts.beforeEach(file);
 | 
						|
    }
 | 
						|
 | 
						|
    function afterAll() {
 | 
						|
      return opts.afterAll();
 | 
						|
    }
 | 
						|
 | 
						|
    function dragEnter(e) {
 | 
						|
      clearTimeout(doc_leave_timer);
 | 
						|
      e.preventDefault();
 | 
						|
      opts.dragEnter.call(this, e);
 | 
						|
    }
 | 
						|
 | 
						|
    function dragOver(e) {
 | 
						|
      clearTimeout(doc_leave_timer);
 | 
						|
      e.preventDefault();
 | 
						|
      opts.docOver.call(this, e);
 | 
						|
      opts.dragOver.call(this, e);
 | 
						|
    }
 | 
						|
 | 
						|
    function dragLeave(e) {
 | 
						|
      clearTimeout(doc_leave_timer);
 | 
						|
      opts.dragLeave.call(this, e);
 | 
						|
      e.stopPropagation();
 | 
						|
    }
 | 
						|
 | 
						|
    function docDrop(e) {
 | 
						|
      e.preventDefault();
 | 
						|
      opts.docLeave.call(this, e);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function docEnter(e) {
 | 
						|
      clearTimeout(doc_leave_timer);
 | 
						|
      e.preventDefault();
 | 
						|
      opts.docEnter.call(this, e);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function docOver(e) {
 | 
						|
      clearTimeout(doc_leave_timer);
 | 
						|
      e.preventDefault();
 | 
						|
      opts.docOver.call(this, e);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function docLeave(e) {
 | 
						|
      doc_leave_timer = setTimeout((function(_this) {
 | 
						|
        return function() {
 | 
						|
          opts.docLeave.call(_this, e);
 | 
						|
        };
 | 
						|
      })(this), 200);
 | 
						|
    }
 | 
						|
 | 
						|
    return this;
 | 
						|
  };
 | 
						|
 | 
						|
  function empty() {}
 | 
						|
 | 
						|
  try {
 | 
						|
    if (XMLHttpRequest.prototype.sendAsBinary) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
 | 
						|
      function byteValue(x) {
 | 
						|
        return x.charCodeAt(0) & 0xff;
 | 
						|
      }
 | 
						|
      var ords = Array.prototype.map.call(datastr, byteValue);
 | 
						|
      var ui8a = new Uint8Array(ords);
 | 
						|
      this.send(ui8a.buffer);
 | 
						|
    };
 | 
						|
  } catch (e) {}
 | 
						|
 | 
						|
})(jQuery);
 |