sogo/UI/WebServerResources/UIxMailEditor.js
2014-05-28 11:21:11 -04:00

730 lines
24 KiB
JavaScript

/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
var contactSelectorAction = 'mailer-contacts';
var attachmentCount = 0;
var MailEditor = {
currentField: null,
selectedIndex: -1,
delay: 750,
delayedSearch: false,
signatureLength: 0,
textFirstFocus: true
};
function onContactAdd(button) {
var div = $("contacts");
if (div.visible()) {
div.hide();
$("rightPanel").setStyle({ left: "0px" });
$(button).removeClassName("active");
}
else {
$("rightPanel").setStyle({ left: $("leftPanel").getStyle("width") });
div.show();
$(button).addClassName("active");
}
$("hiddenDragHandle").adjust();
onWindowResize(null);
}
function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
if (!mailIsRecipient(contactEmail)) {
var neededOptionValue = 0;
if (tag == "cc")
neededOptionValue = 1;
else if (tag == "bcc")
neededOptionValue = 2;
var stop = false;
var counter = 0;
var currentRow = $('row_' + counter);
while (currentRow && !stop) {
var currentValue = $(currentRow.childNodesWithTag("td")[1]).childNodesWithTag("input")[0].value;
if (currentValue == neededOptionValue) {
stop = true;
insertContact($("addr_" + counter), contactName, contactEmail);
}
counter++;
currentRow = $('row_' + counter);
}
if (!stop) {
fancyAddRow("");
var row = $("row_" + currentIndex);
var td = $(row.childNodesWithTag("td")[0]);
var select = $(td.childNodesWithTag("select")[0]);
select.value = neededOptionValue;
insertContact($("addr_" + currentIndex), contactName, contactEmail);
onWindowResize(null);
}
}
}
function onContactFolderChange(event) {
initCriteria();
openContactsFolder(this.value);
}
function mailIsRecipient(mailto) {
var isRecipient = false;
var counter = 0;
var currentRow = $('row_' + counter);
var email = extractEmailAddress(mailto).toUpperCase();
while (currentRow && !isRecipient) {
var currentValue = $("addr_"+counter).value.toUpperCase();
if (currentValue.indexOf(email) > -1)
isRecipient = true;
else
{
counter++;
currentRow = $('row_' + counter);
}
}
return isRecipient;
}
function insertContact(inputNode, contactName, contactEmail) {
var value = '' + inputNode.value;
var newContact = contactName;
if (newContact.length > 0)
newContact += ' <' + contactEmail + '>';
else
newContact = contactEmail;
if (value.length > 0)
value += ", ";
value += newContact;
inputNode.value = value;
}
function updateWindowTitleFromSubject(event) {
if (this.value) {
document.title = this.value;
}else{
document.title = '(' + _("Untitled") + ')';
}
}
/* mail editor */
function onValidate(onSuccess) {
if (document.pageform.action != "send") {
if (!hasRecipients()) {
showAlertDialog(_("error_missingrecipients"));
}
else if (document.pageform.subject.value == "") {
showConfirmDialog(_("Warning"), _("error_missingsubject"), onValidateDone.bind(this, onSuccess), null, _("Send Anyway"), _("Cancel"));
}
else {
onValidateDone(onSuccess);
}
}
}
function onValidateDone(onSuccess) {
// Create "blocking" div to avoid double-clicking on send button
var safetyNet = createElement("div", "javascriptSafetyNet");
$('pageContent').insert({top: safetyNet});
if (!document.busyAnim) {
var toolbar = document.getElementById("toolbar");
document.busyAnim = startAnimation(toolbar);
}
var lastRow = $("lastRow");
lastRow.down("select").name = "popup_last";
window.shouldPreserve = true;
document.pageform.action = "send";
if (typeof onSuccess == 'function')
onSuccess();
disposeDialog();
return true;
}
function onPostComplete(http) {
var response = http.responseText;
if (response && response.length > 0) {
var jsonResponse = response.evalJSON();
if (jsonResponse["status"] == "success") {
var p;
if (window.frameElement && window.frameElement.id)
p = parent;
if (window.opener && window.opener.refreshMessage)
p = window.opener;
if (p && p.refreshMessage)
p.refreshMessage(jsonResponse["sourceFolder"],
jsonResponse["messageID"]);
onCloseButtonClick();
}
else {
var message = jsonResponse["message"];
document.pageform.action = "";
var progressImage = $("progressIndicator");
if (progressImage) {
progressImage.parentNode.removeChild(progressImage);
}
showAlertDialog(jsonResponse["message"]);
// Remove "blocking" div
onFinalLoadHandler(); // from generic.js
}
}
else {
onCloseButtonClick();
}
}
function clickedEditorSend() {
onValidate(function() {
if (CKEDITOR.instances.text) CKEDITOR.instances.text.updateElement();
triggerAjaxRequest(document.pageform.action,
onPostComplete,
null,
Form.serialize(document.pageform), // excludes the file input
{ "Content-type": "application/x-www-form-urlencoded" });
});
return false;
}
function formatBytes(bytes, si) {
var thresh = si ? 1000 : 1024;
if (bytes < thresh) return bytes + ' B';
var units = si ? ['KiB','MiB','GiB'] : ['KB','MB','GB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (bytes >= thresh);
return bytes.toFixed(1) + ' ' + units[u];
}
function createAttachment(file) {
var list = $('attachments');
var attachment;
if (list.select('[data-filename="'+file.name+'"]').length == 0) {
// File is not already uploaded
var attachment = createElement('li', null, ['muted progress0'], null, { 'data-filename': file.name }, list);
attachment.appendChild(new Element('i', { 'class': 'icon-attachment' }));
var a = createElement('a', null, null, null, {'href': '#', 'target': '_new' }, attachment);
a.appendChild(document.createTextNode(file.name));
if (file.size)
attachment.appendChild(new Element('span', { 'class': 'muted' }).update('(' + formatBytes(file.size, true) + ')'));
}
return attachment;
}
function clickedEditorSave() {
var lastRow = $("lastRow");
lastRow.down("select").name = "popup_last";
window.shouldPreserve = true;
document.pageform.action = "save";
if (CKEDITOR.instances.text) CKEDITOR.instances.text.updateElement();
triggerAjaxRequest(document.pageform.action, function (http) {
if (http.readyState == 4) {
if (http.status == 200) {
if (window.opener && window.opener.open && !window.opener.closed)
window.opener.refreshFolderByType('draft');
}
else {
var response = http.responseText.evalJSON(true);
showAlertDialog(_("Error while saving the draft:") + " " + response.textStatus);
}
}
},
null,
Form.serialize(document.pageform), // excludes the file input
{ "Content-type": "application/x-www-form-urlencoded" });
return false;
}
/**
* On first focus of textarea, position the caret with respect to user's preferences
*/
function onTextFocus(event) {
if (MailEditor.textFirstFocus) {
var content = this.getValue();
var replyPlacement = UserDefaults["SOGoMailReplyPlacement"];
if (replyPlacement == "above" || !mailIsReply) {
// For forwards, place caret at top unconditionally
this.setCaretTo(0);
}
else {
var caretPosition = this.getValue().length - MailEditor.signatureLength;
caretPosition = adjustOffset(this, caretPosition);
if (hasSignature())
caretPosition -= 2;
this.setCaretTo(caretPosition);
}
MailEditor.textFirstFocus = false;
}
}
/**
* Change behavior of tab key in textarea (plain-text mail)
*/
function onTextKeyDown(event) {
if (event.keyCode == Event.KEY_TAB) {
if (event.shiftKey) {
// Shift-tab goes back to subject field
var subjectField = $$("div#subjectRow input").first();
subjectField.focus();
subjectField.selectText(0, subjectField.value.length);
preventDefault(event);
}
else {
if (!(event.shiftKey || event.metaKey || event.ctrlKey)) {
// Convert a tab to 4 spaces
if (typeof(this.selectionStart) != "undefined") { // Mozilla and Safari
var cursor = this.selectionStart;
var startText = ((cursor > 0)
? this.value.substr(0, cursor)
: "");
var endText = this.value.substr(cursor);
var newText = startText + " " + endText;
this.value = newText;
cursor += 4;
this.setSelectionRange(cursor, cursor);
}
else if (this.selectionRange) // IE
this.selectionRange.text = " ";
preventDefault(event);
}
}
}
}
function onTextIEUpdateCursorPos(event) {
this.selectionRange = document.selection.createRange().duplicate();
}
function onHTMLFocus(event) {
if (MailEditor.textFirstFocus) {
var s = event.editor.getSelection();
var selected_ranges = s.getRanges();
var children = event.editor.document.getBody().getChildren();
var node;
var caretAtTop = (UserDefaults["SOGoMailReplyPlacement"] == "above")
|| !mailIsReply; // for forwards, place caret at top unconditionally
if (caretAtTop) {
node = children.getItem(0);
}
else {
// Search for signature starting from bottom
node = children.getItem(children.count() - 1);
while (true) {
var x = node.getPrevious();
if (x == null) {
break;
}
if (x.getText() == '--') {
node = x.getPrevious().getPrevious();
break;
}
node = x;
}
}
s.selectElement(node);
// Place the caret
if (caretAtTop)
s.scrollIntoView(); // top
selected_ranges = s.getRanges();
selected_ranges[0].collapse(true);
s.selectRanges(selected_ranges);
if (!caretAtTop)
s.scrollIntoView(); // bottom
MailEditor.textFirstFocus = false;
}
}
function initAddresses() {
var addressList = $("addressList");
addressList.select("input.textField").each(function (input) {
if (!input.readAttribute("readonly")) {
input.addInterface(SOGoAutoCompletionInterface);
input.uidField = "c_name";
input.on("focus", addressFieldGotFocus.bind(input));
input.on("blur", addressFieldLostFocus.bind(input));
input.on("autocompletion:changedlist", expandContactList);
input.on("autocompletion:changed", addressFieldChanged.bind(input));
//input.onListAdded = expandContactList;
}
});
}
/* Overwrite function of MailerUI.js */
function configureDragHandle() {
var handle = $("hiddenDragHandle");
if (handle) {
handle.addInterface(SOGoDragHandlesInterface);
handle.leftMargin = 135; // minimum width
handle.leftBlock = $("leftPanel");
handle.rightBlock = $("rightPanel");
handle.enableRightSafety();
handle.observe("handle:dragged", onWindowResize);
}
}
function configureAttachments() {
var list = $("attachments");
if (!list) return;
list.on('click', 'a', function (event, element) {
// Don't follow links of attachments not yet uploaded
if (!element.up('li').hasClassName('progressDone')) {
Event.stop(event);
return false;
}
});
list.on('click', 'i.icon-attachment', function (event, element) {
// Delete attachment when clicking on small icon
var item = element.up('li');
if (item.hasClassName('progressDone')) {
var filename = item.readAttribute('data-filename');
var url = "" + window.location;
var parts = url.split("/");
parts[parts.length-1] = "deleteAttachment?filename=" + encodeURIComponent(filename);
url = parts.join("/");
triggerAjaxRequest(url, attachmentDeleteCallback, item);
}
});
var dropzone = jQuery('#dropZone');
jQuery('#fileUpload').fileupload({
// With singleFileUploads option enabled, the 'add' and 'done' (or 'fail') callbacks
// are called once for each file in the selection for XHR file uploads
singleFileUploads: true,
pasteZone: null,
dataType: 'json',
add: function (e, data) {
var file = data.files[0];
var attachment = createAttachment(file);
if (attachment) {
file.attachment = attachment;
// Update the text field when using HTML mode
if (CKEDITOR.instances.text) CKEDITOR.instances.text.updateElement();
data.submit();
}
if (dropzone.is(":visible"))
dropzone.fadeOut('fast');
},
done: function (e, data) {
var attachment = data.files[0].attachment;
var attrs = data.result[data.result.length-1];
attachment.className = 'progressDone';
attachment.down('a').setAttribute('href', attrs.url);
if (window.opener && window.opener.open && !window.opener.closed)
window.opener.refreshFolderByType('draft');
},
fail: function (e, data) {
var attachment = data.files[0].attachment;
var filename = data.files[0].name;
var textStatus;
try {
var response = data.xhr().response.evalJSON();
textStatus = response.textStatus;
} catch (e) {}
if (!textStatus)
textStatus = _("Can't contact server");
showAlertDialog(_("Error while uploading the file \"%{0}\":").formatted(filename) + " " + textStatus);
attachment.remove();
},
dragover: function (e, data) {
if (!dropzone.is(":visible"))
dropzone.show();
},
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 4, 10);
var attachment = data.files[0].attachment;
attachment.className = 'muted progress' + progress;
}
});
dropzone.on('dragleave', function (e) {
dropzone.fadeOut('fast');
});
}
function initMailEditor() {
var textarea = $("text");
if (composeMode != "html" && $("text"))
textarea.show();
configureAttachments();
initAddresses();
var focusField = textarea;
if (!mailIsReply) {
focusField = $("addr_0");
focusField.focus();
}
initializePriorityMenu();
initializeReturnReceiptMenu();
configureDragHandle();
// Set current subject as window title if not set, use '(Untitled)'
if (document.pageform.subject.value == "")
document.title = '(' + _("Untitled") + ')';
else
document.title = _(document.pageform.subject.value);
// Change the window title when typing the subject
$$("div#subjectRow input").first().on("keyup", updateWindowTitleFromSubject);
var composeMode = UserDefaults["SOGoMailComposeMessageType"];
if (composeMode == "html") {
// HTML mode
CKEDITOR.replace('text',
{
language : localeCode,
scayt_sLang : localeCode
}
);
CKEDITOR.on('instanceReady', function(event) {
if (focusField == textarea)
// CKEditor reports being ready but it's still not focusable;
// we wait for a few more milliseconds
setTimeout("CKEDITOR.instances.text.focus()", 500);
});
CKEDITOR.instances.text.on('focus', onHTMLFocus);
}
else {
// Plain text mode
var textContent = textarea.getValue();
if (hasSignature()) {
var sigLimit = textContent.lastIndexOf("--");
if (sigLimit > -1)
MailEditor.signatureLength = (textContent.length - sigLimit);
}
if (UserDefaults["SOGoMailReplyPlacement"] != "above") {
textarea.scrollTop = textarea.scrollHeight;
}
textarea.observe("focus", onTextFocus);
textarea.observe("keydown", onTextKeyDown);
if (Prototype.Browser.IE) {
// Hack to allow to replace the tab by spaces in IE < 9
var ieEvents = [ "click", "select", "keyup" ];
for (var i = 0; i < ieEvents.length; i++)
textarea.observe(ieEvents[i], onTextIEUpdateCursorPos, false);
}
if (focusField == textarea)
textarea.focus();
}
$("contactFolder").observe("change", onContactFolderChange);
Event.observe(window, "beforeunload", onMailEditorClose);
}
function initializePriorityMenu() {
var priority = $("priority").value.toUpperCase();
var priorityMenu = $("priorityMenu").childNodesWithTag("ul")[0];
var menuEntries = $(priorityMenu).childNodesWithTag("li");
var chosenNode;
if (priority == "HIGHEST")
chosenNode = menuEntries[0];
else if (priority == "HIGH")
chosenNode = menuEntries[1];
else if (priority == "LOW")
chosenNode = menuEntries[3];
else if (priority == "LOWEST")
chosenNode = menuEntries[4];
else
chosenNode = menuEntries[2];
priorityMenu.chosenNode = chosenNode;
$(chosenNode).addClassName("_chosen");
}
function initializeReturnReceiptMenu() {
var receipt = $("receipt").value.toLowerCase();
if (receipt == "true")
$("optionsMenu").down('li').addClassName("_chosen");
}
function onMenuCheckReturnReceipt(event) {
event.cancelBubble = true;
this.enabled = !this.enabled;
var enabled = this.enabled;
if (enabled) {
this.addClassName("_chosen");
}
else {
this.removeClassName("_chosen");
}
var receiptInput = $("receipt");
receiptInput.value = (enabled ? "true" : "false") ;
}
function getMenus() {
return {
"optionsMenu": [ onMenuCheckReturnReceipt,
"-",
"priorityMenu" ],
"priorityMenu": [ onMenuSetPriority,
onMenuSetPriority,
onMenuSetPriority,
onMenuSetPriority,
onMenuSetPriority ]
};
}
function attachmentDeleteCallback(http) {
if (http.readyState == 4) {
if (isHttpStatus204(http.status)) {
var node = http.callbackData;
node.parentNode.removeChild(node);
}
else
log("attachmentDeleteCallback: an error occured: " + http.responseText);
}
}
/**
* Adjust offset when the browser uses two characters for line feeds.
*/
function adjustOffset(element, offset) {
var val = element.value, newOffset = offset;
if (val.indexOf("\r\n") > -1) {
var matches = val.replace(/\r\n/g, "\n").slice(0, offset).match(/\n/g);
newOffset -= matches ? matches.length - 1 : 0;
}
return newOffset;
}
function hasSignature() {
try {
return(UserDefaults["SOGoMailSignature"].length > 0);
} catch(e) {
return false;
}
}
function onMenuSetPriority(event) {
event.cancelBubble = true;
var priority = this.getAttribute("priority");
if (this.parentNode.chosenNode)
this.parentNode.chosenNode.removeClassName("_chosen");
this.addClassName("_chosen");
this.parentNode.chosenNode = this;
var priorityInput = $("priority");
priorityInput.value = priority;
}
function onSelectOptions(event) {
if (event.button == 0 || (isWebKit() && event.button == 1)) {
var node = getTarget(event);
if (node.tagName != 'A')
node = $(node).up("A");
popupToolbarMenu(node, "optionsMenu");
Event.stop(event);
}
}
/**
* Overwrite definition of MailerUI.js
*/
function onWindowResize(event) {
if (!document.pageform)
return;
var textarea = document.pageform.text;
var rowheight = (Element.getHeight(textarea) / textarea.rows);
var headerarea = $("headerArea");
var totalwidth = $("rightPanel").getWidth();
var subjectfield = headerarea.down("div#subjectRow span.headerField");
var subjectinput = headerarea.down("div#subjectRow input.textField");
// Resize subject field
subjectinput.setStyle({ width: (totalwidth
- $(subjectfield).getWidth()
- 17) + 'px' });
// Resize from field
$("fromSelect").setStyle({ width: (totalwidth
- $("fromField").getWidth()
- 15) + 'px' });
// Resize address fields
// var addresslist = $('addressList');
// addresslist.setStyle({ width: (totalwidth - 10) + 'px' });
// Resize the textarea (message content)
var offsetTop = $('rightPanel').offsetTop + headerarea.getHeight();
var composeMode = UserDefaults["SOGoMailComposeMessageType"];
if (composeMode == "html") {
var editor = $('cke_text');
if (editor == null) {
onWindowResize.defer();
return;
}
var height = window.height() - offsetTop;
CKEDITOR.instances["text"].resize('100%', height);
}
else
textarea.rows = Math.floor((window.height() - offsetTop) / rowheight);
// Resize search contacts addressbook selector
if ($("contacts").visible())
$("contactFolder").setStyle({ width: ($("contactsSearch").getWidth() - 10) + "px" });
}
function onMailEditorClose(event) {
var e = event || window.event;
if (window.shouldPreserve) {
window.shouldPreserve = false;
if (jQuery('#fileUpload').fileupload('active') > 0) {
var msg = _("There is an active file upload. Closing the window will interrupt it.");
if (e) {
e.returnValue = msg;
}
return msg;
}
}
else {
var url = "" + window.location;
var parts = url.split("/");
parts[parts.length-1] = "delete";
url = parts.join("/");
if (window.frameElement && window.frameElement.id)
parent.deleteDraft(url);
else if (window.opener && window.opener.open && !window.opener.closed)
window.opener.deleteDraft(url);
}
Event.stopObserving(window, "beforeunload", onMailEditorClose);
}
document.observe("dom:loaded", initMailEditor);