|
@@ -2,16 +2,15 @@ |
|
|
// MIT License. See license.txt |
|
|
// MIT License. See license.txt |
|
|
|
|
|
|
|
|
frappe.last_edited_communication = {}; |
|
|
frappe.last_edited_communication = {}; |
|
|
frappe.standard_replies = {}; |
|
|
|
|
|
frappe.separator_element = '<div>---</div>'; |
|
|
|
|
|
|
|
|
const separator_element = '<div>---</div>'; |
|
|
|
|
|
|
|
|
frappe.views.CommunicationComposer = Class.extend({ |
|
|
frappe.views.CommunicationComposer = Class.extend({ |
|
|
init: function(opts) { |
|
|
|
|
|
|
|
|
init(opts) { |
|
|
$.extend(this, opts); |
|
|
$.extend(this, opts); |
|
|
this.make(); |
|
|
this.make(); |
|
|
}, |
|
|
}, |
|
|
make: function() { |
|
|
|
|
|
var me = this; |
|
|
|
|
|
|
|
|
make() { |
|
|
|
|
|
const me = this; |
|
|
|
|
|
|
|
|
this.dialog = new frappe.ui.Dialog({ |
|
|
this.dialog = new frappe.ui.Dialog({ |
|
|
title: (this.title || this.subject || __("New Email")), |
|
|
title: (this.title || this.subject || __("New Email")), |
|
@@ -19,56 +18,35 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
fields: this.get_fields(), |
|
|
fields: this.get_fields(), |
|
|
primary_action_label: __("Send"), |
|
|
primary_action_label: __("Send"), |
|
|
size: 'large', |
|
|
size: 'large', |
|
|
primary_action: function() { |
|
|
|
|
|
me.delete_saved_draft(); |
|
|
|
|
|
|
|
|
primary_action() { |
|
|
me.send_action(); |
|
|
me.send_action(); |
|
|
|
|
|
me.clear_cache(); |
|
|
|
|
|
}, |
|
|
|
|
|
secondary_action_label: __("Discard"), |
|
|
|
|
|
secondary_action() { |
|
|
|
|
|
me.dialog.hide(); |
|
|
|
|
|
me.clear_cache(); |
|
|
}, |
|
|
}, |
|
|
minimizable: true |
|
|
minimizable: true |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
this.dialog.sections[0].wrapper.addClass('to_section'); |
|
|
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.prepare(); |
|
|
this.dialog.show(); |
|
|
this.dialog.show(); |
|
|
|
|
|
|
|
|
if (this.frm) { |
|
|
if (this.frm) { |
|
|
$(document).trigger('form-typing', [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"), |
|
|
label: __("To"), |
|
|
fieldtype: "MultiSelect", |
|
|
fieldtype: "MultiSelect", |
|
|
reqd: 0, |
|
|
reqd: 0, |
|
|
fieldname: "recipients", |
|
|
fieldname: "recipients", |
|
|
options: contactList |
|
|
|
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
fieldtype: "Button", |
|
|
fieldtype: "Button", |
|
@@ -87,13 +65,11 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
label: __("CC"), |
|
|
label: __("CC"), |
|
|
fieldtype: "MultiSelect", |
|
|
fieldtype: "MultiSelect", |
|
|
fieldname: "cc", |
|
|
fieldname: "cc", |
|
|
options: contactList |
|
|
|
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
label: __("BCC"), |
|
|
label: __("BCC"), |
|
|
fieldtype: "MultiSelect", |
|
|
fieldtype: "MultiSelect", |
|
|
fieldname: "bcc", |
|
|
fieldname: "bcc", |
|
|
options: contactList |
|
|
|
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
label: __("Email Template"), |
|
|
label: __("Email Template"), |
|
@@ -163,18 +139,16 @@ 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; |
|
|
return fields; |
|
@@ -183,56 +157,58 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
toggle_more_options(show_options) { |
|
|
toggle_more_options(show_options) { |
|
|
show_options = show_options || this.dialog.fields_dict.more_options.df.hidden; |
|
|
show_options = show_options || this.dialog.fields_dict.more_options.df.hidden; |
|
|
this.dialog.set_df_property('more_options', 'hidden', !show_options); |
|
|
this.dialog.set_df_property('more_options', 'hidden', !show_options); |
|
|
let label = frappe.utils.icon(show_options ? 'up-line': 'down'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const label = frappe.utils.icon(show_options ? 'up-line': 'down'); |
|
|
this.dialog.get_field('option_toggle_button').set_label(label); |
|
|
this.dialog.get_field('option_toggle_button').set_label(label); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
prepare: function() { |
|
|
|
|
|
|
|
|
prepare() { |
|
|
|
|
|
this.setup_multiselect_queries(); |
|
|
this.setup_subject_and_recipients(); |
|
|
this.setup_subject_and_recipients(); |
|
|
this.setup_print_language(); |
|
|
this.setup_print_language(); |
|
|
this.setup_print(); |
|
|
this.setup_print(); |
|
|
this.setup_attach(); |
|
|
this.setup_attach(); |
|
|
this.setup_email(); |
|
|
this.setup_email(); |
|
|
this.setup_last_edited_communication(); |
|
|
|
|
|
this.setup_email_template(); |
|
|
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 || ''); |
|
|
|
|
|
|
|
|
|
|
|
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) || '' |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
this.setup_earlier_reply(); |
|
|
|
|
|
|
|
|
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 ('frm' in this && !this.is_a_reply) { |
|
|
|
|
|
// set default email template for the first email in a document |
|
|
|
|
|
this.dialog.set_value("email_template", this.frm.meta.default_email_template || ''); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
frappe.call({ |
|
|
|
|
|
method: "frappe.email.get_contact_list", |
|
|
|
|
|
args: {txt}, |
|
|
|
|
|
callback: (r) => { |
|
|
|
|
|
this.dialog.fields_dict[field].set_data(r.message); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
setup_subject_and_recipients: function() { |
|
|
|
|
|
|
|
|
setup_subject_and_recipients() { |
|
|
this.subject = this.subject || ""; |
|
|
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.recipients = this.last_email.sender; |
|
|
this.cc = this.last_email.cc; |
|
|
this.cc = this.last_email.cc; |
|
|
this.bcc = this.last_email.bcc; |
|
|
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(); |
|
|
this.recipients = this.frm && this.frm.timeline.get_recipient(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if(!this.subject && this.frm) { |
|
|
|
|
|
|
|
|
if (!this.subject && this.frm) { |
|
|
// get subject from last communication |
|
|
// 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; |
|
|
this.subject = last.subject; |
|
|
if(!this.recipients) { |
|
|
if(!this.recipients) { |
|
|
this.recipients = last.sender; |
|
|
this.recipients = last.sender; |
|
@@ -256,7 +232,7 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
// always add an identifier to catch a reply |
|
|
// always add an identifier to catch a reply |
|
|
// some email clients (outlook) may not send the message id to identify |
|
|
// 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 |
|
|
// 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)) { |
|
|
if (!this.subject.includes(identifier)) { |
|
|
this.subject = `${this.subject} (${identifier})`; |
|
|
this.subject = `${this.subject} (${identifier})`; |
|
|
} |
|
|
} |
|
@@ -267,34 +243,23 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
setup_email_template: function() { |
|
|
|
|
|
var me = this; |
|
|
|
|
|
|
|
|
setup_email_template() { |
|
|
|
|
|
const me = this; |
|
|
|
|
|
|
|
|
this.dialog.fields_dict["email_template"].df.onchange = () => { |
|
|
this.dialog.fields_dict["email_template"].df.onchange = () => { |
|
|
var 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() || ""; |
|
|
|
|
|
|
|
|
const email_template = me.dialog.fields_dict.email_template.get_value(); |
|
|
|
|
|
if (!email_template) return; |
|
|
|
|
|
|
|
|
var parts = content.split('<!-- salutation-ends -->'); |
|
|
|
|
|
|
|
|
function prepend_reply(reply) { |
|
|
|
|
|
if (me.reply_added === email_template) return; |
|
|
|
|
|
|
|
|
if(parts.length===2) { |
|
|
|
|
|
content = [reply.message, "<br>", parts[1]]; |
|
|
|
|
|
} else { |
|
|
|
|
|
content = [reply.message, "<br>", content]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const content_field = me.dialog.fields_dict.content; |
|
|
|
|
|
const subject_field = me.dialog.fields_dict.subject; |
|
|
|
|
|
|
|
|
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); |
|
|
subject_field.set_value(reply.subject); |
|
|
|
|
|
|
|
|
me.reply_added = email_template; |
|
|
me.reply_added = email_template; |
|
@@ -307,83 +272,105 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
doc: me.frm.doc, |
|
|
doc: me.frm.doc, |
|
|
_lang: me.dialog.get_value("language_sel") |
|
|
_lang: me.dialog.get_value("language_sel") |
|
|
}, |
|
|
}, |
|
|
callback: function(r) { |
|
|
|
|
|
|
|
|
callback(r) { |
|
|
prepend_reply(r.message); |
|
|
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 { |
|
|
} 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; |
|
|
this.key = this.key + ":" + this.last_email.name; |
|
|
} |
|
|
} |
|
|
if(this.subject){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.subject) { |
|
|
this.key = this.key + ":" + 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]); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
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 || ""); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
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] = {}; |
|
|
|
|
|
console.log('cleared!'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return frappe.last_edited_communication[this.doctype][this.key]; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
get_last_edited_communication: function() { |
|
|
|
|
|
if (!frappe.last_edited_communication[this.doc]) { |
|
|
|
|
|
frappe.last_edited_communication[this.doc] = {}; |
|
|
|
|
|
|
|
|
set_values: async function () { |
|
|
|
|
|
for (const fieldname of ["recipients", "cc", "bcc", "sender"]) { |
|
|
|
|
|
await this.dialog.set_value(fieldname, this[fieldname] || ""); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if(!frappe.last_edited_communication[this.doc][this.key]) { |
|
|
|
|
|
frappe.last_edited_communication[this.doc][this.key] = {}; |
|
|
|
|
|
|
|
|
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); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return frappe.last_edited_communication[this.doc][this.key]; |
|
|
|
|
|
|
|
|
for (const fieldname of ['email_template', 'cc', 'bcc']) { |
|
|
|
|
|
if (this.dialog.get_value(fieldname)) { |
|
|
|
|
|
this.toggle_more_options(true); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
selected_format: function() { |
|
|
|
|
|
return this.dialog.fields_dict.select_print_format.input.value || (this.frm && this.frm.meta.default_print_format) || "Standard"; |
|
|
|
|
|
|
|
|
set_values_from_last_edited_communication: async function () { |
|
|
|
|
|
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_print_format: function(format) { |
|
|
|
|
|
|
|
|
selected_format() { |
|
|
|
|
|
return ( |
|
|
|
|
|
this.dialog.fields_dict.select_print_format.input.value |
|
|
|
|
|
|| this.frm && this.frm.meta.default_print_format |
|
|
|
|
|
|| "Standard" |
|
|
|
|
|
); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
get_print_format(format) { |
|
|
if (!format) { |
|
|
if (!format) { |
|
|
format = this.selected_format(); |
|
|
format = this.selected_format(); |
|
|
} |
|
|
} |
|
@@ -395,9 +382,9 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
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 |
|
|
//Load default print language from doctype |
|
|
this.lang_code = doc.language |
|
|
this.lang_code = doc.language |
|
@@ -407,7 +394,7 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//On selection of language retrieve language code |
|
|
//On selection of language retrieve language code |
|
|
var me = this; |
|
|
|
|
|
|
|
|
const me = this; |
|
|
$(fields.language_sel.input).change(function(){ |
|
|
$(fields.language_sel.input).change(function(){ |
|
|
me.lang_code = this.value |
|
|
me.lang_code = this.value |
|
|
}) |
|
|
}) |
|
@@ -422,9 +409,9 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
setup_print: function() { |
|
|
|
|
|
|
|
|
setup_print() { |
|
|
// print formats |
|
|
// print formats |
|
|
var fields = this.dialog.fields_dict; |
|
|
|
|
|
|
|
|
const fields = this.dialog.fields_dict; |
|
|
|
|
|
|
|
|
// toggle print format |
|
|
// toggle print format |
|
|
$(fields.attach_document_print.input).click(function() { |
|
|
$(fields.attach_document_print.input).click(function() { |
|
@@ -434,8 +421,8 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
// select print format |
|
|
// select print format |
|
|
$(fields.select_print_format.wrapper).toggle(false); |
|
|
$(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) |
|
|
$(fields.select_print_format.input) |
|
|
.empty() |
|
|
.empty() |
|
|
.add_options(print_formats) |
|
|
.add_options(print_formats) |
|
@@ -446,9 +433,9 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
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) { |
|
|
if (!this.attachments) { |
|
|
this.attachments = []; |
|
|
this.attachments = []; |
|
@@ -493,7 +480,7 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
this.render_attachment_rows(); |
|
|
this.render_attachment_rows(); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
render_attachment_rows: function(attachment) { |
|
|
|
|
|
|
|
|
render_attachment_rows(attachment) { |
|
|
const select_attachments = this.dialog.fields_dict.select_attachments; |
|
|
const select_attachments = this.dialog.fields_dict.select_attachments; |
|
|
const attachment_rows = $(select_attachments.wrapper).find(".attach-list"); |
|
|
const attachment_rows = $(select_attachments.wrapper).find(".attach-list"); |
|
|
if (attachment) { |
|
|
if (attachment) { |
|
@@ -536,9 +523,9 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
</p>`); |
|
|
</p>`); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
setup_email: function() { |
|
|
|
|
|
|
|
|
setup_email() { |
|
|
// 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.attach_document_print.input).click(); |
|
@@ -547,21 +534,20 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
|
|
|
|
|
|
$(fields.send_me_a_copy.input).on('click', () => { |
|
|
$(fields.send_me_a_copy.input).on('click', () => { |
|
|
// update send me a copy (make it sticky) |
|
|
// 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.db.set_value('User', frappe.session.user, 'send_me_a_copy', val); |
|
|
frappe.boot.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(); |
|
|
|
|
|
|
|
|
|
|
|
var form_values = this.get_values(); |
|
|
|
|
|
|
|
|
send_action() { |
|
|
|
|
|
const me = this; |
|
|
|
|
|
const btn = me.dialog.get_primary_btn(); |
|
|
|
|
|
const form_values = this.get_values(); |
|
|
if(!form_values) return; |
|
|
if(!form_values) return; |
|
|
|
|
|
|
|
|
var selected_attachments = |
|
|
|
|
|
|
|
|
const selected_attachments = |
|
|
$.map($(me.dialog.wrapper).find("[data-file-name]:checked"), function (element) { |
|
|
$.map($(me.dialog.wrapper).find("[data-file-name]:checked"), function (element) { |
|
|
return $(element).attr("data-file-name"); |
|
|
return $(element).attr("data-file-name"); |
|
|
}); |
|
|
}); |
|
@@ -574,16 +560,16 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
get_values: function() { |
|
|
|
|
|
var form_values = this.dialog.get_values(); |
|
|
|
|
|
|
|
|
get_values() { |
|
|
|
|
|
const form_values = this.dialog.get_values(); |
|
|
|
|
|
|
|
|
// cc |
|
|
// 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 |
|
|
// 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.cc = ( form_values.cc ? (form_values.cc + ", ") : "" ) + df.fieldname; |
|
|
form_values.bcc = ( form_values.bcc ? (form_values.bcc + ", ") : "" ) + df.fieldname; |
|
|
form_values.bcc = ( form_values.bcc ? (form_values.bcc + ", ") : "" ) + df.fieldname; |
|
|
} |
|
|
} |
|
@@ -595,35 +581,40 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
return form_values; |
|
|
return form_values; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
save_as_draft: function() { |
|
|
|
|
|
|
|
|
save_as_draft() { |
|
|
if (this.dialog && this.frm) { |
|
|
if (this.dialog && this.frm) { |
|
|
let message = this.dialog.get_value('content'); |
|
|
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 => { |
|
|
localforage.setItem(this.frm.doctype + this.frm.docname, message).catch(e => { |
|
|
if (e) { |
|
|
if (e) { |
|
|
// silently fail |
|
|
// silently fail |
|
|
console.log(e); // eslint-disable-line |
|
|
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() { |
|
|
delete_saved_draft() { |
|
|
if (this.dialog && this.frm) { |
|
|
if (this.dialog && this.frm) { |
|
|
localforage.removeItem(this.frm.doctype + this.frm.docname).catch(e => { |
|
|
localforage.removeItem(this.frm.doctype + this.frm.docname).catch(e => { |
|
|
if (e) { |
|
|
if (e) { |
|
|
// silently fail |
|
|
// silently fail |
|
|
console.log(e); // eslint-disable-line |
|
|
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(); |
|
|
me.dialog.hide(); |
|
|
|
|
|
|
|
|
if(!form_values.recipients) { |
|
|
if(!form_values.recipients) { |
|
@@ -637,7 +628,7 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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")); |
|
|
frappe.msgprint(__("You are not allowed to send emails related to this document")); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
@@ -658,15 +649,17 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
send_me_a_copy: form_values.send_me_a_copy, |
|
|
send_me_a_copy: form_values.send_me_a_copy, |
|
|
print_format: print_format, |
|
|
print_format: print_format, |
|
|
sender: form_values.sender, |
|
|
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, |
|
|
email_template: form_values.email_template, |
|
|
attachments: selected_attachments, |
|
|
attachments: selected_attachments, |
|
|
_lang : me.lang_code, |
|
|
_lang : me.lang_code, |
|
|
read_receipt:form_values.send_read_receipt, |
|
|
read_receipt:form_values.send_read_receipt, |
|
|
print_letterhead: me.is_print_letterhead_checked(), |
|
|
print_letterhead: me.is_print_letterhead_checked(), |
|
|
}, |
|
|
}, |
|
|
btn: btn, |
|
|
|
|
|
callback: function(r) { |
|
|
|
|
|
|
|
|
btn, |
|
|
|
|
|
callback(r) { |
|
|
if(!r.exc) { |
|
|
if(!r.exc) { |
|
|
frappe.utils.play_sound("email"); |
|
|
frappe.utils.play_sound("email"); |
|
|
|
|
|
|
|
@@ -678,8 +671,8 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
if ((frappe.last_edited_communication[me.doc] || {})[me.key]) { |
|
|
if ((frappe.last_edited_communication[me.doc] || {})[me.key]) { |
|
|
delete frappe.last_edited_communication[me.doc][me.key]; |
|
|
delete frappe.last_edited_communication[me.doc][me.key]; |
|
|
} |
|
|
} |
|
|
if (cur_frm) { |
|
|
|
|
|
cur_frm.reload_doc(); |
|
|
|
|
|
|
|
|
if (this.frm) { |
|
|
|
|
|
this.frm.reload_doc(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// try the success callback if it exists |
|
|
// try the success callback if it exists |
|
@@ -707,7 +700,7 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
is_print_letterhead_checked: function() { |
|
|
|
|
|
|
|
|
is_print_letterhead_checked() { |
|
|
if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){ |
|
|
if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){ |
|
|
return $(this.frm.wrapper).find('.print-letterhead').prop('checked') ? 1 : 0; |
|
|
return $(this.frm.wrapper).find('.print-letterhead').prop('checked') ? 1 : 0; |
|
|
} else { |
|
|
} else { |
|
@@ -716,96 +709,96 @@ frappe.views.CommunicationComposer = Class.extend({ |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
get_default_outgoing_email_account_signature: function() { |
|
|
|
|
|
return frappe.db.get_value('Email Account', { 'default_outgoing': 1, 'add_signature': 1 }, 'signature'); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
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 = res.message.signature ? "<!-- signature-included -->" + res.message.signature : ""; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
set_content: async function() { |
|
|
|
|
|
if (this.content_set) return; |
|
|
|
|
|
|
|
|
if (signature && !frappe.utils.is_html(signature)) { |
|
|
|
|
|
signature = signature.replace(/\n/g, "<br>"); |
|
|
|
|
|
|
|
|
let message = this.txt || ""; |
|
|
|
|
|
if (!message && this.frm) { |
|
|
|
|
|
const { doctype, docname } = this.frm; |
|
|
|
|
|
message = await localforage.getItem(doctype + docname) || ""; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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 (message) { |
|
|
|
|
|
this.content_set = true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if(this.real_name) { |
|
|
|
|
|
this.message = '<p>'+__('Dear') +' ' |
|
|
|
|
|
+ this.real_name + ",</p><!-- salutation-ends --><br>" + (this.message || ""); |
|
|
|
|
|
|
|
|
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.message && signature && this.message.includes(signature)) { |
|
|
|
|
|
signature = ""; |
|
|
|
|
|
|
|
|
if (this.is_a_reply) { |
|
|
|
|
|
message += this.get_earlier_reply(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let reply = (this.message || "") + (signature ? ("<br>" + signature) : ""); |
|
|
|
|
|
let content = ''; |
|
|
|
|
|
|
|
|
await this.dialog.set_value("content", message); |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
if (this.is_a_reply === 'undefined') { |
|
|
|
|
|
this.is_a_reply = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
get_signature: async function () { |
|
|
|
|
|
let signature = frappe.boot.user.email_signature; |
|
|
|
|
|
|
|
|
if (this.is_a_reply) { |
|
|
|
|
|
let last_email = this.last_email; |
|
|
|
|
|
|
|
|
if (!signature) { |
|
|
|
|
|
const response = await frappe.db.get_value( |
|
|
|
|
|
'Email Account', |
|
|
|
|
|
{'default_outgoing': 1, 'add_signature': 1}, |
|
|
|
|
|
'signature' |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
if (!last_email) { |
|
|
|
|
|
last_email = this.frm && this.frm.timeline.get_last_email(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
signature = response.message.signature; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (!last_email) return; |
|
|
|
|
|
|
|
|
if (!signature) return ""; |
|
|
|
|
|
|
|
|
let last_email_content = last_email.original_comment || last_email.content; |
|
|
|
|
|
|
|
|
if (!frappe.utils.is_html(signature)) { |
|
|
|
|
|
signature = signature.replace(/\n/g, "<br>"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 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>'); |
|
|
|
|
|
|
|
|
return "<br><!-- signature-included -->" + signature; |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
// 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); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
get_earlier_reply() { |
|
|
|
|
|
const last_email = ( |
|
|
|
|
|
this.last_email |
|
|
|
|
|
|| this.frm && this.frm.timeline.get_last_email(true) |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
fields.content.set_value(content); |
|
|
|
|
|
|
|
|
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 = last_email.communication_date || last_email.creation; |
|
|
|
|
|
return ` |
|
|
|
|
|
<div><br></div> |
|
|
|
|
|
${separator_element || ''} |
|
|
|
|
|
<p>${__("On {0}, {1} wrote:", [ |
|
|
|
|
|
frappe.datetime.global_date_format(communication_date), |
|
|
|
|
|
last_email.sender |
|
|
|
|
|
])}</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
${last_email_content} |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
`; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
html2text: function(html) { |
|
|
|
|
|
|
|
|
html2text(html) { |
|
|
// convert HTML to text and try and preserve whitespace |
|
|
// 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 |
|
|
d.innerHTML = html.replace(/<\/div>/g, '<br></div>') // replace end of blocks |
|
|
.replace(/<\/p>/g, '<br></p>') // replace end of paragraphs |
|
|
.replace(/<\/p>/g, '<br></p>') // replace end of paragraphs |
|
|
.replace(/<br>/g, '\n'); |
|
|
.replace(/<br>/g, '\n'); |
|
|
let text = d.textContent; |
|
|
|
|
|
|
|
|
|
|
|
// replace multiple empty lines with just one |
|
|
// replace multiple empty lines with just one |
|
|
return text.replace(/\n{3,}/g, '\n\n'); |
|
|
|
|
|
|
|
|
return d.textContent.replace(/\n{3,}/g, '\n\n'); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |