0
0
mirror of https://github.com/salesagility/SuiteCRM.git synced 2024-11-22 07:52:36 +00:00
salesagility_SuiteCRM/modules/Emails/include/ComposeView/EmailsComposeView.js

1625 lines
55 KiB
JavaScript

/**
*
* SugarCRM Community Edition is a customer relationship management program developed by
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along with
* this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "Powered by
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
*/
(function ($) {
/**
*
* @param options
* @returns {jQuery|HTMLElement}
* @constructor
*/
$.fn.EmailsComposeView = function (options) {
"use strict";
var self = $(this);
var opts = $.extend({}, $.fn.EmailsComposeView.defaults, options);
var jQueryFormComposeView = $('form[name="ComposeView"]')[0];
self.attachFile = undefined;
self.attachNote = undefined;
self.attachDocument = undefined;
/**
* Determines if the signature comes before the reply to message
* @type {boolean}
*/
self.prependSignature = false;
/**
* Defines the buttons that are displayed when the user focuses in on a to, cc and bcc field.
*
* @param data-open-popup-module - The module to popup
* @param data-open-popup-email-address-field - the field name that holds a single email address (assumes email1)
*
* To add a button (using popup behavior)
* $('.compose-view#id).EmailsComposeView().qtipBar +=
* '<button class="btn btn-default btn-sm btn-qtip-bar" '+
* 'data-open-popup-module="Contacts" data-open-popup-email-address-field="email1">'+'</button>';
*
* To add a button (using your own behavior)
* $('.compose-view#id).EmailsComposeView().qtipBar += '<button class="btn btn-default btn-sm"></button>';
*
* @type {string}
*/
self.qtipBar =
'<button class="btn btn-default btn-sm btn-qtip-bar" data-open-popup-module="Contacts" data-open-popup-email-address-field="email1" title="' + SUGAR.language.translate('Emails', 'LBL_INSERT_CONTACT_EMAIL') + '"><span class="glyphicon"><img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Contacts.svg"></span></button>' +
'<button class="btn btn-default btn-sm btn-qtip-bar" data-open-popup-module="Accounts" title="' + SUGAR.language.translate('Emails', 'LBL_INSERT_ACCOUNT_EMAIL') + '"><span class="glyphicon"><img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Accounts.svg"></span></button>' +
'<button class="btn btn-default btn-sm btn-qtip-bar" data-open-popup-module="Prospects" title="' + SUGAR.language.translate('Emails', 'LBL_INSERT_TARGET_EMAIL') + '"><span class="glyphicon"><img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Prospects.svg"></span></button>' +
'<button class="btn btn-default btn-sm btn-qtip-bar" data-open-popup-module="Users" title="' + SUGAR.language.translate('Emails', 'LBL_INSERT_USER_EMAIL') + '"><span class="glyphicon"><img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Users.svg"></span></button>' +
'<button class="btn btn-default btn-sm btn-qtip-bar" data-open-popup-module="Leads" title="' + SUGAR.language.translate('Emails', 'LBL_INSERT_LEAD_EMAIL') + '"><span class="glyphicon"><img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Leads.svg"></span></button>';
/**
* opens a popup when a btn-qtip-bar is clicked
*/
self.handleQTipBarClick = function () {
var module = $('#qtip_bar_module');
module.val($(this).attr('data-open-popup-module'));
var fields = {
'id': 'qtip_bar_id',
'name': 'qtip_bar_name'
}
if (typeof $(this).attr('data-open-popup-email-address-field') === "undefined") {
fields['email1'] = 'qtip_bar_email_address';
} else {
fields[$(this).attr('data-open-popup-email-address-field')] = 'qtip_bar_email_address';
}
$.fn.EmailsComposeView.setEmailAddressFieldFromPopup = function(resultData) {
var contact_name = resultData.name_to_value_array.qtip_bar_name;
var contact_email_address = resultData.name_to_value_array.qtip_bar_email_address;
if (trim(contact_email_address) !== '') {
var formatted_email_address = '';
if (trim(contact_name) !== '') {
// use name <email address> format
formatted_email_address = contact_name + ' <' + contact_email_address + '>';
} else {
// use email address
formatted_email_address = contact_email_address;
}
if (trim($(self.active_elementQTipBar).val()) === '') {
$(self.active_elementQTipBar).val(formatted_email_address);
} else {
$(self.active_elementQTipBar).val(
$(self.active_elementQTipBar).val() + ', ' +
formatted_email_address
);
}
}
};
var popupWindow = open_popup(
$(this).attr('data-open-popup-module'),
600,
400,
"",
true,
false,
{
"call_back_function": '$.fn.EmailsComposeView.setEmailAddressFieldFromPopup',
"form_name": "ComposeView",
"field_to_name_array": fields
},
"single",
false
);
};
/**
* Shows the qtip bar when the user focuses in on a to, cc and bcc field.
*
* To reuse this behaviour for an other field simply bind the focus event to this method call
*/
self.showQTipBar = function () {
self.active_elementQTipBar = this;
$(this).qtip({
content: {
text: self.qtipBar
},
position: {
my: 'bottom left',
at: 'top left'
},
show: {solo: true, ready: true, event: false},
hide: {event: false},
style: {classes: 'emails-qtip'}
});
$(this).qtip("show");
$(this).unbind('unfocus').blur(function (e) {
var isButton = $(e.relatedTarget).hasClass('btn-qtip-bar');
var isQtipContent = $(e.relatedTarget).hasClass('qtip-content');
var isQtip = $(e.relatedTarget).hasClass('qtip-tip');
if (isButton || isQtipContent || isQtip) {
return false;
}
$(this).qtip("hide");
});
$('.btn-qtip-bar').unbind('click').click(self.handleQTipBarClick);
};
/**
* @return string UUID
*/
self.generateID = function () {
"use strict";
var characters = ['a', 'b', 'c', 'd', 'e', 'f', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
var format = '0000000-0000-0000-0000-00000000000';
return Array.prototype.map.call(format, function ($obj) {
var min = 0;
var max = characters.length - 1;
if ($obj === '0') {
var index = Math.round(Math.random() * (max - min) + min);
$obj = characters[index];
}
return $obj;
}).toString().replace(/(,)/g, '');
};
/**
* confirms if form is valid
* @returns {boolean}
*/
self.isValid = function () {
"use strict";
return self.isToValid() &&
self.isCcValid() &&
self.isBccValid() &&
self.isSubjectValid() &&
self.isBodyValid();
};
/**
* validates form and displays error
* @returns {boolean}
*/
self.validate = function () {
var valid = self.isValid();
if (valid === false) {
if (typeof messageBox !== "undefined") {
var mb = messageBox({size: 'lg', backdrop: 'static'});
mb.setTitle(SUGAR.language.translate('', 'ERR_INVALID_REQUIRED_FIELDS'));
mb.setBody(self.translatedErrorMessage);
mb.on('ok', function () {
mb.remove();
});
mb.on('cancel', function () {
mb.remove();
});
mb.show();
mb.hideCancel();
} else {
alert(self.translatedErrorMessage);
}
}
return valid;
};
/**
* Is the To field valid
* @returns {boolean}
*/
self.isToValid = function () {
"use strict";
var emailAddresses = $(self).find('[name=to_addrs_names]').val().split('/[,;]/');
if (self.isValidEmailAddresses(emailAddresses)) {
return true;
}
self.setValidationMessage('to_addrs_names', 'LBL_HAS_INVALID_EMAIL_TO');
return false;
};
/**
* Is the CC field valid
* @returns {boolean}
*/
self.isCcValid = function () {
"use strict";
var cc = $(self).find('[name=cc_addrs_names]').val();
var emailAddresses = cc.split('/[,;]/');
if (self.isValidEmailAddresses(emailAddresses) || cc === '') {
return true;
}
self.setValidationMessage('cc_addrs_names', 'LBL_HAS_INVALID_EMAIL_CC');
return false;
};
/**
* Is the BCC field valid
* @returns {boolean}
*/
self.isBccValid = function () {
"use strict";
var bcc = $(self).find('[name=bcc_addrs_names]').val();
var emailAddresses = bcc.split('/[,;]/');
if (self.isValidEmailAddresses(emailAddresses) || bcc === '') {
return true;
}
self.setValidationMessage('bcc_addrs_names', 'LBL_HAS_INVALID_EMAIL_BCC');
return false;
};
/**
* Is the Subject field valid
* @returns {boolean}
*/
self.isSubjectValid = function () {
"use strict";
if ($(self).find('[name=name]').val() !== '') {
return true;
}
self.setValidationMessage('name', 'LBL_HAS_EMPTY_EMAIL_SUBJECT');
return false;
};
/**
* Is the Body field valid
* @returns {boolean}
*/
self.isBodyValid = function () {
"use strict";
if ($(self).find('#description').val() !== '') {
return true;
}
self.setValidationMessage('description_html', 'LBL_HAS_EMPTY_EMAIL_BODY');
return false;
};
/**
*
* @param field string name
* @param label string eg LBL_OK
*/
self.setValidationMessage = function (field, label) {
"use strict";
self.translatedErrorMessage = SUGAR.language.translate('Emails', label);
};
/**
* Determines if a set of email addresses are valid
* @param emailAddresses array|object eg ['a@example.com', 'b@example.com']
* @returns {boolean}
*/
self.isValidEmailAddresses = function (emailAddresses) {
"use strict";
if (typeof emailAddresses === 'object') {
for (var i = 0; i < emailAddresses.length; i++) {
emailAddresses[i] = (emailAddresses[i] !== '') && isValidEmail(emailAddresses[i]);
}
if (emailAddresses.indexOf(false) === -1) {
return true;
}
}
return false;
};
$.fn.EmailsComposeView.updateSignature = self.updateSignature = function ($selected) {
if(!$selected) {
$selected = $('#from_addr_name').find('option:selected');
}
var signatureId = $selected.attr('data-email-signature-id');
if (signatureId === undefined) {
console.warn('Unable to retrieve signature id');
return false;
}
var body = tinymce.activeEditor.getContent();
if (body !== '' && $(body).hasClass('email-signature-element')) {
var $body = $(body);
var $existingSignature = $body.find('.email-signature-element');
$existingSignature.remove();
tinymce.activeEditor.setContent($body.html(), {format: 'html'});
}
var signatureElement = $('<div></div>')
.addClass('email-signature-element');
var signatures = $(self).find('.email-signature');
var htmlSignature = null;
var plainTextSignature = null;
// Find signature
$.each(signatures, function (index, value) {
if ($(value).attr('data-email-signature-id') === signatureId) {
if ($(value).hasClass('html')) {
htmlSignature = $(value).val();
} else if ($(value).hasClass('plain')) {
plainTextSignature = $(value).val();
}
}
});
if (
htmlSignature === null &&
plainTextSignature === null
) {
console.warn('Unable to retrieve signature from document.');
return false;
}
if (htmlSignature === null) {
// use plain signature instead
$(plainTextSignature).appendTo(signatureElement);
} else if (plainTextSignature === null) {
// use html signature
$(htmlSignature).appendTo(signatureElement);
} else {
$(htmlSignature).appendTo(signatureElement);
}
if (tinymce.editors.length < 1) {
console.warn('unable to find tinymce editor');
return false;
}
body = tinymce.activeEditor.getContent();
if (body === '') {
tinymce.activeEditor.setContent('<p></p><p></p>' + signatureElement[0].outerHTML, {format: 'html'});
} else if ($(body).hasClass('email-signature-element')) {
var newBody = $('<div></div>');
$(body).appendTo(newBody);
$(newBody).find('.email-signature-element').replaceWith(signatureElement[0].outerHTML);
tinymce.activeEditor.setContent(newBody.html(), {format: 'html'});
} else {
// reply to / forward
if (self.prependSignature === true) {
tinymce.activeEditor.setContent('<p></p><p></p>' + signatureElement[0].outerHTML + body, {format: 'html'});
} else {
tinymce.activeEditor.setContent(body + signatureElement[0].outerHTML, {format: 'html'});
}
}
};
self.updateFromInfos = function ($selected) {
if (!$selected) {
$selected = $('#from_addr_name').find('option:selected');
}
var infos = $selected.attr('infos');
if(infos === undefined) {
console.warn('Unable to retrieve selected infos in the "From" field.');
return false;
}
if(!$('#from_addr_name_infos').length) {
$('#from_addr_name').parent().append('<span id="from_addr_name_infos"></span>');
}
$('#from_addr_name_infos').html(infos);
};
self.updateFromAddressName = function (selectFrom) {
var newlySelected = selectFrom.find('option:selected');
var newlySelectedFromName = newlySelected.attr('data-from-name');
$('#from_addr_name_hidden').val(newlySelectedFromName);
};
self.updateOutboundEmailId = function (selectFrom, newlySelected) {
if(!newlySelected) {
newlySelected = selectFrom.find('option:selected');
}
var entryType = newlySelected.attr('data-type') || '';
$('#outbound_email_id').val('');
if (entryType === 'OutboundEmailAccount' || entryType === 'system') {
var outboundId = newlySelected.attr('data-outbound-email-id');
$('#outbound_email_id').val(outboundId);
}
};
self.onFromSelect = function (selectFrom, ui) {
var newlySelected = ui.item.element;
var entryType = newlySelected.attr('data-type') || '';
$('#outbound_email_id').val('');
if (entryType === 'OutboundEmailAccount' || entryType === 'system') {
self.updateOutboundEmailId(selectFrom, newlySelected);
} else {
$(self).find('[name=inbound_email_id]').val(newlySelected.attr('inboundId'));
}
self.updateSignature(newlySelected);
};
self.getFromEntryLabel = function (entry) {
if (!entry) {
return '';
}
var entryValue = '';
if(entry.attributes.from && (typeof entry.attributes.from === 'string' || entry.attributes.from instanceof String)) {
entryValue = entry.attributes.from;
}
var entryLabel = '';
if(entry.attributes.name && (typeof entry.attributes.name === 'string' || entry.attributes.name instanceof String)) {
entryLabel = entry.attributes.name;
if (entryValue && entryValue !== entryLabel) {
entryLabel = entryLabel + ' (' + entryValue + ')';
}
} else if (entryValue) {
entryLabel = entryValue;
}
if (entryLabel.length > 40) {
entryLabel = entryLabel.substring(0, 40) + '...';
}
return entryLabel;
};
/**
*
* @param editor
*/
self.tinyMceSetup = function (editor) {
editor.on('init', function () {
this.getDoc().body.style.fontName = 'tahoma';
this.getDoc().body.style.fontSize = '13px';
});
editor.on('change', function () {
// copy html to plain
$(self).find('.html_preview').html(editor.getContent());
$(self).find('input#description_html').val(editor.getContent());
$(self).find('textarea#description').val($(self).find('.html_preview').text());
});
editor.on('SetContent', function () {
// copy html to plain
$(self).find('.html_preview').html(editor.getContent());
$(self).find('input#description_html').val(editor.getContent());
$(self).find('textarea#description').val($(self).find('.html_preview').text());
});
};
/**
*
* @event sendEmail
* @event sentEmailError
* @event sentEmailAlways
* @event sentEmail
* @returns {boolean}
*/
self.onSendEmail = function () {
$(self).trigger("sendEmail", [self]);
// Tell the user we are sending an email
var mb = messageBox({backdrop:'static'});
mb.hideHeader();
mb.hideFooter();
document.activeElement.blur();
mb.setBody('<div class="email-in-progress"><img src="themes/' + SUGAR.themes.theme_name + '/images/loading.gif"></div>');
mb.show();
mb.on('ok', function () {
"use strict";
mb.remove();
});
mb.on('cancel', function () {
"use strict";
mb.remove();
});
var fileCount = 0;
// Use FormData v2 to send form data via ajax
var formData = new FormData(jQueryFormComposeView);
$(this).find('input').each(function (inputIndex, inputValue) {
if ($(inputValue).attr('type').toLowerCase() !== 'file') {
if ($(inputValue).attr('name') === 'action') {
formData.append('refer_' + $(inputValue).attr('name'), $(inputValue).val());
formData.append($(inputValue).attr('name'), 'send');
} else if ($(inputValue).attr('name') === 'send') {
formData.append($(inputValue).attr('name'), 1);
} else {
formData.append($(inputValue).attr('name'), $(inputValue).val());
}
}
});
$(this).find('select').each(function (i, v) {
if (typeof $(v).attr('is_file') === 'undefined') {
formData.append($(v).attr('name'), $(v).val());
}
});
$(this).find('textarea').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$(this).find('button').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$(this).find('input[type=checkbox]').each(function (i, v) {
formData.append($(v).attr('name'), $(v).prop('checked'));
})
$.ajax({
type: "POST",
data: formData,
cache: false,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
url: $(this).attr('action')
}).done(function (response) {
"use strict";
response = JSON.parse(response);
if (typeof response.errors !== "undefined") {
mb.showHeader();
mb.setBody(response.errors.title);
mb.showFooter();
mb.hideCancel();
$(self).trigger("sentEmailError", [self, response]);
} else {
mb.showHeader();
mb.setBody(response.data.title);
mb.showFooter();
mb.hideCancel();
// If the user is viewing the form in the standard view
if ($(self).find('input[type="hidden"][name="return_module"]').val() !== '') {
mb.on('ok', function () {
var url = 'index.php?';
var module = $('#' + self.attr('id') + ' input[type="hidden"][name="return_module"]').val();
if (module !== undefined) {
url = url + 'module=' + module;
}
var action = $('#' + self.attr('id') + ' input[type="hidden"][name="return_action"]').val();
if (action !== undefined) {
url = url + '&action=' + action;
}
var record = $('#' + self.attr('id') + ' input[type="hidden"][name="return_id"]').val();
if (record !== undefined) {
url = url + '&record=' + record;
}
location.href = url;
});
} else {
mb.on('ok', function () {
// The user is viewing in the modal view
$(self).trigger("sentEmail", [self, response]);
});
}
}
}).fail(function (response) {
"use strict";
mb.showHeader();
mb.setBody(response.errors.title);
$(self).trigger("sentEmailError", [self, response]);
}).always(function (data) {
$(self).trigger("sentEmailAlways", [self, data]);
});
return false;
};
/**
* @event sendEmail
* @returns {boolean}
*/
self.sendEmail = function (e) {
"use strict";
e.preventDefault();
$(this).find('[name=action]').val('send');
if (self.validate()) {
$(this).submit();
}
return false;
};
/**
* @event attachFile
* @returns {boolean}
*/
self.attachFile = function (event) {
"use strict";
event.preventDefault();
$(self).trigger("attachFile", [self]);
// Add the file input onto the page
var id = self.generateID();
var fileGroupContainer = $('<div></div>')
.addClass('attachment-group-container')
.appendTo(self.find('.file-attachments'));
var fileInput = $('<input>')
.attr('type', 'file')
.attr('id', 'file_' + id)
.attr('name', 'email_attachment[]')
.attr('multiple', 'true')
.appendTo(fileGroupContainer);
var fileLabel = $('<label></label>')
.attr('for', 'file_' + id)
.addClass('attachment-blank')
.html('<span class="glyphicon glyphicon-paperclip"></span>')
.appendTo(fileGroupContainer);
// use the label to open file dialog
fileLabel.click();
// handle when the a file is selected
fileInput.change(function (event) {
if (event.target.files.length === 0) {
fileGroupContainer.remove();
return false;
}
if (event.target.files.length > 1) {
$(fileLabel.addClass('label-with-multiple-files'));
} else {
$(fileLabel.removeClass('label-with-multiple-files'));
}
fileLabel.html('');
fileLabel.empty();
if (fileGroupContainer.find('.attachment-remove').length === 0) {
var removeAttachment = $('<a class="attachment-remove"><span class="glyphicon glyphicon-remove"></span></a>');
fileGroupContainer.append(removeAttachment);
// handle when user removes attachment
removeAttachment.click(function () {
fileGroupContainer.remove();
});
}
for (var i = 0; i < event.target.files.length; i++) {
var file = event.target.files[i];
var name = file.name;
var size = file.size;
var type = file.type;
var fileContainer = $('<div class="attachment-file-container"></div>');
fileContainer.appendTo(fileLabel);
// Create icons based on file type
if (type.indexOf('image') !== -1) {
fileContainer.addClass('file-image');
fileContainer.append('<span class="attachment-type glyphicon glyphicon-picture"></span>');
} else if (type.indexOf('audio') !== -1) {
fileContainer.addClass('file-audio');
fileContainer.append('<span class="attachment-type glyphicon glyphicon-music"></span>');
} else if (type.indexOf('video') !== -1) {
fileContainer.addClass('file-video');
fileContainer.append('<span class="attachment-type glyphicon glyphicon-film"></span>');
} else if (type.indexOf('zip') !== -1) {
fileContainer.addClass('file-video');
fileContainer.append('<span class="attachment-type glyphicon glyphicon-compressed"></span>');
} else {
fileContainer.addClass('file-other');
fileContainer.append('<span class="attachment-type glyphicon glyphicon-file"></span>');
}
fileContainer.append('<span class="attachment-name"> ' + name + ' </span>');
fileContainer.append('<span class="attachment-size"> ' + self.humanReadableFileSize(size, true) + ' </span>');
fileLabel.removeClass('attachment-blank');
}
});
return false;
};
/**
* @event attachDocument
* @returns {boolean}
*/
self.attachDocument = function (event) {
"use strict";
event.preventDefault();
$(self).trigger("attachDocument", [self]);
// Add the file input onto the page
var id = self.generateID();
var fileGroupContainer = $('<div></div>')
.addClass('attachment-group-container')
.appendTo(self.find('.document-attachments'));
var fileInput = $('<input>')
.attr('type', 'hidden')
.attr('id', 'file_' + id)
.attr('name', 'documentId')
.attr('data-file-input', 'documentId')
.appendTo(fileGroupContainer);
//language=JQuery-CSS
var document_attachment_id = $('[name=document_attachment_id]');
var fileInputID = undefined;
if (document_attachment_id.length === 0) {
fileInputID = $('<input>')
.attr('type', 'hidden')
.attr('name', 'document_attachment_id')
.appendTo(fileGroupContainer.closest('.attachments'));
} else {
fileInputID = document_attachment_id;
}
$.fn.EmailsComposeView.selectDocumentFromPopup = function(resultData) {
set_return(resultData);
if (fileInputID.val().length === 0) {
// id is empty
fileGroupContainer.remove();
self.updateDocumentIDs();
} else {
// id is full
if (fileGroupContainer.find('.attachment-remove').length === 0) {
var removeAttachment = $('<a class="attachment-remove"><span class="glyphicon glyphicon-remove"></span></a>');
fileGroupContainer.append(removeAttachment);
// handle when user removes attachment
removeAttachment.click(function () {
fileGroupContainer.remove();
self.updateDocumentIDs();
});
}
fileInput.val(fileInputID.val());
fileLabel.empty();
var fileContainer = $('<div class="attachment-file-container"></div>');
fileContainer.appendTo(fileLabel);
fileContainer.append('<span class="attachment-name"> ' + fileInputName.val() + ' </span>');
fileLabel.removeClass('attachment-blank');
self.updateDocumentIDs();
}
};
//language=JQuery-CSS
var document_attachment_name = $('[name=document_attachment_name]');
var fileInputName = undefined;
if (document_attachment_name.length === 0) {
fileInputName = $('<input>')
.attr('type', 'hidden')
.attr('name', 'document_attachment_name')
.appendTo(fileGroupContainer.closest('.attachments'));
} else {
fileInputName = document_attachment_name;
}
fileInputName.val('');
var fileLabel = $('<label></label>')
.attr('for', 'file_' + id)
.addClass('attachment-blank')
.html('<img src="themes/' + SUGAR.themes.theme_name + '/images/sidebar/modules/Documents.svg">')
.appendTo(fileGroupContainer);
var showSelectDocumentDialog = function () {
fileInputID.val('');
fileInputName.val('');
var popupWindow = open_popup(
"Documents",
600,
400,
"",
true,
false,
{
"call_back_function": '$.fn.EmailsComposeView.selectDocumentFromPopup',
"form_name": "ComposeView",
"field_to_name_array": {
"id": "document_attachment_id",
"name": "document_attachment_name"
}
},
"single",
false
);
};
// Mimic the file attachment behaviour
fileLabel.click(showSelectDocumentDialog);
// Call the select document dialog
fileLabel.click();
return false;
};
self.updateDocumentIDs = function () {
self.find('.document-attachments')
.find('.attachment-group-container')
.each(function (index, value) {
$(value).find('[data-file-input]').attr('name', 'documentId' + index);
});
};
/**
* @event saveDraft
* @returns {boolean}
*/
self.saveDraft = function (e) {
"use strict";
e.preventDefault();
$(this).closest('[name=action]').val('SaveDraft');
if (self.validate()) {
self.onSavingDraft();
}
return false;
};
self.onSavingDraft = function () {
"use strict";
$(self).trigger("saveDraft", [self]);
// Tell the user we are sending an email
var mb = messageBox({backdrop:'static'});
mb.hideHeader();
mb.hideFooter();
mb.setBody('<div class="email-in-progress"><img src="themes/' + SUGAR.themes.theme_name + '/images/loading.gif"></div>');
mb.show();
mb.on('ok', function () {
"use strict";
mb.remove();
});
mb.on('cancel', function () {
"use strict";
mb.remove();
});
var fileCount = 0;
// Use FormData v2 to send form data via ajax
var formData = new FormData(jQueryFormComposeView);
$(this).find('input').each(function (i, v) {
if ($(v).attr('type').toLowerCase() !== 'file') {
var name = $(v).attr('name');
if (name === 'action') {
formData.append(name, 'SaveDraft');
} else if (name === 'send') {
formData.append(name, 0);
} else {
formData.append(name, $(v).val());
}
}
});
$(this).find('select').each(function (i, v) {
if (typeof $(v).attr('is_file') === 'undefined') {
formData.append($(v).attr('name'), $(v).val());
}
});
$(this).find('textarea').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$(this).find('button').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$.ajax({
type: "POST",
data: formData,
cache: false,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
url: 'index.php?module=Emails'
}).done(function (response) {
"use strict";
response = JSON.parse(response);
if (typeof response.errors !== "undefined") {
mb.showHeader();
mb.setBody(response.errors.title);
mb.showFooter();
mb.hideCancel();
$(self).trigger("saveEmailError", [self, response]);
} else {
mb.showHeader();
mb.setBody(response.data.title);
mb.showFooter();
mb.hideCancel();
$(self).trigger("saveEmailSuccess", [self, response]);
var id = undefined;
if ($(self).find('[name=id]').length === 0) {
id = $('<input>').attr('type', 'hidden').attr('name', 'id').val(response.data.id);
id.appendTo($(self).closest('[name=ComposeView]'));
} else {
id = $(self).find('[name=id]');
$(id).val(response.data.id);
}
$(self).find('input[name=record]').val(response.data.id);
$.fn.EmailsComposeView.checkForDraftAttachments(response.data.id);
}
}).fail(function (response) {
"use strict";
response = JSON.parse(response);
mb.setBody(response.errors.title);
$(self).trigger("saveEmailError", [self, response]);
}).always(function (response) {
response = JSON.parse(response);
$(self).trigger("saveEmailAlways", [self, response]);
});
return false;
};
/**
*
* @event disregardDraft
* @returns {boolean}
*/
self.disregardDraft = function () {
"use strict";
var mb = messageBox();
mb.setTitle(SUGAR.language.translate('Emails', 'LBL_CONFIRM_DISREGARD_DRAFT_TITLE'));
mb.setBody(SUGAR.language.translate('Emails', 'LBL_CONFIRM_DISREGARD_DRAFT_BODY'));
mb.show();
mb.on('ok', function () {
"use strict";
mb.setBody('<div class="email-in-progress"><img src="themes/' + SUGAR.themes.theme_name + '/images/loading.gif"></div>');
$(jQueryFormComposeView).find('input[name=action]').val('DeleteDraft');
// Use FormData v2 to send form data via ajax
var formData = new FormData(jQueryFormComposeView);
$(this).find('input').each(function (i, v) {
if ($(v).attr('type').toLowerCase() !== 'file') {
var name = $(v).attr('name');
if (name === 'action') {
formData.append(name, 'Delete');
} else if (name === 'send') {
formData.append(name, 0);
} else {
formData.append(name, $(v).val());
}
}
});
$(this).find('select').each(function (i, v) {
if (typeof $(v).attr('is_file') === 'undefined') {
formData.append($(v).attr('name'), $(v).val());
}
});
$(this).find('textarea').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$(this).find('button').each(function (i, v) {
formData.append($(v).attr('name'), $(v).val());
});
$.ajax({
type: "POST",
data: formData,
cache: false,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
url: 'index.php?module=Emails'
}).done(function (response) {
$(self).trigger("discardDraftDone", [self, response]);
}).error(function (response) {
mb.setBody(SUGAR.language.translate('', 'LBL_ERROR_SAVING_DRAFT'));
$(self).trigger("discardDraftBody", [self, response]);
}).always(function (response) {
$(self).trigger("discardDraftAlways", [self, response]);
mb.remove();
if ($(self).find('input[type="hidden"][name="return_module"]').val() !== '') {
location.href = 'index.php?module=' + $('#' + self.attr('id') + ' input[type="hidden"][name="return_module"]').val() +
'&action=' +
$(self).find('input[type="hidden"][name="return_action"]').val();
} else {
// The user is viewing in the modal view
location.reload();
}
});
});
mb.on('cancel', function () {
"use strict";
// do something
mb.remove();
});
return false;
};
self.humanReadableFileSize = function (bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
};
/**
* Constructor
*/
self.construct = function () {
"use strict";
if (self.length === 0) {
console.error('EmailsComposeView - Invalid Selector');
return;
}
if (self.attr('id').length === 0) {
console.warn('EmailsComposeView - expects element to have an id. EmailsComposeView has generated one.');
self.attr('id', self.generateID());
}
if (self.find("[name=record]").val().length > 0) {
$.fn.EmailsComposeView.checkForDraftAttachments(self.find("[name=record]").val());
}
if (typeof opts.tinyMceOptions.setup === "undefined") {
opts.tinyMceOptions.setup = self.tinyMceSetup;
}
if (typeof opts.tinyMceOptions.selector === "undefined") {
opts.tinyMceOptions.selector = 'form[name="ComposeView"] textarea[id=description]';
}
if ($(self).find('#from_addr_name').length !== 0) {
var selectFrom = $('<select></select>')
.attr('name', 'from_addr')
.attr('id', 'from_addr_name');
var from_addr = $(self).find('#from_addr_name');
from_addr.replaceWith(selectFrom);
var hiddenOutboundEmailId = $('<input type="hidden" name="outbound_email_id" id="outbound_email_id" value="">');
selectFrom.parent().append(hiddenOutboundEmailId);
$.ajax({
"url": 'index.php?module=Emails&action=getFromFields'
}).done(function (response) {
var json = JSON.parse(response);
if (typeof json.data !== "undefined") {
var optionGroups = {
InboundEmail: {
label: 'LBL_INBOUND_ACCOUNT',
options: []
},
OutboundEmailAccount: {
label: 'LBL_OUTBOUND_ACCOUNT',
options: []
},
system: {
label: 'LBL_SYSTEM_ACCOUNT',
options: []
},
personal: {
label: 'LBL_FROM_SYSTEM',
options: []
},
};
$(json.data).each(function (i, v) {
var selectOption = $('<option></option>');
selectOption.attr('value', v.attributes.from);
var entryType = v.type || '';
var entryLabel = self.getFromEntryLabel(v);
if (entryType === 'OutboundEmailAccount' || entryType === 'system') {
selectOption.attr('data-outbound-email-id', v.id);
} else {
selectOption.attr('inboundId', v.id);
}
var fromName = v.attributes.name;
if (!fromName) {
fromName = v.attributes.from;
}
selectOption.attr('infos', '(<b>Reply-to:</b> ' + v.attributes.reply_to + ' , <b>Reply-to Name:</b> ' + v.attributes.reply_to_name + ' , <b>From:</b> ' + v.attributes.from + ', <b>From Name:</b> ' + v.attributes.name + ')');
selectOption.attr('data-from-name', fromName);
selectOption.attr('data-from-address', v.attributes.from);
selectOption.attr('data-reply-to-name', v.attributes.reply_to_name);
selectOption.attr('data-reply-to-address', v.attributes.reply_to);
selectOption.attr('data-type', v.type);
selectOption.attr('label', entryLabel);
selectOption.html(entryLabel);
optionGroups[entryType].options.push(selectOption);
selectOption.attr('data-email-signature-id', v.id);
// include signature for account
$('<textarea></textarea>')
.val(v.emailSignatures.html)
.addClass('email-signature')
.addClass('html')
.addClass('hidden')
.attr('data-email-signature-id', v.id)
.appendTo(self);
$('<textarea></textarea>')
.val(v.emailSignatures.plain)
.addClass('email-signature')
.addClass('plain')
.addClass('hidden')
.attr('data-email-signature-id', v.id)
.appendTo(self);
if (typeof v.prepend !== "undefined" && v.prepend === true) {
self.prependSignature = true;
}
});
Object.keys(optionGroups).forEach(function (type) {
var optionGroup = optionGroups[type];
if (!optionGroup || !optionGroup.options || !optionGroup.options.length) {
return;
}
var $optionGroup = $('<optgroup>', {
label: SUGAR.language.translate('', optionGroup.label)
});
optionGroup.options.forEach(function (option) {
selectFrom.append(option);
});
});
self.updateOutboundEmailId(selectFrom);
var selectedInboundEmail = $(self).find('[name=inbound_email_id]').val();
var selectInboundEmailOption = $(selectFrom).find('[inboundid="' + selectedInboundEmail + '"]');
if (selectInboundEmailOption.val()) {
$(selectFrom).val(selectInboundEmailOption.val());
}
$.widget( "custom.emailselectmenu", $.ui.selectmenu, {
_renderItem: function( ul, item ) {
var $option = item.element;
var fromName = $option.attr('data-from-name');
var fromAddress = $option.attr('data-from-address');
var $info = $('<div>', {
class: 'compose-from-email-account'
});
$info.append("<div class='compose-from-email-address-name'><span>" + fromName + "</span></div>");
$info.append("<div class='compose-from-email-address-from'><span class='small'>&lt;" + fromAddress + "&gt;</span></div>");
return $( "<li>" )
.append($info)
.appendTo( ul );
}
});
$( selectFrom ).emailselectmenu({
change: function( event, ui ) {
self.onFromSelect(selectFrom, ui);
},
select: function( event, ui ) {
self.onFromSelect(selectFrom, ui);
},
appendTo: selectFrom.parent(),
'max-width': '200px'
});
$(selectFrom).change(function (e) {
var newlySelected = selectFrom.find('option:selected');
var entryType = newlySelected.attr('data-type') || '';
$('#outbound_email_id').val('');
if (entryType === 'OutboundEmailAccount' || entryType === 'system') {
self.updateOutboundEmailId(selectFrom);
} else {
$(self).find('[name=inbound_email_id]').val($(this).find('option:selected').attr('inboundId'));
}
self.updateSignature();
});
$(self).trigger('emailComposeViewGetFromFields');
if (tinymce.initialized === true) {
self.updateSignature();
} else if(tinymce.EditorManager && tinymce.EditorManager.activeEditor) {
tinymce.EditorManager.activeEditor.on('init', function(e) {
self.updateSignature();
});
}
}
if ($(self).find('#is_only_plain_text').length === 1) {
$(self).find('#is_only_plain_text').click(function () {
let tinymceContainer = $(tinymce.EditorManager.activeEditor.getContainer());
let description = $(self).find('#description');
if ($('#is_only_plain_text').prop('checked')) {
tinymceContainer.hide();
description.show();
} else {
description.hide();
tinymceContainer.show();
}
});
}
if (typeof json.errors !== "undefined") {
$.fn.EmailsComposeView.showAjaxErrorMessage(json);
}
}).error(function (response) {
console.error(response);
});
}
/**
* Used to preview email. It also doubles as a means to get the plain text version
* using $('#'+self.attr('id') + ' .html_preview').text();s
*/
$('<div></div>').addClass('hidden').addClass('html_preview').appendTo($(self));
$('<input>')
.attr('name', 'description_html')
.attr('type', 'hidden')
.attr('id', 'description_html')
.appendTo($(self));
if (typeof tinymce === "undefined") {
console.error('EmailsComposeView - Missing Dependency: Cannot find tinyMCE.');
// copy plain to html
$(self).find('#description_html').closest('.edit-view-row-item').addClass('hidden');
$(self).find('textarea#description_html').on("keyup", function () {
$(self).find('input#description_html').val($(self).find('textarea#description').val().replace('\n', '<br>'));
});
} else {
$(self).find('[data-label="description_html"]').closest('.edit-view-row-item').addClass('hidden');
var intervalCheckTinymce = window.setInterval(function () {
var isFromPopulated = $('#from_addr_name').prop("tagName").toLowerCase() === 'select';
if (tinymce.editors.length > 0 && isFromPopulated === true) {
self.updateSignature();
clearInterval(intervalCheckTinymce);
}
}, 300);
tinymce.init(opts.tinyMceOptions);
}
// Handle sent email submission
self.submit(self.onSendEmail);
// Handle toolbar (default) button events
$(self).find('.btn-send-email').click(self.sendEmail);
$(self).find('.btn-attach-file').click(self.attachFile);
$(self).find('.btn-attach-notes').click(self.attachNote);
$(self).find('.btn-attach-document').click(self.attachDocument);
$(self).find('.btn-save-draft').click(self.saveDraft);
$(self).find('.btn-disregard-draft').click(self.disregardDraft);
var file = $('<input />')
.attr('name', file);
$(self).on('remove', self.destruct);
// detect empty rows
$(self).find('.edit-view-row-item').each(function () {
if (trim($(this).html()).length === 0) {
$(this).addClass('empty');
}
});
// qtipBar
var hidden = $('<input type="hidden" id="qtip_bar_module">' +
'<input type="hidden" id="qtip_bar_id">' +
'<input type="hidden" id="qtip_bar_name">' +
'<input type="hidden" id="qtip_bar_email_address">').appendTo(self);
$(self).find('#to_addrs_names').focus(self.showQTipBar);
$(self).find('#cc_addrs_names').focus(self.showQTipBar);
$(self).find('#bcc_addrs_names').focus(self.showQTipBar);
$(self).on('sendEmail', function () {
$('.emails-qtip').remove();
});
$(self).trigger("constructEmailsComposeView", [self]);
};
/**
* @destructor
*/
self.destruct = function () {
// TODO: Find a better way only display one tiny mce
// Remove the hanging tinyMCE div
$('.mce-panel').remove();
var length = tinyMCE.editors.length;
for (var i = length; i > 0; i--) {
tinyMCE.editors[i - 1].remove();
}
$('.emails-qtip').remove();
return true;
};
self.construct();
return $(self);
};
$.fn.EmailsComposeView.checkForDraftAttachments = function (id) {
// Check if this is a draft email with attachments
$.ajax({
"url": 'index.php?module=Emails&action=GetDraftAttachmentData&id=' + id
}).done(function (jsonResponse) {
var response = JSON.parse(jsonResponse);
if (typeof response.data !== "undefined") {
$('.file-attachments').empty();
$.fn.EmailsComposeView.loadAttachmentDataFromAjaxResponse(response);
}
if (typeof response.errors !== "undefined") {
$.fn.EmailsComposeView.showAjaxErrorMessage(response);
}
}).error(function (response) {
console.error(response);
});
};
$.fn.EmailsComposeView.showAjaxErrorMessage = function (response) {
var message = '';
$.each(response.errors, function (i, v) {
message = message + v.title;
});
var mb = messageBox();
mb.setBody(message);
mb.show();
mb.on('ok', function () {
"use strict";
mb.remove();
});
mb.on('cancel', function () {
"use strict";
mb.remove();
});
};
$.fn.EmailsComposeView.loadAttachmentDataFromAjaxResponse = function (response) {
var isDraft = (typeof response.data.draft !== undefined && response.data.draft ? true : false);
var inputName = 'template_attachment[]';
var removeName = 'temp_remove_attachment[]';
if (isDraft) {
var inputName = 'dummy_attachment[]';
var removeName = 'remove_attachment[]';
}
if (typeof response.data.attachments !== 'undefined' && response.data.attachments.length > 0) {
var removeDraftAttachmentInput = $('<input>')
.attr('type', 'hidden')
.attr('name', 'removeAttachment')
.appendTo($('.file-attachments'));
for (i = 0; i < response.data.attachments.length; i++) {
var id = response.data.attachments[i]['id'];
var fileGroupContainer = $('<div></div>')
.addClass('attachment-group-container')
.appendTo($('.file-attachments'));
var fileInput = $('<select></select>')
.attr('style', 'display:none')
.attr('id', id)
.attr('is_file', true)
.attr('name', inputName)
.attr('multiple', 'multiple');
var fileOptions = $('<option></option>')
.attr('selected', 'selected')
.attr('value', id)
.appendTo(fileInput);
fileInput.appendTo(fileGroupContainer);
var fileLabel = $('<label></label>')
.attr('for', 'file_' + id)
.html('<span class="glyphicon glyphicon-paperclip"></span>')
.appendTo(fileGroupContainer);
var fileContainer = $('<div class="attachment-file-container"></div>');
fileContainer.appendTo(fileLabel);
fileContainer.append('<span class="attachment-name"> ' + response.data.attachments[i]['name'] + ' </span>');
var removeAttachment = $('<a class="attachment-remove"><span class="glyphicon glyphicon-remove"></span></a>');
removeAttachment.click(function () {
$(this).parent().hide();
$(this).parent().find('[name="' + inputName + '"]').attr('name', removeName);
if (isDraft) {
removeDraftAttachmentInput.val(removeDraftAttachmentInput.val() + '::' + id);
}
});
fileGroupContainer.append(removeAttachment);
}
}
};
$.fn.EmailsComposeView.onTemplateSelect = function (args) {
var confirmed = function (args) {
var args = JSON.parse(args);
var form = $('[name="' + args.form_name + '"]');
$.post('index.php?entryPoint=emailTemplateData', {
emailTemplateId: args.name_to_value_array.emails_email_templates_idb
}, function (jsonResponse) {
var response = JSON.parse(jsonResponse);
$.fn.EmailsComposeView.loadAttachmentDataFromAjaxResponse(response);
$(form).find('[name="name"]').val(response.data.subject);
tinymce.activeEditor.setContent(response.data.body_from_html, {format: 'html'});
$.fn.EmailsComposeView.updateSignature();
});
set_return(args);
};
var mb = messageBox();
mb.setTitle(SUGAR.language.translate('Emails', 'LBL_CONFIRM_APPLY_EMAIL_TEMPLATE_TITLE'));
mb.setBody(SUGAR.language.translate('Emails', 'LBL_CONFIRM_APPLY_EMAIL_TEMPLATE_BODY'));
mb.show();
var args = JSON.stringify(args);
mb.on('ok', function () {
"use strict";
confirmed(args);
mb.remove();
});
mb.on('cancel', function () {
"use strict";
mb.remove();
});
};
$.fn.EmailsComposeView.onTemplateChange = function (args) {
var confirmed = function (args) {
var args = JSON.parse(args);
var form = $('[name="' + args.form_name + '"]');
$.post('index.php?entryPoint=emailTemplateData', {
emailTemplateId: args.name_to_value_array.emails_email_templates_idb
}, function (jsonResponse) {
var response = JSON.parse(jsonResponse);
$.fn.EmailsComposeView.loadAttachmentDataFromAjaxResponse(response);
$(form).find('[name="name"]').val(response.data.subject);
tinymce.activeEditor.setContent(response.data.body_from_html, {format: 'html'});
$.fn.EmailsComposeView.updateSignature();
});
set_return(args);
};
var mb = messageBox();
mb.setTitle(SUGAR.language.translate('Emails', 'LBL_CONFIRM_APPLY_EMAIL_TEMPLATE_TITLE'));
mb.setBody(SUGAR.language.translate('Emails', 'LBL_CONFIRM_APPLY_EMAIL_TEMPLATE_BODY'));
mb.show();
mb.on('ok', function () {
"use strict";
var id=$('#emails_email_templates_idb').val();
var name=$('#emails_email_templates_name').val();
args = JSON.stringify({"form_name":"ComposeView","name_to_value_array":{"emails_email_templates_idb": id,"emails_email_templates_name": name}})
confirmed(args);
mb.remove();
});
mb.on('cancel', function () {
"use strict";
mb.remove();
});
}
$.fn.EmailsComposeView.onParentSelect = function (args) {
set_return(args);
if (isValidEmail(args.name_to_value_array.email1)) {
var emailAddress = args.name_to_value_array.email1;
var self = $('[name="' + args.form_name + '"]');
var toField = $(self).find('[name=to_addrs_names]');
if (toField.val().indexOf(emailAddress) === -1) {
var toFieldVal = toField.val();
if (toFieldVal === '') {
toField.val(emailAddress);
} else {
toField.val(toFieldVal + ', ' + emailAddress);
}
}
}
};
$.fn.EmailsComposeView.defaults = {
"tinyMceOptions": {
menubar: false,
plugins: ['link'],
toolbar: ['fontselect | fontsizeselect | bold italic underline | forecolor backcolor | styleselect | outdent indent | link'],
formats: {
bold: {inline: 'b'},
italic: {inline: 'i'},
underline: {inline: 'u'}
},
convert_urls: false,
relative_urls: false,
remove_script_host: false,
}
};
}(jQuery));