jquery.FileReader.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. (function( $ ){
  2. var readyCallbacks = $.Callbacks('once unique memory'),
  3. inputsCount = 0,
  4. currentTarget = null;
  5. /**
  6. * JQuery Plugin
  7. */
  8. $.fn.fileReader = function( options ) {
  9. options = $.extend({
  10. id : 'fileReaderSWFObject', // ID for the created swf object container,
  11. multiple : null,
  12. accept : null,
  13. label : null,
  14. extensions : null,
  15. filereader : 'files/filereader.swf', // The path to the filereader swf file
  16. expressInstall : null, // The path to the express install swf file
  17. debugMode : false,
  18. callback : false // Callback function when Filereader is ready
  19. }, options);
  20. var self = this;
  21. readyCallbacks.add(function() {
  22. return main(self, options);
  23. });
  24. if ($.isFunction(options.callback)) readyCallbacks.add(options.callback);
  25. if (!FileAPIProxy.ready) {
  26. FileAPIProxy.init(options);
  27. }
  28. return this;
  29. };
  30. /**
  31. * Plugin callback
  32. * adds an input to registry
  33. */
  34. var main = function(el, options) {
  35. return el.each(function(i, input) {
  36. input = $(input);
  37. var id = input.attr('id');
  38. if (!id) {
  39. id = 'flashFileInput' + inputsCount;
  40. input.attr('id', id);
  41. inputsCount++;
  42. }
  43. options.multiple = !!(options.multiple === null ? input.attr('multiple') : options.multiple);
  44. options.accept = options.accept === null ? input.attr('accept') : options.multiple;
  45. FileAPIProxy.inputs[id] = input;
  46. FileAPIProxy.swfObject.add(id, options.multiple, options.accept, options.label, options.extensions);
  47. input.css('z-index', 0)
  48. .mouseover(function (e) {
  49. if (id !== currentTarget) {
  50. e = e || window.event;
  51. currentTarget = id;
  52. FileAPIProxy.swfObject.mouseover(id);
  53. FileAPIProxy.container
  54. .height(input.outerHeight())
  55. .width(input.outerWidth())
  56. .position({of:input});
  57. }
  58. })
  59. .click(function(e) {
  60. e.preventDefault();
  61. e.stopPropagation();
  62. e.stopImmediatePropagation();
  63. return false;
  64. });
  65. });
  66. };
  67. /**
  68. * Flash FileReader Proxy
  69. */
  70. window.FileAPIProxy = {
  71. ready: false,
  72. init: function(o) {
  73. var self = this;
  74. this.debugMode = o.debugMode;
  75. this.container = $('<div>').attr('id', o.id)
  76. .wrap('<div>')
  77. .parent()
  78. .css({
  79. // position:'absolute',
  80. // top:'0px',
  81. width:'1px',
  82. height:'1px',
  83. display:'inline-block',
  84. background:'transparent',
  85. 'z-index':99999
  86. })
  87. // Hands over mouse events to original input for css styles
  88. .on('mouseover mouseout mousedown mouseup', function(evt) {
  89. if(currentTarget) $('#' + currentTarget).trigger(evt.type);
  90. })
  91. .appendTo('body');
  92. swfobject.embedSWF(o.filereader, o.id, '100%', '100%', '10', o.expressInstall, {debugMode: o.debugMode ? true : ''}, {'wmode':'transparent','allowScriptAccess':'sameDomain'}, {}, function(e) {
  93. self.swfObject = e.ref;
  94. $(self.swfObject)
  95. .css({
  96. display: 'block',
  97. outline: 0
  98. })
  99. .attr('tabindex', 0);
  100. if (self.ready) {
  101. readyCallbacks.fire();
  102. }
  103. self.ready = e.success;
  104. });
  105. },
  106. swfObject: null,
  107. container: null,
  108. // Inputs Registry
  109. inputs: {},
  110. // Readers Registry
  111. readers: {},
  112. // Receives FileInput events
  113. onFileInputEvent: function(evt) {
  114. if (this.debugMode) console.info('FileInput Event ', evt.type, evt);
  115. if (evt.target in this.inputs) {
  116. var el = this.inputs[evt.target];
  117. evt.target = el[0];
  118. if( evt.type === 'change') {
  119. evt.files = new FileList(evt.files);
  120. evt.target = {files: evt.files};
  121. }
  122. el.trigger(evt);
  123. }
  124. window.focus();
  125. },
  126. // Receives FileReader ProgressEvents
  127. onFileReaderEvent: function(evt) {
  128. if (this.debugMode) console.info('FileReader Event ', evt.type, evt, evt.target in this.readers);
  129. if (evt.target in this.readers) {
  130. var reader = this.readers[evt.target];
  131. evt.target = reader;
  132. reader._handleFlashEvent.call(reader, evt);
  133. }
  134. },
  135. // Receives flash FileReader Error Events
  136. onFileReaderError: function(error) {
  137. if (this.debugMode) console.log(error);
  138. },
  139. onSWFReady: function() {
  140. if (this.ready) {
  141. readyCallbacks.fire();
  142. }
  143. this.ready = true;
  144. return true;
  145. }
  146. };
  147. /**
  148. * Add FileReader to the window object
  149. */
  150. window.FileReader = function () {
  151. // states
  152. this.EMPTY = 0;
  153. this.LOADING = 1;
  154. this.DONE = 2;
  155. this.readyState = 0;
  156. // File or Blob data
  157. this.result = null;
  158. this.error = null;
  159. // event handler attributes
  160. this.onloadstart = null;
  161. this.onprogress = null;
  162. this.onload = null;
  163. this.onabort = null;
  164. this.onerror = null;
  165. this.onloadend = null;
  166. // Event Listeners handling using JQuery Callbacks
  167. this._callbacks = {
  168. loadstart : $.Callbacks( "unique" ),
  169. progress : $.Callbacks( "unique" ),
  170. abort : $.Callbacks( "unique" ),
  171. error : $.Callbacks( "unique" ),
  172. load : $.Callbacks( "unique" ),
  173. loadend : $.Callbacks( "unique" )
  174. };
  175. // Custom properties
  176. this._id = null;
  177. };
  178. window.FileReader.prototype = {
  179. // async read methods
  180. readAsBinaryString: function (file) {
  181. this._start(file);
  182. FileAPIProxy.swfObject.read(file.input, file.name, 'readAsBinaryString');
  183. },
  184. readAsText: function (file, encoding) {
  185. this._start(file);
  186. FileAPIProxy.swfObject.read(file.input, file.name, 'readAsText');
  187. },
  188. readAsDataURL: function (file) {
  189. this._start(file);
  190. FileAPIProxy.swfObject.read(file.input, file.name, 'readAsDataURL');
  191. },
  192. readAsArrayBuffer: function(file){
  193. throw("Whoops FileReader.readAsArrayBuffer is unimplemented");
  194. },
  195. abort: function () {
  196. this.result = null;
  197. if (this.readyState === this.EMPTY || this.readyState === this.DONE) return;
  198. FileAPIProxy.swfObject.abort(this._id);
  199. },
  200. // Event Target interface
  201. addEventListener: function (type, listener) {
  202. if (type in this._callbacks) this._callbacks[type].add(listener);
  203. },
  204. removeEventListener: function (type, listener) {
  205. if (type in this._callbacks) this._callbacks[type].remove(listener);
  206. },
  207. dispatchEvent: function (event) {
  208. event.target = this;
  209. if (event.type in this._callbacks) {
  210. var fn = this['on' + event.type];
  211. if ($.isFunction(fn)) fn(event);
  212. this._callbacks[event.type].fire(event);
  213. }
  214. return true;
  215. },
  216. // Custom private methods
  217. // Registers FileReader instance for flash callbacks
  218. _register: function(file) {
  219. this._id = file.input + '.' + file.name;
  220. FileAPIProxy.readers[this._id] = this;
  221. },
  222. _start: function(file) {
  223. this._register(file);
  224. if (this.readyState === this.LOADING) throw {type: 'InvalidStateError', code: 11, message: 'The object is in an invalid state.'};
  225. },
  226. _handleFlashEvent: function(evt) {
  227. switch (evt.type) {
  228. case 'loadstart':
  229. this.readyState = this.LOADING;
  230. break;
  231. case 'loadend':
  232. this.readyState = this.DONE;
  233. break;
  234. case 'load':
  235. this.readyState = this.DONE;
  236. this.result = FileAPIProxy.swfObject.result(this._id);
  237. break;
  238. case 'error':
  239. this.result = null;
  240. this.error = {
  241. name: 'NotReadableError',
  242. message: 'The File cannot be read!'
  243. };
  244. }
  245. this.dispatchEvent(new FileReaderEvent(evt));
  246. }
  247. };
  248. /**
  249. * FileReader ProgressEvent implenting Event interface
  250. */
  251. FileReaderEvent = function (e) {
  252. this.initEvent(e);
  253. };
  254. FileReaderEvent.prototype = {
  255. initEvent: function (event) {
  256. $.extend(this, {
  257. type: null,
  258. target: null,
  259. currentTarget: null,
  260. eventPhase: 2,
  261. bubbles: false,
  262. cancelable: false,
  263. defaultPrevented: false,
  264. isTrusted: false,
  265. timeStamp: new Date().getTime()
  266. }, event);
  267. },
  268. stopPropagation: function (){
  269. },
  270. stopImmediatePropagation: function (){
  271. },
  272. preventDefault: function (){
  273. }
  274. };
  275. /**
  276. * FileList interface (Object with item function)
  277. */
  278. FileList = function(array) {
  279. if (array) {
  280. for (var i = 0; i < array.length; i++) {
  281. this[i] = array[i];
  282. }
  283. this.length = array.length;
  284. } else {
  285. this.length = 0;
  286. }
  287. };
  288. FileList.prototype = {
  289. item: function(index) {
  290. if (index in this) return this[index];
  291. return null;
  292. }
  293. };
  294. })( jQuery );