dropbox.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. function Dropbox(dropbox, url) {
  2. this.box = dropbox;
  3. this.url = url;
  4. this.queue = [];
  5. this.num_current_uploads = 0;
  6. // Add clickable file picker
  7. this.picker = document.createElement('input');
  8. this.picker.setAttribute('type', 'file');
  9. this.box.appendChild(this.picker);
  10. // Add progress bar container
  11. this.uploads = document.createElement('div');
  12. this.box.parentNode.insertBefore(this.uploads, this.box.nextSibling);
  13. // Optional defaults
  14. this.max_concurrent = 2; // Queue uploads after n concurrent
  15. this.max_size = null; // Max size in MB
  16. this.success = null; // Callback on successful upload, passed the response body
  17. this.error = null; // Callback on upload failure, passed the error text
  18. this.mime_types = null; // A regex to match file mime types
  19. var _this = this;
  20. // Init drag and drop handlers
  21. this.box.addEventListener("dragenter", function(e) { _this.drag(e, true) }, false);
  22. this.box.addEventListener("dragleave", function(e) { _this.drag(e, false) }, false);
  23. this.box.addEventListener("dragover", noop, false);
  24. this.box.addEventListener("drop", function(e) { _this.drop(e) }, false);
  25. this.picker.addEventListener("change", function(e) { _this.drop(e) })
  26. }
  27. Dropbox.prototype.drop = function(e) {
  28. this.drag(e, false);
  29. var files = (e.dataTransfer || e.target).files;
  30. for ( var i=0; i<files.length; i++ )
  31. this.handle_file(files[i]);
  32. }
  33. Dropbox.prototype.drag = function(e, active) {
  34. noop(e);
  35. this.box.className = active ? this.box.className += ' active' : this.box.className.replace(/ ?active/, '');
  36. }
  37. Dropbox.prototype.handle_file = function(file) {
  38. // Bad file type
  39. if ( this.mime_types && !file.type.match(this.mime_types) ) {
  40. alertify.error(file.name + ' is not an allowed file type');
  41. // Too large
  42. } else if ( this.max_size && (file.size / 1024 / 1024) > this.max_size ) {
  43. alertify.error(file.name + ' is too large; maximum is ' + this.max_size.toFixed(2) + ' MB');
  44. } else {
  45. file.label = this.add_label(file);
  46. // Enqueue it
  47. if ( this.max_concurrent > -1 && this.num_current_uploads >= this.max_concurrent )
  48. this.queue.push(file);
  49. // Upload it
  50. else this.process_file(file);
  51. }
  52. }
  53. Dropbox.prototype.process_file = function(file) {
  54. this.num_current_uploads += 1;
  55. var _this = this;
  56. var reader = new FileReader();
  57. reader.onload = function(e) {
  58. var file_contents = e.target.result.split(',')[1];
  59. _this.upload_file(file, file_contents);
  60. }
  61. reader.readAsDataURL(file);
  62. }
  63. Dropbox.prototype.upload_file = function(file, file_contents) {
  64. // Build form
  65. var data = new FormData();
  66. data.append('filename', file.name);
  67. data.append('mimetype', file.type);
  68. data.append('data', file_contents);
  69. data.append('size', file.size);
  70. var _this = this;
  71. var xhr = new XMLHttpRequest();
  72. // Update progress bar (if available)
  73. if ( xhr.upload ) xhr.upload.addEventListener('progress', function(e) { _this.handle_upload_progress(e, file.label) }, false)
  74. xhr.open('POST', this.url);
  75. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  76. xhr.onreadystatechange = function(e) {
  77. if ( xhr.readyState === 4 ) {
  78. // Success
  79. if (xhr.status === 200) {
  80. file.label.getElementsByClassName('percent')[0].innerHTML = '100%';
  81. if ( _this.success ) _this.success(file, xhr.responseText);
  82. // Error
  83. } else {
  84. file.label.getElementsByClassName('percent')[0].innerHTML = 'Error';
  85. if ( _this.error ) _this.error(file, xhr.statusText, xhr.responseText);
  86. }
  87. // Pop next upload off the queue
  88. _this.num_current_uploads -= 1;
  89. if ( _this.queue.length > 0 ) _this.process_file(_this.queue.shift())
  90. // Remove the label in 1 second
  91. setTimeout(function() { _this.uploads.removeChild(file.label) }, 1000);
  92. }
  93. }
  94. xhr.send(data)
  95. }
  96. Dropbox.prototype.handle_upload_progress = function(e, label) {
  97. if ( e.lengthComputable ) {
  98. var progress = label.getElementsByTagName('progress')[0];
  99. progress.setAttribute('value', e.loaded);
  100. progress.setAttribute('max', e.total);
  101. label.getElementsByClassName('percent')[0].innerHTML = ((e.loaded / e.total) * 100).toFixed(0) + '%';
  102. }
  103. }
  104. Dropbox.prototype.add_label = function(file) {
  105. var size = (file.size / 1024 / 1024).toFixed(2);
  106. var label = document.createElement('div');
  107. label.setAttribute('class', 'upload-progress');
  108. label.innerHTML = '<progress value="0" max="100"></progress> <span class="desc">' + file.name + ' - <span class="percent">0%</span> (' + size + ' MB)</span>';
  109. this.uploads.insertBefore(label, null);
  110. return label;
  111. }
  112. function noop(e) {
  113. e.stopPropagation();
  114. e.preventDefault();
  115. }