图书馆智能管理系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
12 KiB

5 months ago
  1. /**!
  2. * AngularJS file upload/drop directive and service with progress and abort
  3. * FileAPI Flash shim for old browsers not supporting FormData
  4. * @author Danial <danial.farid@gmail.com>
  5. * @version 4.1.0
  6. */
  7. (function() {
  8. var hasFlash = function() {
  9. try {
  10. var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
  11. if (fo) return true;
  12. } catch(e) {
  13. if (navigator.mimeTypes['application/x-shockwave-flash'] != undefined) return true;
  14. }
  15. return false;
  16. }
  17. function patchXHR(fnName, newFn) {
  18. window.XMLHttpRequest.prototype[fnName] = newFn(window.XMLHttpRequest.prototype[fnName]);
  19. };
  20. if ((window.XMLHttpRequest && !window.FormData) || (window.FileAPI && FileAPI.forceLoad)) {
  21. var initializeUploadListener = function(xhr) {
  22. if (!xhr.__listeners) {
  23. if (!xhr.upload) xhr.upload = {};
  24. xhr.__listeners = [];
  25. var origAddEventListener = xhr.upload.addEventListener;
  26. xhr.upload.addEventListener = function(t, fn, b) {
  27. xhr.__listeners[t] = fn;
  28. origAddEventListener && origAddEventListener.apply(this, arguments);
  29. };
  30. }
  31. }
  32. patchXHR('open', function(orig) {
  33. return function(m, url, b) {
  34. initializeUploadListener(this);
  35. this.__url = url;
  36. try {
  37. orig.apply(this, [m, url, b]);
  38. } catch (e) {
  39. if (e.message.indexOf('Access is denied') > -1) {
  40. this.__origError = e;
  41. orig.apply(this, [m, '_fix_for_ie_crossdomain__', b]);
  42. }
  43. }
  44. }
  45. });
  46. patchXHR('getResponseHeader', function(orig) {
  47. return function(h) {
  48. return this.__fileApiXHR && this.__fileApiXHR.getResponseHeader ? this.__fileApiXHR.getResponseHeader(h) : (orig == null ? null : orig.apply(this, [h]));
  49. };
  50. });
  51. patchXHR('getAllResponseHeaders', function(orig) {
  52. return function() {
  53. return this.__fileApiXHR && this.__fileApiXHR.getAllResponseHeaders ? this.__fileApiXHR.getAllResponseHeaders() : (orig == null ? null : orig.apply(this));
  54. }
  55. });
  56. patchXHR('abort', function(orig) {
  57. return function() {
  58. return this.__fileApiXHR && this.__fileApiXHR.abort ? this.__fileApiXHR.abort() : (orig == null ? null : orig.apply(this));
  59. }
  60. });
  61. patchXHR('setRequestHeader', function(orig) {
  62. return function(header, value) {
  63. if (header === '__setXHR_') {
  64. initializeUploadListener(this);
  65. var val = value(this);
  66. // fix for angular < 1.2.0
  67. if (val instanceof Function) {
  68. val(this);
  69. }
  70. } else {
  71. this.__requestHeaders = this.__requestHeaders || {};
  72. this.__requestHeaders[header] = value;
  73. orig.apply(this, arguments);
  74. }
  75. }
  76. });
  77. function redefineProp(xhr, prop, fn) {
  78. try {
  79. Object.defineProperty(xhr, prop, {get: fn});
  80. } catch (e) {/*ignore*/}
  81. }
  82. patchXHR('send', function(orig) {
  83. return function() {
  84. var xhr = this;
  85. if (arguments[0] && arguments[0].__isFileAPIShim) {
  86. var formData = arguments[0];
  87. var config = {
  88. url: xhr.__url,
  89. jsonp: false, //removes the callback form param
  90. cache: true, //removes the ?fileapiXXX in the url
  91. complete: function(err, fileApiXHR) {
  92. xhr.__completed = true;
  93. if (!err && xhr.__listeners['load'])
  94. xhr.__listeners['load']({type: 'load', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
  95. if (!err && xhr.__listeners['loadend'])
  96. xhr.__listeners['loadend']({type: 'loadend', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
  97. if (err === 'abort' && xhr.__listeners['abort'])
  98. xhr.__listeners['abort']({type: 'abort', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
  99. if (fileApiXHR.status !== undefined) redefineProp(xhr, 'status', function() {return (fileApiXHR.status == 0 && err && err !== 'abort') ? 500 : fileApiXHR.status});
  100. if (fileApiXHR.statusText !== undefined) redefineProp(xhr, 'statusText', function() {return fileApiXHR.statusText});
  101. redefineProp(xhr, 'readyState', function() {return 4});
  102. if (fileApiXHR.response !== undefined) redefineProp(xhr, 'response', function() {return fileApiXHR.response});
  103. var resp = fileApiXHR.responseText || (err && fileApiXHR.status == 0 && err !== 'abort' ? err : undefined);
  104. redefineProp(xhr, 'responseText', function() {return resp});
  105. redefineProp(xhr, 'response', function() {return resp});
  106. if (err) redefineProp(xhr, 'err', function() {return err});
  107. xhr.__fileApiXHR = fileApiXHR;
  108. if (xhr.onreadystatechange) xhr.onreadystatechange();
  109. if (xhr.onload) xhr.onload();
  110. },
  111. fileprogress: function(e) {
  112. e.target = xhr;
  113. xhr.__listeners['progress'] && xhr.__listeners['progress'](e);
  114. xhr.__total = e.total;
  115. xhr.__loaded = e.loaded;
  116. if (e.total === e.loaded) {
  117. // fix flash issue that doesn't call complete if there is no response text from the server
  118. var _this = this
  119. setTimeout(function() {
  120. if (!xhr.__completed) {
  121. xhr.getAllResponseHeaders = function(){};
  122. _this.complete(null, {status: 204, statusText: 'No Content'});
  123. }
  124. }, FileAPI.noContentTimeout || 10000);
  125. }
  126. },
  127. headers: xhr.__requestHeaders
  128. }
  129. config.data = {};
  130. config.files = {}
  131. for (var i = 0; i < formData.data.length; i++) {
  132. var item = formData.data[i];
  133. if (item.val != null && item.val.name != null && item.val.size != null && item.val.type != null) {
  134. config.files[item.key] = item.val;
  135. } else {
  136. config.data[item.key] = item.val;
  137. }
  138. }
  139. setTimeout(function() {
  140. if (!hasFlash()) {
  141. throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
  142. }
  143. xhr.__fileApiXHR = FileAPI.upload(config);
  144. }, 1);
  145. } else {
  146. if (this.__origError) {
  147. throw this.__origError;
  148. }
  149. orig.apply(xhr, arguments);
  150. }
  151. }
  152. });
  153. window.XMLHttpRequest.__isFileAPIShim = true;
  154. function isInputTypeFile(elem) {
  155. return elem[0].tagName.toLowerCase() === 'input' && elem.attr('type') && elem.attr('type').toLowerCase() === 'file';
  156. }
  157. window.FormData = FormData = function() {
  158. return {
  159. append: function(key, val, name) {
  160. if (val.__isFileAPIBlobShim) {
  161. val = val.data[0];
  162. }
  163. this.data.push({
  164. key: key,
  165. val: val,
  166. name: name
  167. });
  168. },
  169. data: [],
  170. __isFileAPIShim: true
  171. };
  172. };
  173. window.Blob = Blob = function(b) {
  174. return {
  175. data: b,
  176. __isFileAPIBlobShim: true
  177. };
  178. };
  179. (function () {
  180. //load FileAPI
  181. if (!window.FileAPI) {
  182. window.FileAPI = {};
  183. }
  184. if (FileAPI.forceLoad) {
  185. FileAPI.html5 = false;
  186. }
  187. if (!FileAPI.upload) {
  188. var jsUrl, basePath, script = document.createElement('script'), allScripts = document.getElementsByTagName('script'), i, index, src;
  189. if (window.FileAPI.jsUrl) {
  190. jsUrl = window.FileAPI.jsUrl;
  191. } else if (window.FileAPI.jsPath) {
  192. basePath = window.FileAPI.jsPath;
  193. } else {
  194. for (i = 0; i < allScripts.length; i++) {
  195. src = allScripts[i].src;
  196. index = src.search(/\/ng\-file\-upload[\-a-zA-z0-9\.]*\.js/)
  197. if (index > -1) {
  198. basePath = src.substring(0, index + 1);
  199. break;
  200. }
  201. }
  202. }
  203. if (FileAPI.staticPath == null) FileAPI.staticPath = basePath;
  204. script.setAttribute('src', jsUrl || basePath + 'FileAPI.min.js');
  205. document.getElementsByTagName('head')[0].appendChild(script);
  206. FileAPI.hasFlash = hasFlash();
  207. }
  208. })();
  209. FileAPI.ngfFixIE = function(elem, createFileElemFn, bindAttr, changeFn, resetModel) {
  210. if (!hasFlash()) {
  211. throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
  212. }
  213. var makeFlashInput = function(evt) {
  214. if (elem.attr('disabled')) {
  215. elem.__ngf_elem__.removeClass('js-fileapi-wrapper');
  216. } else {
  217. var fileElem = elem.__ngf_elem__;
  218. if (!fileElem) {
  219. fileElem = elem.__ngf_elem__ = createFileElemFn();
  220. fileElem.addClass('js-fileapi-wrapper');
  221. if (!isInputTypeFile(elem)) {
  222. // if (fileElem.parent().css('position') === '' || fileElem.parent().css('position') === 'static') {
  223. // fileElem.parent().css('position', 'relative');
  224. // }
  225. // elem.parent()[0].insertBefore(fileElem[0], elem[0]);
  226. // elem.css('overflow', 'hidden');
  227. }
  228. setTimeout(function() {
  229. fileElem.bind('mouseenter', makeFlashInput);
  230. }, 10);
  231. fileElem.bind('change', function(evt) {
  232. fileApiChangeFn.apply(this, [evt]);
  233. changeFn.apply(this, [evt]);
  234. // alert('change' + evt);
  235. });
  236. } else {
  237. bindAttr(elem.__ngf_elem__);
  238. }
  239. if (!isInputTypeFile(elem)) {
  240. fileElem.css('position', 'absolute')
  241. .css('top', getOffset(elem[0]).top + 'px').css('left', getOffset(elem[0]).left + 'px')
  242. .css('width', elem[0].offsetWidth + 'px').css('height', elem[0].offsetHeight + 'px')
  243. .css('filter', 'alpha(opacity=0)').css('display', elem.css('display'))
  244. .css('overflow', 'hidden').css('z-index', '900000');
  245. }
  246. }
  247. function getOffset(obj) {
  248. var left, top;
  249. left = top = 0;
  250. if (obj.offsetParent) {
  251. do {
  252. left += obj.offsetLeft;
  253. top += obj.offsetTop;
  254. } while (obj = obj.offsetParent);
  255. }
  256. return {
  257. left : left,
  258. top : top
  259. };
  260. };
  261. };
  262. elem.bind('mouseenter', makeFlashInput);
  263. var fileApiChangeFn = function(evt) {
  264. var files = FileAPI.getFiles(evt);
  265. //just a double check for #233
  266. for (var i = 0; i < files.length; i++) {
  267. if (files[i].size === undefined) files[i].size = 0;
  268. if (files[i].name === undefined) files[i].name = 'file';
  269. if (files[i].type === undefined) files[i].type = 'undefined';
  270. }
  271. if (!evt.target) {
  272. evt.target = {};
  273. }
  274. evt.target.files = files;
  275. // if evt.target.files is not writable use helper field
  276. if (evt.target.files != files) {
  277. evt.__files_ = files;
  278. }
  279. (evt.__files_ || evt.target.files).item = function(i) {
  280. return (evt.__files_ || evt.target.files)[i] || null;
  281. };
  282. };
  283. };
  284. FileAPI.disableFileInput = function(elem, disable) {
  285. if (disable) {
  286. elem.removeClass('js-fileapi-wrapper')
  287. } else {
  288. elem.addClass('js-fileapi-wrapper');
  289. }
  290. };
  291. }
  292. if (!window.FileReader) {
  293. window.FileReader = function() {
  294. var _this = this, loadStarted = false;
  295. this.listeners = {};
  296. this.addEventListener = function(type, fn) {
  297. _this.listeners[type] = _this.listeners[type] || [];
  298. _this.listeners[type].push(fn);
  299. };
  300. this.removeEventListener = function(type, fn) {
  301. _this.listeners[type] && _this.listeners[type].splice(_this.listeners[type].indexOf(fn), 1);
  302. };
  303. this.dispatchEvent = function(evt) {
  304. var list = _this.listeners[evt.type];
  305. if (list) {
  306. for (var i = 0; i < list.length; i++) {
  307. list[i].call(_this, evt);
  308. }
  309. }
  310. };
  311. this.onabort = this.onerror = this.onload = this.onloadstart = this.onloadend = this.onprogress = null;
  312. var constructEvent = function(type, evt) {
  313. var e = {type: type, target: _this, loaded: evt.loaded, total: evt.total, error: evt.error};
  314. if (evt.result != null) e.target.result = evt.result;
  315. return e;
  316. };
  317. var listener = function(evt) {
  318. if (!loadStarted) {
  319. loadStarted = true;
  320. _this.onloadstart && _this.onloadstart(constructEvent('loadstart', evt));
  321. }
  322. if (evt.type === 'load') {
  323. _this.onloadend && _this.onloadend(constructEvent('loadend', evt));
  324. var e = constructEvent('load', evt);
  325. _this.onload && _this.onload(e);
  326. _this.dispatchEvent(e);
  327. } else if (evt.type === 'progress') {
  328. var e = constructEvent('progress', evt);
  329. _this.onprogress && _this.onprogress(e);
  330. _this.dispatchEvent(e);
  331. } else {
  332. var e = constructEvent('error', evt);
  333. _this.onerror && _this.onerror(e);
  334. _this.dispatchEvent(e);
  335. }
  336. };
  337. this.readAsArrayBuffer = function(file) {
  338. FileAPI.readAsBinaryString(file, listener);
  339. }
  340. this.readAsBinaryString = function(file) {
  341. FileAPI.readAsBinaryString(file, listener);
  342. }
  343. this.readAsDataURL = function(file) {
  344. FileAPI.readAsDataURL(file, listener);
  345. }
  346. this.readAsText = function(file) {
  347. FileAPI.readAsText(file, listener);
  348. }
  349. }
  350. }
  351. })();