Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

communication.js 12 KiB

před 11 roky
před 12 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
před 11 roky
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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. });