447 lines
13 KiB
JavaScript
447 lines
13 KiB
JavaScript
/**
|
|
* Basic compose view.
|
|
*
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @copyright 2014-2015 Horde LLC
|
|
* @license GPL-2 (http://www.horde.org/licenses/gpl)
|
|
*/
|
|
|
|
var ImpCompose = {
|
|
|
|
// Variables defined in PHP code:
|
|
// cancel_url, cursor_pos, discard_url, last_identity,
|
|
// last_msg, last_sig, max_attachments, popup, redirect, reloaded, rte,
|
|
// sc_submit, sm_check, skip_spellcheck, spellcheck, text
|
|
|
|
display_unload_warning: true,
|
|
|
|
confirmCancel: function(discard, e)
|
|
{
|
|
e.stop();
|
|
|
|
if (window.confirm(this.text.cancel)) {
|
|
this.display_unload_warning = false;
|
|
|
|
if (this.popup) {
|
|
if (this.cancel_url) {
|
|
self.location = (discard ? this.discard_url : this.cancel_url);
|
|
} else {
|
|
self.close();
|
|
}
|
|
} else {
|
|
window.location = (discard ? this.discard_url : this.cancel_url);
|
|
}
|
|
}
|
|
},
|
|
|
|
changeIdentity: function(elt)
|
|
{
|
|
var id = $F(elt),
|
|
last = ImpComposeBase.identities[$F('last_identity')],
|
|
next = ImpComposeBase.identities[id],
|
|
bcc = $('bcc'),
|
|
save = $('ssm'),
|
|
sm = $('sent_mail'),
|
|
re, cur_sig;
|
|
|
|
cur_sig = this.sigHash();
|
|
if (this.last_sig &&
|
|
this.last_sig != cur_sig &&
|
|
!window.confirm(this.text.change_identity)) {
|
|
return false;
|
|
}
|
|
this.last_sig = cur_sig;
|
|
|
|
if (this.sm_check) {
|
|
sm.setValue(next.sm_name);
|
|
} else {
|
|
sm.update(next.sm_display);
|
|
}
|
|
|
|
if (save) {
|
|
save.setValue(next.sm_save);
|
|
}
|
|
if (bcc) {
|
|
bccval = $F(bcc);
|
|
|
|
if (last.bcc) {
|
|
re = new RegExp(last.bcc + ",? ?", 'gi');
|
|
bccval = bccval.replace(re, "");
|
|
if (bccval) {
|
|
bccval = bccval.replace(/, ?$/, "");
|
|
}
|
|
}
|
|
|
|
if (next.bcc) {
|
|
if (bccval) {
|
|
bccval += ', ';
|
|
}
|
|
bccval += next.bcc;
|
|
}
|
|
|
|
bcc.setValue(bccval);
|
|
}
|
|
ImpComposeBase.setSignature(ImpComposeBase.editor_on, next);
|
|
this.last_identity = $F('identity');
|
|
|
|
return true;
|
|
},
|
|
|
|
uniqSubmit: function(actionID, e)
|
|
{
|
|
var cur_msg, form, sc;
|
|
|
|
if (!Object.isUndefined(e)) {
|
|
e.stop();
|
|
}
|
|
|
|
switch (actionID) {
|
|
case 'redirect':
|
|
form = $('redirect');
|
|
break;
|
|
|
|
case 'send_message':
|
|
sc = ImpComposeBase.getSpellChecker();
|
|
|
|
if (sc &&
|
|
!this.skip_spellcheck &&
|
|
this.spellcheck &&
|
|
!sc.isActive()) {
|
|
this.sc_submit = { a: actionID, e: e };
|
|
sc.spellCheck();
|
|
return;
|
|
}
|
|
|
|
if ($F('subject').empty() &&
|
|
!window.confirm(this.text.nosubject)) {
|
|
return;
|
|
}
|
|
|
|
this.skip_spellcheck = false;
|
|
|
|
if (sc) {
|
|
sc.resume();
|
|
}
|
|
// fall through
|
|
|
|
case 'add_attachment':
|
|
case 'replyall_revert':
|
|
case 'replylist_revert':
|
|
case 'save_draft':
|
|
case 'save_template':
|
|
form = $('compose');
|
|
$('actionID').setValue(actionID);
|
|
break;
|
|
|
|
case 'auto_save_draft':
|
|
// Move HTML text to textarea field for submission.
|
|
if (this.rte) {
|
|
this.rte.updateElement();
|
|
}
|
|
|
|
cur_msg = IMP_JS.fnv_1a(
|
|
$('to', 'cc', 'bcc', 'subject').compact().invoke('getValue').join('\0') + $F('composeMessage')
|
|
);
|
|
if (this.last_msg && curr_hash != this.last_msg) {
|
|
// Use an AJAX submit here so that the page doesn't reload.
|
|
$('actionID').setValue(actionID);
|
|
HordeCore.submitForm('compose', {
|
|
callback: this._autoSaveDraftCallback.bind(this)
|
|
});
|
|
}
|
|
this.last_msg = cur_msg;
|
|
return;
|
|
|
|
case 'toggle_editor':
|
|
form = $('compose');
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
$(document).fire('AutoComplete:update');
|
|
|
|
if (this.rte && this.rte.busy()) {
|
|
return this.uniqSubmit.bind(this, actionID, e).delay(0.1);
|
|
}
|
|
|
|
// Ticket #6727; this breaks on WebKit w/FCKeditor.
|
|
if (!Prototype.Browser.WebKit) {
|
|
form.setStyle({ cursor: 'wait' });
|
|
}
|
|
|
|
this.display_unload_warning = false;
|
|
form.submit();
|
|
},
|
|
|
|
_autoSaveDraftCallback: function(r)
|
|
{
|
|
$('compose_formToken').setValue(r.formToken);
|
|
$('compose_requestToken').setValue(r.requestToken);
|
|
},
|
|
|
|
attachmentChanged: function()
|
|
{
|
|
var fields = [],
|
|
usedFields = 0,
|
|
input, lastRow, newRow, td;
|
|
|
|
$('upload_atc').select('input[type="file"]').each(function(i) {
|
|
fields[fields.length] = i;
|
|
});
|
|
|
|
if (this.max_attachments !== null &&
|
|
fields.length == this.max_attachments) {
|
|
return;
|
|
}
|
|
|
|
fields.each(function(i) {
|
|
if (i.value.length > 0) {
|
|
usedFields++;
|
|
}
|
|
});
|
|
|
|
if (usedFields == fields.length) {
|
|
lastRow = $('attachment_row_' + usedFields);
|
|
if (lastRow) {
|
|
td = new Element('TD', { align: 'left' }).insert(new Element('STRONG').insert(this.text.file + ' ' + (usedFields + 1) + ':')).insert(' ');
|
|
|
|
input = new Element('INPUT', { type: 'file', id: 'upload_' + (usedFields + 1), name: 'upload_' + (usedFields + 1), size: 25 });
|
|
if (Prototype.Browser.IE) {
|
|
input.observe('change', this.changeHandler.bindAsEventListener(this));
|
|
}
|
|
td.insert(input);
|
|
|
|
newRow = new Element('TR', { id: 'attachment_row_' + (usedFields + 1) }).insert(td);
|
|
|
|
lastRow.parentNode.insertBefore(newRow, lastRow.nextSibling);
|
|
}
|
|
}
|
|
},
|
|
|
|
sigHash: function()
|
|
{
|
|
return $('signature')
|
|
? IMP_JS.fnv_1a(this.rte ? this.rte.getData() : $F('signature'))
|
|
: 0;
|
|
},
|
|
|
|
updateSigHash: function()
|
|
{
|
|
if (this.rte && this.rte.busy()) {
|
|
this.updateSigHash.bind(this).delay(0.1);
|
|
} else {
|
|
this.last_sig = this.sigHash();
|
|
}
|
|
},
|
|
|
|
clickHandler: function(e)
|
|
{
|
|
var name,
|
|
elt = e.element(),
|
|
id = elt.readAttribute('id');
|
|
|
|
switch (id) {
|
|
case 'addressbook_popup':
|
|
window.open(this.contacts_url, "contacts", "toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100");
|
|
break;
|
|
|
|
case 'redirect_abook':
|
|
window.open(this.redirect_contacts, "contacts", "toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100");
|
|
break;
|
|
|
|
case 'rte_toggle':
|
|
$('rtemode').setValue(~~(!ImpComposeBase.editor_on));
|
|
this.uniqSubmit('toggle_editor');
|
|
break;
|
|
|
|
default:
|
|
if (elt.match('INPUT[type=submit]')) {
|
|
name = elt.readAttribute('name');
|
|
switch (name) {
|
|
case 'btn_add_attachment':
|
|
case 'btn_redirect':
|
|
case 'btn_replyall_revert':
|
|
case 'btn_replylist_revert':
|
|
case 'btn_save_draft':
|
|
case 'btn_save_template':
|
|
case 'btn_send_message':
|
|
this.uniqSubmit(name.substring(4), e.memo);
|
|
break;
|
|
|
|
case 'btn_cancel_compose':
|
|
case 'btn_discard_compose':
|
|
this.confirmCancel(name == 'btn_discard_compose', e.memo);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
changeHandler: function(e)
|
|
{
|
|
var elt = e.element(),
|
|
id = elt.identify();
|
|
|
|
switch (id) {
|
|
case 'identity':
|
|
if (!this.changeIdentity(elt)) {
|
|
$('identity').setValue(this.last_identity);
|
|
}
|
|
break;
|
|
|
|
case 'sent_mail':
|
|
$('ssm').writeAttribute('checked', 'checked');
|
|
break;
|
|
|
|
default:
|
|
if (id.substring(0, 7) == 'upload_') {
|
|
this.attachmentChanged();
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
|
|
keyDownHandler: function(e)
|
|
{
|
|
if (e.keyCode == 10 || e.keyCode == Event.KEY_RETURN) {
|
|
e.stop();
|
|
}
|
|
},
|
|
|
|
onDomLoad: function()
|
|
{
|
|
var config, handler;
|
|
|
|
HordeCore.initHandler('click');
|
|
|
|
if (this.redirect) {
|
|
ImpComposeBase.focus('to');
|
|
} else {
|
|
ImpComposeBase.setSignature(
|
|
ImpComposeBase.editor_on,
|
|
($('signature') && $F('signature'))
|
|
? $F('signature')
|
|
: ImpComposeBase.identities[$F('last_identity')]
|
|
);
|
|
|
|
handler = this.keyDownHandler.bindAsEventListener(this);
|
|
/* Prevent Return from sending messages - it should bring us out
|
|
* of autocomplete, not submit the whole form. */
|
|
$('compose').select('INPUT').each(function(i) {
|
|
/* Attach to everything but button and submit elements. */
|
|
if (i.type != 'submit' && i.type != 'button') {
|
|
i.observe('keydown', handler);
|
|
}
|
|
});
|
|
|
|
ImpComposeBase.setCursorPosition('composeMessage', this.cursor_pos);
|
|
|
|
if (Prototype.Browser.IE) {
|
|
$('subject').observe('keydown', function(e) {
|
|
if (e.keyCode == Event.KEY_TAB && !e.shiftKey) {
|
|
e.stop();
|
|
ImpComposeBase.focus('composeMessage');
|
|
}
|
|
});
|
|
}
|
|
|
|
if (ImpComposeBase.editor_on) {
|
|
config = Object.clone(IMP.ckeditor_config);
|
|
config.extraPlugins = 'pasteignore';
|
|
this.rte = new IMP_Editor('composeMessage', config);
|
|
|
|
document.observe('SpellChecker:after', this._onAfterSpellCheck.bind(this));
|
|
document.observe('SpellChecker:before', this._onBeforeSpellCheck.bind(this));
|
|
}
|
|
|
|
if ($('to') && !$F('to')) {
|
|
ImpComposeBase.focus('to');
|
|
} else if (!$F('subject')) {
|
|
ImpComposeBase.focus(this.rte ? 'subject' : 'composeMessage');
|
|
}
|
|
|
|
document.observe('SpellChecker:noerror', this._onNoErrorSpellCheck.bind(this));
|
|
|
|
if (Prototype.Browser.IE) {
|
|
$('identity', 'sent_mail', 'upload_1').compact().invoke('observe', 'change', this.changeHandler.bindAsEventListener(this));
|
|
} else {
|
|
document.observe('change', this.changeHandler.bindAsEventListener(this));
|
|
}
|
|
|
|
if (this.auto_save) {
|
|
/* Immediately execute to get MD5 hash of empty message. */
|
|
new PeriodicalExecuter(this.uniqSubmit.bind(this, 'auto_save_draft'), this.auto_save * 60).execute();
|
|
}
|
|
this.last_identity = $F('identity');
|
|
this.updateSigHash();
|
|
}
|
|
|
|
this.resize.bind(this).delay(0.25);
|
|
},
|
|
|
|
_onAfterSpellCheck: function()
|
|
{
|
|
this.rte.setData($F('composeMessage'));
|
|
$('composeMessage').next().show();
|
|
delete this.sc_submit;
|
|
},
|
|
|
|
_onBeforeSpellCheck: function()
|
|
{
|
|
ImpComposeBase.getSpellChecker().htmlAreaParent = 'composeMessageParent';
|
|
$('composeMessage').next().hide();
|
|
this.rte.updateElement();
|
|
},
|
|
|
|
_onNoErrorSpellCheck: function()
|
|
{
|
|
if (this.sc_submit) {
|
|
this.skip_spellcheck = true;
|
|
this.uniqSubmit(this.sc_submit.a, this.sc_submit.e);
|
|
} else if (ImpComposeBase.editor_on) {
|
|
this._onAfterSpellCheck();
|
|
} else {
|
|
delete this.sc_submit;
|
|
}
|
|
},
|
|
|
|
resize: function()
|
|
{
|
|
var d, e = this.redirect ? $('redirect') : $('compose');
|
|
|
|
if (this.popup && !this.reloaded) {
|
|
e = e.getHeight();
|
|
if (!e) {
|
|
return this.resize.bind(this).delay(0.1);
|
|
}
|
|
d = Math.min(e, screen.height - 50) - document.viewport.getHeight();
|
|
if (d > 0) {
|
|
window.resizeBy(0, d);
|
|
}
|
|
}
|
|
},
|
|
|
|
onBeforeUnload: function()
|
|
{
|
|
if (this.display_unload_warning) {
|
|
return this.text.discard;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/* Code to run on window load. */
|
|
document.observe('dom:loaded', ImpCompose.onDomLoad.bind(ImpCompose));
|
|
|
|
/* Warn before closing the window. */
|
|
Event.observe(window, 'beforeunload', ImpCompose.onBeforeUnload.bind(ImpCompose));
|
|
|
|
/* Attach event handlers. */
|
|
document.observe('HordeCore:click', ImpCompose.clickHandler.bindAsEventListener(ImpCompose));
|
|
document.observe('ImpContacts:update', ImpComposeBase.updateAddressField.bindAsEventListener(ImpComposeBase));
|
|
|
|
/* Catch dialog actions. */
|
|
document.observe('ImpPassphraseDialog:success', ImpCompose.uniqSubmit.bind(ImpCompose, 'send_message'));
|