/pub/System/JQueryCompatibilityModePlugin/plugins/jquery.ajax_upload.src.js

https://github.com/foswiki/JQueryCompatibilityModePlugin · JavaScript · 299 lines · 181 code · 43 blank · 75 comment · 18 complexity · 35c98e958af85599dba36db53dbd3434 MD5 · raw file

  1. /**
  2. * Ajax upload plugin for jQuery
  3. * Project page - http://valums.com/ajax-upload/
  4. * Copyright (c) 2008 Andris Valums, http://valums.com
  5. * Licensed under the MIT license (http://valums.com/mit-license/)
  6. * Version 1.0 (24.01.2009)
  7. */
  8. (function($){
  9. // we need jQuery to run
  10. if ( ! $) return;
  11. /**
  12. * Function generates unique id
  13. */
  14. var get_uid = function(){
  15. var uid = 0;
  16. return function(){
  17. return uid++;
  18. }
  19. }();
  20. /**
  21. * button - jQuery element
  22. * option - hash of options :
  23. * action - URL which iframe will use to post data
  24. * name - file input name
  25. * data - extra data hash to post within the file
  26. * onSubmit - callback to fire on file submit
  27. * onComplete - callback to fire when iframe has finished loading
  28. */
  29. window.Ajax_upload = function(button, options){
  30. // make sure it is jquery object
  31. button = $(button);
  32. if (button.size() != 1 ){
  33. //You should pass only 1 element to ajax upload ot once
  34. return;
  35. }
  36. this.button = button;
  37. this.wrapper = null;
  38. this.form = null;
  39. this.input = null;
  40. this.iframe = null;
  41. this.disabled = false;
  42. this.submitting = false;
  43. this.settings = {
  44. // Location of the server-side upload script
  45. action: 'upload.php',
  46. // File upload name
  47. name: 'userfile',
  48. // Additional data to send
  49. data: {},
  50. // Callback to fire when user selects file
  51. // You can return false to cancel upload
  52. onSubmit: function(file, extension) {},
  53. // Fired when file upload is completed
  54. onComplete: function(file, response) {}
  55. };
  56. // Merge the users options with our defaults
  57. $.extend(this.settings, options);
  58. this.create_wrapper();
  59. this.create_input();
  60. if (jQuery.browser.msie){
  61. //fixes bug, which occur when you use div with transparent background as upload button
  62. this.make_parent_opaque();
  63. }
  64. this.create_iframe();
  65. }
  66. // assigning methods to our class
  67. Ajax_upload.prototype = {
  68. set_data : function(data){
  69. this.settings.data = data;
  70. },
  71. disable : function(){
  72. this.disabled = true;
  73. if ( ! this.submitting){
  74. this.input.attr('disabled', true);
  75. this.button.removeClass('ui-state-hover');
  76. }
  77. },
  78. enable : function(){
  79. this.disabled = false;
  80. this.input.attr('disabled', false);
  81. this.input.css('pointer', "cursor");
  82. },
  83. /**
  84. * Creates wrapper for button and invisible file input
  85. */
  86. create_wrapper : function(){
  87. // Shorten names
  88. var button = this.button, wrapper;
  89. wrapper = this.wrapper = $('<div></div>')
  90. .insertAfter(button)
  91. .append(button);
  92. // wait a bit because of FF bug
  93. // it can't properly calculate the outerHeight
  94. setTimeout(function(){
  95. wrapper.css({
  96. position: 'relative'
  97. ,display: 'block'
  98. ,overflow: 'hidden'
  99. // we need dimensions because of ie bug that allows to move
  100. // input outside even if overflow set to hidden
  101. ,height: button.outerHeight(true)
  102. ,width: button.outerWidth(true)
  103. });
  104. }, 1);
  105. var self = this;
  106. wrapper.mousemove(function(e){
  107. // Move the input with the mouse, so the user can't misclick it
  108. if (!self.input) {
  109. return;
  110. }
  111. self.input.css({
  112. top: e.pageY - wrapper.offset().top - 5 + 'px'
  113. ,left: e.pageX - wrapper.offset().left - 170 + 'px'
  114. });
  115. });
  116. },
  117. /**
  118. * Creates invisible file input above the button
  119. */
  120. create_input : function(){
  121. var self = this;
  122. this.input =
  123. $('<input type="file" />')
  124. .attr('name', this.settings.name)
  125. .css({
  126. 'position' : 'absolute'
  127. ,'margin': 0
  128. ,'padding': 0
  129. ,'width': '220px'
  130. ,'height': '10px'
  131. ,'opacity': 0
  132. , 'z-index' : 999
  133. , 'cursor': 'pointer'
  134. })
  135. .change(function(){
  136. if ($(this).val() == ''){
  137. // there is no file
  138. return;
  139. }
  140. // we need to lock "disable" method
  141. self.submitting = true;
  142. // Submit form when value is changed
  143. self.submit();
  144. if (self.disabled){
  145. self.disable();
  146. }
  147. // unlock "disable" method
  148. self.submitting = false;
  149. // clear input to allow user to select same file
  150. // Thanks to boston for fix
  151. $(this).val('');
  152. })
  153. .appendTo(this.wrapper)
  154. // Emulate button hover effect
  155. .hover(
  156. function(){self.button.addClass('ui-state-hover');}
  157. ,function(){self.button.removeClass('ui-state-hover');}
  158. );
  159. if (this.disabled){
  160. this.input.attr('disabled', true);
  161. }
  162. },
  163. /**
  164. * Creates iframe with unique name
  165. */
  166. create_iframe : function(){
  167. // unique name
  168. // We cannot use getTime, because it sometimes return
  169. // same value in safari :(
  170. var id = 'valums97hhu' + get_uid();
  171. // create iframe, so we dont need to refresh page
  172. this.iframe =
  173. $('<iframe id="' + id + '" name="' + id + '"></iframe>')
  174. .css('display', 'none')
  175. .appendTo('body');
  176. },
  177. /**
  178. * Upload file without refreshing the page
  179. */
  180. submit : function(){
  181. var self = this, settings = this.settings;
  182. // get filename from input
  183. var file = this.file_from_path(this.input.val());
  184. // execute user event
  185. if (settings.onSubmit.call(this, file, this.get_ext(file)) === false){
  186. // Do not continue if user function returns false
  187. return;
  188. }
  189. this.create_form();
  190. this.input.appendTo(this.form);
  191. this.form.submit();
  192. this.input.remove(); this.input = null;
  193. this.form.remove(); this.form = null;
  194. this.submitting = false;
  195. // create new input
  196. this.create_input();
  197. var iframe = this.iframe;
  198. iframe.load(function(){
  199. if (iframe[0].src == "about:blank"){
  200. return;
  201. }
  202. var response = iframe.contents().find('body').html();
  203. settings.onComplete.call(self, file, response);
  204. // Workaround for FF2 bug, which causes cursor to be in busy state after post.
  205. setTimeout(function(){
  206. // Workaround for ie6 bug, which causes progress bar to be in busy state after post.
  207. // Thanks to Lei for the fix
  208. iframe[0].src= "about:blank";
  209. iframe.remove();
  210. }, 1);
  211. });
  212. // Create new iframe, so we can have multiple uploads at once
  213. this.create_iframe();
  214. },
  215. /**
  216. * Creates form, that will be submitted to iframe
  217. */
  218. create_form : function(){
  219. // method, enctype must be specified here
  220. // because changing this attr on the fly is not allowed in IE 6/7
  221. this.form =
  222. $('<form method="post" enctype="multipart/form-data"></form>')
  223. .attr({
  224. "action" : this.settings.action
  225. ,"target" : this.iframe.attr('name')
  226. })
  227. .appendTo('body');
  228. // Create hidden input element for each data key
  229. for (var i in this.settings.data){
  230. $('<input type="hidden" />')
  231. .appendTo(this.form)
  232. .attr({
  233. 'name': i
  234. ,'value': this.settings.data[i]
  235. });
  236. }
  237. },
  238. file_from_path : function(file){
  239. return file.replace(/.*(\/|\\)/, "");
  240. },
  241. get_ext : function(file){
  242. return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
  243. },
  244. make_parent_opaque : function(){
  245. // ie transparent background bug
  246. this.button.add(this.button.parents()).each(function(){
  247. var color = $(this).css('backgroundColor');
  248. var image = $(this).css('backgroundImage');
  249. if ( color != 'transparent' || image != 'none'){
  250. $(this).css('opacity', 1);
  251. return false;
  252. }
  253. });
  254. }
  255. };
  256. })(jQuery);