Merge pull request #12878 from resilient-tech/refactor-communication-composer
refactor: frappe.views.CommunicationComposer
This commit is contained in:
commit
7a910c627d
5 changed files with 331 additions and 307 deletions
|
|
@ -56,6 +56,8 @@
|
|||
"show_preview_popup",
|
||||
"show_name_in_global_search",
|
||||
"email_settings_sb",
|
||||
"default_email_template",
|
||||
"column_break_51",
|
||||
"email_append_to",
|
||||
"sender_field",
|
||||
"subject_field",
|
||||
|
|
@ -535,6 +537,16 @@
|
|||
"fieldname": "is_virtual",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Virtual"
|
||||
},
|
||||
{
|
||||
"fieldname": "default_email_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Email Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_51",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bolt",
|
||||
|
|
@ -616,7 +628,7 @@
|
|||
"link_fieldname": "reference_doctype"
|
||||
}
|
||||
],
|
||||
"modified": "2021-02-17 20:18:06.212232",
|
||||
"modified": "2021-04-16 12:26:41.031135",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
"show_preview_popup",
|
||||
"image_view",
|
||||
"email_settings_section",
|
||||
"default_email_template",
|
||||
"column_break_26",
|
||||
"email_append_to",
|
||||
"sender_field",
|
||||
"subject_field",
|
||||
|
|
@ -264,6 +266,16 @@
|
|||
"label": "Actions",
|
||||
"options": "DocType Action"
|
||||
},
|
||||
{
|
||||
"fieldname": "default_email_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Email Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_26",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "naming_section",
|
||||
|
|
@ -283,7 +295,7 @@
|
|||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2021-02-16 15:22:11.108256",
|
||||
"modified": "2021-03-22 12:27:15.462727",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Customize Form",
|
||||
|
|
@ -304,4 +316,4 @@
|
|||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -491,6 +491,7 @@ doctype_properties = {
|
|||
'allow_auto_repeat': 'Check',
|
||||
'allow_import': 'Check',
|
||||
'show_preview_popup': 'Check',
|
||||
'default_email_template': 'Data',
|
||||
'email_append_to': 'Check',
|
||||
'subject_field': 'Data',
|
||||
'sender_field': 'Data',
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
|
|||
let data;
|
||||
if(this.df.get_data) {
|
||||
data = this.df.get_data();
|
||||
this.set_data(data);
|
||||
if (data) this.set_data(data);
|
||||
} else {
|
||||
data = this._super();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,73 +2,51 @@
|
|||
// MIT License. See license.txt
|
||||
|
||||
frappe.last_edited_communication = {};
|
||||
frappe.standard_replies = {};
|
||||
frappe.separator_element = '<div>---</div>';
|
||||
const separator_element = '<div>---</div>';
|
||||
|
||||
frappe.views.CommunicationComposer = Class.extend({
|
||||
init: function(opts) {
|
||||
frappe.views.CommunicationComposer = class {
|
||||
constructor(opts) {
|
||||
$.extend(this, opts);
|
||||
this.make();
|
||||
},
|
||||
make: function() {
|
||||
var me = this;
|
||||
}
|
||||
|
||||
make() {
|
||||
const me = this;
|
||||
|
||||
this.dialog = new frappe.ui.Dialog({
|
||||
title: (this.title || this.subject || __("New Email")),
|
||||
no_submit_on_enter: true,
|
||||
fields: this.get_fields(),
|
||||
primary_action_label: __("Send"),
|
||||
size: 'large',
|
||||
primary_action: function() {
|
||||
me.delete_saved_draft();
|
||||
primary_action() {
|
||||
me.send_action();
|
||||
},
|
||||
secondary_action_label: __("Discard"),
|
||||
secondary_action() {
|
||||
me.dialog.hide();
|
||||
me.clear_cache();
|
||||
},
|
||||
size: 'large',
|
||||
minimizable: true
|
||||
});
|
||||
|
||||
this.dialog.sections[0].wrapper.addClass('to_section');
|
||||
|
||||
['recipients', 'cc', 'bcc'].forEach(field => {
|
||||
this.dialog.fields_dict[field].get_data = function() {
|
||||
const data = me.dialog.fields_dict[field].get_value();
|
||||
const txt = data.match(/[^,\s*]*$/)[0] || '';
|
||||
let options = [];
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.email.get_contact_list",
|
||||
args: {
|
||||
txt: txt,
|
||||
},
|
||||
callback: (r) => {
|
||||
options = r.message;
|
||||
me.dialog.fields_dict[field].set_data(options);
|
||||
}
|
||||
});
|
||||
return options;
|
||||
}
|
||||
});
|
||||
|
||||
this.prepare();
|
||||
this.dialog.show();
|
||||
|
||||
if (this.frm) {
|
||||
$(document).trigger('form-typing', [this.frm]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.cc || this.bcc) {
|
||||
this.toggle_more_options(true);
|
||||
}
|
||||
},
|
||||
|
||||
get_fields: function() {
|
||||
let contactList = [];
|
||||
let fields = [
|
||||
get_fields() {
|
||||
const fields = [
|
||||
{
|
||||
label: __("To"),
|
||||
fieldtype: "MultiSelect",
|
||||
reqd: 0,
|
||||
fieldname: "recipients",
|
||||
options: contactList
|
||||
},
|
||||
{
|
||||
fieldtype: "Button",
|
||||
|
|
@ -87,13 +65,11 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
label: __("CC"),
|
||||
fieldtype: "MultiSelect",
|
||||
fieldname: "cc",
|
||||
options: contactList
|
||||
},
|
||||
{
|
||||
label: __("BCC"),
|
||||
fieldtype: "MultiSelect",
|
||||
fieldname: "bcc",
|
||||
options: contactList
|
||||
},
|
||||
{
|
||||
label: __("Email Template"),
|
||||
|
|
@ -163,78 +139,83 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
);
|
||||
});
|
||||
|
||||
if (frappe.boot.email_accounts && email_accounts.length > 1) {
|
||||
fields = [
|
||||
{
|
||||
label: __("From"),
|
||||
fieldtype: "Select",
|
||||
reqd: 1,
|
||||
fieldname: "sender",
|
||||
options: email_accounts.map(function(e) {
|
||||
return e.email_id;
|
||||
})
|
||||
}
|
||||
].concat(fields);
|
||||
if (email_accounts.length > 1) {
|
||||
fields.unshift({
|
||||
label: __("From"),
|
||||
fieldtype: "Select",
|
||||
reqd: 1,
|
||||
fieldname: "sender",
|
||||
options: email_accounts.map(function(e) {
|
||||
return e.email_id;
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
}
|
||||
|
||||
toggle_more_options(show_options) {
|
||||
show_options = show_options || this.dialog.fields_dict.more_options.df.hidden;
|
||||
this.dialog.set_df_property('more_options', 'hidden', !show_options);
|
||||
let label = frappe.utils.icon(show_options ? 'up-line': 'down');
|
||||
this.dialog.get_field('option_toggle_button').set_label(label);
|
||||
},
|
||||
|
||||
prepare: function() {
|
||||
const label = frappe.utils.icon(show_options ? 'up-line': 'down');
|
||||
this.dialog.get_field('option_toggle_button').set_label(label);
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this.setup_multiselect_queries();
|
||||
this.setup_subject_and_recipients();
|
||||
this.setup_print_language();
|
||||
this.setup_print();
|
||||
this.setup_attach();
|
||||
this.setup_email();
|
||||
this.setup_last_edited_communication();
|
||||
this.setup_email_template();
|
||||
this.setup_last_edited_communication();
|
||||
this.set_values();
|
||||
}
|
||||
|
||||
this.dialog.set_value("recipients", this.recipients || '');
|
||||
this.dialog.set_value("cc", this.cc || '');
|
||||
this.dialog.set_value("bcc", this.bcc || '');
|
||||
setup_multiselect_queries() {
|
||||
['recipients', 'cc', 'bcc'].forEach(field => {
|
||||
this.dialog.fields_dict[field].get_data = () => {
|
||||
const data = this.dialog.fields_dict[field].get_value();
|
||||
const txt = data.match(/[^,\s*]*$/)[0] || '';
|
||||
|
||||
if(this.dialog.fields_dict.sender) {
|
||||
this.dialog.fields_dict.sender.set_value(this.sender || '');
|
||||
}
|
||||
this.dialog.fields_dict.subject.set_value(
|
||||
frappe.utils.html2text(this.subject) || ''
|
||||
);
|
||||
frappe.call({
|
||||
method: "frappe.email.get_contact_list",
|
||||
args: {txt},
|
||||
callback: (r) => {
|
||||
this.dialog.fields_dict[field].set_data(r.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
this.setup_earlier_reply();
|
||||
},
|
||||
|
||||
setup_subject_and_recipients: function() {
|
||||
setup_subject_and_recipients() {
|
||||
this.subject = this.subject || "";
|
||||
|
||||
if(!this.forward && !this.recipients && this.last_email) {
|
||||
if (!this.forward && !this.recipients && this.last_email) {
|
||||
this.recipients = this.last_email.sender;
|
||||
this.cc = this.last_email.cc;
|
||||
this.bcc = this.last_email.bcc;
|
||||
}
|
||||
|
||||
if(!this.forward && !this.recipients) {
|
||||
if (!this.forward && !this.recipients) {
|
||||
this.recipients = this.frm && this.frm.timeline.get_recipient();
|
||||
}
|
||||
|
||||
if(!this.subject && this.frm) {
|
||||
if (!this.subject && this.frm) {
|
||||
// get subject from last communication
|
||||
var last = this.frm.timeline.get_last_email();
|
||||
const last = this.frm.timeline.get_last_email();
|
||||
|
||||
if(last) {
|
||||
if (last) {
|
||||
this.subject = last.subject;
|
||||
if(!this.recipients) {
|
||||
if (!this.recipients) {
|
||||
this.recipients = last.sender;
|
||||
}
|
||||
|
||||
// prepend "Re:"
|
||||
if(strip(this.subject.toLowerCase().split(":")[0])!="re") {
|
||||
if (strip(this.subject.toLowerCase().split(":")[0])!="re") {
|
||||
this.subject = __("Re: {0}", [this.subject]);
|
||||
}
|
||||
}
|
||||
|
|
@ -251,7 +232,7 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
// always add an identifier to catch a reply
|
||||
// some email clients (outlook) may not send the message id to identify
|
||||
// the thread. So as a backup we use the name of the document as identifier
|
||||
let identifier = `#${this.frm.doc.name}`;
|
||||
const identifier = `#${this.frm.doc.name}`;
|
||||
if (!this.subject.includes(identifier)) {
|
||||
this.subject = `${this.subject} (${identifier})`;
|
||||
}
|
||||
|
|
@ -260,33 +241,25 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
if (this.frm && !this.recipients) {
|
||||
this.recipients = this.frm.doc[this.frm.email_field];
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setup_email_template: function() {
|
||||
var me = this;
|
||||
setup_email_template() {
|
||||
const me = this;
|
||||
|
||||
this.dialog.fields_dict["email_template"].df.onchange = () => {
|
||||
var email_template = me.dialog.fields_dict.email_template.get_value();
|
||||
const email_template = me.dialog.fields_dict.email_template.get_value();
|
||||
if (!email_template) return;
|
||||
|
||||
var prepend_reply = function(reply) {
|
||||
if(me.reply_added===email_template) {
|
||||
return;
|
||||
}
|
||||
var content_field = me.dialog.fields_dict.content;
|
||||
var subject_field = me.dialog.fields_dict.subject;
|
||||
var content = content_field.get_value() || "";
|
||||
var subject = subject_field.get_value() || "";
|
||||
function prepend_reply(reply) {
|
||||
if (me.reply_added === email_template) return;
|
||||
|
||||
var parts = content.split('<!-- salutation-ends -->');
|
||||
const content_field = me.dialog.fields_dict.content;
|
||||
const subject_field = me.dialog.fields_dict.subject;
|
||||
|
||||
if(parts.length===2) {
|
||||
content = [reply.message, "<br>", parts[1]];
|
||||
} else {
|
||||
content = [reply.message, "<br>", content];
|
||||
}
|
||||
|
||||
content_field.set_value(content.join(''));
|
||||
let content = content_field.get_value() || "";
|
||||
content = content.split('<!-- salutation-ends -->')[1] || content;
|
||||
|
||||
content_field.set_value(`${reply.message}<br>${content}`);
|
||||
subject_field.set_value(reply.subject);
|
||||
|
||||
me.reply_added = email_template;
|
||||
|
|
@ -299,83 +272,104 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
doc: me.frm.doc,
|
||||
_lang: me.dialog.get_value("language_sel")
|
||||
},
|
||||
callback: function(r) {
|
||||
callback(r) {
|
||||
prepend_reply(r.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
setup_last_edited_communication: function() {
|
||||
var me = this;
|
||||
if (!this.doc){
|
||||
if (cur_frm){
|
||||
this.doc = cur_frm.doctype;
|
||||
}else{
|
||||
this.doc = "Inbox";
|
||||
}
|
||||
}
|
||||
if (cur_frm && cur_frm.docname) {
|
||||
this.key = cur_frm.docname;
|
||||
setup_last_edited_communication() {
|
||||
if (this.frm) {
|
||||
this.doctype = this.frm.doctype;
|
||||
this.key = this.frm.docname;
|
||||
} else {
|
||||
this.key = "Inbox";
|
||||
this.doctype = this.key = "Inbox";
|
||||
}
|
||||
if(this.last_email) {
|
||||
|
||||
if (this.last_email) {
|
||||
this.key = this.key + ":" + this.last_email.name;
|
||||
}
|
||||
if(this.subject){
|
||||
|
||||
if (this.subject) {
|
||||
this.key = this.key + ":" + this.subject;
|
||||
}
|
||||
this.dialog.onhide = function() {
|
||||
var last_edited_communication = me.get_last_edited_communication();
|
||||
$.extend(last_edited_communication, {
|
||||
sender: me.dialog.get_value("sender"),
|
||||
recipients: me.dialog.get_value("recipients"),
|
||||
cc: me.dialog.get_value("cc"),
|
||||
bcc: me.dialog.get_value("bcc"),
|
||||
subject: me.dialog.get_value("subject"),
|
||||
content: me.dialog.get_value("content"),
|
||||
});
|
||||
|
||||
if (me.frm) {
|
||||
$(document).trigger("form-stopped-typing", [me.frm]);
|
||||
this.dialog.on_hide = () => {
|
||||
$.extend(
|
||||
this.get_last_edited_communication(true),
|
||||
this.dialog.get_values(true)
|
||||
);
|
||||
|
||||
if (this.frm) {
|
||||
$(document).trigger("form-stopped-typing", [this.frm]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get_last_edited_communication(clear) {
|
||||
if (!frappe.last_edited_communication[this.doctype]) {
|
||||
frappe.last_edited_communication[this.doctype] = {};
|
||||
}
|
||||
|
||||
if (clear || !frappe.last_edited_communication[this.doctype][this.key]) {
|
||||
frappe.last_edited_communication[this.doctype][this.key] = {};
|
||||
}
|
||||
|
||||
return frappe.last_edited_communication[this.doctype][this.key];
|
||||
}
|
||||
|
||||
async set_values() {
|
||||
for (const fieldname of ["recipients", "cc", "bcc", "sender"]) {
|
||||
await this.dialog.set_value(fieldname, this[fieldname] || "");
|
||||
}
|
||||
|
||||
const subject = frappe.utils.html2text(this.subject) || '';
|
||||
await this.dialog.set_value("subject", subject);
|
||||
|
||||
await this.set_values_from_last_edited_communication();
|
||||
await this.set_content();
|
||||
|
||||
// set default email template for the first email in a document
|
||||
if (this.frm && !this.is_a_reply && !this.content_set) {
|
||||
const email_template = this.frm.meta.default_email_template || '';
|
||||
await this.dialog.set_value("email_template", email_template);
|
||||
}
|
||||
|
||||
for (const fieldname of ['email_template', 'cc', 'bcc']) {
|
||||
if (this.dialog.get_value(fieldname)) {
|
||||
this.toggle_more_options(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.dialog.on_page_show = function() {
|
||||
if (!me.txt) {
|
||||
var last_edited_communication = me.get_last_edited_communication();
|
||||
if(last_edited_communication.content) {
|
||||
me.dialog.set_value("sender", last_edited_communication.sender || "");
|
||||
me.dialog.set_value("subject", last_edited_communication.subject || "");
|
||||
me.dialog.set_value("recipients", last_edited_communication.recipients || "");
|
||||
me.dialog.set_value("cc", last_edited_communication.cc || "");
|
||||
me.dialog.set_value("bcc", last_edited_communication.bcc || "");
|
||||
me.dialog.set_value("content", last_edited_communication.content || "");
|
||||
}
|
||||
}
|
||||
async set_values_from_last_edited_communication() {
|
||||
if (this.txt) return;
|
||||
|
||||
const last_edited = this.get_last_edited_communication();
|
||||
if (!last_edited.content) return;
|
||||
|
||||
// prevent re-triggering of email template
|
||||
if (last_edited.email_template) {
|
||||
const template_field = this.dialog.fields_dict.email_template;
|
||||
await template_field.set_model_value(last_edited.email_template);
|
||||
delete last_edited.email_template;
|
||||
}
|
||||
|
||||
},
|
||||
await this.dialog.set_values(last_edited);
|
||||
this.content_set = true;
|
||||
}
|
||||
|
||||
get_last_edited_communication: function() {
|
||||
if (!frappe.last_edited_communication[this.doc]) {
|
||||
frappe.last_edited_communication[this.doc] = {};
|
||||
}
|
||||
selected_format() {
|
||||
return (
|
||||
this.dialog.fields_dict.select_print_format.input.value
|
||||
|| this.frm && this.frm.meta.default_print_format
|
||||
|| "Standard"
|
||||
);
|
||||
}
|
||||
|
||||
if(!frappe.last_edited_communication[this.doc][this.key]) {
|
||||
frappe.last_edited_communication[this.doc][this.key] = {};
|
||||
}
|
||||
|
||||
return frappe.last_edited_communication[this.doc][this.key];
|
||||
},
|
||||
|
||||
selected_format: function() {
|
||||
return this.dialog.fields_dict.select_print_format.input.value || (this.frm && this.frm.meta.default_print_format) || "Standard";
|
||||
},
|
||||
|
||||
get_print_format: function(format) {
|
||||
get_print_format(format) {
|
||||
if (!format) {
|
||||
format = this.selected_format();
|
||||
}
|
||||
|
|
@ -385,21 +379,19 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
} else {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setup_print_language: function() {
|
||||
var doc = this.doc || cur_frm.doc;
|
||||
var fields = this.dialog.fields_dict;
|
||||
setup_print_language() {
|
||||
const doc = this.frm && this.frm.doc;
|
||||
const fields = this.dialog.fields_dict;
|
||||
|
||||
//Load default print language from doctype
|
||||
this.lang_code = doc.language
|
||||
|
||||
if (!this.lang_code && this.get_print_format().default_print_language) {
|
||||
this.lang_code = this.get_print_format().default_print_language;
|
||||
}
|
||||
|| this.get_print_format().default_print_language
|
||||
|| frappe.boot.lang;
|
||||
|
||||
//On selection of language retrieve language code
|
||||
var me = this;
|
||||
const me = this;
|
||||
$(fields.language_sel.input).change(function(){
|
||||
me.lang_code = this.value
|
||||
})
|
||||
|
|
@ -412,11 +404,11 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
if (this.lang_code) {
|
||||
$(fields.language_sel.input).val(this.lang_code);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setup_print: function() {
|
||||
setup_print() {
|
||||
// print formats
|
||||
var fields = this.dialog.fields_dict;
|
||||
const fields = this.dialog.fields_dict;
|
||||
|
||||
// toggle print format
|
||||
$(fields.attach_document_print.input).click(function() {
|
||||
|
|
@ -426,8 +418,8 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
// select print format
|
||||
$(fields.select_print_format.wrapper).toggle(false);
|
||||
|
||||
if (cur_frm) {
|
||||
const print_formats = frappe.meta.get_print_formats(cur_frm.meta.name);
|
||||
if (this.frm) {
|
||||
const print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
|
||||
$(fields.select_print_format.input)
|
||||
.empty()
|
||||
.add_options(print_formats)
|
||||
|
|
@ -436,11 +428,11 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
$(fields.attach_document_print.wrapper).toggle(false);
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
setup_attach: function() {
|
||||
var fields = this.dialog.fields_dict;
|
||||
var attach = $(fields.select_attachments.wrapper);
|
||||
setup_attach() {
|
||||
const fields = this.dialog.fields_dict;
|
||||
const attach = $(fields.select_attachments.wrapper);
|
||||
|
||||
if (!this.attachments) {
|
||||
this.attachments = [];
|
||||
|
|
@ -483,9 +475,9 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
.find(".add-more-attachments button")
|
||||
.on('click', () => new frappe.ui.FileUploader(args));
|
||||
this.render_attachment_rows();
|
||||
},
|
||||
}
|
||||
|
||||
render_attachment_rows: function(attachment) {
|
||||
render_attachment_rows(attachment) {
|
||||
const select_attachments = this.dialog.fields_dict.select_attachments;
|
||||
const attachment_rows = $(select_attachments.wrapper).find(".attach-list");
|
||||
if (attachment) {
|
||||
|
|
@ -509,7 +501,7 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
get_attachment_row(attachment, checked) {
|
||||
return $(`<p class="checkbox flex">
|
||||
|
|
@ -526,56 +518,55 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
${frappe.utils.icon('link-url')}
|
||||
</a>
|
||||
</p>`);
|
||||
},
|
||||
}
|
||||
|
||||
setup_email: function() {
|
||||
setup_email() {
|
||||
// email
|
||||
var fields = this.dialog.fields_dict;
|
||||
const fields = this.dialog.fields_dict;
|
||||
|
||||
if(this.attach_document_print) {
|
||||
if (this.attach_document_print) {
|
||||
$(fields.attach_document_print.input).click();
|
||||
$(fields.select_print_format.wrapper).toggle(true);
|
||||
}
|
||||
|
||||
$(fields.send_me_a_copy.input).on('click', () => {
|
||||
// update send me a copy (make it sticky)
|
||||
let val = fields.send_me_a_copy.get_value();
|
||||
const val = fields.send_me_a_copy.get_value();
|
||||
frappe.db.set_value('User', frappe.session.user, 'send_me_a_copy', val);
|
||||
frappe.boot.user.send_me_a_copy = val;
|
||||
});
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
send_action: function() {
|
||||
var me = this;
|
||||
var btn = me.dialog.get_primary_btn();
|
||||
send_action() {
|
||||
const me = this;
|
||||
const btn = me.dialog.get_primary_btn();
|
||||
const form_values = this.get_values();
|
||||
if (!form_values) return;
|
||||
|
||||
var form_values = this.get_values();
|
||||
if(!form_values) return;
|
||||
|
||||
var selected_attachments =
|
||||
const selected_attachments =
|
||||
$.map($(me.dialog.wrapper).find("[data-file-name]:checked"), function (element) {
|
||||
return $(element).attr("data-file-name");
|
||||
});
|
||||
|
||||
|
||||
if(form_values.attach_document_print) {
|
||||
if (form_values.attach_document_print) {
|
||||
me.send_email(btn, form_values, selected_attachments, null, form_values.select_print_format || "");
|
||||
} else {
|
||||
me.send_email(btn, form_values, selected_attachments);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
get_values: function() {
|
||||
var form_values = this.dialog.get_values();
|
||||
get_values() {
|
||||
const form_values = this.dialog.get_values();
|
||||
|
||||
// cc
|
||||
for ( var i=0, l=this.dialog.fields.length; i < l; i++ ) {
|
||||
var df = this.dialog.fields[i];
|
||||
for (let i = 0, l = this.dialog.fields.length; i < l; i++) {
|
||||
const df = this.dialog.fields[i];
|
||||
|
||||
if ( df.is_cc_checkbox ) {
|
||||
if (df.is_cc_checkbox) {
|
||||
// concat in cc
|
||||
if ( form_values[df.fieldname] ) {
|
||||
if (form_values[df.fieldname]) {
|
||||
form_values.cc = ( form_values.cc ? (form_values.cc + ", ") : "" ) + df.fieldname;
|
||||
form_values.bcc = ( form_values.bcc ? (form_values.bcc + ", ") : "" ) + df.fieldname;
|
||||
}
|
||||
|
|
@ -585,22 +576,27 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
}
|
||||
|
||||
return form_values;
|
||||
},
|
||||
}
|
||||
|
||||
save_as_draft: function() {
|
||||
save_as_draft() {
|
||||
if (this.dialog && this.frm) {
|
||||
let message = this.dialog.get_value('content');
|
||||
message = message.split(frappe.separator_element)[0];
|
||||
message = message.split(separator_element)[0];
|
||||
localforage.setItem(this.frm.doctype + this.frm.docname, message).catch(e => {
|
||||
if (e) {
|
||||
// silently fail
|
||||
console.log(e); // eslint-disable-line
|
||||
console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
|
||||
console.warn('[Communication] IndexedDB is full. Cannot save message as draft'); // eslint-disable-line
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clear_cache() {
|
||||
this.delete_saved_draft();
|
||||
this.get_last_edited_communication(true);
|
||||
}
|
||||
|
||||
delete_saved_draft() {
|
||||
if (this.dialog && this.frm) {
|
||||
|
|
@ -608,28 +604,28 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
if (e) {
|
||||
// silently fail
|
||||
console.log(e); // eslint-disable-line
|
||||
console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
|
||||
console.warn('[Communication] IndexedDB is full. Cannot save message as draft'); // eslint-disable-line
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
send_email: function(btn, form_values, selected_attachments, print_html, print_format) {
|
||||
var me = this;
|
||||
send_email(btn, form_values, selected_attachments, print_html, print_format) {
|
||||
const me = this;
|
||||
me.dialog.hide();
|
||||
|
||||
if(!form_values.recipients) {
|
||||
if (!form_values.recipients) {
|
||||
frappe.msgprint(__("Enter Email Recipient(s)"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!form_values.attach_document_print) {
|
||||
if (!form_values.attach_document_print) {
|
||||
print_html = null;
|
||||
print_format = null;
|
||||
}
|
||||
|
||||
|
||||
if(cur_frm && !frappe.model.can_email(me.doc.doctype, cur_frm)) {
|
||||
if (this.frm && !frappe.model.can_email(me.doc.doctype, this.frm)) {
|
||||
frappe.msgprint(__("You are not allowed to send emails related to this document"));
|
||||
return;
|
||||
}
|
||||
|
|
@ -650,28 +646,29 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
send_me_a_copy: form_values.send_me_a_copy,
|
||||
print_format: print_format,
|
||||
sender: form_values.sender,
|
||||
sender_full_name: form_values.sender?frappe.user.full_name():undefined,
|
||||
sender_full_name: form_values.sender
|
||||
? frappe.user.full_name()
|
||||
: undefined,
|
||||
email_template: form_values.email_template,
|
||||
attachments: selected_attachments,
|
||||
_lang : me.lang_code,
|
||||
read_receipt:form_values.send_read_receipt,
|
||||
print_letterhead: me.is_print_letterhead_checked(),
|
||||
},
|
||||
btn: btn,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
btn,
|
||||
callback(r) {
|
||||
if (!r.exc) {
|
||||
frappe.utils.play_sound("email");
|
||||
|
||||
if(r.message["emails_not_sent_to"]) {
|
||||
if (r.message["emails_not_sent_to"]) {
|
||||
frappe.msgprint(__("Email not sent to {0} (unsubscribed / disabled)",
|
||||
[ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) );
|
||||
}
|
||||
|
||||
if ((frappe.last_edited_communication[me.doc] || {})[me.key]) {
|
||||
delete frappe.last_edited_communication[me.doc][me.key];
|
||||
}
|
||||
if (cur_frm) {
|
||||
cur_frm.reload_doc();
|
||||
me.clear_cache();
|
||||
|
||||
if (me.frm) {
|
||||
me.frm.reload_doc();
|
||||
}
|
||||
|
||||
// try the success callback if it exists
|
||||
|
|
@ -679,7 +676,7 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
try {
|
||||
me.success(r);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log(e); // eslint-disable-line
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -691,113 +688,115 @@ frappe.views.CommunicationComposer = Class.extend({
|
|||
try {
|
||||
me.error(r);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log(e); // eslint-disable-line
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
is_print_letterhead_checked: function() {
|
||||
is_print_letterhead_checked() {
|
||||
if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){
|
||||
return $(this.frm.wrapper).find('.print-letterhead').prop('checked') ? 1 : 0;
|
||||
} else {
|
||||
return (frappe.model.get_doc(":Print Settings", "Print Settings") ||
|
||||
{ with_letterhead: 1 }).with_letterhead ? 1 : 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
get_default_outgoing_email_account_signature: function() {
|
||||
return frappe.db.get_value('Email Account', { 'default_outgoing': 1, 'add_signature': 1 }, 'signature');
|
||||
},
|
||||
async set_content() {
|
||||
if (this.content_set) return;
|
||||
|
||||
setup_earlier_reply: async function() {
|
||||
let fields = this.dialog.fields_dict;
|
||||
let signature = frappe.boot.user.email_signature || "";
|
||||
|
||||
if (!signature) {
|
||||
const res = await this.get_default_outgoing_email_account_signature();
|
||||
signature = "<!-- signature-included -->" + res.message.signature;
|
||||
let message = this.txt || "";
|
||||
if (!message && this.frm) {
|
||||
const { doctype, docname } = this.frm;
|
||||
message = await localforage.getItem(doctype + docname) || "";
|
||||
}
|
||||
|
||||
if (signature && !frappe.utils.is_html(signature)) {
|
||||
signature = signature.replace(/\n/g, "<br>");
|
||||
if (message) {
|
||||
this.content_set = true;
|
||||
}
|
||||
|
||||
if(this.txt) {
|
||||
this.message = this.txt + (this.message ? ("<br><br>" + this.message) : "");
|
||||
} else {
|
||||
// saved draft in localStorage
|
||||
const { doctype, docname } = this.frm || {};
|
||||
if (doctype && docname) {
|
||||
this.message = await localforage.getItem(doctype + docname) || '';
|
||||
}
|
||||
}
|
||||
|
||||
if(this.real_name) {
|
||||
this.message = '<p>'+__('Dear') +' '
|
||||
+ this.real_name + ",</p><!-- salutation-ends --><br>" + (this.message || "");
|
||||
}
|
||||
|
||||
if(this.message && signature && this.message.includes(signature)) {
|
||||
signature = "";
|
||||
}
|
||||
|
||||
let reply = (this.message || "") + (signature ? ("<br>" + signature) : "");
|
||||
let content = '';
|
||||
|
||||
if (this.is_a_reply === 'undefined') {
|
||||
this.is_a_reply = true;
|
||||
message += await this.get_signature();
|
||||
if (this.real_name && !message.includes("<!-- salutation-ends -->")) {
|
||||
message = `<p>${__('Dear')} ${this.real_name},</p>
|
||||
<!-- salutation-ends --><br>${message}`;
|
||||
}
|
||||
|
||||
if (this.is_a_reply) {
|
||||
let last_email = this.last_email;
|
||||
|
||||
if (!last_email) {
|
||||
last_email = this.frm && this.frm.timeline.get_last_email(true);
|
||||
}
|
||||
|
||||
if (!last_email) return;
|
||||
|
||||
let last_email_content = last_email.original_comment || last_email.content;
|
||||
|
||||
// convert the email context to text as we are enclosing
|
||||
// this inside <blockquote>
|
||||
last_email_content = this.html2text(last_email_content).replace(/\n/g, '<br>');
|
||||
|
||||
// clip last email for a maximum of 20k characters
|
||||
// to prevent the email content from getting too large
|
||||
if (last_email_content.length > 20 * 1024) {
|
||||
last_email_content += '<div>' + __('Message clipped') + '</div>' + last_email_content;
|
||||
last_email_content = last_email_content.slice(0, 20 * 1024);
|
||||
}
|
||||
|
||||
let communication_date = last_email.communication_date || last_email.creation;
|
||||
content = `
|
||||
${reply}
|
||||
<div><br></div>
|
||||
${frappe.separator_element || ''}
|
||||
<p>${__("On {0}, {1} wrote:", [frappe.datetime.global_date_format(communication_date) , last_email.sender])}</p>
|
||||
<blockquote>
|
||||
${last_email_content}
|
||||
</blockquote>
|
||||
`;
|
||||
} else {
|
||||
content = reply;
|
||||
message += this.get_earlier_reply();
|
||||
}
|
||||
fields.content.set_value(content);
|
||||
},
|
||||
|
||||
html2text: function(html) {
|
||||
await this.dialog.set_value("content", message);
|
||||
}
|
||||
|
||||
async get_signature() {
|
||||
let signature = frappe.boot.user.email_signature;
|
||||
|
||||
if (!signature) {
|
||||
const response = await frappe.db.get_value(
|
||||
'Email Account',
|
||||
{'default_outgoing': 1, 'add_signature': 1},
|
||||
'signature'
|
||||
);
|
||||
|
||||
signature = response.message.signature;
|
||||
}
|
||||
|
||||
if (!signature) return "";
|
||||
|
||||
if (!frappe.utils.is_html(signature)) {
|
||||
signature = signature.replace(/\n/g, "<br>");
|
||||
}
|
||||
|
||||
return "<br>" + signature;
|
||||
}
|
||||
|
||||
get_earlier_reply() {
|
||||
const last_email = (
|
||||
this.last_email
|
||||
|| this.frm && this.frm.timeline.get_last_email(true)
|
||||
);
|
||||
|
||||
if (!last_email) return "";
|
||||
let last_email_content = last_email.original_comment || last_email.content;
|
||||
|
||||
// convert the email context to text as we are enclosing
|
||||
// this inside <blockquote>
|
||||
last_email_content = this.html2text(last_email_content).replace(/\n/g, '<br>');
|
||||
|
||||
// clip last email for a maximum of 20k characters
|
||||
// to prevent the email content from getting too large
|
||||
if (last_email_content.length > 20 * 1024) {
|
||||
last_email_content += '<div>' + __('Message clipped') + '</div>' + last_email_content;
|
||||
last_email_content = last_email_content.slice(0, 20 * 1024);
|
||||
}
|
||||
|
||||
const communication_date = frappe.datetime.global_date_format(
|
||||
last_email.communication_date || last_email.creation
|
||||
);
|
||||
|
||||
return `
|
||||
<div><br></div>
|
||||
${separator_element || ''}
|
||||
<p>
|
||||
${__("On {0}, {1} wrote:", [communication_date, last_email.sender])}
|
||||
</p>
|
||||
<blockquote>
|
||||
${last_email_content}
|
||||
</blockquote>
|
||||
`;
|
||||
}
|
||||
|
||||
html2text(html) {
|
||||
// convert HTML to text and try and preserve whitespace
|
||||
var d = document.createElement( 'div' );
|
||||
const d = document.createElement( 'div' );
|
||||
d.innerHTML = html.replace(/<\/div>/g, '<br></div>') // replace end of blocks
|
||||
.replace(/<\/p>/g, '<br></p>') // replace end of paragraphs
|
||||
.replace(/<br>/g, '\n');
|
||||
let text = d.textContent;
|
||||
|
||||
// replace multiple empty lines with just one
|
||||
return text.replace(/\n{3,}/g, '\n\n');
|
||||
return d.textContent.replace(/\n{3,}/g, '\n\n');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue