require-upload.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. define(['jquery', 'bootstrap', 'plupload', 'template'], function ($, undefined, Plupload, Template) {
  2. var Upload = {
  3. list: {},
  4. config: {
  5. container: document.body,
  6. classname: '.plupload:not([initialized])',
  7. previewtpl: '<li class="col-xs-3"><a href="<%=fullurl%>" data-url="<%=url%>" target="_blank" class="thumbnail"><img src="<%=fullurl%>" onerror="this.src=\'' + Fast.api.fixurl("ajax/icon") + '?suffix=<%=suffix%>\';this.onerror=null;" class="img-responsive"></a><a href="javascript:;" class="btn btn-danger btn-xs btn-trash"><i class="fa fa-trash"></i></a></li>',
  8. },
  9. events: {
  10. onInit: function (up) {
  11. //修复少数安卓浏览器无法上传图片的Bug
  12. var input = $("input[type=file]", up.settings.container);
  13. if (input && input.prop("accept") && input.prop("accept").match(/image\//)) {
  14. input.prop("accept", "image/jpg," + input.prop("accept"));
  15. }
  16. },
  17. //初始化完成
  18. onPostInit: function (up) {
  19. },
  20. //文件添加成功后
  21. onFileAdded: function (up, files) {
  22. var button = up.settings.button;
  23. $(button).data("bakup-html", $(button).html());
  24. var maxcount = $(button).data("maxcount");
  25. var input_id = $(button).data("input-id") ? $(button).data("input-id") : "";
  26. maxcount = typeof maxcount !== "undefined" ? maxcount : 0;
  27. if (maxcount > 0 && input_id) {
  28. var inputObj = $("#" + input_id);
  29. if (inputObj.size() > 0) {
  30. var value = $.trim(inputObj.val());
  31. var nums = value === '' ? 0 : value.split(/\,/).length;
  32. var remains = maxcount - nums;
  33. if (files.length > remains) {
  34. for (var i = 0; i < files.length; i++) {
  35. up.removeFile(files[i]);
  36. }
  37. Toastr.error(__('You can upload up to %d file%s', remains));
  38. return false;
  39. }
  40. }
  41. }
  42. //添加后立即上传
  43. setTimeout(function () {
  44. up.start();
  45. }, 1);
  46. },
  47. //上传进行中的回调
  48. onUploadProgress: function (up, file) {
  49. },
  50. //上传之前的回调
  51. onBeforeUpload: function (up, file) {
  52. },
  53. //上传成功的回调
  54. onUploadSuccess: function (up, ret) {
  55. var button = up.settings.button;
  56. var onUploadSuccess = up.settings.onUploadSuccess;
  57. var data = typeof ret.data !== 'undefined' ? ret.data : null;
  58. //上传成功后回调
  59. if (button) {
  60. //如果有文本框则填充
  61. var input_id = $(button).data("input-id") ? $(button).data("input-id") : "";
  62. if (input_id) {
  63. var urlArr = [];
  64. var inputObj = $("#" + input_id);
  65. if ($(button).data("multiple") && inputObj.val() !== "") {
  66. urlArr.push(inputObj.val());
  67. }
  68. urlArr.push(data.url);
  69. inputObj.val(urlArr.join(",")).trigger("change").trigger("validate");
  70. }
  71. //如果有回调函数
  72. var onDomUploadSuccess = $(button).data("upload-success");
  73. if (onDomUploadSuccess) {
  74. if (typeof onDomUploadSuccess !== 'function' && typeof Upload.api.custom[onDomUploadSuccess] === 'function') {
  75. onDomUploadSuccess = Upload.api.custom[onDomUploadSuccess];
  76. }
  77. if (typeof onDomUploadSuccess === 'function') {
  78. var result = onDomUploadSuccess.call(button, data, ret);
  79. if (result === false)
  80. return;
  81. }
  82. }
  83. }
  84. if (typeof onUploadSuccess === 'function') {
  85. var result = onUploadSuccess.call(button, data, ret);
  86. if (result === false)
  87. return;
  88. }
  89. },
  90. //上传错误的回调
  91. onUploadError: function (up, ret) {
  92. var button = up.settings.button;
  93. var onUploadError = up.settings.onUploadError;
  94. var data = typeof ret.data !== 'undefined' ? ret.data : null;
  95. if (button) {
  96. var onDomUploadError = $(button).data("upload-error");
  97. if (onDomUploadError) {
  98. if (typeof onDomUploadError !== 'function' && typeof Upload.api.custom[onDomUploadError] === 'function') {
  99. onDomUploadError = Upload.api.custom[onDomUploadError];
  100. }
  101. if (typeof onDomUploadError === 'function') {
  102. var result = onDomUploadError.call(button, data, ret);
  103. if (result === false)
  104. return;
  105. }
  106. }
  107. }
  108. if (typeof onUploadError === 'function') {
  109. var result = onUploadError.call(button, data, ret);
  110. if (result === false) {
  111. return;
  112. }
  113. }
  114. Toastr.error(ret.msg + "(code:" + ret.code + ")");
  115. },
  116. //服务器响应数据后
  117. onUploadResponse: function (response) {
  118. try {
  119. var ret = typeof response === 'object' ? response : JSON.parse(response);
  120. if (!ret.hasOwnProperty('code')) {
  121. $.extend(ret, {code: -2, msg: response, data: null});
  122. }
  123. } catch (e) {
  124. var ret = {code: -1, msg: e.message, data: null};
  125. }
  126. return ret;
  127. },
  128. //上传全部结束后
  129. onUploadComplete: function (up, files) {
  130. var button = up.settings.button;
  131. var onUploadComplete = up.settings.onUploadComplete;
  132. if (button) {
  133. var onDomUploadComplete = $(button).data("upload-complete");
  134. if (onDomUploadComplete) {
  135. if (typeof onDomUploadComplete !== 'function' && typeof Upload.api.custom[onDomUploadComplete] === 'function') {
  136. onDomUploadComplete = Upload.api.custom[onDomUploadComplete];
  137. }
  138. if (typeof onDomUploadComplete === 'function') {
  139. var result = onDomUploadComplete.call(button, files);
  140. if (result === false)
  141. return;
  142. }
  143. }
  144. }
  145. if (typeof onUploadComplete === 'function') {
  146. var result = onUploadComplete.call(button, files);
  147. if (result === false) {
  148. return;
  149. }
  150. }
  151. }
  152. },
  153. api: {
  154. //Plupload上传
  155. plupload: function (element, onUploadSuccess, onUploadError, onUploadComplete) {
  156. element = typeof element === 'undefined' ? Upload.config.classname : element;
  157. $(element, Upload.config.container).each(function () {
  158. if ($(this).attr("initialized")) {
  159. return true;
  160. }
  161. $(this).attr("initialized", true);
  162. var that = this;
  163. var id = $(this).prop("id");
  164. var url = $(this).data("url");
  165. var maxsize = $(this).data("maxsize");
  166. var mimetype = $(this).data("mimetype");
  167. var multipart = $(this).data("multipart");
  168. var multiple = $(this).data("multiple");
  169. //填充ID
  170. var input_id = $(that).data("input-id") ? $(that).data("input-id") : "";
  171. //预览ID
  172. var preview_id = $(that).data("preview-id") ? $(that).data("preview-id") : "";
  173. //上传URL
  174. url = url ? url : Config.upload.uploadurl;
  175. url = Fast.api.fixurl(url);
  176. //最大可上传文件大小
  177. maxsize = typeof maxsize !== "undefined" ? maxsize : Config.upload.maxsize;
  178. //文件类型
  179. mimetype = typeof mimetype !== "undefined" ? mimetype : Config.upload.mimetype;
  180. //请求的表单参数
  181. multipart = typeof multipart !== "undefined" ? multipart : Config.upload.multipart;
  182. //是否支持批量上传
  183. multiple = typeof multiple !== "undefined" ? multiple : Config.upload.multiple;
  184. var mimetypeArr = new Array();
  185. //支持后缀和Mimetype格式,以,分隔
  186. if (mimetype && mimetype !== "*" && mimetype.indexOf("/") === -1) {
  187. var tempArr = mimetype.split(',');
  188. for (var i = 0; i < tempArr.length; i++) {
  189. mimetypeArr.push({title: __('Files'), extensions: tempArr[i]});
  190. }
  191. mimetype = mimetypeArr;
  192. }
  193. //生成Plupload实例
  194. Upload.list[id] = new Plupload.Uploader({
  195. runtimes: 'html5,flash,silverlight,html4',
  196. multi_selection: multiple, //是否允许多选批量上传
  197. browse_button: id, // 浏览按钮的ID
  198. container: $(this).parent().get(0), //取按钮的上级元素
  199. flash_swf_url: '/assets/libs/plupload/js/Moxie.swf',
  200. silverlight_xap_url: '/assets/libs/plupload/js/Moxie.xap',
  201. drop_element: [id, $(this).data("input-id")],
  202. filters: {
  203. max_file_size: maxsize,
  204. mime_types: mimetype,
  205. },
  206. url: url,
  207. multipart_params: $.isArray(multipart) ? {} : multipart,
  208. init: {
  209. Init: Upload.events.onInit,
  210. PostInit: Upload.events.onPostInit,
  211. FilesAdded: Upload.events.onFileAdded,
  212. BeforeUpload: Upload.events.onBeforeUpload,
  213. UploadProgress: function (up, file) {
  214. var button = up.settings.button;
  215. $(button).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + file.percent + "%");
  216. Upload.events.onUploadProgress(up, file);
  217. },
  218. FileUploaded: function (up, file, info) {
  219. var button = up.settings.button;
  220. //还原按钮文字及状态
  221. $(button).prop("disabled", false).html($(button).data("bakup-html"));
  222. var ret = Upload.events.onUploadResponse(info.response, info, up, file);
  223. file.ret = ret;
  224. if (ret.code === 1) {
  225. Upload.events.onUploadSuccess(up, ret, file);
  226. } else {
  227. Upload.events.onUploadError(up, ret, file);
  228. }
  229. },
  230. UploadComplete: Upload.events.onUploadComplete,
  231. Error: function (up, err) {
  232. var button = up.settings.button;
  233. $(button).prop("disabled", false).html($(button).data("bakup-html"));
  234. var ret = {code: err.code, msg: err.message, data: null};
  235. Upload.events.onUploadError(up, ret);
  236. }
  237. },
  238. onUploadSuccess: onUploadSuccess,
  239. onUploadError: onUploadError,
  240. onUploadComplete: onUploadComplete,
  241. button: that
  242. });
  243. //拖动排序
  244. if (preview_id && multiple) {
  245. require(['dragsort'], function () {
  246. $("#" + preview_id).dragsort({
  247. dragSelector: "li a:not(.btn-trash)",
  248. dragEnd: function () {
  249. $("#" + preview_id).trigger("fa.preview.change");
  250. },
  251. placeHolderTemplate: '<li class="col-xs-3"></li>'
  252. });
  253. });
  254. }
  255. //刷新隐藏textarea的值
  256. var refresh = function (name) {
  257. var data = {};
  258. var textarea = $("textarea[name='" + name + "']");
  259. var container = textarea.prev("ul");
  260. $.each($("input,select,textarea", container).serializeArray(), function (i, j) {
  261. var reg = /\[?(\w+)\]?\[(\w+)\]$/g;
  262. var match = reg.exec(j.name);
  263. if (!match)
  264. return true;
  265. if (!isNaN(match[2])) {
  266. data[i] = j.value;
  267. } else {
  268. match[1] = "x" + parseInt(match[1]);
  269. if (typeof data[match[1]] === 'undefined') {
  270. data[match[1]] = {};
  271. }
  272. data[match[1]][match[2]] = j.value;
  273. }
  274. });
  275. var result = [];
  276. $.each(data, function (i, j) {
  277. result.push(j);
  278. });
  279. textarea.val(JSON.stringify(result));
  280. };
  281. if (preview_id && input_id) {
  282. $(document.body).on("keyup change", "#" + input_id, function (e) {
  283. var inputStr = $("#" + input_id).val();
  284. var inputArr = inputStr.split(/\,/);
  285. $("#" + preview_id).empty();
  286. var tpl = $("#" + preview_id).data("template") ? $("#" + preview_id).data("template") : "";
  287. var extend = $("#" + preview_id).next().is("textarea") ? $("#" + preview_id).next("textarea").val() : "{}";
  288. var json = {};
  289. try {
  290. json = JSON.parse(extend);
  291. } catch (e) {
  292. }
  293. $.each(inputArr, function (i, j) {
  294. if (!j) {
  295. return true;
  296. }
  297. var suffix = /[\.]?([a-zA-Z0-9]+)$/.exec(j);
  298. suffix = suffix ? suffix[1] : 'file';
  299. var data = {url: j, fullurl: Fast.api.cdnurl(j), data: $(that).data(), key: i, index: i, value: (json && typeof json[i] !== 'undefined' ? json[i] : null), suffix: suffix};
  300. var html = tpl ? Template(tpl, data) : Template.render(Upload.config.previewtpl, data);
  301. $("#" + preview_id).append(html);
  302. });
  303. });
  304. $("#" + input_id).trigger("change");
  305. }
  306. if (preview_id) {
  307. //监听文本框改变事件
  308. $("#" + preview_id).on('change keyup', "input,textarea,select", function () {
  309. refresh($(this).closest("ul").data("name"));
  310. });
  311. // 监听事件
  312. $(document.body).on("fa.preview.change", "#" + preview_id, function () {
  313. var urlArr = [];
  314. $("#" + preview_id + " [data-url]").each(function (i, j) {
  315. urlArr.push($(this).data("url"));
  316. });
  317. if (input_id) {
  318. $("#" + input_id).val(urlArr.join(","));
  319. }
  320. refresh($("#" + preview_id).data("name"));
  321. });
  322. // 移除按钮事件
  323. $(document.body).on("click", "#" + preview_id + " .btn-trash", function () {
  324. $(this).closest("li").remove();
  325. $("#" + preview_id).trigger("fa.preview.change");
  326. });
  327. }
  328. if (input_id) {
  329. //粘贴上传
  330. $("body").on('paste', "#" + input_id, function (event) {
  331. var that = this;
  332. var image, pasteEvent;
  333. pasteEvent = event.originalEvent;
  334. if (pasteEvent.clipboardData && pasteEvent.clipboardData.items) {
  335. image = Upload.api.getImageFromClipboard(pasteEvent);
  336. if (image) {
  337. event.preventDefault();
  338. var button = $(".plupload[data-input-id='" + $(that).attr("id") + "']");
  339. Upload.api.send(image, function (data) {
  340. var urlArr = [];
  341. if (button && button.data("multiple") && $(that).val() !== '') {
  342. urlArr.push($(that).val());
  343. }
  344. urlArr.push(data.url);
  345. $(that).val(urlArr.join(",")).trigger("change").trigger("validate");
  346. });
  347. }
  348. }
  349. });
  350. //拖拽上传
  351. $("body").on('drop', "#" + input_id, function (event) {
  352. var that = this;
  353. var images, pasteEvent;
  354. pasteEvent = event.originalEvent;
  355. if (pasteEvent.dataTransfer && pasteEvent.dataTransfer.files) {
  356. images = Upload.api.getImageFromDrop(pasteEvent);
  357. if (images.length > 0) {
  358. event.preventDefault();
  359. var button = $(".plupload[data-input-id='" + $(that).attr("id") + "']");
  360. $.each(images, function (i, image) {
  361. Upload.api.send(image, function (data) {
  362. var urlArr = [];
  363. if (button && button.data("multiple") && $(that).val() !== '') {
  364. urlArr.push($(that).val());
  365. }
  366. urlArr.push(data.url);
  367. $(that).val(urlArr.join(",")).trigger("change").trigger("validate");
  368. });
  369. });
  370. }
  371. }
  372. });
  373. }
  374. Upload.list[id].init();
  375. });
  376. },
  377. // AJAX异步上传
  378. send: function (file, onUploadSuccess, onUploadError, onUploadComplete) {
  379. var index = Layer.msg(__('Uploading'), {offset: 't', time: 0});
  380. var id = Plupload.guid();
  381. var _onPostInit = Upload.events.onPostInit;
  382. Upload.events.onPostInit = function () {
  383. // 当加载完成后添加文件并上传
  384. Upload.list[id].addFile(file);
  385. //Upload.list[id].start();
  386. };
  387. $('<button type="button" id="' + id + '" class="btn btn-danger hidden plupload" />').appendTo("body");
  388. $("#" + id).data("upload-complete", function (files) {
  389. Upload.events.onPostInit = _onPostInit;
  390. Layer.close(index);
  391. });
  392. Upload.api.plupload("#" + id, onUploadSuccess, onUploadError, onUploadComplete);
  393. },
  394. custom: {
  395. //自定义上传完成回调
  396. afteruploadcallback: function (response) {
  397. console.log(this, response);
  398. alert("Custom Callback,Response URL:" + response.url);
  399. },
  400. },
  401. getImageFromClipboard: function (data) {
  402. var i, item;
  403. i = 0;
  404. while (i < data.clipboardData.items.length) {
  405. item = data.clipboardData.items[i];
  406. if (item.type.indexOf("image") !== -1) {
  407. return item.getAsFile() || false;
  408. }
  409. i++;
  410. }
  411. return false;
  412. },
  413. getImageFromDrop: function (data) {
  414. var i, item, images;
  415. i = 0;
  416. images = [];
  417. while (i < data.dataTransfer.files.length) {
  418. item = data.dataTransfer.files[i];
  419. if (item.type.indexOf("image") !== -1) {
  420. images.push(item);
  421. }
  422. i++;
  423. }
  424. return images;
  425. }
  426. }
  427. }
  428. ;
  429. return Upload;
  430. });