fileuploaderextended.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. qq.extend(qq.FileUploader.prototype, {
  2. _createUploadHandler: function(){
  3. var self = this,
  4. handlerClass;
  5. if(qq.UploadHandlerXhr.isSupported()){
  6. handlerClass = 'UploadHandlerXhr';
  7. //handlerClass = 'UploadHandlerForm';
  8. } else {
  9. handlerClass = 'UploadHandlerForm';
  10. }
  11. var handler = new qq[handlerClass]({
  12. debug: this._options.debug,
  13. action: this._options.action,
  14. maxConnections: this._options.maxConnections,
  15. onProgress: function(id, fileName, loaded, total){
  16. self._onProgress(id, fileName, loaded, total);
  17. self._options.onProgress(id, fileName, loaded, total);
  18. },
  19. onComplete: function(id, fileName, result){
  20. self._onComplete(id, fileName, result);
  21. self._options.onComplete(id, fileName, result);
  22. },
  23. onCancel: function(id, fileName){
  24. self._onCancel(id, fileName);
  25. self._options.onCancel(id, fileName);
  26. },
  27. onUpload: function(){
  28. self._onUpload();
  29. }
  30. });
  31. return handler;
  32. },
  33. _onUpload: function(){
  34. this._handler.uploadAll(this._options.params);
  35. },
  36. _uploadFile: function(fileContainer){
  37. var id = this._handler.add(fileContainer);
  38. var fileName = this._handler.getName(id);
  39. if (this._options.onSubmit(id, fileName) !== false){
  40. this._onSubmit(id, fileName);
  41. }
  42. },
  43. _addToList: function(id, fileName){
  44. var item = qq.toElement(this._options.fileTemplate);
  45. item.qqFileId = id;
  46. var fileElement = this._find(item, 'file');
  47. qq.setText(fileElement, fileName);
  48. this._find(item, 'size').style.display = 'none';
  49. // name suggestion (simplified cleanID)
  50. var nameElement = this._find(item, 'nameInput');
  51. fileName = fileName.toLowerCase();
  52. fileName = fileName.replace(/([ !"#$%&\'()+,\/;<=>?@[\]^`{|}~:]+)/g, '_');
  53. fileName = fileName.replace(/^_+/,'');
  54. nameElement.value = fileName;
  55. nameElement.id = 'mediamanager__upload_item'+id;
  56. this._listElement.appendChild(item);
  57. }
  58. });
  59. qq.FileUploaderExtended = function(o){
  60. // call parent constructor
  61. qq.FileUploaderBasic.apply(this, arguments);
  62. qq.extend(this._options, {
  63. element: null,
  64. // if set, will be used instead of qq-upload-list in template
  65. listElement: null,
  66. template: '<div class="qq-uploader">' +
  67. '<div class="qq-upload-drop-area"><span>' + LANG.media_drop + '</span></div>' +
  68. '<div class="qq-upload-button">' + LANG.media_select + '</div>' +
  69. '<ul class="qq-upload-list"></ul>' +
  70. '<div class="qq-action-container">' +
  71. ' <button class="qq-upload-action" type="submit" id="mediamanager__upload_button">' + LANG.media_upload_btn + '</button>' +
  72. ' <label class="qq-overwrite-check"><input type="checkbox" value="1" name="ow" class="dw__ow"> <span>' + LANG.media_overwrt + '</span></label>' +
  73. '</div>' +
  74. '</div>',
  75. // template for one item in file list
  76. fileTemplate: '<li>' +
  77. '<span class="qq-upload-file hidden"></span>' +
  78. ' <input class="qq-upload-name-input edit" type="text" value="" />' +
  79. ' <span class="qq-upload-spinner hidden"></span>' +
  80. ' <span class="qq-upload-size"></span>' +
  81. ' <a class="qq-upload-cancel" href="#">' + LANG.media_cancel + '</a>' +
  82. ' <span class="qq-upload-failed-text error">Failed</span>' +
  83. '</li>',
  84. classes: {
  85. // used to get elements from templates
  86. button: 'qq-upload-button',
  87. drop: 'qq-upload-drop-area',
  88. dropActive: 'qq-upload-drop-area-active',
  89. list: 'qq-upload-list',
  90. nameInput: 'qq-upload-name-input',
  91. overwriteInput: 'qq-overwrite-check',
  92. uploadButton: 'qq-upload-action',
  93. file: 'qq-upload-file',
  94. spinner: 'qq-upload-spinner',
  95. size: 'qq-upload-size',
  96. cancel: 'qq-upload-cancel',
  97. // added to list item when upload completes
  98. // used in css to hide progress spinner
  99. success: 'qq-upload-success',
  100. fail: 'qq-upload-fail',
  101. failedText: 'qq-upload-failed-text'
  102. }
  103. });
  104. qq.extend(this._options, o);
  105. this._element = this._options.element;
  106. this._element.innerHTML = this._options.template;
  107. this._listElement = this._options.listElement || this._find(this._element, 'list');
  108. this._classes = this._options.classes;
  109. this._button = this._createUploadButton(this._find(this._element, 'button'));
  110. this._bindCancelEvent();
  111. this._bindUploadEvent();
  112. this._setupDragDrop();
  113. };
  114. qq.extend(qq.FileUploaderExtended.prototype, qq.FileUploader.prototype);
  115. qq.extend(qq.FileUploaderExtended.prototype, {
  116. _bindUploadEvent: function(){
  117. var self = this,
  118. list = this._listElement;
  119. qq.attach(document.getElementById('mediamanager__upload_button'), 'click', function(e){
  120. e = e || window.event;
  121. var target = e.target || e.srcElement;
  122. qq.preventDefault(e);
  123. self._handler._options.onUpload();
  124. jQuery(".qq-upload-name-input").each(function (i) {
  125. jQuery(this).prop('disabled', true);
  126. });
  127. });
  128. },
  129. _onComplete: function(id, fileName, result){
  130. this._filesInProgress--;
  131. // mark completed
  132. var item = this._getItemByFileId(id);
  133. qq.remove(this._find(item, 'cancel'));
  134. qq.remove(this._find(item, 'spinner'));
  135. var nameInput = this._find(item, 'nameInput');
  136. var fileElement = this._find(item, 'file');
  137. qq.setText(fileElement, nameInput.value);
  138. qq.removeClass(fileElement, 'hidden');
  139. qq.remove(nameInput);
  140. jQuery('.qq-upload-button, #mediamanager__upload_button').remove();
  141. jQuery('.dw__ow').parent().hide();
  142. jQuery('.qq-upload-drop-area').remove();
  143. if (result.success){
  144. qq.addClass(item, this._classes.success);
  145. $link = '<a href="' + result.link + '" id="h_:' + result.id + '" class="select">' + nameInput.value + '</a>';
  146. jQuery(fileElement).html($link);
  147. } else {
  148. qq.addClass(item, this._classes.fail);
  149. var fail = this._find(item, 'failedText');
  150. if (result.error) qq.setText(fail, result.error);
  151. }
  152. if (document.getElementById('media__content') && !document.getElementById('mediamanager__done_form')) {
  153. var action = document.location.href;
  154. var i = action.indexOf('?');
  155. if (i) action = action.substr(0, i);
  156. var button = '<form method="post" action="' + action + '" id="mediamanager__done_form"><div>';
  157. button += '<input type="hidden" value="' + result.ns + '" name="ns">';
  158. button += '<input type="hidden" value="1" name="recent">';
  159. button += '<button type="submit">' + LANG.media_done_btn + '</button></div></form>';
  160. jQuery('#mediamanager__uploader').append(button);
  161. }
  162. }
  163. });
  164. qq.extend(qq.UploadHandlerForm.prototype, {
  165. uploadAll: function(params){
  166. this._uploadAll(params);
  167. },
  168. getName: function(id){
  169. var file = this._inputs[id];
  170. var name = document.getElementById('mediamanager__upload_item'+id);
  171. if (name != null) {
  172. return name.value;
  173. } else {
  174. if (file != null) {
  175. // get input value and remove path to normalize
  176. return file.value.replace(/.*(\/|\\)/, "");
  177. } else {
  178. return null;
  179. }
  180. }
  181. },
  182. _uploadAll: function(params){
  183. jQuery(".qq-upload-spinner").each(function (i) {
  184. jQuery(this).removeClass('hidden');
  185. });
  186. for (key in this._inputs) {
  187. this.upload(key, params);
  188. }
  189. },
  190. _upload: function(id, params){
  191. var input = this._inputs[id];
  192. if (!input){
  193. throw new Error('file with passed id was not added, or already uploaded or cancelled');
  194. }
  195. var fileName = this.getName(id);
  196. var iframe = this._createIframe(id);
  197. var form = this._createForm(iframe, params);
  198. form.appendChild(input);
  199. var nameInput = qq.toElement('<input name="mediaid" value="' + fileName + '" type="text">');
  200. form.appendChild(nameInput);
  201. var checked = jQuery('.dw__ow').is(':checked');
  202. var owCheckbox = jQuery('.dw__ow').clone();
  203. owCheckbox.attr('checked', checked);
  204. jQuery(form).append(owCheckbox);
  205. var self = this;
  206. this._attachLoadEvent(iframe, function(){
  207. self.log('iframe loaded');
  208. var response = self._getIframeContentJSON(iframe);
  209. self._options.onComplete(id, fileName, response);
  210. self._dequeue(id);
  211. delete self._inputs[id];
  212. // timeout added to fix busy state in FF3.6
  213. setTimeout(function(){
  214. qq.remove(iframe);
  215. }, 1);
  216. });
  217. form.submit();
  218. qq.remove(form);
  219. return id;
  220. }
  221. });
  222. qq.extend(qq.UploadHandlerXhr.prototype, {
  223. uploadAll: function(params){
  224. this._uploadAll(params);
  225. },
  226. getName: function(id){
  227. var file = this._files[id];
  228. var name = document.getElementById('mediamanager__upload_item'+id);
  229. if (name != null) {
  230. return name.value;
  231. } else {
  232. if (file != null) {
  233. // fix missing name in Safari 4
  234. return file.fileName != null ? file.fileName : file.name;
  235. } else {
  236. return null;
  237. }
  238. }
  239. },
  240. getSize: function(id){
  241. var file = this._files[id];
  242. if (file == null) return null;
  243. return file.fileSize != null ? file.fileSize : file.size;
  244. },
  245. _upload: function(id, params){
  246. var file = this._files[id],
  247. name = this.getName(id),
  248. size = this.getSize(id);
  249. if (name == null || size == null) return;
  250. this._loaded[id] = 0;
  251. var xhr = this._xhrs[id] = new XMLHttpRequest();
  252. var self = this;
  253. xhr.upload.onprogress = function(e){
  254. if (e.lengthComputable){
  255. self._loaded[id] = e.loaded;
  256. self._options.onProgress(id, name, e.loaded, e.total);
  257. }
  258. };
  259. xhr.onreadystatechange = function(){
  260. if (xhr.readyState == 4){
  261. self._onComplete(id, xhr);
  262. }
  263. };
  264. // build query string
  265. params = params || {};
  266. params['qqfile'] = name;
  267. params['ow'] = jQuery('.dw__ow').is(':checked');
  268. var queryString = qq.obj2url(params, this._options.action);
  269. xhr.open("POST", queryString, true);
  270. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  271. xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
  272. xhr.setRequestHeader("Content-Type", "application/octet-stream");
  273. xhr.send(file);
  274. },
  275. _uploadAll: function(params){
  276. jQuery(".qq-upload-spinner").each(function (i) {
  277. jQuery(this).removeClass('hidden');
  278. });
  279. for (key in this._files) {
  280. this.upload(key, params);
  281. }
  282. }
  283. });