egroupware/mail/js/app.js

5509 lines
163 KiB
JavaScript

/* global msg */
/**
* mail - static javaScript functions
*
* @link http://www.egroupware.org
* @author EGroupware GmbH [info@egroupware.org]
* @copyright (c) 2013-2014 by EGroupware GmbH <info-AT-egroupware.org>
* @package mail
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/*egw:uses
/api/js/jquery/jquery.base64.js;
*/
/**
* UI for mail
*
* @augments AppJS
*/
app.classes.mail = AppJS.extend(
{
appname: 'mail',
/**
* et2 widget container
*/
et2: null,
doStatus: null,
mail_queuedFolders: [],
mail_queuedFoldersIndex: 0,
mail_selectedMails: [],
mail_currentlyFocussed: '',
mail_previewAreaActive: true, // we start with the area active
nm_index: 'nm', // nm name of index
mail_fileSelectorWindow: null,
mail_isMainWindow: true,
// Some state variables to track preview pre-loading
preview_preload: {
timeout: null,
request: null
},
/**
*
*/
subscription_treeLastState : "",
/**
* abbrevations for common access rights
* @array
*
*/
aclCommonRights:['lrs','lprs','ilprs', 'ilprsw', 'aeiklprstwx', 'custom'],
/**
* Demonstrates ACL rights
* @array
*
*/
aclRights:['l','r','s','w','i','p','c','d','a'],
/**
* In order to store Intervals assigned to window
* @array of setted intervals
*/
W_INTERVALS:[],
/**
* Initialize javascript for this application
*
* @memberOf mail
*/
init: function() {
this._super.apply(this,arguments);
if (!this.egw.is_popup())
// Turn on client side, persistent cache
// egw.data system runs encapsulated below etemplate, so this must be
// done before the nextmatch is created.
this.egw.dataCacheRegister('mail',
// Called to determine cache key
this.nm_cache,
// Called whenever cache is used
// TODO: Change this as needed
function(server_query)
{
// Unlock tree if using a cache, since the server won't
if(!server_query) this.unlock_tree();
},
this
);
},
/**
* Destructor
*/
destroy: function()
{
// Unbind from nm refresh
if(this.et2 != null)
{
var nm = this.et2.getWidgetById(this.nm_index);
if(nm != null)
{
jQuery(nm).off('refresh');
}
}
// Unregister client side cache
this.egw.dataCacheUnregister('mail');
delete this.et2_obj;
// call parent
this._super.apply(this, arguments);
},
/**
* check and try to reinitialize et2 of module
*/
checkET2: function()
{
//this.et2 should do the same as etemplate2.getByApplication('mail')[0].widgetContainer
if (!this.et2) // if not defined try this in order to recover
{
try
{
this.et2 = etemplate2.getByApplication('mail')[0].widgetContainer;
}
catch(e)
{
return false;
}
}
return true;
},
/**
* This function is called when the etemplate2 object is loaded
* and ready. If you must store a reference to the et2 object,
* make sure to clean it up in destroy().
*
* @param et2 etemplate2 Newly ready object
* @param {string} _name template name
*/
et2_ready: function(et2, _name)
{
// call parent; somehow this function is called more often. (twice on a display and compose) why?
this._super.apply(this, arguments);
this.et2_obj = et2;
switch (_name)
{
case 'mail.sieve.vacation':
this.vacationFilterStatusChange();
break;
case 'mail.index':
var self = this;
jQuery('iframe#mail-index_messageIFRAME').on('load', function()
{
// decrypt preview body if mailvelope is available
self.mailvelopeAvailable(self.mailvelopeDisplay);
self.mail_prepare_print();
});
var nm = this.et2.getWidgetById(this.nm_index);
this.mail_isMainWindow = true;
this.mail_disablePreviewArea(true);
//Get initial folder status
this.mail_refreshFolderStatus(undefined,undefined,false);
// Bind to nextmatch refresh to update folder status
if(nm != null && (typeof jQuery._data(nm).events=='undefined'||typeof jQuery._data(nm).events.refresh == 'undefined'))
{
var self = this;
jQuery(nm).on('refresh',function() {self.mail_refreshFolderStatus.call(self,undefined,undefined,false);});
}
var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
if (tree_wdg)
{
tree_wdg.set_onopenstart(jQuery.proxy(this.openstart_tree, this));
tree_wdg.set_onopenend(jQuery.proxy(this.openend_tree, this));
}
// Show vacation notice on load for the current profile (if not called by mail_searchtype_change())
var alreadyrefreshed = this.mail_searchtype_change();
if (!alreadyrefreshed) this.mail_callRefreshVacationNotice();
break;
case 'mail.display':
var self = this;
// Prepare display dialog for printing
// copies iframe content to a DIV, as iframe causes
// trouble for multipage printing
jQuery('iframe#mail-display_mailDisplayBodySrc').on('load', function(e)
{
// encrypt body if mailvelope is available
self.mailvelopeAvailable(self.mailvelopeDisplay);
self.mail_prepare_print();
self.resolveExternalImages(this.contentWindow.document);
// Trigger print command if the mail oppend for printing porpuse
// load event fires twice in IE and the first time the content is not ready
// Check if the iframe content is loaded then trigger the print command
if (window.location.search.search('&print=') >= 0 && jQuery(this.contentWindow.document.body).children().length >0 )
{
self.mail_print();
}
});
this.mail_isMainWindow = false;
this.mail_display();
// Register attachments for drag
this.register_for_drag(
this.et2.getArrayMgr("content").getEntry('mail_id'),
this.et2.getArrayMgr("content").getEntry('mail_displayattachments')
);
break;
case 'mail.compose':
if (this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp') &&
this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').checked ||
this.et2.getArrayMgr('content').data.mail_plaintext &&
this.et2.getArrayMgr('content').data.mail_plaintext.indexOf(this.begin_pgp_message) != -1)
{
this.mailvelopeAvailable(this.mailvelopeCompose);
}
var that = this;
var textAreaWidget = this.et2.getWidgetById('mail_htmltext');
this.mail_isMainWindow = false;
this.compose_fieldExpander_init();
this.check_sharing_filemode();
this.subject2title();
// Set autosaving interval to 2 minutes for compose message
this.W_INTERVALS.push(window.setInterval(function (){
that.saveAsDraft(null, 'autosaving');
}, 120000));
/* Control focus actions on subject to handle expanders properly.*/
jQuery("#mail-compose_subject").on({
focus:function(){
that.compose_fieldExpander_init();
that.compose_fieldExpander();
}
});
/*Trigger compose_resizeHandler after the CKEditor is fully loaded*/
jQuery('#mail-compose').on ('load',function() {
if (textAreaWidget && textAreaWidget.ckeditor)
{
textAreaWidget.ckeditor.on('instanceReady', function(){
that.compose_fieldExpander();
if (egwIsMobile()) jQuery(jQuery('iframe.cke_wysiwyg_frame')[0].contentWindow.document.body).css({margin:'0'});
});
}
else
{
that.compose_fieldExpander();
}
});
//Resize compose after window resize to not getting scrollbar
jQuery(window).on ('resize',function(e) {
// Stop immediately the resize event if we are in mobile template
if (egwIsMobile())
{
e.stopImmediatePropagation();
return false;
}
that.compose_resizeHandler();
});
//Call drag_n_drop initialization for emails on compose
this.init_dndCompose();
// Set focus on To/body field
// depending on To field value
var to = this.et2.getWidgetById('to');
if (to && to.get_value() && to.get_value() != '')
{
var content = this.et2.getArrayMgr('content').data;
if (content.is_plain)
{
var plainText = this.et2.getWidgetById('mail_plaintext');
// focus
jQuery(plainText.node).focus();
// get the cursor to the top of the textarea
if (typeof plainText.node.setSelectionRange !='undefined') plainText.node.setSelectionRange(0);
}
else
{
textAreaWidget.ckeditor.on('instanceReady', function(e) {
this.focus();
});
}
}
else if(to)
{
jQuery('input',to.node).focus();
}
break;
case 'mail.subscribe':
if (this.subscription_treeLastState != "")
{
var tree = this.et2.getWidgetById('foldertree');
//Saved state of tree
var state = jQuery.parseJSON(this.subscription_treeLastState);
tree.input.loadJSONObject(tree._htmlencode_node(state));
}
break;
case 'mail.folder_management':
this.egw.message(this.egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'),'info',true);
break;
case 'mail.view':
// we need to set mail_currentlyFocused var otherwise mail
// defined actions won't work
this.mail_currentlyFocussed = this.et2.mail_currentlyFocussed;
}
},
/**
* Observer method receives update notifications from all applications
*
* App is responsible for only reacting to "messages" it is interested in!
*
* @param {string} _msg message (already translated) to show, eg. 'Entry deleted'
* @param {string} _app application name
* @param {(string|number)} _id id of entry to refresh or null
* @param {string} _type either 'update', 'edit', 'delete', 'add' or null
* - update: request just modified data from given rows. Sorting is not considered,
* so if the sort field is changed, the row will not be moved.
* - edit: rows changed, but sorting may be affected. Requires full reload.
* - delete: just delete the given rows clientside (no server interaction neccessary)
* - add: requires full reload for proper sorting
* @param {string} _msg_type 'error', 'warning' or 'success' (default)
* @param {object|null} _links app => array of ids of linked entries
* or null, if not triggered on server-side, which adds that info
* @return {false|*} false to stop regular refresh, thought all observers are run
*/
observer: function(_msg, _app, _id, _type, _msg_type, _links)
{
switch(_app)
{
case 'mail':
if (_id === 'sieve')
{
var iframe = this.et2.getWidgetById('extra_iframe');
if (iframe && iframe.getDOMNode())
{
var contentWindow = iframe.getDOMNode().contentWindow;
if (contentWindow && contentWindow.app && contentWindow.app.mail)
{
contentWindow.app.mail.sieve_refresh();
}
}
return false; // mail nextmatch needs NOT to be refreshed
}
break;
case 'emailadmin': // update tree with given mail account _id and _type
var tree = this.et2 ? this.et2.getWidgetById(this.nm_index+'[foldertree]') : null;
if (!tree) break;
var node = tree.getNode(_id);
switch(_type)
{
case 'delete':
if (node) // we dont care for deleted accounts not shown (eg. other users)
{
tree.deleteItem(_id);
// ToDo: blank list, if _id was active account
}
break
case 'update':
case 'edit':
if (node) // we dont care for updated accounts not shown (eg. other users)
{
//tree.refreshItem(_id);
egw.json('mail.mail_ui.ajax_reloadNode',[_id])
.sendRequest(true);
}
break;
case 'add':
tree.refreshItem(0); // refresh root
break;
default: // null
}
}
return undefined;
},
/**
* Callback function for dataFetch caching.
*
* We only cache the first chunk (50 rows), and only if search filter is not set,
* but we cache this for every combination of folder, filter & filter2.
*
* We do not cache, if we dont find selectedFolder in query_context,
* as looking it up in tree causes mails to be cached for wrong folder
* (Probably because user already clicked on an other folder)!
*
* @param {object} query_context Query information from egw.dataFetch()
* @returns {string|false} Cache key, or false to not cache
*/
nm_cache: function(query_context)
{
// Only cache first chunk of rows, if no search filter
if((!query_context || !query_context.start) && query_context.count == 0 &&
query_context.filters && query_context.filters.selectedFolder &&
!(!query_context.filters || query_context.filters.search)
)
{
// Make sure keys match, even if some filters are not defined
// using JSON.stringfy() directly gave a crash in Safari 7.0.4
return this.egw.jsonEncode({
selectedFolder: query_context.filters.selectedFolder || '',
cat_id: query_context.filters.cat_id || '',
filter: query_context.filters.filter || '',
filter2: query_context.filters.filter2 || '',
sort: query_context.filters.sort
});
}
return false;
},
/**
* mail rebuild Action menu On nm-list
*
* @param _actions
*/
mail_rebuildActionsOnList: function(_actions)
{
this.et2.getWidgetById(this.nm_index).set_actions(_actions);
},
/**
* mail_fetchCurrentlyFocussed - implementation to decide wich mail of all the selected ones is the current
*
* @param _selected array of the selected mails
* @param _reset bool - tell the function to reset the global vars used
*/
mail_fetchCurrentlyFocussed: function(_selected, _reset) {
// reinitialize the buffer-info on selected mails
if (_reset == true || typeof _selected == 'undefined')
{
if (_reset == true)
{
// Request updated data, if possible
if (this.mail_currentlyFocussed!='') egw.dataRefreshUID(this.mail_currentlyFocussed);
for(var k = 0; k < this.mail_selectedMails.length; k++) egw.dataRefreshUID(this.mail_selectedMails[k]);
//nm.refresh(this.mail_selectedMails,'delete');
}
this.mail_selectedMails = [];
this.mail_currentlyFocussed = '';
return '';
}
for(var k = 0; k < _selected.length; k++)
{
if (jQuery.inArray(_selected[k],this.mail_selectedMails)==-1)
{
this.mail_currentlyFocussed = _selected[k];
break;
}
}
this.mail_selectedMails = _selected;
return this.mail_currentlyFocussed;
},
/**
* mail_open - implementation of the open action
*
* @param _action
* @param _senders - the representation of the elements(s) the action is to be performed on
* @param _mode - you may pass the mode. if not given view is used (tryastext|tryashtml are supported)
*/
mail_open: function(_action, _senders, _mode) {
if (typeof _senders == 'undefined' || _senders.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _senders = [];
_senders.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _senders == 'undefined' || _senders.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _senders = [];
_senders.push({id:this.mail_currentlyFocussed});
}
}
}
var _id = _senders[0].id;
// reinitialize the buffer-info on selected mails
if (!(_mode == 'tryastext' || _mode == 'tryashtml' || _mode == 'view' || _mode == 'print')) _mode = 'view';
this.mail_selectedMails = [];
this.mail_selectedMails.push(_id);
this.mail_currentlyFocussed = _id;
var dataElem = egw.dataGetUIDdata(_id);
var subject = dataElem.data.subject;
//alert('Open Message:'+_id+' '+subject);
var h = egw().open( _id,'mail','view',_mode+'='+_id.replace(/=/g,"_")+'&mode='+_mode);
egw(h).ready(function() {
h.document.title = subject;
});
// THE FOLLOWING IS PROBABLY NOT NEEDED, AS THE UNEVITABLE PREVIEW IS HANDLING THE COUNTER ISSUE
var messages = {};
messages['msg'] = [_id];
// When body is requested, mail is marked as read by the mail server. Update UI to match.
if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class'] != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
{
this.mail_removeRowClass(messages,'recent');
this.mail_removeRowClass(messages,'unseen');
// reduce counter without server roundtrip
this.mail_reduceCounterWithoutServerRoundtrip();
// not needed, as an explizit read flags the message as seen anyhow
//egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
}
},
/**
* Open a single message in html mode
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_openAsHtml: function(_action, _elems)
{
this.mail_open(_action, _elems,'tryashtml');
},
/**
* Open a single message in plain text mode
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_openAsText: function(_action, _elems)
{
this.mail_open(_action, _elems,'tryastext');
},
/**
* Compose, reply or forward a message
*
* @function
* @memberOf mail
* @param _action _action.id is 'compose', 'composeasnew', 'reply', 'reply_all' or 'forward' (forward can be multiple messages)
* @param _elems _elems[0].id is the row-id
*/
mail_compose: function(_action, _elems)
{
if (typeof _elems == 'undefined' || _elems.length==0)
{
if (this.et2 && this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
// Extra info passed to egw.open()
var settings = {
// 'Source' Mail UID
id: '',
// How to pull data from the Mail IDs for the compose
from: ''
};
// We only handle one for everything but forward
settings.id = (typeof _elems == 'undefined'?'':_elems[0].id);
switch(_action.id)
{
case 'compose':
if (_elems.length == 1)
{
//mail_parentRefreshListRowStyle(settings.id,settings.id);
}
else
{
return this.mail_compose('forward',_elems);
}
break;
case 'forward':
case 'forwardinline':
case 'forwardasattach':
if (_elems.length>1||_action.id == 'forwardasattach')
{
settings.from = 'forward';
settings.mode = 'forwardasattach';
if (typeof _elems != 'undefined' && _elems.length>1)
{
for(var j = 1; j < _elems.length; j++)
settings.id = settings.id + ',' + _elems[j].id;
}
}
else
{
settings.from = 'forward';
settings.mode = 'forwardinline';
}
break;
default:
// No further client side processing needed for these
settings.from = _action.id;
}
var compose_list = egw.getOpenWindows("mail", /^compose_/);
var window_name = 'compose_' + compose_list.length + '_'+ (settings.from || '') + '_' + settings.id;
return egw().open('','mail','add',settings,window_name,'mail');
},
/**
* Set content into a compose window
*
* @function
* @memberOf mail
*
* @param {String} window_name The name of an open content window.
* @param {object} content
*
* @description content Data to set into the window's fields
* content.to Addresses to add to the to line
* content.cc Addresses to add to the CC line
* content.bcc Addresses to add to the BCC line
*
* @return {boolean} Success
*/
setCompose: function(window_name, content)
{
// Get window
var compose = window.open('', window_name);
if(!compose || compose.closed) return false;
// Get etemplate of popup
var compose_et2 = compose.etemplate2.getByApplication('mail');
if(!compose_et2 || compose_et2.length != 1 || !compose_et2[0].widgetContainer)
{
return false;
}
// Set each field provided
var success = true;
var arrContent = [];
for(var field in content)
{
try
{
var widget = compose_et2[0].widgetContainer.getWidgetById(field);
// Merge array values, replace strings
var value = widget.getValue() || content[field];
if(jQuery.isArray(value))
{
if(jQuery.isArray(content[field]))
{
value.concat(content[field]);
}
else
{
arrContent = content[field].split(',');
for (var k=0;k < arrContent.length;k++)
{
value.push(arrContent[k]);
}
}
}
widget.set_value(value);
}
catch(e)
{
egw.log("error", "Unable to set field %s to '%s' in window '%s'", field, content[field],window_name);
success = false;
continue;
}
}
if (content['cc'] || content['bcc'])
{
this.compose_fieldExpander();
this.compose_fieldExpander_init();
}
return success;
},
/**
* mail_disablePreviewArea - implementation of the disablePreviewArea action
*
* @param _value
*/
mail_disablePreviewArea: function(_value) {
var splitter = this.et2.getWidgetById('mailSplitter');
// return if there's no splitter we maybe in mobile mode
if (typeof splitter == 'undefined' || splitter == null) return;
if(splitter.isDocked())
{
this.mail_previewAreaActive = false;
}
this.et2.getWidgetById('mailPreview').set_disabled(_value);
//Dock the splitter always if we are browsing with mobile
if (_value==true)
{
if (this.mail_previewAreaActive) splitter.dock();
this.mail_previewAreaActive = false;
}
else
{
if (!this.mail_previewAreaActive)
{
splitter.undock();
window.setTimeout(function(){splitter.left.trigger('resize.et2_split.mailSplitter');},200);
}
this.mail_previewAreaActive = true;
}
},
/**
* Create an expand on click box
*
* @param {object} _expContent an object with at least these elements
* {build_children, data_one, data, widget, line}
*
* @param {object} _dataElem includes data of the widget which need to be expand
* @param {object} _et2 widget container of relevant template, default is this.et2
*
* @return _dataElem content of widgets
*/
url_email_expandOnClick: function (_expContent, _dataElem, _et2)
{
var et2 = _et2 || this.et2;
for(var j = 0; j < _expContent.length; j++)
{
var field = _expContent[j] || [];
var content = _dataElem.data[field.data] || [];
// Add in single address, if there
if(typeof field.data_one != 'undefined' && field.data != field.data_one)
{
if (jQuery.isArray(_dataElem.data[field.data_one]))
content = content.concat(_dataElem.data[field.data_one]);
else
content.unshift(_dataElem.data[field.data_one]);
// Unique
content = content.filter(function(value, index, self) {
return self.indexOf(value) === index;
});
}
// Disable whole box if there are none
var line = et2.getWidgetById(field.line);
if(line != null) line.set_disabled(content.length == 0);
var widget = et2.getWidgetById(field.widget);
if(widget == null) continue;
jQuery(widget.getDOMNode()).removeClass('visible');
// Programatically build the child elements
if(field.build_children)
{
// Remove any existing
var children = widget.getChildren();
for(var i = children.length-1; i >= 0; i--)
{
children[i].destroy();
widget.removeChild(children[i]);
}
if (content.length == 1 && typeof content[0] != 'undefined' && content[0])
{
content = content[0].split(',');
}
// Add for current record
var remembervalue = '';
for(var i = 0; i < content.length; i++)
{
if (typeof content[i] != 'string' || !content[i]) continue;
// if there is no @ in string, its most likely that we have a comma in the personal name part of the emailaddress
if (content[i].indexOf('@')< 0)
{
remembervalue = content[i];
}
else
{
var value = remembervalue+(remembervalue?',':'')+content[i];
var url_email_options = {
id:widget.id+'_'+i,
value:value,
readonly:true,
contact_plus:true,
full_email:typeof field['full_email'] !='undefined'?field['full_email']:true
};
var email = et2_createWidget('url-email',url_email_options,widget);
email.loadingFinished();
remembervalue = '';
}
}
}
else
{
widget.set_value({content: content});
}
// Show or hide button, as needed
line.iterateOver(function(button) {
// Avoid binding to any child buttons
if(button.getParent() != line) return;
button.set_disabled(
// Disable if only 1 address
content.length <=1 || (
// Disable if all content is visible
jQuery(widget.getDOMNode()).innerWidth() >= widget.getDOMNode().scrollWidth &&
jQuery(widget.getDOMNode()).innerHeight() >= widget.getDOMNode().scrollHeight)
);
},this,et2_button);
}
return _dataElem;
},
/**
* Set values for mail dispaly From,Sender,To,Cc, and Bcc
* Additionally, apply expand on click feature on thier widgets
*
*/
mail_display: function()
{
var dataElem = {data:{FROM:"",SENDER:"",TO:"",CC:"",BCC:""}};
var content = this.et2.getArrayMgr('content').data;
var expand_content = [
{build_children: true, data_one: 'FROM', data: 'FROM', widget: 'FROM', line: 'mailDisplayHeadersFrom', full_email:false},
{build_children: true, data: 'SENDER', widget: 'SENDER', line: 'mailDisplayHeadersSender'},
{build_children: true, data: 'TO', widget: 'TO', line: 'mailDisplayHeadersTo'},
{build_children: true, data: 'CC', widget: 'CC', line: 'mailDisplayHeadersCc'},
{build_children: true, data: 'BCC', widget:'BCC', line: 'mailDisplayHeadersBcc'}
];
if (typeof content != 'undefiend')
{
dataElem.data = jQuery.extend(dataElem.data, content);
this.url_email_expandOnClick(expand_content, dataElem);
var toolbaractions = ((typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.displayToolbaractions != 'undefined')?JSON.parse(dataElem.data.displayToolbaractions):undefined);
if (toolbaractions) this.et2.getWidgetById('displayToolbar').set_actions(toolbaractions);
}
},
/**
* mail_preview - implementation of the preview action
*
* @param nextmatch et2_nextmatch The widget whose row was selected
* @param selected Array Selected row IDs. May be empty if user unselected all rows.
*/
mail_preview: function(selected, nextmatch) {
// Empty values, just in case selected is empty (user cleared selection)
//dataElem.data is populated, when available with fromaddress(string),toaddress(string),additionaltoaddress(array),ccaddress (array)
var dataElem = {data:{subject:"",fromaddress:"",toaddress:"",ccaddress:"",date:"",attachmentsBlock:""}};
var attachmentArea = this.et2.getWidgetById('previewAttachmentArea');
if(typeof selected != 'undefined' && selected.length == 1)
{
var _id = this.mail_fetchCurrentlyFocussed(selected);
dataElem = jQuery.extend(dataElem, egw.dataGetUIDdata(_id));
// Try to resolve winmail.data attachment
if (dataElem.data && dataElem.data.attachmentsBlock[0]
&& dataElem.data.attachmentsBlock[0].winmailFlag
&& (dataElem.data.attachmentsBlock[0].mimetype =='application/ms-tnef' ||
dataElem.data.attachmentsBlock[0].filename == "winmail.dat"))
{
attachmentArea.getDOMNode().classList.add('loading');
this.egw.jsonq('mail.mail_ui.ajax_resolveWinmail',[_id], jQuery.proxy(function(_data){
attachmentArea.getDOMNode().classList.remove('loading');
if (typeof _data == 'object')
{
attachmentArea.set_value({content:_data});
this.data.attachmentsBlock = _data;
// Update client cache to avoid resolving winmail.dat attachment again
egw.dataStoreUID(this.data.uid, this.data);
set_prev_iframe_top();
}
else
{
console.log('Can not resolve the winmail.data!');
}
},dataElem));
}
}
var $preview_iframe = jQuery('#mail-index_mailPreviewContainer');
// Re calculate the position of preview iframe according to its visible sibilings
var set_prev_iframe_top = function ()
{
// Need to make sure that the iframe is fullyLoad before calculation
window.setTimeout(function(){
var lastEl = $preview_iframe.prev().prev();
// Top offset of preview iframe calculated from top level
var iframeTop = $preview_iframe.offset().top;
while (lastEl.css('display') === "none")
{
lastEl = lastEl.prev();
}
var offset = iframeTop - (lastEl.offset().top + lastEl.height()) || 130; // fallback to 130 px if can not calculate new top
// preview iframe parent has position absolute, therefore need to calculate the top via position
$preview_iframe.css ('top', $preview_iframe.position().top - offset + 10);
}, 50);
};
if (attachmentArea && typeof _id != 'undefined' && _id !='' && typeof dataElem !== 'undefined')
{
// If there is content to show recalculate the size
set_prev_iframe_top();
}
else
{
// Leave if we're here and there is nothing selected, too many, or no data
var prevAttchArea = this.et2.getWidgetById('previewAttachmentArea');
if (prevAttchArea)
{
prevAttchArea.set_value({content:[]});
this.et2.getWidgetById('previewAttachmentArea').set_class('previewAttachmentArea noContent mail_DisplayNone');
var IframeHandle = this.et2.getWidgetById('messageIFRAME');
IframeHandle.set_src('about:blank');
this.mail_disablePreviewArea(true);
}
if (!egwIsMobile())return;
}
// Not applied to mobile preview
if (!egwIsMobile())
{
// Widget ID:data key map of widgets we can directly set from cached data
var data_widgets = {
'previewFromAddress': 'fromaddress',
'previewDate': 'date',
'previewSubject': 'subject'
};
// Set widget values from cached data
for(var id in data_widgets)
{
var widget = this.et2.getWidgetById(id);
if(widget == null) continue;
widget.set_value(dataElem.data[data_widgets[id]] || "");
}
// Blank first, so we don't show previous email while loading
var IframeHandle = this.et2.getWidgetById('messageIFRAME');
IframeHandle.set_src('about:blank');
// show iframe, in case we hide it from mailvelopes one and remove that
jQuery(IframeHandle.getDOMNode()).show()
.next(this.mailvelope_iframe_selector).remove();
// Set up additional content that can be expanded.
// We add a new URL widget for each address, so they get all the UI
// TO addresses have the first one split out, not all together
// list of keys:
var expand_content = [
{build_children: true, data_one: 'toaddress', data: 'additionaltoaddress', widget: 'additionalToAddress', line: 'mailPreviewHeadersTo'},
{build_children: true, data: 'ccaddress', widget: 'additionalCCAddress', line: 'mailPreviewHeadersCC'},
{build_children: false, data: 'attachmentsBlock', widget:'previewAttachmentArea', line: 'mailPreviewHeadersAttachments'}
];
// Undock the preview before running expandOnClick, because we
// need to have the DOM ready for calculation.
this.mail_disablePreviewArea(false);
dataElem = this.url_email_expandOnClick(expand_content,dataElem);
// Update the internal list of selected mails, if needed
if(this.mail_selectedMails.indexOf(_id) < 0)
{
this.mail_selectedMails.push(_id);
}
var self = this;
// Request email body from server
IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:_id}));
jQuery(IframeHandle.getDOMNode()).on('load', function(e){
self.resolveExternalImages (this.contentWindow.document);
});
}
var messages = {};
messages['msg'] = [_id];
// When body is requested, mail is marked as read by the mail server. Update UI to match.
if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class'] != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
{
this.mail_removeRowClass(messages,'recent');
this.mail_removeRowClass(messages,'unseen');
// reduce counter without server roundtrip
this.mail_reduceCounterWithoutServerRoundtrip();
if (typeof dataElem.data.dispositionnotificationto != 'undefined' && dataElem.data.dispositionnotificationto &&
typeof dataElem.data.flags.mdnsent == 'undefined' && typeof dataElem.data.flags.mdnnotsent == 'undefined')
{
var buttons = [
{text: this.egw.lang("Yes"), id: "mdnsent"},
{text: this.egw.lang("No"), id:"mdnnotsent"}
];
et2_dialog.show_dialog(function(_button_id, _value) {
switch (_button_id)
{
case "mdnsent":
egw.jsonq('mail.mail_ui.ajax_sendMDN',[messages]);
egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnsent', messages, true]);
return;
case "mdnnotsent":
egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnnotsent', messages, true]);
}
},
this.egw.lang("The message sender has requested a response to indicate that you have read this message. Would you like to send a receipt?"),
this.egw.lang("Confirm"),
messages, buttons);
}
egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
}
},
resolveExternalImages: function (_node)
{
//Do not run resolve images if it's forced already to show them all
// or forced to not show them all.
var pref_img = egw.preference('allowExternalIMGs', 'mail');
if (pref_img == 1 || pref_img == 0) return;
var external_images = jQuery(_node).find('img[alt*="[blocked external image:"]');
if (external_images.length > 0 && jQuery(_node).find('.mail_externalImagesMsg').length == 0)
{
var container = jQuery(document.createElement('div'))
.click(function(){jQuery(this).remove();})
.addClass('mail_externalImagesMsg');
var getUrlParts = function (_rawUrl) {
var u = _rawUrl.split('[blocked external image:');
u = u[1].replace(']','');
var url = u;
if (u.substr(0,7) == 'http://') u = u.replace ('http://','');
if (u.substr(0,8) == 'https://') u = u.replace ('https://','');
var url_parts = u.split('/');
return {
url: url,
domain: url_parts[0]
};
}
var host = getUrlParts(external_images[0].alt);
var showImages = function (_images, _save)
{
var save = _save || false;
_images.each(function(i, node) {
var parts = getUrlParts (node.alt);
if (save)
{
if (pref && pref.length)
{
if (pref.indexOf(parts.domain) == -1)
{
pref.push(parts.domain);
egw.set_preference( 'mail', 'allowExternalDomains', pref);
}
}
else
{
pref = [parts.domain];
egw.set_preference( 'mail', 'allowExternalDomains', pref);
}
}
node.src = parts.url;
});
}
var pref = egw.preference('allowExternalDomains', 'mail') || {};
pref = Object.values(pref);
if (pref.indexOf(host.domain)>-1)
{
showImages (external_images);
return;
}
jQuery(document.createElement('p'))
.text(egw.lang('In order to protect your privacy all external sources within this email are blocked.'))
.appendTo(container);
jQuery(document.createElement('button'))
.addClass ('closeBtn')
.click (function (){
container.remove();
})
.appendTo(container);
jQuery(document.createElement('button'))
.text(egw.lang('Allow'))
.attr ('title', egw.lang('Always allow external sources from %1', host.domain))
.click (function (){
showImages(external_images, true);
container.remove();
})
.appendTo(container);
jQuery(document.createElement('button'))
.text(egw.lang('Show'))
.attr ('title', egw.lang('Show them this time only'))
.click(function(){
showImages(external_images);
container.remove();
})
.appendTo(container);
container.appendTo(_node.body? _node.body:_node);
}
},
/**
* If a preview header is partially hidden, this is the handler for clicking the
* expand button that shows all the content for that header.
* The button must be directly after the widget to be expanded in the template.
* The widget to be expended is set in the event data.
*
* requires: mainWindow, one mail selected for preview
*
* @param {jQuery event} event
* @param {Object} widget
* @param {DOMNode} button
*/
showAllHeader: function(event,widget,button) {
// Show list as a list
var list = jQuery(button).prev();
/* if (list.length <= 0)
{
list = jQuery(button.target).prev();
}*/
list.toggleClass('visible');
// Revert if user clicks elsewhere
jQuery('body').one('click', list, function(ev) {
ev.data.removeClass('visible');
});
},
mail_setMailBody: function(content) {
var IframeHandle = this.et2.getWidgetById('messageIFRAME');
IframeHandle.set_value('');
},
/**
* mail_refreshFolderStatus, function to call to read the counters of a folder and apply them
*
* @param {stirng} _nodeID
* @param {string} mode
* @param {boolean} _refreshGridArea
* @param {boolean} _refreshQuotaDisplay
*
*/
mail_refreshFolderStatus: function(_nodeID,mode,_refreshGridArea,_refreshQuotaDisplay) {
if (typeof _nodeID != 'undefined' && typeof _nodeID[_nodeID] != 'undefined' && _nodeID[_nodeID])
{
_refreshGridArea = _nodeID[_refreshGridArea];
mode = _nodeID[mode];
_nodeID = _nodeID[_nodeID];
}
var nodeToRefresh = 0;
var mode2use = "none";
if (typeof _refreshGridArea == 'undefined') _refreshGridArea=true;
if (typeof _refreshQuotaDisplay == 'undefined') _refreshQuotaDisplay=true;
if (_nodeID) nodeToRefresh = _nodeID;
if (mode) {
if (mode == "forced") {mode2use = mode;}
}
try
{
var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var activeFolders = tree_wdg.getTreeNodeOpenItems(nodeToRefresh,mode2use);
//alert(activeFolders.join('#,#'));
this.mail_queueRefreshFolderList((mode=='thisfolderonly'&&nodeToRefresh?[_nodeID]:activeFolders));
if (_refreshGridArea)
{
// maybe to use the mode forced as trigger for grid reload and using the grids own autorefresh
// would solve the refresh issue more accurately
//if (mode == "forced") this.mail_refreshMessageGrid();
this.mail_refreshMessageGrid();
}
if (_refreshQuotaDisplay)
{
this.mail_refreshQuotaDisplay();
}
//the two lines below are not working yet.
//var no =tree_wdg.getSelectedNode();
//tree_wdg.focusItem(no.id);
} catch(e) { } // ignore the error; maybe the template is not loaded yet
},
/**
* mail_refreshQuotaDisplay, function to call to read the quota for the active server
*
* @param {object} _server
*
*/
mail_refreshQuotaDisplay: function(_server)
{
egw.json('mail.mail_ui.ajax_refreshQuotaDisplay',[_server])
.sendRequest(true);
},
/**
* mail_setQuotaDisplay, function to call to read the quota for the active server
*
* @param {object} _data
*
*/
mail_setQuotaDisplay: function(_data)
{
if (!this.et2 && !this.checkET2()) return;
var quotabox = this.et2.getWidgetById(this.nm_index+'[quotainpercent]');
// Check to make sure it's there
if(quotabox)
{
//try to set it via set_value and set label
quotabox.set_class(_data.data.quotaclass);
quotabox.set_value(_data.data.quotainpercent);
quotabox.set_label(_data.data.quota);
}
},
/**
* mail_callRefreshVacationNotice, function to call the serverside function to refresh the vacationnotice for the active server
*
* @param {object} _server
*
*/
mail_callRefreshVacationNotice: function(_server)
{
egw.jsonq('mail_ui::ajax_refreshVacationNotice',[_server]);
},
/**
* Make sure attachments have all needed data, so they can be found for
* HTML5 native dragging
*
* @param {string} mail_id Mail UID
* @param {array} attachments Attachment information.
*/
register_for_drag: function(mail_id, attachments)
{
// Put required info in global store
var data = {};
if (!attachments) return;
for (var i = 0; i < attachments.length; i++)
{
var data = attachments[i] || {};
if(!data.filename || !data.type) continue;
// Add required info
data.mime = data.type;
data.download_url = egw.link('/index.php', {
menuaction: 'mail.mail_ui.getAttachment',
id: mail_id,
part: data.partID,
is_winmail: data.winmailFlag
});
data.name = data.filename;
}
},
/**
* Display helper for dragging attachments
*
* @param {egwAction} _action
* @param {egwActionElement[]} _elems
* @returns {DOMNode}
*/
drag_attachment: function(_action, _elems)
{
var div = jQuery(document.createElement("div"))
.css({
position: 'absolute',
top: '0px',
left: '0px',
width: '300px'
});
var data = _elems[0].data || {};
var text = jQuery(document.createElement('div')).css({left: '30px', position: 'absolute'});
// add filename or number of files for multiple files
text.text(_elems.length > 1 ? _elems.length+' '+this.egw.lang('files') : data.name || '');
div.append(text);
// Add notice of Ctrl key, if supported
if(window.FileReader && 'draggable' in document.createElement('span') &&
navigator && navigator.userAgent.indexOf('Chrome') >= 0)
{
var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command';
text.append('<br />' + this.egw.lang('Hold %1 to drag files to your computer',key));
}
return div;
},
/**
* mail_refreshVacationNotice, function to call with appropriate data to refresh the vacationnotice for the active server
*
* @param {object} _data
*
*/
mail_refreshVacationNotice: function(_data)
{
if (!this.et2 && !this.checkET2()) return;
if (_data == null)
{
this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value('');
this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value('');
}
else
{
this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value(_data.vacationnotice);
this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value(_data.vacationrange);
}
},
/**
* Enable or disable the date filter
*
* If the searchtype (cat_id) is set to something that needs dates, we enable the
* header_right template. Otherwise, it is disabled.
*/
mail_searchtype_change: function()
{
var filter = this.et2.getWidgetById('cat_id');
var nm = this.et2.getWidgetById(this.nm_index);
var dates = this.et2.getWidgetById('mail.index.datefilter');
if(nm && filter)
{
switch(filter.getValue())
{
case 'bydate':
if (filter && dates)
{
dates.set_disabled(false);
if (this.et2.getWidgetById('startdate')) jQuery(this.et2.getWidgetById('startdate').getDOMNode()).find('input').focus();
}
this.mail_callRefreshVacationNotice();
return true;
default:
if (dates)
{
dates.set_disabled(true);
}
this.mail_callRefreshVacationNotice();
return true;
}
}
return false;
},
/**
* mail_refreshFilter2Options, function to call with appropriate data to refresh the filter2 options for the active server
*
* @param {object} _data
*
*/
mail_refreshFilter2Options: function(_data)
{
//alert('mail_refreshFilter2Options');
if (_data == null) return;
if (!this.et2 && !this.checkET2()) return;
var filter2 = this.et2.getWidgetById('filter2');
var current = filter2.value;
var currentexists=false;
for (var k in _data)
{
if (k==current) currentexists=true;
}
if (!currentexists) filter2.set_value('');
filter2.set_select_options(_data);
},
/**
* mail_refreshFilterOptions, function to call with appropriate data to refresh the filter options for the active server
*
* @param {object} _data
*
*/
mail_refreshFilterOptions: function(_data)
{
//alert('mail_refreshFilterOptions');
if (_data == null) return;
if (!this.et2 && !this.checkET2()) return;
var filter = this.et2.getWidgetById('filter');
var current = filter.value;
var currentexists=false;
for (var k in _data)
{
if (k==current) currentexists=true;
}
if (!currentexists) filter.set_value('any');
filter.set_select_options(_data);
},
/**
* mail_refreshCatIdOptions, function to call with appropriate data to refresh the filter options for the active server
*
* @param {object} _data
*
*/
mail_refreshCatIdOptions: function(_data)
{
//alert('mail_refreshCatIdOptions');
if (_data == null) return;
if (!this.et2 && !this.checkET2()) return;
var filter = this.et2.getWidgetById('cat_id');
var current = filter.value;
var currentexists=false;
for (var k in _data)
{
if (k==current) currentexists=true;
}
if (!currentexists) filter.set_value('quick');
filter.set_select_options(_data);
},
/**
* Queues a refreshFolderList request for 10ms. Actually this will just execute the
* code after the calling script has finished.
*
* @param {array} _folders description
*/
mail_queueRefreshFolderList: function(_folders)
{
var self = this;
// as jsonq is too fast wrap it to be delayed a bit, to ensure the folder actions
// are executed last of the queue
window.setTimeout(function() {
egw.jsonq('mail.mail_ui.ajax_setFolderStatus',[_folders], function (){self.unlock_tree();});
}, 100);
},
/**
* mail_CheckFolderNoSelect - implementation of the mail_CheckFolderNoSelect action to control right click options on the tree
*
* @param {object} action
* @param {object} _senders the representation of the tree leaf to be manipulated
* @param {object} _currentNode
*/
mail_CheckFolderNoSelect: function(action,_senders,_currentNode) {
// Abort if user selected an un-selectable node
// Use image over anything else because...?
var ftree, node;
ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
if (ftree)
{
node = ftree.getNode(_senders[0].id);
}
if (node && node.im0.indexOf('NoSelect') !== -1)
{
//ftree.reSelectItem(_previous);
return false;
}
return true;
},
/**
* Check if SpamFolder is enabled on that account
*
* SpamFolder enabled is stored as data { spamfolder: true/false } on account node.
*
* @param {object} _action
* @param {object} _senders the representation of the tree leaf to be manipulated
* @param {object} _currentNode
*/
spamfolder_enabled: function(_action,_senders,_currentNode)
{
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var acc_id = _senders[0].id.split('::')[0];
var node = ftree ? ftree.getNode(acc_id) : null;
return node && node.data && node.data.spamfolder;
},
/**
* Check if archiveFolder is enabled on that account
*
* ArchiveFolder enabled is stored as data { archivefolder: true/false } on account node.
*
* @param {object} _action
* @param {object} _senders the representation of the tree leaf to be manipulated
* @param {object} _currentNode
*/
archivefolder_enabled: function(_action,_senders,_currentNode)
{
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var acc_id = _senders[0].id.split('::')[2]; // this is operating on mails
var node = ftree ? ftree.getNode(acc_id) : null;
return node && node.data && node.data.archivefolder;
},
/**
* Check if Sieve is enabled on that account
*
* Sieve enabled is stored as data { sieve: true/false } on account node.
*
* @param {object} _action
* @param {object} _senders the representation of the tree leaf to be manipulated
* @param {object} _currentNode
*/
sieve_enabled: function(_action,_senders,_currentNode)
{
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var acc_id = _senders[0].id.split('::')[0];
var node = ftree ? ftree.getNode(acc_id) : null;
return node && node.data && node.data.sieve;
},
/**
* Check if ACL is enabled on that account
*
* ACL enabled is stored as data { acl: true/false } on INBOX node.
* We also need to check if folder is marked as no-select!
*
* @param {object} _action
* @param {object} _senders the representation of the tree leaf to be manipulated
* @param {object} _currentNode
*/
acl_enabled: function(_action,_senders,_currentNode)
{
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var inbox = _senders[0].id.split('::')[0]+'::INBOX';
var node = ftree ? ftree.getNode(inbox) : null;
return node && node.data.acl && this.mail_CheckFolderNoSelect(_action,_senders,_currentNode);
},
/**
* mail_setFolderStatus, function to set the status for the visible folders
*
* @param {array} _status
*/
mail_setFolderStatus: function(_status) {
if (!this.et2 && !this.checkET2()) return;
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
for (var i in _status) {
ftree.setLabel(i,_status[i]);
// display folder-name bold for unseen mails
ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
//alert(i +'->'+_status[i]);
}
},
/**
* mail_setLeaf, function to set the id and description for the folder given by status key
* @param {array} _status status array with the required data (new id, desc, old desc)
* key is the original id of the leaf to change
* multiple sets can be passed to mail_setLeaf
*/
mail_setLeaf: function(_status) {
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var selectedNode = ftree.getSelectedNode();
for (var i in _status)
{
// if olddesc is undefined or #skip# then skip the message, as we process subfolders
if (typeof _status[i]['olddesc'] !== 'undefined' && _status[i]['olddesc'] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Renamed Folder %1 to %2",_status[i]['olddesc'],_status[i]['desc']));
ftree.renameItem(i,_status[i]['id'],_status[i]['desc']);
ftree.setStyle(i, 'font-weight: '+(_status[i]['desc'].match(this._unseen_regexp) ? 'bold' : 'normal'));
//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
if (_status[i]['id']==selectedNode.id)
{
var nm = this.et2.getWidgetById(this.nm_index);
nm.activeFilters["selectedFolder"] = _status[i]['id'];
nm.applyFilters();
}
}
},
/**
* mail_removeLeaf, function to remove the leaf represented by the given ID
* @param {array} _status status array with the required data (KEY id, VALUE desc)
* key is the id of the leaf to delete
* multiple sets can be passed to mail_deleteLeaf
*/
mail_removeLeaf: function(_status) {
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var selectedNode = ftree.getSelectedNode();
for (var i in _status)
{
// if olddesc is undefined or #skip# then skip the message, as we process subfolders
if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Removed Folder %1 ",_status[i]));
ftree.deleteItem(i,(selectedNode.id==i));
var selectedNodeAfter = ftree.getSelectedNode();
//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
if (selectedNodeAfter.id!=selectedNode.id && selectedNode.id==i)
{
var nm = this.et2.getWidgetById(this.nm_index);
nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
nm.applyFilters();
}
}
},
/**
* mail_reloadNode, function to reload the leaf represented by the given ID
* @param {Object.<string,string>|Object.<string,Object}} _status
* Object with the required data (KEY id, VALUE desc), or ID => {new data}
*/
mail_reloadNode: function(_status) {
var ftree = this.et2?this.et2.getWidgetById(this.nm_index+'[foldertree]'):null;
if (!ftree) return;
var selectedNode = ftree.getSelectedNode();
for (var i in _status)
{
// if olddesc is undefined or #skip# then skip the message, as we process subfolders
if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#')
{
if (typeof _status[i].parent !== 'undefined')
{
this.egw.message(this.egw.lang("Reloaded Folder %1",typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') : _status[i].text.replace(this._unseen_regexp, '')));
} else {
this.egw.message(this.egw.lang("Reloaded Account %1",typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') : _status[i].text.replace(this._unseen_regexp, '')));
}
}
ftree.refreshItem(i,typeof _status[i] == "object" ? _status[i] : null);
if (typeof _status[i] == "string") ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
}
var selectedNodeAfter = ftree.getSelectedNode();
// If selected folder changed, refresh nextmatch
if (selectedNodeAfter != null && selectedNodeAfter.id!=selectedNode.id)
{
var nm = this.et2.getWidgetById(this.nm_index);
nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
nm.applyFilters();
}
},
/**
* mail_refreshMessageGrid, function to call to reread ofthe current folder
*
* @param {boolean} _isPopup
* @param {boolean} _refreshVacationNotice
*/
mail_refreshMessageGrid: function(_isPopup, _refreshVacationNotice) {
if (typeof _isPopup == 'undefined') _isPopup = false;
if (typeof _refreshVacationNotice == 'undefined') _refreshVacationNotice = false;
var nm;
if (_isPopup && !this.mail_isMainWindow)
{
nm = window.opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index);
}
else
{
nm = this.et2.getWidgetById(this.nm_index);
}
var dates = this.et2.getWidgetById('mail.index.datefilter');
var filter = this.et2.getWidgetById('cat_id');
if(nm && filter)
{
nm.activeFilters["startdate"]=null;
nm.activeFilters["enddate"]=null;
switch(filter.getValue())
{
case 'bydate':
if (filter && dates)
{
if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) nm.activeFilters["startdate"] = this.et2.getWidgetById('startdate').date;
if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) nm.activeFilters["enddate"] = this.et2.getWidgetById('enddate').date;
}
}
}
nm.applyFilters(); // this should refresh the active folder
if (_refreshVacationNotice) this.mail_callRefreshVacationNotice();
},
/**
* mail_getMsg - gets the current Message
* @return string
*/
mail_getMsg: function()
{
var msg_wdg = this.et2.getWidgetById('msg');
if (msg_wdg)
{
return msg_wdg.valueOf().htmlNode[0].innerHTML;
}
return "";
},
/**
* mail_setMsg - sets a Message, with the msg container, and controls if the container is enabled/disabled
* @param {string} myMsg - the message
*/
mail_setMsg: function(myMsg)
{
var msg_wdg = this.et2.getWidgetById('msg');
if (msg_wdg)
{
msg_wdg.set_value(myMsg);
msg_wdg.set_disabled(myMsg.trim().length==0);
}
},
/**
* Delete mails
* takes in all arguments
* @param _action
* @param _elems
*/
mail_delete: function(_action,_elems)
{
this.mail_checkAllSelected(_action,_elems,null,true);
},
/**
* call Delete mails
* takes in all arguments
* @param {object} _action
* @param {array} _elems
* @param {boolean} _allMessagesChecked
*/
mail_callDelete: function(_action,_elems,_allMessagesChecked)
{
var calledFromPopup = false;
if (typeof _allMessagesChecked == 'undefined') _allMessagesChecked=false;
if (typeof _elems == 'undefined' || _elems.length==0)
{
calledFromPopup = true;
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
var msg = this.mail_getFormData(_elems);
msg['all'] = _allMessagesChecked;
if (msg['all']=='cancel') return false;
if (msg['all']) msg['activeFilters'] = this.mail_getActiveFilters(_action);
//alert(_action.id+','+ msg);
if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted');
this.mail_deleteMessages(msg,'no',calledFromPopup);
if (calledFromPopup && this.mail_isMainWindow==false)
{
egw(window).close();
}
else if (typeof this.et2_view!='undefined' && typeof this.et2_view.close == 'function')
{
this.et2_view.close();
}
},
/**
* function to find (and reduce) unseen count from folder-name
*/
mail_reduceCounterWithoutServerRoundtrip: function()
{
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var _foldernode = ftree.getSelectedNode();
var counter = _foldernode.label.match(this._unseen_regexp);
var icounter = 0;
if ( counter ) icounter = parseInt(counter[0].replace(' (','').replace(')',''));
if (icounter>0)
{
var newcounter = icounter-1;
if (newcounter>0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')',' ('+String(newcounter)+')');
if (newcounter==0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')','');
ftree.setLabel(_foldernode.id,_foldernode.label);
}
},
/**
* Regular expression to find (and remove) unseen count from folder-name
*/
_unseen_regexp: / \([0-9]+\)$/,
/**
* mail_splitRowId
*
* @param {string} _rowID
*
*/
mail_splitRowId: function(_rowID)
{
var res = _rowID.split('::');
// as a rowID is perceeded by app::, should be mail!
if (res.length==4 && !isNaN(parseInt(res[0])))
{
// we have an own created rowID; prepend app=mail
res.unshift('mail');
}
return res;
},
/**
* Delete mails - actually calls the backend function for deletion
* takes in all arguments
* @param {string} _msg - message list
* @param {object} _action - optional action
* @param {object} _calledFromPopup
*/
mail_deleteMessages: function(_msg,_action,_calledFromPopup)
{
var message, ftree, _foldernode, displayname;
ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
if (ftree)
{
_foldernode = ftree.getSelectedNode();
displayname = _foldernode.label.replace(this._unseen_regexp, '');
}
else
{
message = this.mail_splitRowId(_msg['msg'][0]);
if (message[3]) _foldernode = displayname = jQuery.base64Decode(message[3]);
}
// Tell server
egw.json('mail.mail_ui.ajax_deleteMessages',[_msg,(typeof _action == 'undefined'?'no':_action)])
.sendRequest(true);
if (_msg['all']) this.egw.refresh(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current folder'))),'mail');//,ids,'delete');
this.egw.message(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current Folder'))));
},
/**
* Delete mails show result - called from the backend function for display of deletionmessages
* takes in all arguments
* @param _msg - message list
*/
mail_deleteMessagesShowResult: function(_msg)
{
// Update list
var ids = [];
for (var i = 0; i < _msg['msg'].length; i++)
{
ids.push(_msg['msg'][i].replace(/mail::/,''));
}
//this.egw.message(_msg['egw_message']);
if (_msg['all'])
{
this.egw.refresh(_msg['egw_message'],'mail');
}
else
{
this.egw.refresh(_msg['egw_message'],'mail',ids,'delete');
// Nextmatch automatically selects the next row and calls preview.
// Unselect it and thanks to the timeout selectionMgr uses, preview
// will close when the selection callback fires.
this.et2.getWidgetById(this.nm_index).controller._selectionMgr.resetSelection();
}
},
/**
* retry to Delete mails
* @param responseObject ->
* reason - reason to report
* messageList
*/
mail_retryForcedDelete: function(responseObject)
{
var reason = responseObject['response'];
var messageList = responseObject['messageList'];
if (confirm(reason))
{
this.mail_deleteMessages(messageList,'remove_immediately');
}
else
{
this.egw.message(this.egw.lang('canceled deletion due to userinteraction'));
this.mail_removeRowClass(messageList,'deleted');
}
this.mail_refreshMessageGrid();
this.mail_preview();
},
/**
* UnDelete mailMessages
*
* @param _messageList
*/
mail_undeleteMessages: function(_messageList) {
// setting class of row, the old style
},
/**
* mail_emptySpam
*
* @param {object} action
* @param {object} _senders
*/
mail_emptySpam: function(action,_senders) {
var server = _senders[0].iface.id.split('::');
var activeFilters = this.mail_getActiveFilters();
var self = this;
this.egw.message(this.egw.lang('empty junk'));
egw.json('mail.mail_ui.ajax_emptySpam',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
.sendRequest(true);
// Directly delete any trash cache for selected server
if(window.localStorage)
{
for(var i = 0; i < window.localStorage.length; i++)
{
var key = window.localStorage.key(i);
// Find directly by what the key would look like
if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
key.toLowerCase().indexOf(egw.lang('junk').toLowerCase()) > 0)
{
window.localStorage.removeItem(key);
}
}
}
},
/**
* mail_emptyTrash
*
* @param {object} action
* @param {object} _senders
*/
mail_emptyTrash: function(action,_senders) {
var server = _senders[0].iface.id.split('::');
var activeFilters = this.mail_getActiveFilters();
var self = this;
this.egw.message(this.egw.lang('empty trash'));
egw.json('mail.mail_ui.ajax_emptyTrash',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
.sendRequest(true);
// Directly delete any trash cache for selected server
if(window.localStorage)
{
for(var i = 0; i < window.localStorage.length; i++)
{
var key = window.localStorage.key(i);
// Find directly by what the key would look like
if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
key.toLowerCase().indexOf(egw.lang('trash').toLowerCase()) > 0)
{
window.localStorage.removeItem(key);
}
}
}
},
/**
* mail_compressFolder
*
* @param {object} action
* @param {object} _senders
*
*/
mail_compressFolder: function(action,_senders) {
this.egw.message(this.egw.lang('compress folder'));
egw.jsonq('mail.mail_ui.ajax_compressFolder',[_senders[0].iface.id]);
// .sendRequest(true);
// since the json reply is using this.egw.refresh, we should not need to call refreshFolderStatus
// as the actions thereof are now bound to run after grid refresh
//this.mail_refreshFolderStatus();
},
/**
* mail_changeProfile
*
* @param {string} folder the ID of the selected Node -> should be an integer
* @param {object} _widget handle to the tree widget
* @param {boolean} getFolders Flag to indicate that the profile needs the mail
* folders. False means they're already loaded in the tree, and we don't need
* them again
*/
mail_changeProfile: function(folder,_widget, getFolders) {
if(typeof getFolders == 'undefined')
{
getFolders = true;
}
// alert(folder);
this.egw.message(this.egw.lang('Connect to Profile %1',_widget.getSelectedLabel().replace(this._unseen_regexp, '')));
//Open unloaded tree to get loaded
_widget.openItem(folder, true);
this.lock_tree();
egw.json('mail_ui::ajax_changeProfile',[folder, getFolders, this.et2._inst.etemplate_exec_id], jQuery.proxy(function() {
// Profile changed, select inbox
var inbox = folder + '::INBOX';
_widget.reSelectItem(inbox);
this.mail_changeFolder(inbox,_widget,'');
this.unlock_tree();
},this))
.sendRequest(true);
return true;
},
/**
* mail_changeFolder
* @param {string} _folder the ID of the selected Node
* @param {widget object} _widget handle to the tree widget
* @param {string} _previous - Previously selected node ID
*/
mail_changeFolder: function(_folder,_widget, _previous) {
// to reset iframes to the normal status
this.loadIframe();
// Abort if user selected an un-selectable node
// Use image over anything else because...?
var img = _widget.getSelectedNode().images[0];
if (img.indexOf('NoSelect') !== -1)
{
_widget.reSelectItem(_previous);
return;
}
// Check if this is a top level node and
// change profile if server has changed
var server = _folder.split('::');
var previousServer = _previous.split('::');
var profile_selected = (_folder.indexOf('::') === -1);
if (server[0] != previousServer[0] && profile_selected)
{
// mail_changeProfile triggers a refresh, no need to do any more
return this.mail_changeProfile(_folder,_widget, _widget.getSelectedNode().childsCount == 0);
}
// Apply new selected folder to list, which updates data
var nm = _widget.getRoot().getWidgetById(this.nm_index);
if(nm)
{
this.lock_tree();
nm.applyFilters({'selectedFolder': _folder});
}
// Get nice folder name for message, if selected is not a profile
if(!profile_selected)
{
var displayname = _widget.getSelectedLabel();
var myMsg = (displayname?displayname:_folder).replace(this._unseen_regexp, '')+' '+this.egw.lang('selected');
this.egw.message(myMsg);
}
// Update non-grid
this.mail_refreshFolderStatus(_folder,'forced',false,false);
this.mail_refreshQuotaDisplay(server[0]);
this.mail_preview();
if (server[0]!=previousServer[0])
{
this.mail_callRefreshVacationNotice(server[0]);
egw.jsonq('mail.mail_ui.ajax_refreshFilters',[server[0]]);
}
},
/**
* mail_checkAllSelected
*
* @param _action
* @param _elems
* @param _target
* @param _confirm
*/
mail_checkAllSelected: function(_action, _elems, _target, _confirm)
{
if (typeof _confirm == 'undefined') _confirm = false;
// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
var that = this;
var rvMain = false;
if ((obj_manager && _elems.length>1 && obj_manager.getAllSelected() && !_action.paste) || _action.id=='readall')
{
if (_confirm)
{
var buttons = [
{text: this.egw.lang("Yes"), id: "all", "class": "ui-priority-primary", "default": true, image: 'check'},
{text: this.egw.lang("Cancel"), id:"cancel"}
];
var messageToDisplay = '';
var actionlabel =_action.id;
switch (_action.id)
{
case "readall":
messageToDisplay = this.egw.lang("Do you really want to mark ALL messages as read in the current folder?")+" ";
break;
case "unlabel":
messageToDisplay = this.egw.lang("Do you really want to remove ALL labels from ALL messages in the current folder?")+" ";
break;
case "label1":
if (_action.id=="label1") actionlabel="important";
case "label2":
if (_action.id=="label2") actionlabel="job";
case "label3":
if (_action.id=="label3") actionlabel="personal";
case "label4":
if (_action.id=="label4") actionlabel="to do";
case "label5":
if (_action.id=="label5") actionlabel="later";
case "flagged":
case "read":
case "undelete":
messageToDisplay = this.egw.lang("Do you really want to toggle flag %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
if (_action.id.substr(0,5)=='label') messageToDisplay = this.egw.lang("Do you really want to toggle label %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
break;
default:
var type = null;
if (_action.id.substr(0,4)=='move' || _action.id === "drop_move_mail")
{
type = 'Move';
}
if (_action.id.substr(0,4)=='copy' || _action.id === "drop_copy_mail")
{
type = 'Copy';
}
messageToDisplay = this.egw.lang("Do you really want to apply %1 to ALL messages in the current view?",this.egw.lang(type?type:_action.id))+" ";
}
return et2_dialog.show_dialog(function(_button_id) {
var rv = false;
switch (_button_id)
{
case "all":
rv = true;
break;
case "cancel":
rv = 'cancel';
}
if (rv !="cancel") that.lock_tree();
switch (_action.id)
{
case "delete":
that.mail_callDelete(_action, _elems,rv);
break;
case "readall":
case "unlabel":
case "label1":
case "label2":
case "label3":
case "label4":
case "label5":
case "flagged":
case "read":
case "undelete":
that.mail_callFlagMessages(_action, _elems,rv);
break;
case "drop_move_mail":
that.mail_callMove(_action, _elems,_target, rv);
break;
case "drop_copy_mail":
that.mail_callCopy(_action, _elems,_target, rv);
break;
default:
if (_action.id.substr(0,4)=='move') that.mail_callMove(_action, _elems,_target, rv);
if (_action.id.substr(0,4)=='copy') that.mail_callCopy(_action, _elems,_target, rv);
}
},
messageToDisplay,
this.egw.lang("Confirm"),
_action.id, buttons);
}
else
{
rvMain = true;
}
}
switch (_action.id)
{
case "delete":
this.mail_callDelete(_action, _elems,rvMain);
break;
case "unlabel":
case "label1":
case "label2":
case "label3":
case "label4":
case "label5":
case "flagged":
case "read":
case "undelete":
this.mail_callFlagMessages(_action, _elems,rvMain);
break;
case "drop_move_mail":
this.mail_callMove(_action, _elems,_target, rvMain);
break;
case "drop_copy_mail":
this.mail_callCopy(_action, _elems,_target, rvMain);
break;
default:
if (_action.id.substr(0,4)=='move') this.mail_callMove(_action, _elems,_target, rvMain);
if (_action.id.substr(0,4)=='copy') this.mail_callCopy(_action, _elems,_target, rvMain);
}
},
/**
* mail_doActionCall
*
* @param _action
* @param _elems
*/
mail_doActionCall: function(_action, _elems)
{
},
/**
* mail_getActiveFilters
*
* @param _action
* @return mixed boolean/activeFilters object
*/
mail_getActiveFilters: function(_action)
{
// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
if (obj_manager && obj_manager.manager && obj_manager.manager.data && obj_manager.manager.data.nextmatch && obj_manager.manager.data.nextmatch.activeFilters)
{
var af = obj_manager.manager.data.nextmatch.activeFilters;
// merge startdate and enddate into the active filters (if set)
if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) af["startdate"] = this.et2.getWidgetById('startdate').date;
if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) af["enddate"] = this.et2.getWidgetById('enddate').date;
return af;
}
return false;
},
/**
* Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
*
* @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
* @param _elems
*/
mail_flag: function(_action, _elems)
{
this.mail_checkAllSelected(_action,_elems,null,true);
},
/**
* Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
*
* @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
* @param _elems
* @param _allMessagesChecked
*/
mail_callFlagMessages: function(_action, _elems, _allMessagesChecked)
{
/**
* vars
*/
var folder = '',
tree = {},
formData = {},
data = {
msg: [this.et2.getArrayMgr("content").getEntry('mail_id')] || '',
all: _allMessagesChecked || false,
popup: typeof this.et2_view!='undefined' || egw(window).is_popup() || false,
activeFilters: _action.id == 'readall'? false : this.mail_getActiveFilters(_action)
},
rowClass = _action.id;
if (typeof _elems === 'undefined' || _elems.length == 0)
{
if (this.mail_isMainWindow && this.mail_currentlyFocussed)
{
data.msg = [this.mail_currentlyFocussed];
_elems = data;
data.msg = this.mail_getFormData(_elems).msg;
}
}
else // action called by contextmenu
{
data.msg = this.mail_getFormData(_elems).msg;
}
switch (_action.id)
{
case 'read':
rowClass = 'seen';
if (data.popup)
{
var et_2 = typeof this.et2_view!='undefined'? etemplate2:opener.etemplate2;
tree = et_2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
}
else
{
tree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
}
folder = tree.getSelectedNode().id;
break;
case 'readall':
rowClass = 'seen';
break;
case 'label1':
rowClass = 'labelone';
break;
case 'label2':
rowClass = 'labeltwo';
break;
case 'label3':
rowClass = 'labelthree';
break;
case 'label4':
rowClass = 'labelfour';
break;
case 'label5':
rowClass = 'labelfive';
break;
default:
break;
}
jQuery(data).extend({},data, formData);
if (data['all']=='cancel') return false;
if (_action.id.substring(0,2)=='un') {
//old style, only available for undelete and unlabel (no toggle)
if ( _action.id=='unlabel') // this means all labels should be removed
{
var labels = ['labelone','labeltwo','labelthree','labelfour','labelfive'];
for (var i=0; i<labels.length; i++) this.mail_removeRowClass(_elems,labels[i]);
this.mail_flagMessages(_action.id,data);
}
else
{
this.mail_removeRowClass(_elems,_action.id.substring(2));
this.mail_setRowClass(_elems,_action.id);
this.mail_flagMessages(_action.id,data);
}
}
else if (_action.id=='readall')
{
this.mail_flagMessages('read',data);
}
else
{
var msg_set = {msg:[]};
var msg_unset = {msg:[]};
var dataElem;
var flags;
var classes = '';
for (var i=0; i<data.msg.length; i++)
{
dataElem = egw.dataGetUIDdata(data.msg[i]);
if(typeof dataElem.data.flags == 'undefined')
{
dataElem.data.flags = {};
}
flags = dataElem.data.flags;
classes = dataElem.data['class'] || "";
classes = classes.split(' ');
// since we toggle we need to unset the ones already set, and set the ones not set
// flags is data, UI is done by class, so update both
// Flags are there or not, class names are flag or 'un'+flag
if(classes.indexOf(rowClass) >= 0)
{
classes.splice(classes.indexOf(rowClass),1);
}
if(classes.indexOf('un' + rowClass) >= 0)
{
classes.splice(classes.indexOf('un' + rowClass),1);
}
if (flags[_action.id])
{
msg_unset['msg'].push(data.msg[i]);
classes.push('un'+rowClass);
delete flags[_action.id];
}
else
{
msg_set['msg'].push(data.msg[i]);
flags[_action.id] = _action.id;
classes.push(rowClass);
}
// Update cache & call callbacks - updates list
dataElem.data['class'] = classes.join(' ');
egw.dataStoreUID(data.msg[i],dataElem.data);
//Refresh the nm rows after we told dataComponent about all changes, since the dataComponent doesn't talk to nm, we need to do it manually
this.updateFilter_data(data.msg[i], _action.id, data.activeFilters);
}
// Notify server of changes
if (msg_unset['msg'] && msg_unset['msg'].length)
{
if (!data['all']) this.mail_flagMessages('un'+_action.id,msg_unset);
}
if (msg_set['msg'] && msg_set['msg'].length)
{
if (!data['all']) this.mail_flagMessages(_action.id,msg_set);
}
//server must do the toggle, as we apply to ALL, not only the visible
if (data['all']) this.mail_flagMessages(_action.id,data);
// No further update needed, only in case of read, the counters should be refreshed
if (_action.id=='read') this.mail_refreshFolderStatus(folder,'thisfolderonly',false,true);
return;
}
},
/**
* Update changes on filtered mail rows in nm, triggers manual refresh
*
* @param {type} _uid mail uid
* @param {type} _actionId action id sended by nm action
* @param {type} _filters activefilters
*/
updateFilter_data: function (_uid, _actionId, _filters)
{
var uid = _uid.replace('mail::','');
var action = '';
switch (_actionId)
{
case 'flagged':
action = 'flagged';
break;
case 'read':
if (_filters.filter == 'seen')
{
action = 'seen';
}
else if (_filters.filter == 'unseen')
{
action = 'unseen';
}
break;
case 'label1':
action = 'keyword1';
break;
case 'label2':
action = 'keyword2';
break;
case 'label3':
action = 'keyword3';
break;
case 'label4':
action = 'keyword4';
break;
case 'label4':
action = 'keyword4';
break;
}
if (action == _filters.filter)
{
egw.refresh('','mail',uid, 'delete');
}
},
/**
* Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
*
* @param {object} _flag
* @param {object} _elems
* @param {boolean} _isPopup
*/
mail_flagMessages: function(_flag, _elems,_isPopup)
{
egw.jsonq('mail.mail_ui.ajax_flagMessages',[_flag, _elems]);
// .sendRequest(true);
},
/**
* display header lines, or source of mail, depending on the url given
*
* @param _url
*/
mail_displayHeaderLines: function(_url) {
// only used by right clickaction
egw_openWindowCentered(_url,'mail_display_headerLines','870','600',window.outerWidth/2,window.outerHeight/2);
},
/**
* View header of a message
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_header: function(_action, _elems)
{
if (typeof _elems == 'undefined'|| _elems.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
//alert('mail_header('+_elems[0].id+')');
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=mail.mail_ui.displayHeader'; // todo compose for Draft folder
url += '&id='+_elems[0].id;
this.mail_displayHeaderLines(url);
},
/**
* View message source
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_mailsource: function(_action, _elems)
{
if (typeof _elems == 'undefined' || _elems.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined'|| _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
//alert('mail_mailsource('+_elems[0].id+')');
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=mail.mail_ui.saveMessage'; // todo compose for Draft folder
url += '&id='+_elems[0].id;
url += '&location=display';
this.mail_displayHeaderLines(url);
},
/**
* Save a message
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_save: function(_action, _elems)
{
if (typeof _elems == 'undefined' || _elems.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
//alert('mail_save('+_elems[0].id+')');
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=mail.mail_ui.saveMessage'; // todo compose for Draft folder
url += '&id='+_elems[0].id;
//window.open(url,'_blank','dependent=yes,width=100,height=100,scrollbars=yes,status=yes');
this.et2._inst.download(url);
},
/**
* User clicked an address (FROM, TO, etc)
*
* @param {object} tag_info with values for attributes id, label, title, ...
* @param {widget object} widget
*
* @todo seems this function is not implemented, need to be checked if it is neccessary at all
*/
address_click: function(tag_info, widget)
{
},
/**
* displayAttachment
*
* @param {object} tag_info
* @param {widget object} widget
* @param {object} calledForCompose
*/
displayAttachment: function(tag_info, widget, calledForCompose)
{
var mailid;
var attgrid;
if (typeof calledForCompose == 'undefined' || typeof calledForCompose == 'object') calledForCompose=false;
if (calledForCompose===false)
{
if (this.mail_isMainWindow)
{
mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
var p = widget.getParent();
var cont = p.getArrayMgr("content").data;
attgrid = cont[widget.id.replace(/\[filename\]/,'')];
}
else
{
mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[filename\]/,'')];
}
}
if (calledForCompose===true)
{
// CALLED FOR COMPOSE; processedmail_id could hold several IDs seperated by comma
attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
var mailids = this.et2.getArrayMgr("content").getEntry('processedmail_id');
var mailida = mailids.split(',');
// either several attachments of one email, or multiple emlfiles
mailid = mailida.length==1 ? mailida[0] : mailida[widget.id.replace(/\[name\]/,'')];
if (typeof attgrid.uid != 'undefined' && attgrid.uid && mailid.indexOf(attgrid.uid)==-1)
{
for (var i=0; i<mailida.length; i++)
{
if (mailida[i].indexOf('::'+attgrid.uid)>-1) mailid = mailida[i];
}
}
}
var url = window.egw_webserverUrl+'/index.php?';
var width;
var height;
var windowName ='mail';
switch(attgrid.type.toUpperCase())
{
case 'MESSAGE/RFC822':
url += 'menuaction=mail.mail_ui.displayMessage'; // todo compose for Draft folder
url += '&mode=display';//message/rfc822 attachments should be opened in display mode
url += '&id='+mailid;
url += '&part='+attgrid.partID;
url += '&is_winmail='+attgrid.winmailFlag;
windowName = windowName+'displayMessage_'+mailid+'_'+attgrid.partID;
width = 870;
height = egw_getWindowOuterHeight();
break;
case 'IMAGE/JPEG':
case 'IMAGE/PNG':
case 'IMAGE/GIF':
case 'IMAGE/BMP':
case 'APPLICATION/PDF':
case 'TEXT/PLAIN':
case 'TEXT/HTML':
case 'TEXT/DIRECTORY':
/*
$sfxMimeType = $value['mimeType'];
$buff = explode('.',$value['name']);
$suffix = '';
if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime
if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix);
if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD')
{
$attachments[$key]['mimeType'] = $sfxMimeType;
$value['mimeType'] = strtoupper($sfxMimeType);
}
*/
case 'TEXT/X-VCARD':
case 'TEXT/VCARD':
case 'TEXT/CALENDAR':
case 'TEXT/X-VCALENDAR':
url += 'menuaction=mail.mail_ui.getAttachment'; // todo compose for Draft folder
url += '&id='+mailid;
url += '&part='+attgrid.partID;
url += '&is_winmail='+attgrid.winmailFlag;
windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
var reg = '800x600';
var reg2;
// handle calendar/vcard
if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
{
windowName = 'maildisplayEvent_'+mailid+'_'+attgrid.partID;
reg2 = egw.link_get_registry('calendar');
if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
{
reg = reg2['view_popup'];
}
}
if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
{
windowName = 'maildisplayContact_'+mailid+'_'+attgrid.partID;
reg2 = egw.link_get_registry('addressbook');
if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
{
reg = reg2['add_popup'];
}
}
var w_h =reg.split('x');
width = w_h[0];
height = w_h[1];
break;
default:
url += 'menuaction=mail.mail_ui.getAttachment'; // todo compose for Draft folder
url += '&id='+mailid;
url += '&part='+attgrid.partID;
url += '&is_winmail='+attgrid.winmailFlag;
windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
width = 870;
height = 600;
break;
}
egw_openWindowCentered(url,windowName,width,height);
},
/**
* displayUploadedFile
*
* @param {object} tag_info
* @param {widget object} widget
*/
displayUploadedFile: function(tag_info, widget)
{
var attgrid;
attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
if (attgrid.uid && (attgrid.partID||attgrid.folder))
{
this.displayAttachment(tag_info, widget, true);
return;
}
var get_param = {
menuaction: 'mail.mail_compose.getAttachment', // todo compose for Draft folder
tmpname: attgrid.tmp_name,
etemplate_exec_id: this.et2._inst.etemplate_exec_id
};
var width;
var height;
var windowName ='maildisplayAttachment_'+attgrid.file.replace(/\//g,"_");
switch(attgrid.type.toUpperCase())
{
case 'IMAGE/JPEG':
case 'IMAGE/PNG':
case 'IMAGE/GIF':
case 'IMAGE/BMP':
case 'APPLICATION/PDF':
case 'TEXT/PLAIN':
case 'TEXT/HTML':
case 'TEXT/DIRECTORY':
case 'TEXT/X-VCARD':
case 'TEXT/VCARD':
case 'TEXT/CALENDAR':
case 'TEXT/X-VCALENDAR':
var reg = '800x600';
var reg2;
// handle calendar/vcard
if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
{
windowName = 'maildisplayEvent_'+attgrid.file.replace(/\//g,"_");
reg2 = egw.link_get_registry('calendar');
if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
{
reg = reg2['view_popup'];
}
}
if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
{
windowName = 'maildisplayContact_'+attgrid.file.replace(/\//g,"_");
reg2 = egw.link_get_registry('addressbook');
if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
{
reg = reg2['add_popup'];
}
}
var w_h =reg.split('x');
width = w_h[0];
height = w_h[1];
break;
case 'MESSAGE/RFC822':
default:
get_param.mode = 'save';
width = 870;
height = 600;
break;
}
egw.openPopup(egw.link('/index.php', get_param), width, height, windowName);
},
saveAttachment: function(tag_info, widget)
{
var mailid;
var attgrid;
if (this.mail_isMainWindow)
{
mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
var p = widget.getParent();
var cont = p.getArrayMgr("content").data;
attgrid = cont[widget.id.replace(/\[save\]/,'')];
}
else
{
mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
}
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=mail.mail_ui.getAttachment'; // todo compose for Draft folder
url += '&mode=save';
url += '&id='+mailid;
url += '&part='+attgrid.partID;
url += '&is_winmail='+attgrid.winmailFlag;
this.et2._inst.download(url);
},
saveAllAttachmentsToZip: function(tag_info, widget)
{
var mailid;
var attgrid;
if (this.mail_isMainWindow)
{
mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
var p = widget.getParent();
var cont = p.getArrayMgr("content").data;
attgrid = cont[widget.id.replace(/\[save\]/,'')];
}
else
{
mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
}
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=mail.mail_ui.download_zip'; // todo compose for Draft folder
url += '&mode=save';
url += '&id='+mailid;
this.et2._inst.download(url);
},
saveAttachmentToVFS: function(tag_info, widget)
{
var mailid;
var attgrid;
if (this.mail_isMainWindow)
{
mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
var p = widget.getParent();
var cont = p.getArrayMgr("content").data;
attgrid = cont[widget.id.replace(/\[saveAsVFS\]/,'')];
}
else
{
mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[saveAsVFS\]/,'')];
}
var url = window.egw_webserverUrl+'/index.php?';
var width=640;
var height=570;
var windowName ='mail';
url += 'menuaction=filemanager.filemanager_select.select'; // todo compose for Draft folder
url += '&mode=saveas';
url += '&id='+mailid+'::'+attgrid.partID+'::'+attgrid.winmailFlag;
url += '&name='+attgrid.filename;
url += '&type='+attgrid.type.toLowerCase();
url += '&method=mail.mail_ui.vfsSaveAttachment';
url += '&label='+egw.lang('Save');
egw_openWindowCentered(url,windowName,width,height);
},
saveAllAttachmentsToVFS: function(tag_info, widget)
{
var mailid;
var attgrid;
if (this.mail_isMainWindow)
{
mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
var p = widget.getParent();
attgrid = p.getArrayMgr("content").data;
}
else
{
mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments');
}
var url = window.egw_webserverUrl+'/index.php?';
var width=640;
var height=570;
var windowName ='mail';
url += 'menuaction=filemanager.filemanager_select.select'; // todo compose for Draft folder
url += '&mode=select-dir';
url += '&method=mail.mail_ui.vfsSaveAttachment';
url += '&label='+egw.lang('Save all');
for (var i=0;i<attgrid.length;i++)
{
if (attgrid[i] != null) url += '&id['+i+']='+mailid+'::'+attgrid[i].partID+'::'+attgrid[i].winmailFlag+'::'+attgrid[i].filename;
}
egw_openWindowCentered(url,windowName,width,height);
},
/**
* Save a message to filemanager
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_save2fm: function(_action, _elems)
{
if (typeof _elems == 'undefined' || _elems.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
var _id = _elems[0].id;
var dataElem = egw.dataGetUIDdata(_id);
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=filemanager.filemanager_select.select'; // todo compose for Draft folder
url += '&mode=saveas';
var subject = dataElem? dataElem.data.subject: _elems[0].subject;
var filename = subject.replace(/[\f\n\t\v]/g,"_")|| 'unknown';
url += '&name='+encodeURIComponent(filename+'.eml');
url += '&mime=message'+encodeURIComponent('/')+'rfc822';
url += '&method=mail.mail_ui.vfsSaveMessage';
url += '&id='+_elems[0].id;
url += '&label=Save';
egw_openWindowCentered(url,'vfs_save_message_'+_elems[0].id,'680','400',window.outerWidth/2,window.outerHeight/2);
},
/**
* Integrate mail message into another app's entry
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_integrate: function(_action, _elems)
{
var app = _action.id;
var w_h = ['750','580']; // define a default wxh if there's no popup size registered
if (typeof _action.data != 'undefined' )
{
if (typeof _action.data.popup != 'undefined' && _action.data.popup) w_h = _action.data.popup.split('x');
if (typeof _action.data.mail_import != 'undefined') var mail_import_hook = _action.data.mail_import;
}
if (typeof _elems == 'undefined' || _elems.length==0)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
}
}
}
var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
if (mail_import_hook && typeof mail_import_hook.app_entry_method != 'undefined')
{
var data = egw.dataGetUIDdata(_elems[0].id);
var subject = (data && typeof data.data != 'undefined')? data.data.subject : '';
this.integrate_checkAppEntry('Select '+ app + ' entry', app, subject, url, mail_import_hook.app_entry_method, function (args){
egw_openWindowCentered(args.url+ (args.entryid ?'&entry_id=' + args.entryid: ''),'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
});
}
else
{
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
}
},
/**
* Checks the application entry existance and offers user
* to select desire app id to append mail content into it,
* or add the mail content as a new app entry
*
* @param {string} _title select app entry title
* @param {string} _appName app to be integrated
* @param {string} _subject
* @param {string} _url
* @param {string} _appCheckCallback registered mail_import hook method
* @param {function} _execCallback function to get called on dialog actions
*/
integrate_checkAppEntry: function (_title, _appName, _subject ,_url, _appCheckCallback, _execCallback)
{
var subject = _subject || '';
var execCallback = _execCallback;
egw.json(_appCheckCallback, subject,function(_entryId){
// if there's no entry saved already
// open dialog in order to select one
if (!_entryId)
{
var buttons = [
{text: 'Append', id: 'append', image: 'check', default:true},
{text: 'Add as new', id: 'new', image: 'check'},
{text: 'Cancel', id: 'cancel', image: 'check'}
];
et2_createWidget("dialog",
{
callback: function(_buttons, _value)
{
if (_buttons == 'cancel') return;
if (_buttons == 'append' && _value)
{
_entryId = _value.id;
}
execCallback.call(this,{entryid:_entryId,url:_url});
},
title: egw.lang(_title),
buttons: buttons||et2_dialog.BUTTONS_OK_CANCEL,
value:{
content:{
appName:_appName // appName to search on its list later
}},
template: egw.webserverUrl+'/mail/templates/default/integration_to_entry_dialog.xet'
},et2_dialog._create_parent('mail'));
}
else // there is an entry saved related to this mail's subject
{
execCallback.call(this,{entryid:_entryId,url:_url});
}
},this,true,this).sendRequest();
},
/**
* mail_getFormData
*
* @param {object} _actionObjects the senders
*
* @return structured array of message ids: array(msg=>message-ids)
*/
mail_getFormData: function(_actionObjects) {
var messages = {};
// if
if (typeof _actionObjects['msg'] != 'undefined' && _actionObjects['msg'].length>0) return _actionObjects;
if (_actionObjects.length>0)
{
messages['msg'] = [];
}
for (var i = 0; i < _actionObjects.length; i++)
{
if (_actionObjects[i].id.length>0)
{
messages['msg'][i] = _actionObjects[i].id;
}
}
return messages;
},
/**
* mail_setRowClass
*
* @param {object} _actionObjects the senders
* @param {string} _class
*/
mail_setRowClass: function(_actionObjects,_class) {
if (typeof _class == 'undefined') return false;
if (typeof _actionObjects['msg'] == 'undefined')
{
for (var i = 0; i < _actionObjects.length; i++)
{
// Check that the ID & interface is there. Paste is missing iface.
if (_actionObjects[i].id.length>0 && _actionObjects[i].iface)
{
var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
dataElem.addClass(_class);
}
}
}
else
{
for (var i = 0; i < _actionObjects['msg'].length; i++)
{
var mail_uid = _actionObjects['msg'][i];
// Get the record from data cache
var dataElem = egw.dataGetUIDdata(mail_uid);
if(dataElem == null || typeof dataElem == undefined)
{
// Unknown ID, nothing to update
return;
}
// Update class
dataElem.data['class'] += ' ' + _class;
// need to update flags too
switch(_class)
{
case 'unseen':
delete dataElem.data.flags.read;
break;
}
// Update record, which updates all listeners (including nextmatch)
egw.dataStoreUID(mail_uid,dataElem.data);
}
}
},
/**
* mail_removeRowFlag
* Removes a flag and updates the CSS class. Updates the UI, but not the server.
*
* @param {action object} _actionObjects the senders, or a messages object
* @param {string} _class the class to be removed
*/
mail_removeRowClass: function(_actionObjects,_class) {
if (typeof _class == 'undefined') return false;
if (typeof _actionObjects['msg'] == 'undefined')
{
for (var i = 0; i < _actionObjects.length; i++)
{
if (_actionObjects[i].id.length>0)
{
var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
dataElem.removeClass(_class);
}
}
}
else
{
for (var i = 0; i < _actionObjects['msg'].length; i++)
{
var mail_uid = _actionObjects['msg'][i];
// Get the record from data cache
var dataElem = egw.dataGetUIDdata(mail_uid);
if(dataElem == null || typeof dataElem == undefined)
{
// Unknown ID, nothing to update
return;
}
// Update class
var classes = dataElem.data['class'] || "";
classes = classes.split(' ');
if(classes.indexOf(_class) >= 0)
{
classes.splice(classes.indexOf(_class),1);
dataElem.data['class'] = classes.join(' ');
// need to update flags too
switch(_class)
{
case 'unseen':
dataElem.data.flags.read = true;
break;
}
// Update record, which updates all listeners (including nextmatch)
egw.dataStoreUID(mail_uid,dataElem.data);
}
}
}
},
/**
* mail_move2folder - implementation of the move action from action menu
*
* @param _action _action.id holds folder target information
* @param _elems - the representation of the elements to be affected
*/
mail_move2folder: function(_action, _elems) {
this.mail_move(_action, _elems, null);
},
/**
* mail_move - implementation of the move action from drag n drop
*
* @param _action
* @param _senders - the representation of the elements dragged
* @param _target - the representation of the target
*/
mail_move: function(_action,_senders,_target) {
this.mail_checkAllSelected(_action,_senders,_target,true);
},
/**
* mail_move - implementation of the move action from drag n drop
*
* @param _action
* @param _senders - the representation of the elements dragged
* @param _target - the representation of the target
* @param _allMessagesChecked
*/
mail_callMove: function(_action,_senders,_target,_allMessagesChecked) {
var target = _action.id == 'drop_move_mail' ? _target.iface.id : _action.id.substr(5);
var messages = this.mail_getFormData(_senders);
if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
// Directly delete any cache for target
if(window.localStorage)
{
for(var i = 0; i < window.localStorage.length; i++)
{
var key = window.localStorage.key(i);
// Find directly by what the key would look like
if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+target+'"') == 0)
{
window.localStorage.removeItem(key);
}
}
}
// TODO: Write move/copy function which cares about doing the same stuff
// as the "onNodeSelect" function!
messages['all'] = _allMessagesChecked;
if (messages['all']=='cancel') return false;
if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
// Make sure a default target folder is set in case of drop target is parent 0 (mail account name)
if (!target.match(/::/g)) target += '::INBOX';
var self = this;
var nm = this.et2.getWidgetById(this.nm_index);
// thev 4th param indicates if it is a normal move messages action. if not the action is a move2.... (archiveFolder) action
egw.json('mail.mail_ui.ajax_copyMessages',[target, messages, 'move', (_action.id.substr(0,4)=='move'&&_action.id.substr(4,1)=='2'?'2':'_') ], function(){
self.unlock_tree();
// Nextmatch automatically selects the next row and calls preview.
// Unselect it and thanks to the timeout selectionMgr uses, preview
// will close when the selection callback fires instead of load the
// next message
nm.controller._selectionMgr.resetSelection();
// Server response may contain refresh, but it's always delete
// Refresh list if current view is the target (happens when pasting)
var tree = self.et2.getWidgetById('nm[foldertree]');
if(nm && tree && target == tree.getValue())
{
// Can't trust the sorting, needs to be full refresh
nm.refresh();
}
})
.sendRequest();
this.mail_setRowClass(_senders,'deleted');
// Server response may contain refresh, not needed here
},
/**
* mail_copy - implementation of the move action from drag n drop
*
* @param _action
* @param _senders - the representation of the elements dragged
* @param _target - the representation of the target
*/
mail_copy: function(_action,_senders,_target) {
this.mail_checkAllSelected(_action,_senders,_target,true);
},
/**
* mail_callCopy - implementation of the copy action from drag n drop
*
* @param _action
* @param _senders - the representation of the elements dragged
* @param _target - the representation of the target
* @param _allMessagesChecked
*/
mail_callCopy: function(_action,_senders,_target,_allMessagesChecked) {
var target = _action.id == 'drop_copy_mail' ? _target.iface.id : _action.id.substr(5);
var messages = this.mail_getFormData(_senders);
if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
// TODO: Write move/copy function which cares about doing the same stuff
// as the "onNodeSelect" function!
messages['all'] = _allMessagesChecked;
if (messages['all']=='cancel') return false;
if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
var self = this;
egw.json('mail.mail_ui.ajax_copyMessages',[target, messages],function (){self.unlock_tree();})
.sendRequest();
// Server response contains refresh
},
/**
* mail_AddFolder - implementation of the AddFolder action of right click options on the tree
*
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
mail_AddFolder: function(_action,_senders) {
//action.id == 'add'
//_senders.iface.id == target leaf / leaf to edit
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
var buttons = [
{text: this.egw.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
{text: this.egw.lang("Cancel"), id:"cancel"}
];
et2_dialog.show_prompt(function(_button_id, _value) {
var NewFolderName = null;
if (_value.length>0) NewFolderName = _value;
//alert(NewFolderName);
if (NewFolderName && NewFolderName.length>0)
{
switch (_button_id)
{
case "add":
egw.json('mail.mail_ui.ajax_addFolder',[_senders[0].id, NewFolderName])
.sendRequest(true);
return;
case "cancel":
}
}
},
this.egw.lang("Enter the name for the new Folder:"),
this.egw.lang("Add a new Folder to %1:",OldFolderName),
'', buttons);
},
/**
* mail_RenameFolder - implementation of the RenameFolder action of right click options on the tree
*
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
mail_RenameFolder: function(_action,_senders) {
//action.id == 'rename'
//_senders.iface.id == target leaf / leaf to edit
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
var buttons = [
{text: this.egw.lang("Rename"), id: "rename", "class": "ui-priority-primary", image: 'edit', "default": true},
{text: this.egw.lang("Cancel"), id:"cancel"}
];
et2_dialog.show_prompt(function(_button_id, _value) {
var NewFolderName = null;
if (_value.length>0) NewFolderName = _value;
//alert(NewFolderName);
if (NewFolderName && NewFolderName.length>0)
{
switch (_button_id)
{
case "rename":
egw.json('mail.mail_ui.ajax_renameFolder',[_senders[0].id, NewFolderName])
.sendRequest(true);
return;
case "cancel":
}
}
},
this.egw.lang("Rename Folder %1 to:",OldFolderName),
this.egw.lang("Rename Folder %1 ?",OldFolderName),
OldFolderName, buttons);
},
/**
* mail_MoveFolder - implementation of the MoveFolder action on the tree
*
* @param {egwAction} _action
* @param {egwActionObject[]} _senders - the representation of the tree leaf to be manipulated
* @param {egwActionObject} destination Drop target egwActionObject representing the destination
*/
mail_MoveFolder: function(_action,_senders,destination) {
if(!destination || !destination.id)
{
egw.debug('warn', "Move folder, but no target");
return;
}
var sourceProfile = _senders[0].id.split('::');
var targetProfile = destination.id.split('::');
if (sourceProfile[0]!=targetProfile[0])
{
egw.message(this.egw.lang('Moving Folders from one Mailaccount to another is not supported'),'error');
return;
}
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var src_label = _senders[0].id.replace(/^[0-9]+::/,'');
var dest_label = destination.id.replace(/^[0-9]+::/,'');
var callback = function (_button)
{
if (_button == et2_dialog.YES_BUTTON)
{
egw.appName='mail';
egw.message (egw.lang('Folder %1 is moving to folder %2',src_label,dest_label ));
egw.loading_prompt('mail_moveFolder', true,'','#egw_fw_basecontainer');
for(var i = 0; i < _senders.length; i++)
{
egw.jsonq('mail.mail_ui.ajax_MoveFolder',[_senders[i].id, destination.id],
// Move is done (successfully or not), remove loading
function() {
var id = destination.id.split('::');
//refersh the top parent
ftree.refreshItem(id[0],null);
egw.loading_prompt('mail_moveFolder', false);
}
);
}
}
};
et2_dialog.show_dialog(callback, this.egw.lang('Are you sure you want to move folder %1 to folder %2?',
src_label, dest_label), this.egw.lang('Move folder'), {},et2_dialog.BUTTONS_YES_NO, et2_dialog.WARNING_MESSAGE);
},
/**
* mail_DeleteFolder - implementation of the DeleteFolder action of right click options on the tree
*
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
mail_DeleteFolder: function(_action,_senders) {
//action.id == 'delete'
//_senders.iface.id == target leaf / leaf to edit
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
var buttons = [
{text: this.egw.lang("Yes"), id: "delete", "class": "ui-priority-primary", "default": true},
{text: this.egw.lang("Cancel"), id:"cancel"}
];
et2_dialog.show_dialog(function(_button_id, _value) {
switch (_button_id)
{
case "delete":
egw.json('mail.mail_ui.ajax_deleteFolder',[_senders[0].id])
.sendRequest(true);
return;
case "cancel":
}
},
this.egw.lang("Do you really want to DELETE Folder %1 ?",OldFolderName)+" "+(ftree.hasChildren(_senders[0].id)?this.egw.lang("All subfolders will be deleted too, and all messages in all affected folders will be lost"):this.egw.lang("All messages in the folder will be lost")),
this.egw.lang("DELETE Folder %1 ?",OldFolderName),
OldFolderName, buttons);
},
/**
* Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
*
* @param _event
* @param _file_count
* @param {string?} _path where the file is uploaded to, default current directory
*/
uploadForImport: function(_event, _file_count, _path)
{
// path is probably not needed when uploading for file; maybe it is when from vfs
if(typeof _path == 'undefined')
{
//_path = this.get_path();
}
if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
{
var widget = _event.data;
// var request = new egw_json_request('mail_ui::ajax_importMessage', ['upload', widget.getValue(), _path], this);
// widget.set_value('');
// request.sendRequest();//false, this._upload_callback, this);
this.et2_obj.submit();
}
},
/**
* Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
*
* @param {event object} _event
* @param {string} _file_count
* @param {string} _path [_path=current directory] Where the file is uploaded to.
*/
uploadForCompose: function(_event, _file_count, _path)
{
// path is probably not needed when uploading for file; maybe it is when from vfs
if(typeof _path == 'undefined')
{
//_path = this.get_path();
}
if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
{
var widget = _event.data;
this.et2_obj.submit();
}
},
/**
* Visible attachment box in compose dialog as soon as the file starts to upload
*/
composeUploadStart: function ()
{
var boxAttachment = this.et2.getWidgetById('attachments');
if (boxAttachment)
{
var groupbox = boxAttachment.getParent();
if (groupbox) groupbox.set_disabled(false);
}
//Resize the compose dialog
var self = this;
setTimeout(function(){self.compose_resizeHandler();}, 100);
return true;
},
/**
* Upload for import (VFS)
*
* @param {egw object} _egw
* @param {widget object} _widget
* @param {window object} _window
*/
vfsUploadForImport: function(_egw, _widget, _window) {
if (jQuery.isEmptyObject(_widget)) return;
if (!jQuery.isEmptyObject(_widget.getValue()))
{
this.et2_obj.submit();
}
},
/**
* Upload for compose (VFS)
*
* @param {egw object} _egw
* @param {widget object} _widget
* @param {window object} _window
*/
vfsUploadForCompose: function(_egw, _widget, _window)
{
if (jQuery.isEmptyObject(_widget)) return;
if (!jQuery.isEmptyObject(_widget.getValue()))
{
this.et2_obj.submit();
}
},
/**
* Submit on change (VFS)
*
* @param {egw object} _egw
* @param {widget object} _widget
*/
submitOnChange: function(_egw, _widget)
{
if (!jQuery.isEmptyObject(_widget))
{
if (typeof _widget.id !== 'undefined') var widgetId = _widget.id;
switch (widgetId)
{
case 'mimeType':
this.et2_obj.submit();
break;
default:
if (!jQuery.isEmptyObject(_widget.getValue()))
{
this.et2_obj.submit();
}
}
}
},
/**
* Save as Draft (VFS)
* -handel both actions save as draft and save as draft and print
*
* @param {egwAction} _egw_action
* @param {array|string} _action string "autosaving", if that triggered the action
*/
saveAsDraft: function(_egw_action, _action)
{
//this.et2_obj.submit();
var content = this.et2.getArrayMgr('content').data;
var action = _action;
if (_egw_action && _action !== 'autosaving')
{
action = _egw_action.id;
}
var widgets = ['from','to','cc','bcc','subject','folder','replyto','mailaccount',
'mail_htmltext', 'mail_plaintext', 'lastDrafted', 'filemode', 'expiration', 'password'];
var widget = {};
for (var index in widgets)
{
widget = this.et2.getWidgetById(widgets[index]);
if (widget)
{
content[widgets[index]] = widget.get_value();
}
}
var self = this;
if (content)
{
// if we compose an encrypted message, we have to get the encrypted content
if (this.mailvelope_editor)
{
this.mailvelope_editor.encrypt([]).then(function(_armored)
{
content['mail_plaintext'] = _armored;
self.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
self.savingDraft_response(_data,action);
}).sendRequest(true);
}, function(_err)
{
self.egw.message(_err.message, 'error');
});
return false;
}
this.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
self.savingDraft_response(_data,action);
}).sendRequest(true);
}
},
/**
* Set content of drafted message with new information sent back from server
* This function would be used as callback of send request to ajax_saveAsDraft.
*
* @param {object} _responseData response data sent back from server by ajax_saveAsDraft function.
* the object conatins below items:
* -draftedId: new drafted id created by server
* -message: resault message
* -success: true if saving was successful otherwise false
* -draftfolder: Name of draft folder including its delimiter
*
* @param {string} _action action is the element which caused saving draft, it could be as such:
* -button[saveAsDraft]
* -button[saveAsDraftAndPrint]
* -autosaving
*/
savingDraft_response: function(_responseData, _action)
{
//Make sure there's a response from server otherwise shoot an error message
if (jQuery.isEmptyObject(_responseData))
{
this.egw.message('Could not saved the message. Because, the response from server failed.', 'error');
return false;
}
if (_responseData.success)
{
var content = this.et2.getArrayMgr('content');
var lastDrafted = this.et2.getWidgetById('lastDrafted');
var folderTree = typeof opener.etemplate2.getByApplication('mail')[0] !='undefined'?
opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('nm[foldertree]'): null;
var activeFolder = folderTree?folderTree.getSelectedNode():null;
if (content)
{
var prevDraftedId = content.data.lastDrafted;
content.data.lastDrafted = _responseData.draftedId;
this.et2.setArrayMgr('content', content);
lastDrafted.set_value(_responseData.draftedId);
if (folderTree && activeFolder)
{
if (typeof activeFolder.id !='undefined' && _responseData.draftfolder == activeFolder.id)
{
if (prevDraftedId)
{
opener.egw_refresh(_responseData.message,'mail', prevDraftedId, 'delete');
}
this.egw.refresh(_responseData.message,'mail',_responseData.draftedId);
}
}
switch (_action)
{
case 'button[saveAsDraftAndPrint]':
this.mail_compose_print('mail::'+_responseData.draftedId);
this.egw.message(_responseData.message);
break;
case 'autosaving':
//Any sort of thing if it's an autosaving action
default:
this.egw.message(_responseData.message);
}
}
}
else
{
this.egw.message(_responseData.message, 'error');
}
},
/**
* Focus handler for folder, address, reject textbox/taglist to automatic check associated radio button
*
* @param {event} _ev
* @param {object} _widget taglist
*
*/
sieve_focus_radioBtn: function(_ev, _widget)
{
_widget.getRoot().getWidgetById('action').set_value(_widget.id.replace(/^action_([^_]+)_text$/, '$1'));
},
/**
* Select all aliases
*
*/
sieve_vac_all_aliases: function()
{
var aliases = [];
var tmp = [];
var addr = this.et2.getWidgetById('addresses');
var addresses = this.et2.getArrayMgr('sel_options').data.addresses;
for(var id in addresses) aliases.push(id);
if (addr)
{
tmp = aliases.concat(addr.get_value());
// returns de-duplicate items of an array
var deDuplicator = function (item,pos)
{
return tmp.indexOf(item) == pos;
};
aliases = tmp.filter(deDuplicator);
addr.set_value(aliases);
}
},
/**
* Disable/Enable date widgets on vacation seive rules form when status is "by_date"
*
*/
vacationFilterStatusChange: function()
{
var status = this.et2.getWidgetById('status');
var s_date = this.et2.getWidgetById('start_date');
var e_date = this.et2.getWidgetById('end_date');
var by_date_label = this.et2.getWidgetById('by_date_label');
if (status && s_date && e_date && by_date_label)
{
s_date.set_disabled(status.get_value() != "by_date");
e_date.set_disabled(status.get_value() != "by_date");
by_date_label.set_disabled(status.get_value() != "by_date");
}
},
/**
* action - handling actions on sieve rules
*
* @param _type - action name
* @param _selected - selected row from the sieve rule list
*/
action: function(_type, _selected)
{
var actionData ;
var that = this;
var typeId = _type.id;
var linkData = '';
var ruleID = ((_selected[0].id.split("_").pop()) - 1); // subtract the row id from 1 because the first row id is reserved by grid header
if (_type)
{
switch (_type.id)
{
case 'delete':
var callbackDeleteDialog = function (button_id)
{
if (button_id == et2_dialog.YES_BUTTON )
{
actionData = _type.parent.data.widget.getArrayMgr('content');
that._do_action(typeId, actionData['data'],ruleID);
}
};
et2_dialog.show_dialog(callbackDeleteDialog, this.egw.lang("Do you really want to DELETE this Rule"),this.egw.lang("Delete"), {},et2_dialog.BUTTONS_YES_CANCEL, et2_dialog.WARNING_MESSAGE);
break;
case 'add' :
linkData = "mail.mail_sieve.edit";
this.egw.open_link(linkData,'_blank',"600x480");
break;
case 'edit' :
linkData = "mail.mail_sieve.edit&ruleID="+ruleID;
this.egw.open_link(linkData,'_blank',"600x480");
break;
case 'enable':
actionData = _type.parent.data.widget.getArrayMgr('content');
this._do_action(typeId,actionData['data'],ruleID);
break;
case 'disable':
actionData = _type.parent.data.widget.getArrayMgr('content');
this._do_action(typeId,actionData['data'],ruleID);
break;
}
}
},
/**
* Send back sieve action result to server
*
* @param {string} _typeID action name
* @param {object} _data content
* @param {string} _selectedID selected row id
* @param {string} _msg message
*
*/
_do_action: function(_typeID, _data,_selectedID,_msg)
{
if (_typeID && _data)
{
var request = this.egw.json('mail.mail_sieve.ajax_action', [_typeID,_selectedID,_msg],null,null,true);
request.sendRequest();
}
},
/**
* Send ajax request to server to refresh the sieve grid
*/
sieve_refresh: function()
{
this.et2._inst.submit();
},
/**
* Select the right combination of the rights for radio buttons from the selected common right
*
* @@param {jQuery event} event
* @param {widget} widget common right selectBox
*
*/
acl_common_rights_selector: function(event,widget)
{
var rowId = widget.id.replace(/[^0-9.]+/g, '');
var rights = [];
switch (widget.get_value())
{
case 'custom':
break;
case 'aeiklprstwx':
rights = widget.get_value().replace(/[k,x,t,e]/g,"cd").split("");
break;
default:
rights = widget.get_value().split("");
}
if (rights.length > 0)
{
for (var i=0;i<this.aclRights.length;i++)
{
var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
rightsWidget.set_value((jQuery.inArray(this.aclRights[i],rights) != -1 )?true:false);
}
}
},
/**
*
* Choose the right common right option for common ACL selecBox
*
* @param {jQuery event} event
* @param {widget} widget radioButton rights
*
*/
acl_common_rights: function(event, widget)
{
var rowId = widget.id.replace(/[^0-9.]+/g, '');
var aclCommonWidget = this.et2.getWidgetById(rowId + '[acl]');
var rights = '';
for (var i=0;i<this.aclRights.length;i++)
{
var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
if (rightsWidget.get_value() == "true")
rights += this.aclRights[i];
}
for (var i=0;i<this.aclCommonRights.length;i++)
{
if (rights.split("").sort().toString() == this.aclCommonRights[i].split("").sort().toString())
rights = this.aclCommonRights[i];
}
if (jQuery.inArray(rights,this.aclCommonRights ) == -1 && rights !='lrswipcda')
{
aclCommonWidget.set_value('custom');
}
else if (rights =='lrswipcda')
{
aclCommonWidget.set_value('aeiklprstwx');
}
else
{
aclCommonWidget.set_value(rights);
}
},
/**
* Open seive filter list
*
* @param {action} _action
* @param {sender} _senders
*
*/
edit_sieve: function(_action, _senders)
{
var acc_id = parseInt(_senders[0].id);
var url = this.egw.link('/index.php',{
'menuaction': 'mail.mail_sieve.index',
'acc_id': acc_id,
'ajax': 'true'
});
// an ugly hack for idots to show up sieve rules not in an iframe
// but as new link, better to remove it after get rid of idots template
if (typeof window.framework == 'undefined')
{
this.egw.open_link(url);
}
else
{
this.loadIframe(url);
}
},
/**
* Load an url on an iframe
*
* @param {string} _url string egw url
* @param {iframe widget} _iFrame an iframe to be set if non, extra_iframe is default
*
* @return {boolean} return TRUE if success, and FALSE if iframe not given
*/
loadIframe: function (_url, _iFrame)
{
var mailSplitter = this.et2.getWidgetById('splitter');
var quotaipercent = this.et2.getWidgetById('nm[quotainpercent]');
var iframe = _iFrame || this.et2.getWidgetById('extra_iframe');
if (typeof iframe != 'undefined' && iframe)
{
if (_url)
{
iframe.set_src(_url);
}
if (typeof mailSplitter != 'undefined' && mailSplitter && typeof quotaipercent != 'undefined')
{
mailSplitter.set_disabled(!!_url);
quotaipercent.set_disabled(!!_url);
iframe.set_disabled(!_url);
}
// extra_iframe used for showing up sieve rules
// need some special handling for mobile device
// as we wont have splitter, and also a fix for
// iframe with display none
if (iframe.id == "extra_iframe")
{
if (egwIsMobile())
{
var nm = this.et2.getWidgetById(this.nm_index);
nm.set_disabled(!!_url);
iframe.set_disabled(!_url);
}
// Set extra_iframe a class with height and width
// and position relative, seems iframe display none
// with 100% height/width covers mail tree and block
// therefore block the click handling
if (!iframe.disabled)
{
iframe.set_class('mail-index-extra-iframe');
}
else
{
iframe.set_class('');
}
}
return true;
}
return false;
},
/**
* Edit vacation message
*
* @param {action} _action
* @param {sender} _senders
*/
edit_vacation: function(_action, _senders)
{
var acc_id = parseInt(_senders[0].id);
this.egw.open_link('mail.mail_sieve.editVacation&acc_id='+acc_id,'_blank','700x480');
},
subscription_refresh: function(_data)
{
console.log(_data);
},
/**
* Submit on apply button and save current tree state
*
* @param {type} _egw
* @param {type} _widget
* @returns {undefined}
*/
subscription_apply: function (_egw, _widget)
{
var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('foldertree');
if (tree)
{
tree.input._xfullXML = true;
this.subscription_treeLastState = tree.input.serializeTreeToJSON();
}
this.et2._inst.submit(_widget);
},
/**
* Show ajax-loader when the autoloading get started
*
* @param {type} _id item id
* @param {type} _widget tree widget
* @returns {Boolean}
*/
subscription_autoloadingStart: function (_id, _widget)
{
var node = _widget.input._globalIdStorageFind(_id);
if (node && typeof node.htmlNode != 'undefined')
{
var img = jQuery('img',node.htmlNode)[0];
img.src = egw.image('ajax-loader', 'admin');
}
return true;
},
/**
* Revert back the icon after autoloading is finished
* @returns {Boolean}
*/
subscription_autoloadingEnd: function ()
{
return true;
},
/**
* Popup the subscription dialog
*
* @param {action} _action
* @param {sender} _senders
*/
edit_subscribe: function (_action,_senders)
{
var acc_id = parseInt(_senders[0].id);
this.egw.open_link('mail.mail_ui.subscription&acc_id='+acc_id, '_blank', '720x500');
},
/**
* Subscribe selected unsubscribed folder
*
* @param {action} _action
* @param {sender} _senders
*/
subscribe_folder: function(_action,_senders)
{
var mailbox = _senders[0].id.split('::');
var folder = mailbox[1], acc_id = mailbox[0];
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
this.egw.message(this.egw.lang('Subscribe to Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,true])
.sendRequest();
},
/**
* Unsubscribe selected subscribed folder
*
* @param {action} _action
* @param {sender} _senders
*/
unsubscribe_folder: function(_action,_senders)
{
var mailbox = _senders[0].id.split('::');
var folder = mailbox[1], acc_id = mailbox[0];
var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
this.egw.message(this.egw.lang('Unsubscribe from Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,false])
.sendRequest();
},
/**
* Onclick for node/foldername in subscription popup
*
* Used to (un)check node including all children
*
* @param {string} _id id of clicked node
* @param {et2_tree} _widget reference to tree widget
*/
subscribe_onclick: function(_id, _widget)
{
_widget.setSubChecked(_id, "toggle");
},
/**
* Edit a folder acl for account(s)
*
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
edit_acl: function(_action, _senders)
{
var mailbox = _senders[0].id.split('::');
var folder = mailbox[1] || 'INBOX', acc_id = mailbox[0];
this.egw.open_link('mail.mail_acl.edit&mailbox='+ jQuery.base64Encode(folder)+'&acc_id='+acc_id, '_blank', '640x480');
},
/**
* Submit new selected folder back to server in order to read its acl's rights
*/
acl_folderChange: function ()
{
var mailbox = this.et2.getWidgetById('mailbox');
if (mailbox)
{
if (mailbox.taglist.getValue().length > 0)
{
this.et2._inst.submit();
}
}
},
/**
* Edit a mail account
*
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
edit_account: function(_action, _senders)
{
var acc_id = parseInt(_senders[0].id);
this.egw.open_link('mail.mail_wizard.edit&acc_id='+acc_id, '_blank', '720x500');
},
/**
* Set expandable fields (Folder, Cc and Bcc) based on their content
* - Only fields which have no content should get hidden
*/
compose_fieldExpander_init: function ()
{
var widgets = {
cc:{
widget:{},
jQClass: '.mailComposeJQueryCc'
},
bcc:{
widget:{},
jQClass: '.mailComposeJQueryBcc'
},
folder:{
widget:{},
jQClass: '.mailComposeJQueryFolder'
},
replyto:{
widget:{},
jQClass: '.mailComposeJQueryReplyto'
}};
for(var widget in widgets)
{
var expanderBtn = widget + '_expander';
widgets[widget].widget = this.et2.getWidgetById(widget);
// Add expander button widget to the widgets object
widgets[expanderBtn] = {widget:this.et2.getWidgetById(expanderBtn)};
if (typeof widgets[widget].widget != 'undefined'
&& typeof widgets[expanderBtn].widget != 'undefined'
&& widgets[widget].widget.get_value().length == 0)
{
widgets[expanderBtn].widget.set_disabled(false);
jQuery(widgets[widget].jQClass).hide();
}
}
},
/**
* Control textArea size based on available free space at the bottom
*
*/
compose_resizeHandler: function()
{
// Do not resize compose dialog if it's running on mobile device
// in this case user would be able to edit mail body by scrolling down,
// which is more convenient on small devices. Also resize mailbody with
// ckeditor may causes performance regression, especially on devices with
// very limited resources and slow proccessor.
if (egwIsMobile()) return false;
try {
var bodyH = egw_getWindowInnerHeight();
var textArea = this.et2.getWidgetById('mail_plaintext');
var $headerSec = jQuery('.mailComposeHeaderSection');
var attachments = this.et2.getWidgetById('attachments');
var content = this.et2.getArrayMgr('content').data;
// @var arrbitary int represents px
// Visible height of attachment progress
var prgV_H = 150;
// @var arrbitary int represents px
// Visible height of attchements list
var attchV_H = 68;
if (typeof textArea != 'undefined' && textArea != null)
{
if (textArea.getParent().disabled)
{
textArea = this.et2.getWidgetById('mail_htmltext');
}
// Tolerate values base on plain text or html, in order to calculate freespaces
var textAreaDelta = textArea.id == "mail_htmltext"?20:40;
// while attachments are in progress take progress visiblity into account
// otherwise the attachment progress is finished and consider attachments list
var delta = (attachments.table.find('li').length>0 && attachments.table.height() > 0)? prgV_H: (content.attachments? attchV_H: textAreaDelta);
var bodySize = (bodyH - Math.round($headerSec.height() + $headerSec.offset().top) - delta);
if (textArea.id != "mail_htmltext")
{
textArea.getParent().set_height(bodySize);
textArea.set_height(bodySize);
}
else if (typeof textArea != 'undefined' && textArea.id == 'mail_htmltext')
{
textArea.ckeditor.resize('100%', bodySize);
}
else
{
textArea.set_height(bodySize - 90);
}
}
}
catch(e) {
// ignore errors causing compose to load twice
}
},
/**
* Display Folder,Cc or Bcc fields in compose popup
*
* @param {jQuery event} event
* @param {widget object} widget clicked label (Folder, Cc or Bcc) from compose popup
*
*/
compose_fieldExpander: function(event,widget)
{
var expWidgets = {cc:{},bcc:{},folder:{},replyto:{}};
for (var name in expWidgets)
{
expWidgets[name] = this.et2.getWidgetById(name+'_expander');
}
if (typeof widget !='undefined')
{
switch (widget.id)
{
case 'cc_expander':
jQuery(".mailComposeJQueryCc").show();
if (typeof expWidgets.cc !='undefined')
{
expWidgets.cc.set_disabled(true);
}
break;
case 'bcc_expander':
jQuery(".mailComposeJQueryBcc").show();
if (typeof expWidgets.bcc !='undefined')
{
expWidgets.bcc.set_disabled(true);
}
break;
case 'folder_expander':
jQuery(".mailComposeJQueryFolder").show();
if (typeof expWidgets.folder !='undefined')
{
expWidgets.folder.set_disabled(true);
}
break;
case 'replyto_expander':
jQuery(".mailComposeJQueryReplyto").show();
if (typeof expWidgets.replyto !='undefined')
{
expWidgets.replyto.set_disabled(true);
}
break;
}
}
else if (typeof widget == "undefined")
{
var widgets = {cc:{},bcc:{},folder:{},replyto:{}};
for(var widget in widgets)
{
widgets[widget] = this.et2.getWidgetById(widget);
if (widgets[widget].get_value().length)
{
switch (widget)
{
case 'cc':
jQuery(".mailComposeJQueryCc").show();
if (typeof expWidgets.cc != 'undefiend')
{
expWidgets.cc.set_disabled(true);
}
break;
case 'bcc':
jQuery(".mailComposeJQueryBcc").show();
if (typeof expWidgets.bcc != 'undefiend')
{
expWidgets.bcc.set_disabled(true);
}
break;
case 'folder':
jQuery(".mailComposeJQueryFolder").show();
if (typeof expWidgets.folder != 'undefiend')
{
expWidgets.folder.set_disabled(true);
}
break;
case 'replyto':
jQuery(".mailComposeJQueryReplyto").show();
if (typeof expWidgets.replyto != 'undefiend')
{
expWidgets.replyto.set_disabled(true);
}
break;
}
}
}
}
this.compose_resizeHandler();
},
/**
* Lock tree so it does NOT receive any more mouse-clicks
*/
lock_tree: function()
{
if (!document.getElementById('mail_folder_lock_div'))
{
var parent = jQuery('#mail-index_nm\\[foldertree\\]');
var lock_div = jQuery(document.createElement('div'));
lock_div.attr('id', 'mail_folder_lock_div')
.addClass('mail_folder_lock');
parent.prepend(lock_div);
}
},
/**
* Unlock tree so it receives again mouse-clicks after calling lock_tree()
*/
unlock_tree: function()
{
jQuery('#mail_folder_lock_div').remove();
},
/**
* Called when tree opens up an account or folder
*
* @param {String} _id account-id[::folder-name]
* @param {et2_widget_tree} _widget
* @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
*/
openstart_tree: function(_id, _widget, _hasChildren)
{
if (_id.indexOf('::') == -1 && // it's an account, not a folder in an account
!_hasChildren)
{
this.lock_tree();
}
return true; // allow opening of node
},
/**
* Called when tree opens up an account or folder
*
* @param {String} _id account-id[::folder-name]
* @param {et2_widget_tree} _widget
* @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
*/
openend_tree: function(_id, _widget, _hasChildren)
{
if (_id.indexOf('::') == -1 && // it's an account, not a folder in an account
_hasChildren == 1)
{
this.unlock_tree();
}
},
/**
* Print a mail from list
* @param _action
* @param _senders - the representation of the tree leaf to be manipulated
*/
mail_print: function(_action, _senders)
{
var currentTemp = this.et2._inst.name;
switch (currentTemp)
{
case 'mail.index':
this.mail_prev_print(_action, _senders);
break;
case 'mail.display':
this.mail_display_print();
}
},
/**
* Print a mail from compose
* @param {stirng} _id id of new draft
*/
mail_compose_print:function (_id)
{
this.egw.open(_id,'mail','view','&print='+_id+'&mode=print');
},
/**
* Bind special handler on print media.
* -FF and IE have onafterprint event, and as Chrome does not have that event we bind afterprint function to onFocus
*/
print_for_compose: function()
{
var afterprint = function (){
egw(window).close();
};
if (!window.onafterprint)
{
// For browsers which does not support onafterprint event, eg. Chrome
setTimeout(function() {
egw(window).close();
}, 2000);
}
else
{
window.onafterprint = afterprint;
}
},
/**
* Prepare display dialog for printing
* copies iframe content to a DIV, as iframe causes
* trouble for multipage printing
* @param {jQuery object} _iframe mail body iframe
* @returns {undefined}
*/
mail_prepare_print: function(_iframe)
{
var $mainIframe = _iframe || jQuery('#mail-display_mailDisplayBodySrc');
var tmpPrintDiv = jQuery('#tempPrintDiv');
if (tmpPrintDiv.length == 0 && tmpPrintDiv.children())
{
tmpPrintDiv = jQuery(document.createElement('div'))
.attr('id', 'tempPrintDiv')
.addClass('tmpPrintDiv');
var notAttached = true;
}
if ($mainIframe)
{
tmpPrintDiv[0].innerHTML = $mainIframe.contents().find('body').html();
}
// Attach the element to the DOM after maniupulation
if (notAttached) $mainIframe.after(tmpPrintDiv);
tmpPrintDiv.find('#divAppboxHeader').remove();
},
/**
* Print a mail from Display
*/
mail_display_print: function ()
{
this.egw.message('Printing....');
// Make sure the print happens after the content is loaded. Seems Firefox and IE can't handle timing for print command correctly
setTimeout(function(){
egw(window).window.print();
},100);
},
/**
* Print a mail from list
*
* @param {Object} _action
* @param {Object} _elems
*
*/
mail_prev_print: function (_action, _elems)
{
this.mail_open(_action, _elems, 'print');
},
/**
* Print a mail from list
*
* @param {egw object} _egw
* @param {widget object} _widget mail account selectbox
*
*/
vacation_change_account: function (_egw, _widget)
{
_widget.getInstanceManager().submit();
},
/**
* OnChange callback for recipients:
* - make them draggable
* - check if we have keys for recipients, if we compose an encrypted mail
**/
recipients_onchange: function()
{
// if we compose an encrypted mail, check if we have keys for new recipient
if (this.mailvelope_editor)
{
var self = this;
this.mailvelopeGetCheckRecipients().catch(function(_err)
{
self.egw.message(_err.message, 'error');
});
}
this.set_dragging_dndCompose();
},
/**
* Make recipients draggable
*/
set_dragging_dndCompose: function ()
{
var zIndex = 100;
var dragItems = jQuery('div.ms-sel-item:not(div.ui-draggable)');
dragItems.each(function(i,item){
var $isErr = jQuery(item).find('.ui-state-error');
if ($isErr.length > 0)
{
delete dragItems.splice(i,1);
}
});
if (dragItems.length > 0)
{
dragItems.draggable({
appendTo:'body',
//Performance wise better to not add ui-draggable class to items since we are not using that class
containment:'document',
distance: 0,
cursor:'move',
cursorAt:{left:2},
//cancel dragging on close button to avoid conflict with close action
cancel:'.ms-close-btn',
delay: '300',
/**
* function to act on draggable item on revert's event
* @returns {Boolean} return true
*/
revert: function (){
this.parent().find('.ms-sel-item').css('position','relative');
var $input = this.parent().children('input');
// Make sure input field not getting into second line after revert
$input.width($input.width()-10);
return true;
},
/**
* function to act as draggable starts dragging
*
* @param {type} event
* @param {type} ui
*/
start:function(event, ui)
{
var dragItem = jQuery(this);
if (event.ctrlKey || event.metaKey)
{
dragItem.addClass('mailCompose_copyEmail')
.css('cursor','copy');
}
dragItem.css ('z-index',zIndex++);
dragItem.css('position','absolute');
},
/**
*
* @param {type} event
* @param {type} ui
*/
create:function(event,ui)
{
jQuery(this).css('css','move');
}
}).draggable('disable');
window.setTimeout(function(){
if(dragItems && dragItems.data() && typeof dragItems.data()['uiDraggable'] !== 'undefined') dragItems.draggable('enable');
},100);
}
},
/**
* Initialize dropping targets for draggable emails
* -
*/
init_dndCompose: function ()
{
var self = this;
var emailTags = jQuery('#mail-compose_to,#mail-compose_cc,#mail-compose_bcc');
//Call to make new items draggable
emailTags.hover(function(){
self.set_dragging_dndCompose();
});
//Make used email-tag list widgets in mail compose droppable
emailTags.droppable({
accept:'.ms-sel-item',
/**
* Run after a draggable email item dropped over one of the email-taglists
* -Set the dropped item to the dropped current target widget
*
* @param {type} event
* @param {type} ui
*/
drop:function (event, ui)
{
var widget = self.et2.getWidgetById(this.getAttribute('name'));
var emails, distLists = [];
var fromWidget = {};
var parentWidgetDOM = ui.draggable.parentsUntil('div[id^="mail-compoe_"]','.ui-droppable');
if (parentWidgetDOM != 'undefined' && parentWidgetDOM.length > 0)
{
fromWidget = self.et2.getWidgetById(parentWidgetDOM.attr('name'));
}
var draggedValue = ui.draggable.text();
// index of draggable item in selection list
var dValueKey = draggedValue;
var distItem = ui.draggable.find('.mailinglist');
if (distItem.length>0)
{
var distItemId = parseInt(distItem.attr('data'));
if (distItemId)
{
var fromDistLists = resolveDistList(fromWidget);
for (var i=0;i<fromDistLists.length;i++)
{
if (distItemId == fromDistLists[i]['id'])
{
draggedValue = fromDistLists[i];
// dist list item index
dValueKey = fromDistLists[i]['id'];
}
}
}
}
if (typeof widget != 'undefined')
{
emails = widget.get_value();
if (emails) emails = emails.concat([draggedValue]);
// Resolve the dist list and normal emails
distLists = resolveDistList(widget, emails);
// Add normal emails
if (emails) widget.set_value(emails);
// check if there's any dist list to be added
if (distLists.length>0) widget.taglist.addToSelection(distLists);
if (!jQuery.isEmptyObject(fromWidget)
&& !(ui.draggable.attr('class').search('mailCompose_copyEmail') > -1))
{
if (widget.node != fromWidget.node && !_removeDragged(fromWidget, dValueKey))
{
//Not successful remove, returns the item to its origin
jQuery(ui.draggable).draggable('option','revert',true);
}
}
else
{
ui.draggable
.removeClass('mailCompose_copyEmail')
.css('cursor','move');
}
var dragItems = jQuery('div.ms-sel-item');
dragItems.each(function(i,item){
var $isErr = jQuery(item).find('.ui-state-error');
if ($isErr.length > 0)
{
delete dragItems.splice(i,1);
}
});
}
}
});
/**
* Remove dragged item from the widget which the item was dragged
*
* @param {type} _widget
* @param {type} _value
* @return {boolean} true if successul | false unsuccessul
*/
var _removeDragged = function (_widget, _value)
{
if (_widget && _value)
{
var emails = _widget.get_value();
var itemIndex = emails.indexOf(_value);
var dist = [];
if (itemIndex > -1)
{
emails.splice(itemIndex,1);
// Resolve the dist list and normal emails
var dist = resolveDistList(_widget, emails);
// Add normal emails
_widget.set_value(emails);
//check if there's any dist list to be added
if (dist)
{
for(var i=0;i<dist.length;i++)
{
if (dist[i]['id'] == _value) dist.splice(i,1);
}
_widget.taglist.addToSelection(dist);
}
}
else
{
return false;
}
}
return true;
};
/**
* Resolve taglist widget which has distribution list
*
* @param {type} _widget
* @param {type} _emails
* @returns {Array} returns an array of distribution lists in selected widget
*/
var resolveDistList = function (_widget, _emails)
{
var list = [];
var selectedList = _widget.taglist.getSelection();
// Make a list of distribution list from the selection
for (var i=0;i<selectedList.length;i++)
{
if (!isNaN(selectedList[i]['id']) && selectedList[i]['class'] === 'mailinglist')
{
list.push(selectedList[i]);
}
}
// Remove dist list from emails list
for(var key in _emails)
{
if (!isNaN(_emails[key]))
{
_emails.splice(key,1);
}
}
// returns distlist
return list;
};
},
/**
* Check sharing mode and disable not available options
*
* @param {DOMNode} _node
* @param {et2_widget} _widget
*/
check_sharing_filemode: function(_node, _widget)
{
if (!_widget) _widget = this.et2.getWidgetById('filemode');
var extended_settings = _widget.get_value() != 'attach' && this.egw.app('stylite');
this.et2.getWidgetById('expiration').set_readonly(!extended_settings);
this.et2.getWidgetById('password').set_readonly(!extended_settings);
if (_widget.get_value() == 'share_rw' && !this.egw.app('stylite'))
{
this.egw.message(this.egw.lang('Writable sharing requires EPL version!'), 'info');
_widget.set_value('share_ro');
}
},
/**
* Write / update compose window title with subject
*
* @param {DOMNode} _node
* @param {et2_widget} _widget
*/
subject2title: function(_node, _widget)
{
if (!_widget) _widget = this.et2.getWidgetById('subject');
if (_widget && _widget.get_value())
{
document.title = _widget.get_value();
}
},
/**
* Clear intervals stored in W_INTERVALS which assigned to window
*/
clearIntevals: function ()
{
for(var i=0;i<this.W_INTERVALS.length;i++)
{
clearInterval(this.W_INTERVALS[i]);
delete this.W_INTERVALS[i];
}
},
/**
* Window title getter function in order to set the window title
*
* @returns {string|undefined} window title
*/
getWindowTitle: function ()
{
var widget = {};
switch(this.et2._inst.name)
{
case 'mail.display':
widget = this.et2.getWidgetById('mail_displaysubject');
if (widget) return widget.options.value;
break;
case 'mail.compose':
widget = this.et2.getWidgetById('subject');
if (widget) return widget.get_value();
break;
}
return undefined;
},
/**
*
* @returns {undefined}
*/
prepareMailvelopePrint: function()
{
var tempPrint = jQuery('div#tempPrintDiv');
var mailvelopeTopContainer = jQuery('div.mailDisplayContainer');
var originFrame = jQuery('#mail-display_mailDisplayBodySrc');
var iframe = jQuery(this.mailvelope_iframe_selector);
if (tempPrint.length >0)
{
// Mailvelope iframe height is approximately equal to the height of encrypted origin message
// we add an arbitary plus pixels to make sure it's covering the full content in print view and
// it is not getting acrollbar in normal view
// @TODO: after Mailvelope plugin provides a hieght value, we can replace the height with an accurate value
iframe.addClass('mailvelopeIframe').height(originFrame[0].contentWindow.document.body.scrollHeight + 400);
tempPrint.hide();
mailvelopeTopContainer.addClass('mailvelopeTopContainer');
}
},
/**
* Mailvelope (clientside PGP) integration:
* - detect Mailvelope plugin and open "egroupware" keyring (app_base.mailvelopeAvailable and _mailvelopeOpenKeyring)
* - display and preview of encrypted messages (mailvelopeDisplay)
* - button to toggle between regular and encrypted mail (togglePgpEncrypt)
* - compose encrypted messages (mailvelopeCompose, compose_submitAction)
* - fix autosave and save as draft to store encrypted content (saveAsDraft)
* - fix inline reply to encrypted message to clientside decrypt message and add signature (mailvelopeCompose)
*/
/**
* Called on load of preview or display iframe, if mailvelope is available
*
* @param {Keyring} _keyring Mailvelope keyring to use
* @ToDo signatures
*/
mailvelopeDisplay: function(_keyring)
{
var self = this;
var mailvelope = window.mailvelope;
var iframe = jQuery('iframe#mail-display_mailDisplayBodySrc,iframe#mail-index_messageIFRAME');
var armored = iframe.contents().find('td.td_display > pre').text().trim();
if (armored == "" || armored.indexOf(this.begin_pgp_message) === -1) return;
var container = iframe.parent()[0];
var container_selector = container.id ? '#'+container.id : 'div.mailDisplayContainer';
options = {
showExternalContent: this.egw.preference('allowExternalIMGs') == 1 // "1", or "0", undefined --> true or false
};
// get sender address, so Mailvelope can check signature
var from_widget = this.et2.getWidgetById('FROM_0') || this.et2.getWidgetById('previewFromAddress');
if (from_widget && from_widget.value)
{
options.senderAddress = from_widget.value.replace(/^.*<([^<>]+)>$/, '$1');
}
mailvelope.createDisplayContainer(container_selector, armored, _keyring, options).then(function()
{
// hide our iframe to give space for mailvelope iframe with encrypted content
iframe.hide();
self.prepareMailvelopePrint();
},
function(_err)
{
self.egw.message(_err.message, 'error');
});
},
/**
* Editor object of active compose
*
* @var {Editor}
*/
mailvelope_editor: undefined,
/**
* Called on compose, if mailvelope is available
*
* @param {Keyring} _keyring Mailvelope keyring to use
*/
mailvelopeCompose: function(_keyring)
{
delete this.mailvelope_editor;
// currently Mailvelope only supports plain-text, to this is unnecessary
var mimeType = this.et2.getWidgetById('mimeType');
var is_html = mimeType.get_value();
var container = is_html ? '.mailComposeHtmlContainer' : '.mailComposeTextContainer';
var editor = this.et2.getWidgetById(is_html ? 'mail_htmltext' : 'mail_plaintext');
var options = { predefinedText: editor.get_value() };
// check if we have some sort of reply to an encrypted message
// --> parse header, encrypted mail to quote and signature so Mailvelope understands it
var start_pgp = options.predefinedText.indexOf(this.begin_pgp_message);
if (start_pgp != -1)
{
var end_pgp = options.predefinedText.indexOf(this.end_pgp_message);
if (end_pgp != -1)
{
options = {
quotedMailHeader: options.predefinedText.slice(0, start_pgp).replace(/> /mg, '').trim()+"\n",
quotedMail: options.predefinedText.slice(start_pgp, end_pgp+this.end_pgp_message.length+1).replace(/> /mg, ''),
quotedMailIndent: start_pgp != 0,
predefinedText: options.predefinedText.slice(end_pgp+this.end_pgp_message.length+1).replace(/^> \s*/m,''),
signMsg: true // for now (no UI) always sign, when we encrypt
};
// set encrypted checkbox, if not already set
var composeToolbar = this.et2.getWidgetById('composeToolbar');
if (!composeToolbar.checkbox('pgp'))
{
composeToolbar.checkbox('pgp',true);
}
}
}
var self = this;
mailvelope.createEditorContainer(container, _keyring, options).then(function(_editor)
{
self.mailvelope_editor = _editor;
editor.set_disabled(true);
mimeType.set_readonly(true);
},
function(_err)
{
self.egw.message(_err.message, 'error');
});
},
/**
* Switch sending PGP encrypted mail on and off
*
* @param {object} _action toolbar action
*/
togglePgpEncrypt: function (_action)
{
var self = this;
if (_action.checked)
{
if (typeof mailvelope == 'undefined')
{
this.mailvelopeInstallationOffer();
// switch encrypt button off again
this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
return;
}
// check if we have keys for all recipents, before switching
this.mailvelopeGetCheckRecipients().then(function(_recipients)
{
var mimeType = self.et2.getWidgetById('mimeType');
// currently Mailvelope only supports plain-text, switch to it if necessary
if (mimeType.get_value())
{
mimeType.set_value(false);
self.et2._inst.submit();
return; // ToDo: do that without reload
}
self.mailvelopeOpenKeyring().then(function(_keyring)
{
self.mailvelopeCompose(_keyring);
});
})
.catch(function(_err)
{
self.egw.message(_err.message, 'error');
self.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
return;
});
}
else
{
// switch Mailvelop off again, but warn user he will loose his content
et2_dialog.show_dialog(function (_button_id)
{
if (_button_id == et2_dialog.YES_BUTTON )
{
self.et2.getWidgetById('mimeType').set_readonly(false);
self.et2.getWidgetById('mail_plaintext').set_disabled(false);
jQuery(self.mailvelope_iframe_selector).remove();
}
else
{
self.et2.getWidgetById('composeToolbar').checkbox('pgp',true);
}
},
this.egw.lang('You will loose current message body, unless you save it to your clipboard!'),
this.egw.lang('Switch off encryption?'),
{}, et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, this.egw);
}
},
/**
* Check if we have a key for all recipients
*
* @returns {Promise.<Array, Error>} Array of recipients or Error with recipients without key
*/
mailvelopeGetCheckRecipients: function()
{
// collect all recipients
var recipients = this.et2.getWidgetById('to').get_value();
recipients = recipients.concat(this.et2.getWidgetById('cc').get_value());
recipients = recipients.concat(this.et2.getWidgetById('bcc').get_value());
return this._super.call(this, recipients);
},
/**
* Set the relevant widget to toolbar actions and submit
*
* @param {object|boolean} _action toolbar action or boolean value to stop extra call on
* compose_integrated_submit
*/
compose_submitAction: function (_action)
{
if (this.compose_integrate_submit() && _action) return false;
if (this.mailvelope_editor)
{
var self = this;
this.mailvelopeGetCheckRecipients().then(function(_recipients)
{
return self.mailvelope_editor.encrypt(_recipients);
}).then(function(_armored)
{
self.et2.getWidgetById('mimeType').set_value(false);
self.et2.getWidgetById('mail_plaintext').set_disabled(false);
self.et2.getWidgetById('mail_plaintext').set_value(_armored);
self.et2._inst.submit(null,null,true);
}).catch(function(_err)
{
self.egw.message(_err.message, 'error');
});
return false;
}
this.et2._inst.submit(null,null,true);
},
/**
* This function runs before client submit (send) mail to server
* and takes care of mail integration modules to popup entry selection
* dialog to give user a choice to which entry of selected app the compose
* should be integereated.
* @param {int|boolean} _integIndex
*
* @returns {Boolean} return true if to_tracker is checked otherwise false
*/
compose_integrate_submit: function (_integIndex)
{
if (_integIndex == false) return false;
var index = _integIndex || 0;
var integApps = ['to_tracker', 'to_infolog', 'to_calendar'];
var subject = this.et2.getWidgetById('subject');
var toolbar = this.et2.getWidgetById('composeToolbar');
var to_integrate_ids = this.et2.getWidgetById('to_integrate_ids');
var integWidget= {};
var self = this;
integWidget = this.et2.getWidgetById(integApps[index]);
if (toolbar.options.actions[integApps[index]] &&
typeof toolbar.options.actions[integApps[index]]['mail_import'] != 'undefined' &&
typeof toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'] != 'unefined')
{
var mail_import_hook = toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'];
if (integWidget.get_value() == 'on')
{
this.integrate_checkAppEntry(egw.lang('Select %1 entry',integApps[index]), integApps[index].substr(3), subject.get_value(), '', mail_import_hook , function (args){
var value = {};
value[integApps[index]] = args.entryid;
var oldValue = to_integrate_ids.get_value()[0];
to_integrate_ids.set_value(jQuery.extend(value,oldValue));
index = index<integApps.length? ++index:false;
self.compose_integrate_submit(index);
});
return true;
}
}
else if(index<integApps.length)
{
this.compose_integrate_submit(++index);
}
else
{
this.compose_submitAction(false);
}
return false;
},
/**
* Set the selected checkbox action
*
* @param {type} _action selected toolbar action with checkbox
* @returns {undefined}
*/
compose_setToggle: function (_action)
{
var widget = this.et2.getWidgetById (_action.id);
if (widget && typeof _action.checkbox != 'undefined' && _action.checkbox)
{
widget.set_value(_action.checked?"on":"off");
}
},
/**
* Set the selected priority value
* @param {type} _action selected action
* @returns {undefined}
*/
compose_priorityChange: function (_action)
{
var widget = this.et2.getWidgetById ('priority');
if (widget)
{
widget.set_value(_action.id);
}
},
/**
* Triger relative widget via its toolbar identical action
* @param {type} _action toolbar action
*/
compose_triggerWidget:function (_action)
{
var widget = this.et2.getWidgetById(_action.id);
if (widget)
{
switch(widget.id)
{
case 'uploadForCompose':
document.getElementById('mail-compose_uploadForCompose').click();
break;
default:
widget.click();
}
}
},
/**
* Save drafted compose as eml file into VFS
* @param {type} _action action
*/
compose_saveDraft2fm: function (_action)
{
var content = this.et2.getArrayMgr('content').data;
var subject = this.et2.getWidgetById('subject');
var elem = {0:{id:"", subject:""}};
if (typeof content != 'undefined' && content.lastDrafted && subject)
{
elem[0].id = content.lastDrafted;
elem[0].subject = subject.get_value();
this.mail_save2fm(_action, elem);
}
else
{
et2_dialog.alert('You need to save the message as draft first before to be able to save it into VFS','Save into VFS','info');
}
},
/**
* Folder Management, opens the folder magnt. dialog
* with the selected acc_id from index tree
*
* @param {egw action object} _action actions
* @param {object} _senders selected node
*/
folderManagement: function (_action,_senders)
{
var acc_id = parseInt(_senders[0].id);
this.egw.open_link('mail.mail_ui.folderManagement&acc_id='+acc_id, '_blank', '720x500');
},
/**
* Show ajax-loader when the autoloading get started
*
* @param {type} _id item id
* @param {type} _widget tree widget
* @returns {Boolean}
*/
folderMgmt_autoloadingStart: function(_id, _widget)
{
return this.subscription_autoloadingStart (_id, _widget);
},
/**
* Revert back the icon after autoloading is finished
* @param {type} _id item id
* @param {type} _widget tree widget
* @returns {Boolean}
*/
folderMgmt_autoloadingEnd: function(_id, _widget)
{
return true;
},
/**
*
* @param {type} _ids
* @param {type} _widget
* @returns {undefined}
*/
folderMgmt_onSelect: function(_ids, _widget)
{
// Flag to reset selected items
var resetSelection = false;
var self = this;
/**
* helper function to multiselect range of nodes in same level
*
* @param {string} _a start node id
* @param {string} _b end node id
* @param {string} _branch totall node ids in the level
*/
var rangeSelector = function(_a,_b, _branch)
{
var branchItems = _branch.split(_widget.input.dlmtr);
var _aIndex = _widget.input.getIndexById(_a);
var _bIndex = _widget.input.getIndexById(_b);
if (_bIndex<_aIndex)
{
var tmpIndex = _aIndex;
_aIndex = _bIndex;
_bIndex = tmpIndex;
}
for(var i =_aIndex;i<=_bIndex;i++)
{
self.folderMgmt_setCheckbox(_widget, branchItems[i], !_widget.input.isItemChecked(branchItems[i]));
}
};
// extract items ids
var itemIds = _ids.split(_widget.input.dlmtr);
if(itemIds.length == 2) // there's a range selected
{
var branch = _widget.input.getSubItems(_widget.input.getParentId(itemIds[0]));
// Set range of selected/unselected
rangeSelector(itemIds[0], itemIds[1], branch);
}
else if(itemIds.length != 1)
{
resetSelection = true;
}
if (resetSelection)
{
_widget.input._unselectItems();
}
},
/**
* Set enable/disable checkbox
*
* @param {object} _widget tree widget
* @param {string} _itemId item tree id
* @param {boolean} _stat - status to be set on checkbox true/false
*/
folderMgmt_setCheckbox: function (_widget, _itemId, _stat)
{
if (_widget)
{
_widget.input.setCheck(_itemId, _stat);
_widget.input.setSubChecked(_itemId,_stat);
}
},
/**
*
* @param {type} _id
* @param {type} _widget
* @TODO: Implement onCheck handler in order to select or deselect subItems
* of a checked parent node
*/
folderMgmt_onCheck: function (_id, _widget)
{
var selected = _widget.input.getAllChecked();
if (selected && selected.split(_widget.input.dlmtr).length > 5)
{
egw.message(egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'));
}
},
/**
* Detele button handler
* triggers longTask dialog and send delete operation url
*
*/
folderMgmt_deleteBtn: function ()
{
var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('tree');
var menuaction= 'mail.mail_ui.ajax_folderMgmt_delete';
var callbackDialog = function(_btn)
{
egw.appName='mail';
if (_btn === et2_dialog.YES_BUTTON)
{
if (tree)
{
var selFolders = tree.input.getAllChecked();
if (selFolders)
{
var selFldArr = selFolders.split(tree.input.dlmtr);
var msg = egw.lang('Deleting %1 folders in progress ...', selFldArr.length);
et2_dialog.long_task(function(_val, _resp){
console.log(_val, _resp);
if (_val && _resp.type !== 'error')
{
var stat = [];
var folderName = '';
for(var i=0;i<selFldArr.length;i++)
{
folderName = selFldArr[i].split('::');
stat[selFldArr[i]] = folderName[1];
}
// delete the item from index folderTree
egw.window.app.mail.mail_removeLeaf(stat);
}
else
{
// submit
etemplate2.getByApplication('mail')[0].widgetContainer._inst.submit();
}
}, msg, egw.lang('Deleting folders'), menuaction, selFldArr, 'mail');
return true;
}
}
}
};
et2_dialog.show_dialog(callbackDialog, this.egw.lang('Are you sure you want to delete all selected folders?'), this.egw.lang('Delete folder'), {},
et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, egw);
},
/**
* Implement mobile view
*
* @param {type} _action
* @param {type} _sender
*/
mobileView: function(_action, _sender)
{
// row id in nm
var id = _sender[0].id;
var defaultActions= {
actions:['delete', 'forward','reply','flagged'], // default actions to display
check:function(_action){
for (var i=0;i<= this.actions.length;i++)
{
if (_action == this.actions[i]) return true;
}
return false;
}
};
var content = {};
var self = this;
if (id){
content = egw.dataGetUIDdata(id);
content.data['toolbar'] = this.et2.getArrayMgr('sel_options').getEntry('toolbar');
// Set default actions
for(var action in content.data['toolbar'])
{
content.data.toolbar[action]['toolbarDefault'] = defaultActions.check(action);
}
// update local storage with added toolbar actions
egw.dataStoreUID(id,content.data);
}
this.viewEntry(_action, _sender, true, function(etemplate){
// et2 object in view
var et2 = etemplate.widgetContainer;
// iframe to load message
var iframe = et2.getWidgetById('iframe');
// toolbar widget
var toolbar = et2.getWidgetById('toolbar');
// attachments details title DOM node
var $attachment = jQuery('.attachments span.et2_details_title');
// details DOM
var $details = jQuery('.et2_details.details');
// Content
var content = et2.getArrayMgr('content').data;
// set the current selected row
et2.mail_currentlyFocussed = id;
if (content.attachmentsBlock.length>0 && content.attachmentsBlock[0].filename)
{
$attachment.text(self.egw.lang('%1 attachments', content.attachmentsBlock.length));
}
else
{
// disable attachments area if there's no attachments
$attachment.parent().hide();
}
// disable the detials if there's no details
if (!content.ccaddress && !content.additionaltoaddress) $details.hide();
toolbar.set_actions(content.toolbar);
var toaddressdetails = self.et2_view.widgetContainer.getWidgetById('toaddressdetails');
if (toaddressdetails && content.additionaltoaddress)
{
toaddressdetails.set_value('... ' +content.additionaltoaddress.length + egw.lang(' more'));
jQuery(toaddressdetails.getDOMNode()).off().on('click', function(){
$details.find('.et2_details_toggle').click();
});
}
// Request email body from server
iframe.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:id}));
jQuery(iframe.getDOMNode()).on('load',function(){
if (jQuery(this.contentWindow.document.body).find('#calendar-meeting').length > 0)
{
var frame = this;
jQuery(this).show();
// calendar meeting mails still need to be in iframe, therefore, we calculate the height
// and set the iframe with a fixed height to be able to see all content without getting
// scrollbar becuase of scrolling issue in iframe
window.setTimeout(function(){jQuery(frame).height(frame.contentWindow.document.body.scrollHeight);}, 500);
}
else
{
self.resolveExternalImages(this.contentWindow.document)
// Use prepare print function to copy iframe content into div
// as we don't want to show content in iframe (scrolling problem).
self.mail_prepare_print(jQuery(this));
}
});
});
}
});