您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

404 行
12 KiB

  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. // opts - parent, list, doc, email
  4. wn.views.CommunicationList = Class.extend({
  5. init: function(opts) {
  6. this.comm_list = [];
  7. $.extend(this, opts);
  8. if(this.doc.__islocal) {
  9. $(this.parent).empty();
  10. return;
  11. }
  12. if(!this.list)
  13. this.list = wn.model.get("Communication", {"parenttype": this.doc.doctype, "parent": this.doc.name});
  14. var sortfn = function (a, b) { return (b.creation > a.creation) ? 1 : -1; }
  15. this.list = this.list.sort(sortfn);
  16. this.make();
  17. },
  18. make: function() {
  19. var me = this;
  20. this.make_body();
  21. if(this.list && this.list.length) {
  22. $.each(this.list, function(i, d) {
  23. me.prepare(d);
  24. me.make_line(d);
  25. });
  26. // show first
  27. this.comm_list[0].find('.comm-content').toggle(true);
  28. } else {
  29. this.clear_list()
  30. }
  31. },
  32. clear_list: function() {
  33. this.body.remove();
  34. $("<p class='text-muted'>" + wn._("No Communication tagged with this ")
  35. + this.doc.doctype +" yet.</p>").appendTo(this.wrapper);
  36. },
  37. make_body: function() {
  38. $(this.parent)
  39. .empty()
  40. this.wrapper = $("<div>\
  41. <div style='margin-bottom: 8px;'>\
  42. <button class='btn btn-default' \
  43. onclick='cur_frm.communication_view.add_reply()'>\
  44. <i class='icon-plus'></i> "+wn._("Add Message")+"</button></div>\
  45. </div>")
  46. .appendTo(this.parent);
  47. this.body = $('<div class="list-group">')
  48. .css({"border":"1px solid #dddddd", "border-radius":"4px"})
  49. .appendTo(this.wrapper);
  50. },
  51. add_reply: function() {
  52. var subject = this.doc.subject;
  53. if(!subject && this.list.length) {
  54. // get subject from previous message
  55. subject = this.list[0].subject || "[No Subject]";
  56. if(strip(subject.toLowerCase().split(":")[0])!="re") {
  57. subject = "Re: " + subject;
  58. }
  59. }
  60. new wn.views.CommunicationComposer({
  61. doc: this.doc,
  62. subject: subject,
  63. recipients: this.recipients
  64. })
  65. },
  66. prepare: function(doc) {
  67. //doc.when = comment_when(this.doc.modified);
  68. doc.when = doc.creation;
  69. if(!doc.content) doc.content = "[no content]";
  70. if(!wn.utils.is_html(doc.content)) {
  71. doc.content = doc.content.replace(/\n/g, "<br>");
  72. }
  73. doc.content = wn.utils.remove_script_and_style(doc.content);
  74. if(!doc.sender) doc.sender = "[unknown sender]";
  75. doc._sender = doc.sender.replace(/</, "&lt;").replace(/>/, "&gt;");
  76. doc.content = doc.content.split("-----"+wn._("In response to")+"-----")[0];
  77. doc.content = doc.content.split("-----"+wn._("Original Message")+"-----")[0];
  78. },
  79. make_line: function(doc) {
  80. var me = this;
  81. doc.icon = {
  82. "Email": "icon-envelope",
  83. "Chat": "icon-comments",
  84. "Phone": "icon-phone",
  85. "SMS": "icon-mobile-phone",
  86. }[doc.communication_medium] || "icon-envelope";
  87. var comm = $(repl('<div class="list-group-item">\
  88. <div class="comm-header row" title="'+wn._('Click to Expand / Collapse')+'">\
  89. <div class="col-sm-3"><i class="%(icon)s"></i> %(_sender)s</div>\
  90. <div class="col-sm-6">%(subject)s</div>\
  91. <div class="col-sm-3 text-right">%(when)s</div>\
  92. </div>\
  93. <div class="comm-content" style="overflow-x: auto; display: none;">\
  94. <div class="inner" style="border-top: 1px solid #f3f3f3; margin-top: 10px; padding-top: 10px;">\
  95. </div>\
  96. <div class="show-details pull-right" style="margin-right: 10px;">\
  97. <a href="#Form/Communication/%(name)s">'+wn._('Show Details')+'</a>\
  98. </div>\
  99. </div>\
  100. </td></tr>', doc))
  101. .appendTo(this.body);
  102. if(!doc.name) {
  103. comm.find(".show-details").toggle(false);
  104. }
  105. comm.find(".comm-header")
  106. .css({"cursor":"pointer"})
  107. .click(function() {
  108. $(this).parent().find(".comm-content").toggle();
  109. });
  110. this.comm_list.push(comm);
  111. comm.find(".comm-content .inner").html(doc.content);
  112. }
  113. });
  114. wn.views.CommunicationComposer = Class.extend({
  115. init: function(opts) {
  116. $.extend(this, opts)
  117. this.make();
  118. this.dialog.show();
  119. },
  120. make: function() {
  121. var me = this;
  122. this.dialog = new wn.ui.Dialog({
  123. title: wn._("Add Reply") + ": " + (this.subject || ""),
  124. no_submit_on_enter: true,
  125. fields: [
  126. {label:wn._("To"), fieldtype:"Data", reqd: 1, fieldname:"recipients",
  127. description:wn._("Email addresses, separted by commas")},
  128. {label:wn._("Subject"), fieldtype:"Data", reqd: 1,
  129. fieldname:"subject"},
  130. {label:wn._("Message"), fieldtype:"Text Editor", reqd: 1,
  131. fieldname:"content"},
  132. {label:wn._("Send As Email"), fieldtype:"Check",
  133. fieldname:"send_email"},
  134. {label:wn._("Communication Medium"), fieldtype:"Select",
  135. options: ["Phone", "Chat", "Email", "SMS", "Other"],
  136. fieldname:"communication_medium"},
  137. {label:wn._("Sent or Received"), fieldtype:"Select",
  138. options: ["Received", "Sent"],
  139. fieldname:"sent_or_received"},
  140. {label:wn._("Send"), fieldtype:"Button",
  141. fieldname:"send"},
  142. {label:wn._("Send Me A Copy"), fieldtype:"Check",
  143. fieldname:"send_me_a_copy"},
  144. {label:wn._("Attach Document Print"), fieldtype:"Check",
  145. fieldname:"attach_document_print"},
  146. {label:wn._("Select Print Format"), fieldtype:"Select",
  147. fieldname:"select_print_format"},
  148. {label:wn._("Select Attachments"), fieldtype:"HTML",
  149. fieldname:"select_attachments"}
  150. ]
  151. });
  152. this.dialog.$wrapper.find("[data-edit='outdent']").remove();
  153. this.dialog.get_input("send").addClass("btn-primary");
  154. $(document).on("upload_complete", function(event, filename, fileurl) {
  155. if(me.dialog.display) {
  156. var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);
  157. // find already checked items
  158. var checked_items = wrapper.find('[data-file-name]:checked').map(function() {
  159. return $(this).attr("data-file-name");
  160. });
  161. // reset attachment list
  162. me.setup_attach();
  163. // check latest added
  164. checked_items.push(filename);
  165. $.each(checked_items, function(i, filename) {
  166. wrapper.find('[data-file-name="'+ filename +'"]').prop("checked", true);
  167. });
  168. }
  169. })
  170. this.prepare();
  171. },
  172. prepare: function() {
  173. this.setup_print();
  174. this.setup_attach();
  175. this.setup_email();
  176. this.setup_autosuggest();
  177. $(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change();
  178. $(this.dialog.fields_dict.subject.input).val(this.subject || "").change();
  179. this.setup_earlier_reply();
  180. },
  181. setup_print: function() {
  182. // print formats
  183. var fields = this.dialog.fields_dict;
  184. // toggle print format
  185. $(fields.attach_document_print.input).click(function() {
  186. $(fields.select_print_format.wrapper).toggle($(this).prop("checked"));
  187. });
  188. // select print format
  189. $(fields.select_print_format.wrapper).toggle(false);
  190. $(fields.select_print_format.input)
  191. .empty()
  192. .add_options(cur_frm.print_formats)
  193. .val(cur_frm.print_formats[0]);
  194. },
  195. setup_attach: function() {
  196. var fields = this.dialog.fields_dict;
  197. var attach = $(fields.select_attachments.wrapper);
  198. var files = cur_frm.get_files();
  199. if(files.length) {
  200. $("<p><b>"+wn._("Add Attachments")+":</b></p>").appendTo(attach.empty());
  201. $.each(files, function(i, f) {
  202. $(repl("<p><input type='checkbox' \
  203. data-file-name='%(file)s'> %(file)s</p>", {file:f})).appendTo(attach)
  204. });
  205. }
  206. },
  207. setup_email: function() {
  208. // email
  209. var me = this;
  210. var fields = this.dialog.fields_dict;
  211. if(this.attach_document_print) {
  212. $(fields.send_me_a_copy.input).click();
  213. $(fields.attach_document_print.input).click();
  214. $(fields.select_print_format.wrapper).toggle(true);
  215. }
  216. $(fields.send_email.input).prop("checked", true)
  217. // toggle print format
  218. $(fields.send_email.input).click(function() {
  219. $(fields.communication_medium.wrapper).toggle(!!!$(this).prop("checked"));
  220. $(fields.sent_or_received.wrapper).toggle(!!!$(this).prop("checked"));
  221. $(fields.send.input).html($(this).prop("checked") ? "Send" : "Add Communication");
  222. });
  223. // select print format
  224. $(fields.communication_medium.wrapper).toggle(false);
  225. $(fields.sent_or_received.wrapper).toggle(false);
  226. $(fields.send.input).click(function() {
  227. var btn = this;
  228. var form_values = me.dialog.get_values();
  229. if(!form_values) return;
  230. var selected_attachments = $.map($(me.dialog.wrapper)
  231. .find("[data-file-name]:checked"), function(element) {
  232. return $(element).attr("data-file-name");
  233. })
  234. if(form_values.attach_document_print) {
  235. _p.build(form_values.select_print_format || "", function(print_format_html) {
  236. me.send_email(btn, form_values, selected_attachments, print_format_html);
  237. });
  238. } else {
  239. me.send_email(btn, form_values, selected_attachments);
  240. }
  241. });
  242. },
  243. send_email: function(btn, form_values, selected_attachments, print_html) {
  244. var me = this;
  245. if(!form_values.attach_document_print) {
  246. print_html = "";
  247. }
  248. if(form_values.send_email) {
  249. if(cur_frm && !wn.model.can_email(me.doc.doctype, cur_frm)) {
  250. msgprint(wn._("You are not allowed to send emails related to this document."));
  251. return;
  252. }
  253. form_values.communication_medium = "Email";
  254. form_values.sent_or_received = "Sent";
  255. };
  256. return wn.call({
  257. method:"webnotes.core.doctype.communication.communication.make",
  258. args: {
  259. sender: [wn.user_info(user).fullname, wn.boot.profile.email],
  260. recipients: form_values.recipients,
  261. subject: form_values.subject,
  262. content: form_values.content,
  263. doctype: me.doc.doctype,
  264. name: me.doc.name,
  265. send_me_a_copy: form_values.send_me_a_copy,
  266. send_email: form_values.send_email,
  267. print_html: print_html,
  268. communication_medium: form_values.communication_medium,
  269. sent_or_received: form_values.sent_or_received,
  270. attachments: selected_attachments
  271. },
  272. btn: btn,
  273. callback: function(r) {
  274. if(!r.exc) {
  275. if(form_values.send_email)
  276. msgprint("Email sent to " + form_values.recipients);
  277. me.dialog.hide();
  278. cur_frm.reload_doc();
  279. } else {
  280. msgprint("There were errors while sending email. Please try again.")
  281. }
  282. }
  283. });
  284. },
  285. setup_earlier_reply: function() {
  286. var fields = this.dialog.fields_dict;
  287. var comm_list = cur_frm.communication_view
  288. ? cur_frm.communication_view.list
  289. : [];
  290. var signature = wn.boot.profile.email_signature || "";
  291. if(!wn.utils.is_html(signature)) {
  292. signature = signature.replace(/\n/g, "<br>");
  293. }
  294. if(this.real_name) {
  295. this.message = '<p>'+wn._('Dear') +' ' + this.real_name + ",</p>" + (this.message || "");
  296. }
  297. var reply = (this.message || "")
  298. + "<p></p>" + signature;
  299. if(comm_list.length > 0) {
  300. fields.content.set_input(reply
  301. + "<p></p>"
  302. +"-----"+wn._("In response to")+"-----<p></p>"
  303. + comm_list[0].content);
  304. } else {
  305. fields.content.set_input(reply);
  306. }
  307. },
  308. setup_autosuggest: function() {
  309. var me = this;
  310. function split( val ) {
  311. return val.split( /,\s*/ );
  312. }
  313. function extractLast( term ) {
  314. return split(term).pop();
  315. }
  316. $(this.dialog.fields_dict.recipients.input)
  317. .bind( "keydown", function(event) {
  318. if (event.keyCode === $.ui.keyCode.TAB &&
  319. $(this).data( "autocomplete" ).menu.active ) {
  320. event.preventDefault();
  321. }
  322. })
  323. .autocomplete({
  324. source: function(request, response) {
  325. return wn.call({
  326. method:'webnotes.utils.email_lib.get_contact_list',
  327. args: {
  328. 'select': "email_id",
  329. 'from': "Contact",
  330. 'where': "email_id",
  331. 'txt': extractLast(request.term).value || '%'
  332. },
  333. callback: function(r) {
  334. response($.ui.autocomplete.filter(
  335. r.cl || [], extractLast(request.term)));
  336. }
  337. });
  338. },
  339. appendTo: this.dialog.$wrapper,
  340. focus: function() {
  341. // prevent value inserted on focus
  342. return false;
  343. },
  344. select: function( event, ui ) {
  345. var terms = split( this.value );
  346. // remove the current input
  347. terms.pop();
  348. // add the selected item
  349. terms.push( ui.item.value );
  350. // add placeholder to get the comma-and-space at the end
  351. terms.push( "" );
  352. this.value = terms.join( ", " );
  353. return false;
  354. }
  355. });
  356. }
  357. });