Completed
Push — 16.1 ( 05ede2...3d52b1 )
by Hadi
30:00 queued 13:16
created

AppJS.extend.spamTitan_setActionTitle   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 9
nop 2
dl 0
loc 38
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like AppJS.extend.spamTitan_setActionTitle often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* global msg */
2
3
/**
4
 * mail - static javaScript functions
5
 *
6
 * @link http://www.egroupware.org
7
 * @author EGroupware GmbH [[email protected]]
8
 * @copyright (c) 2013-2014 by EGroupware GmbH <info-AT-egroupware.org>
9
 * @package mail
10
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
11
 * @version $Id$
12
 */
13
14
/*egw:uses
15
	/api/js/jquery/jquery.base64.js;
16
*/
17
18
/**
19
 * UI for mail
20
 *
21
 * @augments AppJS
22
 */
23
app.classes.mail = AppJS.extend(
24
{
25
	appname: 'mail',
26
27
	/**
28
	 * et2 widget container
29
	 */
30
	et2: null,
31
	doStatus: null,
32
33
	mail_queuedFolders: [],
34
	mail_queuedFoldersIndex: 0,
35
36
	mail_selectedMails: [],
37
	mail_currentlyFocussed: '',
38
	mail_previewAreaActive: true, // we start with the area active
39
40
	nm_index: 'nm', // nm name of index
41
	mail_fileSelectorWindow: null,
42
	mail_isMainWindow: true,
43
44
	// Some state variables to track preview pre-loading
45
	preview_preload: {
46
		timeout: null,
47
		request: null
48
	},
49
	/**
50
	 *
51
	 */
52
	subscription_treeLastState : "",
53
54
	/**
55
	 * abbrevations for common access rights
56
	 * @array
57
	 *
58
	 */
59
	aclCommonRights:['lrs','lprs','ilprs',	'ilprsw', 'aeiklprstwx', 'custom'],
60
	/**
61
	 * Demonstrates ACL rights
62
	 * @array
63
	 *
64
	 */
65
	aclRights:['l','r','s','w','i','p','c','d','a'],
66
67
	/**
68
	 * In order to store Intervals assigned to window
69
	 * @array of setted intervals
70
	 */
71
	W_INTERVALS:[],
72
73
	/**
74
	 * Initialize javascript for this application
75
	 *
76
	 * @memberOf mail
77
	 */
78
	init: function() {
79
		this._super.apply(this,arguments);
80
		if (!this.egw.is_popup())
81
			// Turn on client side, persistent cache
82
			// egw.data system runs encapsulated below etemplate, so this must be
83
			// done before the nextmatch is created.
84
			this.egw.dataCacheRegister('mail',
85
				// Called to determine cache key
86
				this.nm_cache,
87
				// Called whenever cache is used
88
				// TODO: Change this as needed
89
				function(server_query)
90
				{
91
					// Unlock tree if using a cache, since the server won't
92
					if(!server_query) this.unlock_tree();
93
				},
94
				this
95
			);
96
	},
97
98
	/**
99
	 * Destructor
100
	 */
101
	destroy: function()
102
	{
103
		// Unbind from nm refresh
104
		if(this.et2 != null)
105
		{
106
			var nm = this.et2.getWidgetById(this.nm_index);
107
			if(nm != null)
108
			{
109
				jQuery(nm).off('refresh');
110
			}
111
		}
112
113
		// Unregister client side cache
114
		this.egw.dataCacheUnregister('mail');
115
116
		delete this.et2_obj;
117
		// call parent
118
		this._super.apply(this, arguments);
119
	},
120
121
	/**
122
	 * check and try to reinitialize et2 of module
123
	 */
124
	checkET2: function()
125
	{
126
		//this.et2 should do the same as etemplate2.getByApplication('mail')[0].widgetContainer
127
		if (!this.et2) // if not defined try this in order to recover
128
		{
129
			try
130
			{
131
				this.et2 = etemplate2.getByApplication('mail')[0].widgetContainer;
132
			}
133
			catch(e)
134
			{
135
				return false;
136
			}
137
		}
138
		return true;
139
	},
140
141
	/**
142
	 * This function is called when the etemplate2 object is loaded
143
	 * and ready.  If you must store a reference to the et2 object,
144
	 * make sure to clean it up in destroy().
145
	 *
146
	 * @param et2 etemplate2 Newly ready object
147
	 * @param {string} _name template name
148
	 */
149
	et2_ready: function(et2, _name)
150
	{
151
		// call parent; somehow this function is called more often. (twice on a display and compose) why?
152
		this._super.apply(this, arguments);
153
		this.et2_obj = et2;
154
155
		switch (_name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
156
		{
157
			case 'mail.sieve.vacation':
158
				this.vacationFilterStatusChange();
159
				break;
160
			case 'mail.index':
161
				var self = this;
162
				jQuery('iframe#mail-index_messageIFRAME').on('load', function()
163
				{
164
					// decrypt preview body if mailvelope is available
165
					self.mailvelopeAvailable(self.mailvelopeDisplay);
166
					self.mail_prepare_print();
167
				});
168
				var nm = this.et2.getWidgetById(this.nm_index);
169
				this.mail_isMainWindow = true;
170
				this.mail_disablePreviewArea(this.egw.preference('previewPane', 'mail') !== 'fixed');
171
				//Get initial folder status
172
				this.mail_refreshFolderStatus(undefined,undefined,false);
173
174
				// Bind to nextmatch refresh to update folder status
175
				if(nm != null && (typeof jQuery._data(nm).events=='undefined'||typeof jQuery._data(nm).events.refresh == 'undefined'))
176
				{
177
					var self = this;
178
					jQuery(nm).on('refresh',function() {self.mail_refreshFolderStatus.call(self,undefined,undefined,false);});
179
				}
180
				var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
181
				if (tree_wdg)
182
				{
183
					tree_wdg.set_onopenstart(jQuery.proxy(this.openstart_tree, this));
184
					tree_wdg.set_onopenend(jQuery.proxy(this.openend_tree, this));
185
				}
186
				// Show vacation notice on load for the current profile (if not called by mail_searchtype_change())
187
				var alreadyrefreshed = this.mail_searchtype_change();
188
				if (!alreadyrefreshed) this.mail_callRefreshVacationNotice();
189
				break;
190
			case 'mail.display':
191
				var self = this;
192
				// Prepare display dialog for printing
193
				// copies iframe content to a DIV, as iframe causes
194
				// trouble for multipage printing
195
196
				jQuery('iframe#mail-display_mailDisplayBodySrc').on('load', function(e)
197
				{
198
					// encrypt body if mailvelope is available
199
					self.mailvelopeAvailable(self.mailvelopeDisplay);
200
					self.mail_prepare_print();
201
202
					// Trigger print command if the mail oppend for printing porpuse
203
					// load event fires twice in IE and the first time the content is not ready
204
					// Check if the iframe content is loaded then trigger the print command
205
					if (window.location.search.search('&print=') >= 0 && jQuery(this.contentWindow.document.body).children().length >0 )
206
					{
207
						self.mail_print();
208
					}
209
				});
210
211
				this.mail_isMainWindow = false;
212
				this.mail_display();
213
214
				// Register attachments for drag
215
				this.register_for_drag(
216
					this.et2.getArrayMgr("content").getEntry('mail_id'),
217
					this.et2.getArrayMgr("content").getEntry('mail_displayattachments')
218
				);
219
				break;
220
			case 'mail.compose':
221
				if (this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp') &&
222
					this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').checked ||
223
					this.et2.getArrayMgr('content').data.mail_plaintext &&
224
						this.et2.getArrayMgr('content').data.mail_plaintext.indexOf(this.begin_pgp_message) != -1)
225
				{
226
					this.mailvelopeAvailable(this.mailvelopeCompose);
227
				}
228
				var that = this;
229
				var textAreaWidget = this.et2.getWidgetById('mail_htmltext');
230
				this.mail_isMainWindow = false;
231
				this.compose_fieldExpander_init();
232
				this.check_sharing_filemode();
233
234
				this.subject2title();
235
236
				// Set autosaving interval to 2 minutes for compose message
237
				this.W_INTERVALS.push(window.setInterval(function (){
238
					that.saveAsDraft(null, 'autosaving');
239
				}, 120000));
240
241
				/* Control focus actions on subject to handle expanders properly.*/
242
				jQuery("#mail-compose_subject").on({
243
					focus:function(){
244
						that.compose_fieldExpander_init();
245
						that.compose_fieldExpander();
246
					}
247
				});
248
				/*Trigger compose_resizeHandler after the CKEditor is fully loaded*/
249
				jQuery('#mail-compose').on ('load',function() {
250
					if (textAreaWidget && textAreaWidget.ckeditor)
251
					{
252
						textAreaWidget.ckeditor.on('instanceReady', function(){
253
							that.compose_fieldExpander();
254
							if (egwIsMobile()) jQuery(jQuery('iframe.cke_wysiwyg_frame')[0].contentWindow.document.body).css({margin:'0'})
255
						});
256
					}
257
					else
258
					{
259
						that.compose_fieldExpander();
260
					}
261
				});
262
263
				//Resize compose after window resize to not getting scrollbar
264
				jQuery(window).on ('resize',function(e) {
265
					// Stop immediately the resize event if we are in mobile template
266
					if (egwIsMobile())
267
					{
268
						e.stopImmediatePropagation();
269
						return false;
270
					}
271
					that.compose_resizeHandler();
272
				});
273
274
				//Call drag_n_drop initialization for emails on compose
275
				this.init_dndCompose();
276
277
				// Set focus on To/body field
278
				// depending on To field value
279
				var to = this.et2.getWidgetById('to');
280
				if (to && to.get_value() && to.get_value() != '')
281
				{
282
					var content = this.et2.getArrayMgr('content').data;
283
					if (content.is_plain)
284
					{
285
						var plainText = this.et2.getWidgetById('mail_plaintext');
286
						// focus
287
						jQuery(plainText.node).focus();
288
						// get the cursor to the top of the textarea
289
						if (typeof plainText.node.setSelectionRange !='undefined') plainText.node.setSelectionRange(0,0);
290
					}
291
					else
292
					{
293
						textAreaWidget.ckeditor.on('instanceReady', function(e) {
294
							this.focus();
295
						});
296
					}
297
				}
298
				else if(to)
299
				{
300
					jQuery('input',to.node).focus();
301
				}
302
				break;
303
			case 'mail.subscribe':
304
				if (this.subscription_treeLastState != "")
305
				{
306
					var tree = this.et2.getWidgetById('foldertree');
307
					//Saved state of tree
308
					var state = jQuery.parseJSON(this.subscription_treeLastState);
309
310
					tree.input.loadJSONObject(tree._htmlencode_node(state));
311
				}
312
				break;
313
			case 'mail.folder_management':
314
				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','mail:folder_management');
315
				break;
316
			case 'mail.view':
317
				// we need to set mail_currentlyFocused var otherwise mail
318
				// defined actions won't work
319
				this.mail_currentlyFocussed = this.et2.mail_currentlyFocussed;
320
321
		}
322
	},
323
324
	/**
325
	 * Observer method receives update notifications from all applications
326
	 *
327
	 * App is responsible for only reacting to "messages" it is interested in!
328
	 *
329
	 * @param {string} _msg message (already translated) to show, eg. 'Entry deleted'
330
	 * @param {string} _app application name
331
	 * @param {(string|number)} _id id of entry to refresh or null
332
	 * @param {string} _type either 'update', 'edit', 'delete', 'add' or null
333
	 * - update: request just modified data from given rows.  Sorting is not considered,
334
	 *		so if the sort field is changed, the row will not be moved.
335
	 * - edit: rows changed, but sorting may be affected.  Requires full reload.
336
	 * - delete: just delete the given rows clientside (no server interaction neccessary)
337
	 * - add: requires full reload for proper sorting
338
	 * @param {string} _msg_type 'error', 'warning' or 'success' (default)
339
	 * @param {object|null} _links app => array of ids of linked entries
340
	 * or null, if not triggered on server-side, which adds that info
341
	 * @return {false|*} false to stop regular refresh, thought all observers are run
342
	 */
343
	observer: function(_msg, _app, _id, _type, _msg_type, _links)
344
	{
345
		switch(_app)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
346
		{
347
			case 'mail':
348
				if (_id === 'sieve')
349
				{
350
					var iframe = this.et2.getWidgetById('extra_iframe');
351
					if (iframe && iframe.getDOMNode())
352
					{
353
						var contentWindow = iframe.getDOMNode().contentWindow;
354
						if (contentWindow && contentWindow.app && contentWindow.app.mail)
355
						{
356
							contentWindow.app.mail.sieve_refresh();
357
						}
358
					}
359
					return false;	// mail nextmatch needs NOT to be refreshed
360
				}
361
				break;
362
363
			case 'emailadmin':	// update tree with given mail account _id and _type
364
				var tree = this.et2 ? this.et2.getWidgetById(this.nm_index+'[foldertree]') : null;
365
				if (!tree) break;
366
				var node = tree.getNode(_id);
367
				switch(_type)
368
				{
369
					case 'delete':
370
						if (node)	// we dont care for deleted accounts not shown (eg. other users)
371
						{
372
							tree.deleteItem(_id);
373
							// ToDo: blank list, if _id was active account
374
						}
375
						break
376
					case 'update':
377
					case 'edit':
378
						if (node)	// we dont care for updated accounts not shown (eg. other users)
379
						{
380
							//tree.refreshItem(_id);
381
							egw.json('mail.mail_ui.ajax_reloadNode',[_id])
382
								.sendRequest(true);
383
						}
384
						break;
385
					case 'add':
386
						tree.refreshItem(0);	// refresh root
387
						break;
388
					default: // null
389
				}
390
		}
391
		return undefined;
392
	},
393
394
	/**
395
	 * Callback function for dataFetch caching.
396
	 *
397
	 * We only cache the first chunk (50 rows), and only if search filter is not set,
398
	 * but we cache this for every combination of folder, filter & filter2.
399
	 *
400
	 * We do not cache, if we dont find selectedFolder in query_context,
401
	 * as looking it up in tree causes mails to be cached for wrong folder
402
	 * (Probably because user already clicked on an other folder)!
403
	 *
404
	 * @param {object} query_context Query information from egw.dataFetch()
405
	 * @returns {string|false} Cache key, or false to not cache
406
	 */
407
	nm_cache: function(query_context)
408
	{
409
		// Only cache first chunk of rows, if no search filter
410
		if((!query_context || !query_context.start) && query_context.count == 0 &&
411
			query_context.filters && query_context.filters.selectedFolder &&
412
			!(!query_context.filters || query_context.filters.search)
413
		)
414
		{
415
			// Make sure keys match, even if some filters are not defined
416
			// using JSON.stringfy() directly gave a crash in Safari 7.0.4
417
			return this.egw.jsonEncode({
418
				selectedFolder: query_context.filters.selectedFolder || '',
419
				cat_id: query_context.filters.cat_id || '',
420
				filter: query_context.filters.filter || '',
421
				filter2: query_context.filters.filter2 || '',
422
				sort: query_context.filters.sort
423
			});
424
		}
425
		return false;
426
	},
427
428
	/**
429
	 * mail rebuild Action menu On nm-list
430
	 *
431
	 * @param _actions
432
	 */
433
	mail_rebuildActionsOnList: function(_actions)
434
	{
435
		this.et2.getWidgetById(this.nm_index).set_actions(_actions);
436
	},
437
438
	/**
439
	 * mail_fetchCurrentlyFocussed - implementation to decide wich mail of all the selected ones is the current
440
	 *
441
	 * @param _selected array of the selected mails
442
	 * @param _reset bool - tell the function to reset the global vars used
443
	 */
444
	mail_fetchCurrentlyFocussed: function(_selected, _reset) {
445
		// reinitialize the buffer-info on selected mails
446
		if (_reset == true || typeof _selected == 'undefined')
447
		{
448
			if (_reset == true)
449
			{
450
				// Request updated data, if possible
451
				if (this.mail_currentlyFocussed!='') egw.dataRefreshUID(this.mail_currentlyFocussed);
452
				for(var k = 0; k < this.mail_selectedMails.length; k++) egw.dataRefreshUID(this.mail_selectedMails[k]);
453
				//nm.refresh(this.mail_selectedMails,'delete');
454
			}
455
			this.mail_selectedMails = [];
456
			this.mail_currentlyFocussed = '';
457
			return '';
458
		}
459
		for(var k = 0; k < _selected.length; k++)
460
		{
461
			if (jQuery.inArray(_selected[k],this.mail_selectedMails)==-1)
462
			{
463
				this.mail_currentlyFocussed = _selected[k];
464
				break;
465
			}
466
		}
467
		this.mail_selectedMails = _selected;
468
		return this.mail_currentlyFocussed;
469
	},
470
471
	/**
472
	 * mail_open - implementation of the open action
473
	 *
474
	 * @param _action
475
	 * @param _senders - the representation of the elements(s) the action is to be performed on
476
	 * @param _mode - you may pass the mode. if not given view is used (tryastext|tryashtml are supported)
477
	 */
478
	mail_open: function(_action, _senders, _mode) {
479
		if (typeof _senders == 'undefined' || _senders.length==0)
480
		{
481
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
482
			{
483
				var _senders = [];
484
				_senders.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
485
			}
486
			if ((typeof _senders == 'undefined' || _senders.length==0) && this.mail_isMainWindow)
487
			{
488
				if (this.mail_currentlyFocussed)
489
				{
490
					var _senders = [];
491
					_senders.push({id:this.mail_currentlyFocussed});
492
				}
493
			}
494
		}
495
		var _id = _senders[0].id;
496
		// reinitialize the buffer-info on selected mails
497
		if (!(_mode == 'tryastext' || _mode == 'tryashtml' || _mode == 'view' || _mode == 'print')) _mode = 'view';
498
		this.mail_selectedMails = [];
499
		this.mail_selectedMails.push(_id);
500
		this.mail_currentlyFocussed = _id;
501
502
		var dataElem = egw.dataGetUIDdata(_id);
503
		var subject = dataElem.data.subject;
504
		//alert('Open Message:'+_id+' '+subject);
505
		var h = egw().open( _id,'mail','view',_mode+'='+_id.replace(/=/g,"_")+'&mode='+_mode);
506
		egw(h).ready(function() {
507
			h.document.title = subject;
508
		});
509
		// THE FOLLOWING IS PROBABLY NOT NEEDED, AS THE UNEVITABLE PREVIEW IS HANDLING THE COUNTER ISSUE
510
		var messages = {};
511
		messages['msg'] = [_id];
512
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
513
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
514
		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))
515
		{
516
			this.mail_removeRowClass(messages,'recent');
517
			this.mail_removeRowClass(messages,'unseen');
518
			// reduce counter without server roundtrip
519
			this.mail_reduceCounterWithoutServerRoundtrip();
520
			// not needed, as an explizit read flags the message as seen anyhow
521
			//egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
522
		}
523
	},
524
525
	/**
526
	 * Open a single message in html mode
527
	 *
528
	 * @param _action
529
	 * @param _elems _elems[0].id is the row-id
530
	 */
531
	mail_openAsHtml: function(_action, _elems)
532
	{
533
		this.mail_open(_action, _elems,'tryashtml');
534
	},
535
536
	/**
537
	 * Open a single message in plain text mode
538
	 *
539
	 * @param _action
540
	 * @param _elems _elems[0].id is the row-id
541
	 */
542
	mail_openAsText: function(_action, _elems)
543
	{
544
		this.mail_open(_action, _elems,'tryastext');
545
	},
546
547
	/**
548
	 * Compose, reply or forward a message
549
	 *
550
	 * @function
551
	 * @memberOf mail
552
	 * @param _action _action.id is 'compose', 'composeasnew', 'reply', 'reply_all' or 'forward' (forward can be multiple messages)
553
	 * @param _elems _elems[0].id is the row-id
554
	 */
555
	mail_compose: function(_action, _elems)
556
	{
557
		if (typeof _elems == 'undefined' || _elems.length==0)
558
		{
559
			if (this.et2 && this.et2.getArrayMgr("content").getEntry('mail_id'))
560
			{
561
				var _elems = [];
562
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
563
			}
564
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
565
			{
566
				if (this.mail_currentlyFocussed)
567
				{
568
					var _elems = [];
569
					_elems.push({id:this.mail_currentlyFocussed});
570
				}
571
			}
572
		}
573
		// Extra info passed to egw.open()
574
		var settings = {
575
			// 'Source' Mail UID
576
			id: '',
577
			// How to pull data from the Mail IDs for the compose
578
			from: ''
579
		};
580
581
		// We only handle one for everything but forward
582
		settings.id = (typeof _elems == 'undefined'?'':_elems[0].id);
583
584
		switch(_action.id)
585
		{
586
			case 'compose':
587
				if (_elems.length == 1)
588
				{
589
					//mail_parentRefreshListRowStyle(settings.id,settings.id);
590
				}
591
				else
592
				{
593
					return this.mail_compose('forward',_elems);
594
				}
595
				break;
596
			case 'forward':
597
			case 'forwardinline':
598
			case 'forwardasattach':
599
				if (_elems.length>1||_action.id == 'forwardasattach')
600
				{
601
					settings.from = 'forward';
602
					settings.mode = 'forwardasattach';
603
					if (typeof _elems != 'undefined' && _elems.length>1)
604
					{
605
						for(var j = 1; j < _elems.length; j++)
606
						settings.id = settings.id + ',' + _elems[j].id;
607
					}
608
				}
609
				else
610
				{
611
					settings.from = 'forward';
612
					settings.mode = 'forwardinline';
613
				}
614
				break;
615
			default:
616
				// No further client side processing needed for these
617
				settings.from = _action.id;
618
		}
619
		var compose_list = egw.getOpenWindows("mail", /^compose_/);
620
		var window_name = 'compose_' + compose_list.length + '_'+ (settings.from || '') + '_' + settings.id;
621
		return egw().open('','mail','add',settings,window_name,'mail');
622
	},
623
624
	/**
625
	 * Set content into a compose window
626
	 *
627
	 * @function
628
	 * @memberOf mail
629
	 *
630
	 * @param {String} window_name The name of an open content window.
631
	 * @param {object} content
632
	 *
633
	 * @description content Data to set into the window's fields
634
	 * content.to Addresses to add to the to line
635
	 * content.cc Addresses to add to the CC line
636
	 * content.bcc Addresses to add to the BCC line
637
	 *
638
	 * @return {boolean} Success
639
	 */
640
	setCompose: function(window_name, content)
641
	{
642
		// Get window
643
		var compose = window.open('', window_name);
644
		if(!compose || compose.closed) return false;
645
646
		// Get etemplate of popup
647
		var compose_et2 = compose.etemplate2.getByApplication('mail');
648
		if(!compose_et2 || compose_et2.length != 1 || !compose_et2[0].widgetContainer)
649
		{
650
			return false;
651
		}
652
653
		// Set each field provided
654
		var success = true;
655
		var arrContent = [];
656
		for(var field in content)
657
		{
658
			try
659
			{
660
				var widget = compose_et2[0].widgetContainer.getWidgetById(field);
661
662
				// Merge array values, replace strings
663
				var value = widget.getValue() || content[field];
664
				if(jQuery.isArray(value))
665
				{
666
					if(jQuery.isArray(content[field]))
667
					{
668
						value.concat(content[field]);
669
					}
670
					else
671
					{
672
						arrContent = content[field].split(',');
673
						for (var k=0;k < arrContent.length;k++)
674
						{
675
							value.push(arrContent[k]);
676
						}
677
					}
678
				}
679
				widget.set_value(value);
680
			}
681
			catch(e)
682
			{
683
				egw.log("error", "Unable to set field %s to '%s' in window '%s'", field, content[field],window_name);
684
				success = false;
685
				continue;
0 ignored issues
show
Unused Code introduced by
This continue has no effect on the loop flow and can be removed.
Loading history...
686
			}
687
		}
688
		if (content['cc'] || content['bcc'])
689
		{
690
			this.compose_fieldExpander();
691
			this.compose_fieldExpander_init();
692
		}
693
		return success;
694
	},
695
696
	/**
697
	 * mail_disablePreviewArea - implementation of the disablePreviewArea action
698
	 *
699
	 * @param _value
700
	 */
701
	mail_disablePreviewArea: function(_value) {
702
		var splitter = this.et2.getWidgetById('mailSplitter');
703
		// return if there's no splitter we maybe in mobile mode
704
		if (typeof splitter == 'undefined' || splitter == null) return;
705
		if(splitter.isDocked())
706
		{
707
			this.mail_previewAreaActive = false;
708
		}
709
		this.et2.getWidgetById('mailPreview').set_disabled(_value);
710
		//Dock the splitter always if we are browsing with mobile
711
		if (_value==true)
712
		{
713
			if (this.mail_previewAreaActive) splitter.dock();
714
			this.mail_previewAreaActive = false;
715
		}
716
		else
717
		{
718
			if (!this.mail_previewAreaActive)
719
			{
720
				splitter.undock();
721
				window.setTimeout(function(){splitter.left.trigger('resize.et2_split.mailSplitter');},200);
722
			}
723
			this.mail_previewAreaActive = true;
724
		}
725
	},
726
727
	/**
728
	 * Create an expand on click box
729
	 *
730
	 * @param {object} _expContent an object with at least these elements
731
	 *					{build_children, data_one, data, widget, line}
732
	 *
733
	 * @param {object} _dataElem includes data of the widget which need to be expand
734
	 * @param {object} widget container of relevant template, default is this.et2
0 ignored issues
show
Documentation introduced by
The parameter widget does not exist. Did you maybe forget to remove this comment?
Loading history...
735
	 *
736
	 * @return _dataElem content of widgets
737
	 */
738
	url_email_expandOnClick: function (_expContent, _dataElem, _et2)
739
	{
740
741
		var et2 = _et2 || this.et2;
742
		for(var j = 0; j < _expContent.length; j++)
743
		{
744
			var field = _expContent[j] || [];
745
			var content = _dataElem.data[field.data] || [];
746
747
			// Add in single address, if there
748
			if(typeof field.data_one != 'undefined' && field.data != field.data_one)
749
			{
750
				if (jQuery.isArray(_dataElem.data[field.data_one]))
751
					content = content.concat(_dataElem.data[field.data_one]);
752
				else
753
					content.unshift(_dataElem.data[field.data_one]);
754
				// Unique
755
				content = content.filter(function(value, index, self) {
756
					return self.indexOf(value) === index;
757
				});
758
			}
759
760
			// Disable whole box if there are none
761
			var line = et2.getWidgetById(field.line);
762
			if(line != null) line.set_disabled(content.length == 0);
763
764
			var widget = et2.getWidgetById(field.widget);
765
			if(widget == null) continue;
766
			jQuery(widget.getDOMNode()).removeClass('visible');
767
768
			// Programatically build the child elements
769
			if(field.build_children)
770
			{
771
				// Remove any existing
772
				var children = widget.getChildren();
773
				for(var i = children.length-1; i >= 0; i--)
774
				{
775
					children[i].destroy();
776
					widget.removeChild(children[i]);
777
				}
778
				if (content.length == 1 && typeof content[0] != 'undefined' && content[0])
779
				{
780
					content = content[0].split(',');
781
				}
782
				// Add for current record
783
				var remembervalue = '';
784
				for(var i = 0; i < content.length; i++)
785
				{
786
					if (typeof content[i] != 'string' || !content[i]) continue;
787
					// if there is no @ in string, its most likely that we have a comma in the personal name part of the emailaddress
788
					if (content[i].indexOf('@')< 0)
789
					{
790
						remembervalue = content[i];
791
					}
792
					else
793
					{
794
						var value = remembervalue+(remembervalue?',':'')+content[i];
795
						var url_email_options = {
796
							id:widget.id+'_'+i,
797
							value:value,
798
							readonly:true,
799
							contact_plus:true,
800
							full_email:typeof field['full_email'] !='undefined'?field['full_email']:true
801
						};
802
						var email = et2_createWidget('url-email',url_email_options,widget);
803
						email.loadingFinished();
804
						remembervalue = '';
805
					}
806
				}
807
			}
808
			else
809
			{
810
				widget.set_value({content: content});
811
			}
812
813
			// Show or hide button, as needed
814
			line.iterateOver(function(button) {
815
				// Avoid binding to any child buttons
816
				if(button.getParent() != line) return;
0 ignored issues
show
Bug introduced by
The variable line is changed as part of the for loop for example by et2.getWidgetById(field.line) on line 761. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
817
				button.set_disabled(
818
					// Disable if only 1 address
819
					content.length <=1 || (
0 ignored issues
show
Bug introduced by
The variable content is changed as part of the for loop for example by content.0.split(",") on line 780. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
820
					// Disable if all content is visible
821
					jQuery(widget.getDOMNode()).innerWidth() >= widget.getDOMNode().scrollWidth &&
0 ignored issues
show
Bug introduced by
The variable widget is changed as part of the for loop for example by et2.getWidgetById(field.widget) on line 764. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
822
					jQuery(widget.getDOMNode()).innerHeight() >= widget.getDOMNode().scrollHeight)
823
				);
824
			},this,et2_button);
825
		}
826
827
		return _dataElem;
828
	},
829
830
	/**
831
	 * Set values for mail dispaly From,Sender,To,Cc, and Bcc
832
	 * Additionally, apply expand on click feature on thier widgets
833
	 *
834
	 */
835
	mail_display: function()
836
	{
837
		var dataElem = {data:{FROM:"",SENDER:"",TO:"",CC:"",BCC:""}};
838
		var content = this.et2.getArrayMgr('content').data;
839
		var expand_content = [
840
			{build_children: true, data_one: 'FROM', data: 'FROM', widget: 'FROM', line: 'mailDisplayHeadersFrom', full_email:false},
841
			{build_children: true,  data: 'SENDER', widget: 'SENDER', line: 'mailDisplayHeadersSender'},
842
			{build_children: true, data: 'TO', widget: 'TO', line: 'mailDisplayHeadersTo'},
843
			{build_children: true, data: 'CC', widget: 'CC', line: 'mailDisplayHeadersCc'},
844
			{build_children: true, data: 'BCC', widget:'BCC', line: 'mailDisplayHeadersBcc'}
845
		];
846
847
		if (typeof  content != 'undefiend')
848
		{
849
			dataElem.data = jQuery.extend(dataElem.data, content);
850
851
			this.url_email_expandOnClick(expand_content, dataElem);
852
			var toolbaractions = ((typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.displayToolbaractions != 'undefined')?JSON.parse(dataElem.data.displayToolbaractions):undefined);
853
			if (toolbaractions) this.et2.getWidgetById('displayToolbar').set_actions(toolbaractions);
854
		}
855
	},
856
857
	/**
858
	 * mail_preview - implementation of the preview action
859
	 *
860
	 * @param nextmatch et2_nextmatch The widget whose row was selected
861
	 * @param selected Array Selected row IDs.  May be empty if user unselected all rows.
862
	 */
863
	mail_preview: function(selected, nextmatch) {
864
		// Empty values, just in case selected is empty (user cleared selection)
865
		//dataElem.data is populated, when available with fromaddress(string),toaddress(string),additionaltoaddress(array),ccaddress (array)
866
		var dataElem = {data:{subject:"",fromaddress:"",toaddress:"",ccaddress:"",date:"",attachmentsBlock:""}};
867
		var attachmentArea = this.et2.getWidgetById('previewAttachmentArea');
868
		if(typeof selected != 'undefined' && selected.length == 1)
869
		{
870
			var _id = this.mail_fetchCurrentlyFocussed(selected);
871
			dataElem = jQuery.extend(dataElem, egw.dataGetUIDdata(_id));
872
873
			// Try to resolve winmail.data attachment
874
			if (dataElem.data && dataElem.data.attachmentsBlock[0]
875
					&& dataElem.data.attachmentsBlock[0].winmailFlag
876
					&& (dataElem.data.attachmentsBlock[0].mimetype =='application/ms-tnef' ||
877
					dataElem.data.attachmentsBlock[0].filename == "winmail.dat"))
878
			{
879
				attachmentArea.getDOMNode().classList.add('loading');
880
				this.egw.jsonq('mail.mail_ui.ajax_resolveWinmail',[_id], jQuery.proxy(function(_data){
881
					attachmentArea.getDOMNode().classList.remove('loading');
882
					if (typeof _data == 'object')
883
					{
884
						attachmentArea.set_value({content:_data});
885
886
						this.data.attachmentsBlock = _data;
887
						// Update client cache to avoid resolving winmail.dat attachment again
888
						egw.dataStoreUID(this.data.uid, this.data);
889
890
						set_prev_iframe_top();
891
					}
892
					else
893
					{
894
						console.log('Can not resolve the winmail.data!');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
895
					}
896
				},dataElem));
897
			}
898
		}
899
900
		var $preview_iframe = jQuery('#mail-index_mailPreviewContainer');
901
902
		// Re calculate the position of preview iframe according to its visible sibilings
903
		var set_prev_iframe_top = function ()
904
		{
905
			// Need to make sure that the iframe is fullyLoad before calculation
906
			window.setTimeout(function(){
907
				var lastEl = $preview_iframe.prev().prev();
908
				// Top offset of preview iframe calculated from top level
909
				var iframeTop = $preview_iframe.offset().top;
910
				while (lastEl.css('display') === "none")
911
				{
912
					lastEl = lastEl.prev();
913
				}
914
				var offset = iframeTop - (lastEl.offset().top + lastEl.height()) || 130; // fallback to 130 px if can not calculate new top
915
916
				// preview iframe parent has position absolute, therefore need to calculate the top via position
917
				$preview_iframe.css ('top', $preview_iframe.position().top - offset + 10);
918
			}, 50);
919
		};
920
921
		// Show / hide 'Select something' in preview
922
		var blank = this.et2.getWidgetById('blank');
923
		if(blank)
924
		{
925
			blank.set_disabled(true);
926
		}
927
		if (attachmentArea && typeof _id != 'undefined' && _id !='' && typeof dataElem !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable _id does not seem to be initialized in case typeof selected != "und...&& selected.length == 1 on line 868 is false. Are you sure this can never be the case?
Loading history...
928
		{
929
			// If there is content to show recalculate the size
930
			set_prev_iframe_top();
931
		}
932
		else if (this.egw.preference('previewPane', 'mail') == 'fixed')
933
		{
934
			if(blank)
935
			{
936
				blank.set_disabled(false);
937
			}
938
			this.mail_disablePreviewArea(false);
939
			if (!egwIsMobile())return;
940
		}
941
		else
942
		{
943
			// Leave if we're here and there is nothing selected, too many, or no data
944
			var prevAttchArea = this.et2.getWidgetById('previewAttachmentArea');
945
			if (prevAttchArea)
946
			{
947
				prevAttchArea.set_value({content:[]});
948
				this.et2.getWidgetById('previewAttachmentArea').set_class('previewAttachmentArea noContent mail_DisplayNone');
949
				var IframeHandle = this.et2.getWidgetById('messageIFRAME');
950
				IframeHandle.set_src('about:blank');
951
				this.mail_disablePreviewArea(true);
952
			}
953
			if (!egwIsMobile())return;
954
		}
955
		// Not applied to mobile preview
956
		if (!egwIsMobile())
957
		{
958
959
			// Widget ID:data key map of widgets we can directly set from cached data
960
			var data_widgets = {
961
				'previewFromAddress':	'fromaddress',
962
				'previewDate':			'date',
963
				'previewSubject':		'subject'
964
			};
965
966
			// Set widget values from cached data
967
			for(var id in data_widgets)
968
			{
969
				var widget = this.et2.getWidgetById(id);
970
				if(widget == null) continue;
971
				widget.set_value(dataElem.data[data_widgets[id]] || "");
972
			}
973
974
			// Blank first, so we don't show previous email while loading
975
			var IframeHandle = this.et2.getWidgetById('messageIFRAME');
976
			IframeHandle.set_src('about:blank');
977
978
			// show iframe, in case we hide it from mailvelopes one and remove that
979
			jQuery(IframeHandle.getDOMNode()).show()
980
				.next(this.mailvelope_iframe_selector).remove();
981
982
			// Set up additional content that can be expanded.
983
			// We add a new URL widget for each address, so they get all the UI
984
			// TO addresses have the first one split out, not all together
985
			// list of keys:
986
			var expand_content = [
987
				{build_children: true, data_one: 'toaddress', data: 'additionaltoaddress', widget: 'additionalToAddress', line: 'mailPreviewHeadersTo'},
988
				{build_children: true, data: 'ccaddress', widget: 'additionalCCAddress', line: 'mailPreviewHeadersCC'},
989
				{build_children: false, data: 'attachmentsBlock', widget:'previewAttachmentArea', line: 'mailPreviewHeadersAttachments'}
990
			];
991
992
			// Undock the preview before running expandOnClick, because we
993
			// need to have the DOM ready for calculation.
994
			this.mail_disablePreviewArea(false);
995
996
			dataElem = this.url_email_expandOnClick(expand_content,dataElem);
997
998
			// Update the internal list of selected mails, if needed
999
			if(this.mail_selectedMails.indexOf(_id) < 0)
1000
			{
1001
				this.mail_selectedMails.push(_id);
1002
			}
1003
1004
			// Request email body from server
1005
			IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:_id}));
1006
		}
1007
1008
		var messages = {};
1009
		messages['msg'] = [_id];
1010
1011
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
1012
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
1013
		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))
1014
		{
1015
			this.mail_removeRowClass(messages,'recent');
1016
			this.mail_removeRowClass(messages,'unseen');
1017
			// reduce counter without server roundtrip
1018
			this.mail_reduceCounterWithoutServerRoundtrip();
1019
			if (typeof dataElem.data.dispositionnotificationto != 'undefined' && dataElem.data.dispositionnotificationto &&
1020
				typeof dataElem.data.flags.mdnsent == 'undefined' && typeof dataElem.data.flags.mdnnotsent == 'undefined')
1021
			{
1022
				var buttons = [
1023
					{text: this.egw.lang("Yes"), id: "mdnsent"},
1024
					{text: this.egw.lang("No"), id:"mdnnotsent"}
1025
				];
1026
				et2_dialog.show_dialog(function(_button_id, _value) {
1027
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1028
					{
1029
						case "mdnsent":
1030
							egw.jsonq('mail.mail_ui.ajax_sendMDN',[messages]);
1031
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnsent', messages, true]);
1032
							return;
1033
						case "mdnnotsent":
1034
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnnotsent', messages, true]);
1035
					}
1036
				},
1037
				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?"),
1038
				this.egw.lang("Confirm"),
1039
				messages, buttons);
1040
			}
1041
			egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
1042
		}
1043
	},
1044
1045
	/**
1046
	 * If a preview header is partially hidden, this is the handler for clicking the
1047
	 * expand button that shows all the content for that header.
1048
	 * The button must be directly after the widget to be expanded in the template.
1049
	 * The widget to be expended is set in the event data.
1050
	 *
1051
	 * requires: mainWindow, one mail selected for preview
1052
	 *
1053
	 * @param {jQuery event} event
1054
	 * @param {Object} widget
1055
	 * @param {DOMNode} button
1056
	 */
1057
	showAllHeader: function(event,widget,button) {
1058
		// Show list as a list
1059
		var list = jQuery(button).prev();
1060
	/*	if (list.length <= 0)
1061
		{
1062
			list = jQuery(button.target).prev();
1063
		}*/
1064
1065
		list.toggleClass('visible');
1066
1067
		// Revert if user clicks elsewhere
1068
		jQuery('body').one('click', list, function(ev) {
1069
			ev.data.removeClass('visible');
1070
		});
1071
	},
1072
1073
	mail_setMailBody: function(content) {
1074
		var IframeHandle = this.et2.getWidgetById('messageIFRAME');
1075
		IframeHandle.set_value('');
1076
	},
1077
1078
	/**
1079
	 * mail_refreshFolderStatus, function to call to read the counters of a folder and apply them
1080
	 *
1081
	 * @param {stirng} _nodeID
1082
	 * @param {string} mode
1083
	 * @param {boolean} _refreshGridArea
1084
	 * @param {boolean} _refreshQuotaDisplay
1085
	 *
1086
	 */
1087
	mail_refreshFolderStatus: function(_nodeID,mode,_refreshGridArea,_refreshQuotaDisplay) {
1088
		if (typeof _nodeID != 'undefined' && typeof _nodeID[_nodeID] != 'undefined' && _nodeID[_nodeID])
1089
		{
1090
			_refreshGridArea = _nodeID[_refreshGridArea];
1091
			mode = _nodeID[mode];
1092
			_nodeID = _nodeID[_nodeID];
1093
		}
1094
		var nodeToRefresh = 0;
1095
		var mode2use = "none";
1096
		if (typeof _refreshGridArea == 'undefined') _refreshGridArea=true;
1097
		if (typeof _refreshQuotaDisplay == 'undefined') _refreshQuotaDisplay=true;
1098
		if (_nodeID) nodeToRefresh = _nodeID;
1099
		if (mode) {
1100
			if (mode == "forced") {mode2use = mode;}
1101
		}
1102
		try
1103
		{
1104
			var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1105
1106
			var activeFolders = tree_wdg.getTreeNodeOpenItems(nodeToRefresh,mode2use);
1107
			//alert(activeFolders.join('#,#'));
1108
			this.mail_queueRefreshFolderList((mode=='thisfolderonly'&&nodeToRefresh?[_nodeID]:activeFolders));
1109
			if (_refreshGridArea)
1110
			{
1111
				// maybe to use the mode forced as trigger for grid reload and using the grids own autorefresh
1112
				// would solve the refresh issue more accurately
1113
				//if (mode == "forced") this.mail_refreshMessageGrid();
1114
				this.mail_refreshMessageGrid();
1115
			}
1116
			if (_refreshQuotaDisplay)
1117
			{
1118
				this.mail_refreshQuotaDisplay();
1119
			}
1120
			//the two lines below are not working yet.
1121
			//var no =tree_wdg.getSelectedNode();
1122
			//tree_wdg.focusItem(no.id);
1123
		} catch(e) { } // ignore the error; maybe the template is not loaded yet
1124
	},
1125
1126
	/**
1127
	 * mail_refreshQuotaDisplay, function to call to read the quota for the active server
1128
	 *
1129
	 * @param {object} _server
1130
	 *
1131
	 */
1132
	mail_refreshQuotaDisplay: function(_server)
1133
	{
1134
		egw.json('mail.mail_ui.ajax_refreshQuotaDisplay',[_server])
1135
			.sendRequest(true);
1136
	},
1137
1138
	/**
1139
	 * mail_setQuotaDisplay, function to call to read the quota for the active server
1140
	 *
1141
	 * @param {object} _data
1142
	 *
1143
	 */
1144
	mail_setQuotaDisplay: function(_data)
1145
	{
1146
		if (!this.et2 && !this.checkET2()) return;
1147
1148
		var quotabox = this.et2.getWidgetById(this.nm_index+'[quotainpercent]');
1149
1150
		// Check to make sure it's there
1151
		if(quotabox)
1152
		{
1153
			//try to set it via set_value and set label
1154
			quotabox.set_class(_data.data.quotaclass);
1155
			quotabox.set_value(_data.data.quotainpercent);
1156
			quotabox.set_label(_data.data.quota);
1157
			if (_data.data.quotawarning)
1158
			{
1159
				var self = this;
1160
				var buttons = [
1161
					{text: this.egw.lang("Empty Trash and Junk"), id: "cleanup", class: "ui-priority-primary", default: true, image:"delete"},
1162
					{text: this.egw.lang("Cancel"), id:"cancel"}
1163
				];
1164
				var server = [{iface:{id: _data.data.profileid+'::'}}];
1165
				et2_dialog.show_dialog(function(_button_id) {
1166
					if (_button_id == "cleanup")
1167
					{
1168
						self.mail_emptySpam (null, server);
1169
						self.mail_emptyTrash (null, server);
1170
					}
1171
					return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
1172
				},
1173
				this.egw.lang("Your mail quota is %1% full, you may not be able to send/receive further emails.\n Although cleaning up emails in trash or junk folder might help you to get some free space back.\n If that didn't help, please ask administrator for more quota.", _data.data.quotainpercent),
1174
				this.egw.lang("Mail cleanup"),
1175
				'', buttons, et2_dialog.WARNING_MESSAGE);
1176
			}
1177
		}
1178
	},
1179
1180
	/**
1181
	 * mail_callRefreshVacationNotice, function to call the serverside function to refresh the vacationnotice for the active server
1182
	 *
1183
	 * @param {object} _server
1184
	 *
1185
	 */
1186
	mail_callRefreshVacationNotice: function(_server)
1187
	{
1188
		egw.jsonq('mail_ui::ajax_refreshVacationNotice',[_server]);
1189
	},
1190
	/**
1191
	 * Make sure attachments have all needed data, so they can be found for
1192
	 * HTML5 native dragging
1193
	 *
1194
	 * @param {string} mail_id Mail UID
1195
	 * @param {array} attachments Attachment information.
1196
	 */
1197
	register_for_drag: function(mail_id, attachments)
1198
	{
1199
		// Put required info in global store
1200
		var data = {};
1201
		if (!attachments) return;
1202
		for (var i = 0; i < attachments.length; i++)
1203
		{
1204
			var data = attachments[i] || {};
1205
			if(!data.filename || !data.type) continue;
1206
1207
			// Add required info
1208
			data.mime = data.type;
1209
			data.download_url = egw.link('/index.php', {
1210
				menuaction: 'mail.mail_ui.getAttachment',
1211
				id: mail_id,
1212
				part: data.partID,
1213
				is_winmail: data.winmailFlag
1214
			});
1215
			data.name = data.filename;
1216
		}
1217
	},
1218
1219
	/**
1220
	 * Display helper for dragging attachments
1221
	 *
1222
	 * @param {egwAction} _action
1223
	 * @param {egwActionElement[]} _elems
1224
	 * @returns {DOMNode}
1225
	 */
1226
	drag_attachment: function(_action, _elems)
1227
	{
1228
		var div = jQuery(document.createElement("div"))
1229
			.css({
1230
				position: 'absolute',
1231
				top: '0px',
1232
				left: '0px',
1233
				width: '300px'
1234
			});
1235
1236
		var data = _elems[0].data || {};
1237
1238
		var text = jQuery(document.createElement('div')).css({left: '30px', position: 'absolute'});
1239
		// add filename or number of files for multiple files
1240
		text.text(_elems.length > 1 ? _elems.length+' '+this.egw.lang('files') : data.name || '');
1241
		div.append(text);
1242
1243
		// Add notice of Ctrl key, if supported
1244
		if(window.FileReader && 'draggable' in document.createElement('span') &&
1245
			navigator && navigator.userAgent.indexOf('Chrome') >= 0)
1246
		{
1247
			var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command';
1248
			text.append('<br />' + this.egw.lang('Hold %1 to drag files to your computer',key));
1249
		}
1250
		return div;
1251
	},
1252
1253
	/**
1254
	 * mail_refreshVacationNotice, function to call with appropriate data to refresh the vacationnotice for the active server
1255
	 *
1256
	 * @param {object} _data
1257
	 *
1258
	 */
1259
	mail_refreshVacationNotice: function(_data)
1260
	{
1261
		if (!this.et2 && !this.checkET2()) return;
1262
		if (_data == null)
1263
		{
1264
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value('');
1265
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value('');
1266
		}
1267
		else
1268
		{
1269
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value(_data.vacationnotice);
1270
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value(_data.vacationrange);
1271
		}
1272
	},
1273
1274
	/**
1275
	 * Enable or disable the date filter
1276
	 *
1277
	 * If the searchtype (cat_id) is set to something that needs dates, we enable the
1278
	 * header_right template.  Otherwise, it is disabled.
1279
	 */
1280
	mail_searchtype_change: function()
1281
	{
1282
		var filter = this.et2.getWidgetById('cat_id');
1283
		var nm = this.et2.getWidgetById(this.nm_index);
1284
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1285
		if(nm && filter)
1286
		{
1287
			switch(filter.getValue())
1288
			{
1289
				case 'bydate':
1290
1291
					if (filter && dates)
1292
					{
1293
						dates.set_disabled(false);
1294
						if (this.et2.getWidgetById('startdate')) jQuery(this.et2.getWidgetById('startdate').getDOMNode()).find('input').focus();
1295
					}
1296
					this.mail_callRefreshVacationNotice();
1297
					return true;
1298
				default:
1299
					if (dates)
1300
					{
1301
						dates.set_disabled(true);
1302
					}
1303
					this.mail_callRefreshVacationNotice();
1304
					return true;
1305
			}
1306
		}
1307
		return false;
1308
	},
1309
1310
	/**
1311
	 * mail_refreshFilter2Options, function to call with appropriate data to refresh the filter2 options for the active server
1312
	 *
1313
	 * @param {object} _data
1314
	 *
1315
	 */
1316
	mail_refreshFilter2Options: function(_data)
1317
	{
1318
		//alert('mail_refreshFilter2Options');
1319
		if (_data == null) return;
1320
		if (!this.et2 && !this.checkET2()) return;
1321
1322
		var filter2 = this.et2.getWidgetById('filter2');
1323
		var current = filter2.value;
1324
		var currentexists=false;
1325
		for (var k in _data)
1326
		{
1327
			if (k==current) currentexists=true;
1328
		}
1329
		if (!currentexists) filter2.set_value('');
1330
		filter2.set_select_options(_data);
1331
	},
1332
1333
	/**
1334
	 * mail_refreshFilterOptions, function to call with appropriate data to refresh the filter options for the active server
1335
	 *
1336
	 * @param {object} _data
1337
	 *
1338
	 */
1339
	mail_refreshFilterOptions: function(_data)
1340
	{
1341
		//alert('mail_refreshFilterOptions');
1342
		if (_data == null) return;
1343
		if (!this.et2 && !this.checkET2()) return;
1344
1345
		var filter = this.et2.getWidgetById('filter');
1346
		var current = filter.value;
1347
		var currentexists=false;
1348
		for (var k in _data)
1349
		{
1350
			if (k==current) currentexists=true;
1351
		}
1352
		if (!currentexists) filter.set_value('any');
1353
		filter.set_select_options(_data);
1354
1355
	},
1356
1357
	/**
1358
	 * mail_refreshCatIdOptions, function to call with appropriate data to refresh the filter options for the active server
1359
	 *
1360
	 * @param {object} _data
1361
	 *
1362
	 */
1363
	mail_refreshCatIdOptions: function(_data)
1364
	{
1365
		//alert('mail_refreshCatIdOptions');
1366
		if (_data == null) return;
1367
		if (!this.et2 && !this.checkET2()) return;
1368
1369
		var filter = this.et2.getWidgetById('cat_id');
1370
		var current = filter.value;
1371
		var currentexists=false;
1372
		for (var k in _data)
1373
		{
1374
			if (k==current) currentexists=true;
1375
		}
1376
		if (!currentexists) filter.set_value('quick');
1377
		filter.set_select_options(_data);
1378
1379
	},
1380
1381
	/**
1382
	 * Queues a refreshFolderList request for 500ms. Actually this will just execute the
1383
	 * code after the calling script has finished.
1384
	 *
1385
	 * @param {array} _folders description
1386
	 */
1387
	mail_queueRefreshFolderList: function(_folders)
1388
	{
1389
		var self = this;
1390
		// as jsonq is too fast wrap it to be delayed a bit, to ensure the folder actions
1391
		// are executed last of the queue
1392
		window.setTimeout(function() {
1393
			egw.jsonq('mail.mail_ui.ajax_setFolderStatus',[_folders], function (){self.unlock_tree();});
1394
		}, 500);
1395
	},
1396
1397
	/**
1398
	 * mail_CheckFolderNoSelect - implementation of the mail_CheckFolderNoSelect action to control right click options on the tree
1399
	 *
1400
	 * @param {object} action
1401
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1402
	 * @param {object} _currentNode
1403
	 */
1404
	mail_CheckFolderNoSelect: function(action,_senders,_currentNode) {
1405
1406
		// Abort if user selected an un-selectable node
1407
		// Use image over anything else because...?
1408
		var ftree, node;
1409
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1410
		if (ftree)
1411
		{
1412
			node = ftree.getNode(_senders[0].id);
1413
		}
1414
1415
		if (node && node.im0.indexOf('NoSelect') !== -1)
1416
		{
1417
			//ftree.reSelectItem(_previous);
1418
			return false;
1419
		}
1420
1421
		return true;
1422
	},
1423
1424
	/**
1425
	 * Check if SpamFolder is enabled on that account
1426
	 *
1427
	 * SpamFolder enabled is stored as data { spamfolder: true/false } on account node.
1428
	 *
1429
	 * @param {object} _action
1430
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1431
	 * @param {object} _currentNode
1432
	 */
1433
	spamfolder_enabled: function(_action,_senders,_currentNode)
1434
	{
1435
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1436
		var acc_id = _senders[0].id.split('::')[0];
1437
		var node = ftree ? ftree.getNode(acc_id) : null;
1438
1439
		return node && node.data && node.data.spamfolder;
1440
	},
1441
1442
1443
	/**
1444
	 * Check if archiveFolder is enabled on that account
1445
	 *
1446
	 * ArchiveFolder enabled is stored as data { archivefolder: true/false } on account node.
1447
	 *
1448
	 * @param {object} _action
1449
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1450
	 * @param {object} _currentNode
1451
	 */
1452
	archivefolder_enabled: function(_action,_senders,_currentNode)
1453
	{
1454
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1455
		var acc_id = _senders[0].id.split('::')[2]; // this is operating on mails
1456
		var node = ftree ? ftree.getNode(acc_id) : null;
1457
1458
		return node && node.data && node.data.archivefolder;
1459
	},
1460
1461
	/**
1462
	 * Check if Sieve is enabled on that account
1463
	 *
1464
	 * Sieve enabled is stored as data { sieve: true/false } on account node.
1465
	 *
1466
	 * @param {object} _action
1467
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1468
	 * @param {object} _currentNode
1469
	 */
1470
	sieve_enabled: function(_action,_senders,_currentNode)
1471
	{
1472
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1473
		var acc_id = _senders[0].id.split('::')[0];
1474
		var node = ftree ? ftree.getNode(acc_id) : null;
1475
1476
		return node && node.data && node.data.sieve;
1477
	},
1478
1479
	/**
1480
	 * Check if ACL is enabled on that account
1481
	 *
1482
	 * ACL enabled is stored as data { acl: true/false } on INBOX node.
1483
	 * We also need to check if folder is marked as no-select!
1484
	 *
1485
	 * @param {object} _action
1486
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1487
	 * @param {object} _currentNode
1488
	 */
1489
	acl_enabled: function(_action,_senders,_currentNode)
1490
	{
1491
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1492
		var inbox = _senders[0].id.split('::')[0]+'::INBOX';
1493
		var node = ftree ? ftree.getNode(inbox) : null;
1494
1495
		return node && node.data && node.data.acl && this.mail_CheckFolderNoSelect(_action,_senders,_currentNode);
1496
	},
1497
1498
	/**
1499
	 * mail_setFolderStatus, function to set the status for the visible folders
1500
	 *
1501
	 * @param {array} _status
1502
	 */
1503
	mail_setFolderStatus: function(_status) {
1504
		if (!this.et2 && !this.checkET2()) return;
1505
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1506
		for (var i in _status) {
1507
			ftree.setLabel(i,_status[i]);
1508
			// display folder-name bold for unseen mails
1509
			ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1510
			//alert(i +'->'+_status[i]);
1511
		}
1512
	},
1513
1514
	/**
1515
	 * mail_setLeaf, function to set the id and description for the folder given by status key
1516
	 * @param {array} _status status array with the required data (new id, desc, old desc)
1517
	 *		key is the original id of the leaf to change
1518
	 *		multiple sets can be passed to mail_setLeaf
1519
	 */
1520
	mail_setLeaf: function(_status) {
1521
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1522
		var selectedNode = ftree.getSelectedNode();
1523
		for (var i in _status)
1524
		{
1525
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1526
			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']));
1527
			ftree.renameItem(i,_status[i]['id'],_status[i]['desc']);
1528
			ftree.setStyle(i, 'font-weight: '+(_status[i]['desc'].match(this._unseen_regexp) ? 'bold' : 'normal'));
1529
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1530
			if (_status[i]['id']==selectedNode.id)
1531
			{
1532
				var nm = this.et2.getWidgetById(this.nm_index);
1533
				nm.activeFilters["selectedFolder"] = _status[i]['id'];
1534
				nm.applyFilters();
1535
			}
1536
		}
1537
	},
1538
1539
	/**
1540
	 * mail_removeLeaf, function to remove the leaf represented by the given ID
1541
	 * @param {array} _status status array with the required data (KEY id, VALUE desc)
1542
	 *		key is the id of the leaf to delete
1543
	 *		multiple sets can be passed to mail_deleteLeaf
1544
	 */
1545
	mail_removeLeaf: function(_status) {
1546
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1547
		var selectedNode = ftree.getSelectedNode();
1548
		for (var i in _status)
1549
		{
1550
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1551
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Removed Folder %1 ",_status[i]));
1552
			ftree.deleteItem(i,(selectedNode.id==i));
1553
			var selectedNodeAfter = ftree.getSelectedNode();
1554
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1555
			if (selectedNodeAfter.id!=selectedNode.id && selectedNode.id==i)
1556
			{
1557
				var nm = this.et2.getWidgetById(this.nm_index);
1558
				nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1559
				nm.applyFilters();
1560
			}
1561
		}
1562
	},
1563
1564
	/**
1565
	 * mail_reloadNode, function to reload the leaf represented by the given ID
1566
	 * @param {Object.<string,string>|Object.<string,Object}}  _status
1567
	 *		Object with the required data (KEY id, VALUE desc), or ID => {new data}
1568
	 */
1569
	mail_reloadNode: function(_status) {
1570
		var ftree = this.et2?this.et2.getWidgetById(this.nm_index+'[foldertree]'):null;
1571
		if (!ftree) return;
1572
		var selectedNode = ftree.getSelectedNode();
1573
		for (var i in _status)
1574
		{
1575
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1576
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#')
1577
			{
1578
					this.egw.message(this.egw.lang((typeof _status[i].parent !== 'undefined'? "Reloaded Folder %1" : "Reloaded Account %1") ,
1579
					(typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') :
1580
							(_status[i].text ? _status[i].text.replace(this._unseen_regexp, '') : _status[i].id))));
1581
			}
1582
			ftree.refreshItem(i,typeof _status[i] == "object" ? _status[i] : null);
1583
			if (typeof _status[i] == "string") ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1584
		}
1585
1586
		var selectedNodeAfter = ftree.getSelectedNode();
1587
1588
		// If selected folder changed, refresh nextmatch
1589
		if (selectedNodeAfter != null && selectedNodeAfter.id!=selectedNode.id)
1590
		{
1591
			var nm = this.et2.getWidgetById(this.nm_index);
1592
			nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1593
			nm.applyFilters();
1594
		}
1595
	},
1596
1597
	/**
1598
	 * mail_refreshMessageGrid, function to call to reread ofthe current folder
1599
	 *
1600
	 * @param {boolean} _isPopup
1601
	 */
1602
	mail_refreshMessageGrid: function(_isPopup, _refreshVacationNotice) {
1603
		if (typeof _isPopup == 'undefined') _isPopup = false;
1604
		if (typeof _refreshVacationNotice == 'undefined') _refreshVacationNotice = false;
1605
		var nm;
1606
		if (_isPopup && !this.mail_isMainWindow)
1607
		{
1608
			nm = window.opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index);
1609
		}
1610
		else
1611
		{
1612
			nm = this.et2.getWidgetById(this.nm_index);
1613
		}
1614
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1615
		var filter = this.et2.getWidgetById('cat_id');
1616
		if(nm && filter)
1617
		{
1618
			nm.activeFilters["startdate"]=null;
1619
			nm.activeFilters["enddate"]=null;
1620
			switch(filter.getValue())
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1621
			{
1622
				case 'bydate':
1623
1624
					if (filter && dates)
1625
					{
1626
						if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) nm.activeFilters["startdate"] = this.et2.getWidgetById('startdate').date;
1627
						if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) nm.activeFilters["enddate"] = this.et2.getWidgetById('enddate').date;
1628
					}
1629
			}
1630
		}
1631
		nm.applyFilters(); // this should refresh the active folder
1632
		if (_refreshVacationNotice) this.mail_callRefreshVacationNotice();
1633
	},
1634
1635
	/**
1636
	 * mail_getMsg - gets the current Message
1637
	 * @return string
1638
	 */
1639
	mail_getMsg: function()
1640
	{
1641
		var msg_wdg = this.et2.getWidgetById('msg');
1642
		if (msg_wdg)
1643
		{
1644
			return msg_wdg.valueOf().htmlNode[0].innerHTML;
1645
		}
1646
		return "";
1647
	},
1648
1649
	/**
1650
	 * mail_setMsg - sets a Message, with the msg container, and controls if the container is enabled/disabled
1651
	 * @param {string} myMsg - the message
1652
	 */
1653
	mail_setMsg: function(myMsg)
1654
	{
1655
		var msg_wdg = this.et2.getWidgetById('msg');
1656
		if (msg_wdg)
1657
		{
1658
			msg_wdg.set_value(myMsg);
1659
			msg_wdg.set_disabled(myMsg.trim().length==0);
1660
		}
1661
	},
1662
1663
	/**
1664
	 * Delete mails
1665
	 * takes in all arguments
1666
	 * @param _action
1667
	 * @param _elems
1668
	 */
1669
	mail_delete: function(_action,_elems)
1670
	{
1671
		this.mail_checkAllSelected(_action,_elems,null,true);
1672
	},
1673
1674
	/**
1675
	 * call Delete mails
1676
	 * takes in all arguments
1677
	 * @param {object} _action
1678
	 * @param {array} _elems
1679
	 * @param {boolean} _allMessagesChecked
1680
	 */
1681
	mail_callDelete: function(_action,_elems,_allMessagesChecked)
1682
	{
1683
		var calledFromPopup = false;
1684
		if (typeof _allMessagesChecked == 'undefined') _allMessagesChecked=false;
1685
		if (typeof _elems == 'undefined' || _elems.length==0)
1686
		{
1687
			calledFromPopup = true;
1688
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
1689
			{
1690
				var _elems = [];
1691
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
1692
			}
1693
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
1694
			{
1695
				if (this.mail_currentlyFocussed)
1696
				{
1697
					var _elems = [];
1698
					_elems.push({id:this.mail_currentlyFocussed});
1699
				}
1700
			}
1701
		}
1702
		var msg = this.mail_getFormData(_elems);
1703
		msg['all'] = _allMessagesChecked;
1704
		if (msg['all']=='cancel') return false;
1705
		if (msg['all']) msg['activeFilters'] = this.mail_getActiveFilters(_action);
1706
		//alert(_action.id+','+ msg);
1707
		if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted');
1708
		this.mail_deleteMessages(msg,'no',calledFromPopup);
1709
		if (calledFromPopup && this.mail_isMainWindow==false)
1710
		{
1711
			egw(window).close();
1712
		}
1713
		else if (typeof this.et2_view!='undefined' && typeof this.et2_view.close == 'function')
1714
		{
1715
			this.et2_view.close();
1716
		}
1717
	},
1718
1719
	/**
1720
	 * function to find (and reduce) unseen count from folder-name
1721
	 */
1722
	mail_reduceCounterWithoutServerRoundtrip: function()
1723
	{
1724
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1725
		var _foldernode = ftree.getSelectedNode();
1726
		var counter = _foldernode.label.match(this._unseen_regexp);
1727
		var icounter = 0;
1728
		if ( counter ) icounter = parseInt(counter[0].replace(' (','').replace(')',''));
1729
		if (icounter>0)
1730
		{
1731
			var newcounter = icounter-1;
1732
			if (newcounter>0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')',' ('+String(newcounter)+')');
1733
			if (newcounter==0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')','');
1734
			ftree.setLabel(_foldernode.id,_foldernode.label);
1735
		}
1736
	},
1737
1738
	/**
1739
	 * Regular expression to find (and remove) unseen count from folder-name
1740
	 */
1741
	_unseen_regexp: / \([0-9]+\)$/,
1742
1743
	/**
1744
	 * mail_splitRowId
1745
	 *
1746
	 * @param {string} _rowID
1747
	 *
1748
	 */
1749
	mail_splitRowId: function(_rowID)
1750
	{
1751
		var res = _rowID.split('::');
1752
		// as a rowID is perceeded by app::, should be mail!
1753
		if (res.length==4 && !isNaN(parseInt(res[0])))
1754
		{
1755
			// we have an own created rowID; prepend app=mail
1756
			res.unshift('mail');
1757
		}
1758
		return res;
1759
	},
1760
1761
	/**
1762
	 * Delete mails - actually calls the backend function for deletion
1763
	 * takes in all arguments
1764
	 * @param {string} _msg - message list
1765
	 * @param {object} _action - optional action
1766
	 * @param {object} _calledFromPopup
1767
	 */
1768
	mail_deleteMessages: function(_msg,_action,_calledFromPopup)
1769
	{
1770
		var message, ftree, _foldernode, displayname;
1771
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1772
		if (ftree)
1773
		{
1774
			_foldernode = ftree.getSelectedNode();
1775
1776
			displayname = _foldernode.label.replace(this._unseen_regexp, '');
1777
		}
1778
		else
1779
		{
1780
			message = this.mail_splitRowId(_msg['msg'][0]);
1781
			if (message[3]) _foldernode = displayname = jQuery.base64Decode(message[3]);
1782
		}
1783
1784
		// Tell server
1785
		egw.json('mail.mail_ui.ajax_deleteMessages',[_msg,(typeof _action == 'undefined'?'no':_action)])
1786
			.sendRequest(true);
1787
1788
		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');
1789
		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'))));
1790
	},
1791
1792
	/**
1793
	 * Delete mails show result - called from the backend function for display of deletionmessages
1794
	 * takes in all arguments
1795
	 * @param _msg - message list
1796
	 */
1797
	mail_deleteMessagesShowResult: function(_msg)
1798
	{
1799
		// Update list
1800
		var ids = [];
1801
		for (var i = 0; i < _msg['msg'].length; i++)
1802
		{
1803
			ids.push(_msg['msg'][i].replace(/mail::/,''));
1804
		}
1805
		//this.egw.message(_msg['egw_message']);
1806
		if (_msg['all'])
1807
		{
1808
			this.egw.refresh(_msg['egw_message'],'mail');
1809
		}
1810
		else
1811
		{
1812
			this.egw.refresh(_msg['egw_message'],'mail',ids,'delete');
1813
1814
			// Nextmatch automatically selects the next row and calls preview.
1815
			// Unselect it and thanks to the timeout selectionMgr uses, preview
1816
			// will close when the selection callback fires.
1817
			this.et2.getWidgetById(this.nm_index).controller._selectionMgr.resetSelection();
1818
		}
1819
	},
1820
1821
	/**
1822
	 * retry to Delete mails
1823
	 * @param responseObject ->
1824
	 * 	 reason - reason to report
1825
	 * 	 messageList
1826
	 */
1827
	mail_retryForcedDelete: function(responseObject)
1828
	{
1829
		var reason = responseObject['response'];
1830
		var messageList = responseObject['messageList'];
1831
		if (confirm(reason))
1832
		{
1833
			this.mail_deleteMessages(messageList,'remove_immediately');
1834
		}
1835
		else
1836
		{
1837
			this.egw.message(this.egw.lang('canceled deletion due to userinteraction'));
1838
			this.mail_removeRowClass(messageList,'deleted');
1839
		}
1840
		this.mail_refreshMessageGrid();
1841
		this.mail_preview();
1842
	},
1843
1844
	/**
1845
	 * UnDelete mailMessages
1846
	 *
1847
	 * @param _messageList
1848
	 */
1849
	mail_undeleteMessages: function(_messageList) {
1850
	// setting class of row, the old style
1851
	},
1852
1853
	/**
1854
	 * mail_emptySpam
1855
	 *
1856
	 * @param {object} action
1857
	 * @param {object} _senders
1858
	 */
1859
	mail_emptySpam: function(action,_senders) {
1860
		var server = _senders[0].iface.id.split('::');
1861
		var activeFilters = this.mail_getActiveFilters();
1862
		var self = this;
1863
1864
		this.egw.message(this.egw.lang('empty junk'));
1865
		egw.json('mail.mail_ui.ajax_emptySpam',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1866
			.sendRequest(true);
1867
1868
		// Directly delete any trash cache for selected server
1869
		if(window.localStorage)
1870
		{
1871
			for(var i = 0; i < window.localStorage.length; i++)
1872
			{
1873
				var key = window.localStorage.key(i);
1874
1875
				// Find directly by what the key would look like
1876
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1877
					key.toLowerCase().indexOf(egw.lang('junk').toLowerCase()) > 0)
1878
				{
1879
					window.localStorage.removeItem(key);
1880
				}
1881
			}
1882
		}
1883
	},
1884
1885
	/**
1886
	 * mail_emptyTrash
1887
	 *
1888
	 * @param {object} action
1889
	 * @param {object} _senders
1890
	 */
1891
	mail_emptyTrash: function(action,_senders) {
1892
		var server = _senders[0].iface.id.split('::');
1893
		var activeFilters = this.mail_getActiveFilters();
1894
		var self = this;
1895
1896
		this.egw.message(this.egw.lang('empty trash'));
1897
		egw.json('mail.mail_ui.ajax_emptyTrash',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1898
			.sendRequest(true);
1899
1900
		// Directly delete any trash cache for selected server
1901
		if(window.localStorage)
1902
		{
1903
			for(var i = 0; i < window.localStorage.length; i++)
1904
			{
1905
				var key = window.localStorage.key(i);
1906
1907
				// Find directly by what the key would look like
1908
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1909
					key.toLowerCase().indexOf(egw.lang('trash').toLowerCase()) > 0)
1910
				{
1911
					window.localStorage.removeItem(key);
1912
				}
1913
			}
1914
		}
1915
	},
1916
1917
	/**
1918
	 * mail_compressFolder
1919
	 *
1920
	 * @param {object} action
1921
	 * @param {object} _senders
1922
	 *
1923
	 */
1924
	mail_compressFolder: function(action,_senders) {
1925
		this.egw.message(this.egw.lang('compress folder'));
1926
		egw.jsonq('mail.mail_ui.ajax_compressFolder',[_senders[0].iface.id]);
1927
		//	.sendRequest(true);
1928
		// since the json reply is using this.egw.refresh, we should not need to call refreshFolderStatus
1929
		// as the actions thereof are now bound to run after grid refresh
1930
		//this.mail_refreshFolderStatus();
1931
	},
1932
1933
	/**
1934
	 * mail_changeProfile
1935
	 *
1936
	 * @param {string} folder the ID of the selected Node -> should be an integer
1937
	 * @param {object} _widget handle to the tree widget
1938
	 * @param {boolean} getFolders Flag to indicate that the profile needs the mail
1939
	 *		folders.  False means they're already loaded in the tree, and we don't need
1940
	 *		them again
1941
	 */
1942
	mail_changeProfile: function(folder,_widget, getFolders) {
1943
		if(typeof getFolders == 'undefined')
1944
		{
1945
			getFolders = true;
1946
		}
1947
	//	alert(folder);
1948
		this.egw.message(this.egw.lang('Connect to Profile %1',_widget.getSelectedLabel().replace(this._unseen_regexp, '')));
1949
1950
		//Open unloaded tree to get loaded
1951
		_widget.openItem(folder, true);
1952
1953
		this.lock_tree();
1954
		egw.json('mail_ui::ajax_changeProfile',[folder, getFolders, this.et2._inst.etemplate_exec_id], jQuery.proxy(function() {
1955
			// Profile changed, select inbox
1956
			var inbox = folder + '::INBOX';
1957
			_widget.reSelectItem(inbox);
1958
			this.mail_changeFolder(inbox,_widget,'');
1959
			this.unlock_tree();
1960
		},this))
1961
			.sendRequest(true);
1962
1963
		return true;
1964
	},
1965
1966
	/**
1967
	 * mail_changeFolder
1968
	 * @param {string} _folder the ID of the selected Node
1969
	 * @param {widget object} _widget handle to the tree widget
1970
	 * @param {string} _previous - Previously selected node ID
1971
	 */
1972
	mail_changeFolder: function(_folder,_widget, _previous) {
1973
1974
		// to reset iframes to the normal status
1975
		this.loadIframe();
1976
1977
		// Abort if user selected an un-selectable node
1978
		// Use image over anything else because...?
1979
		var img = _widget.getSelectedNode().images[0];
1980
		if (img.indexOf('NoSelect') !== -1)
1981
		{
1982
			_widget.reSelectItem(_previous);
1983
			return;
1984
		}
1985
1986
		// Check if this is a top level node and
1987
		// change profile if server has changed
1988
		var server = _folder.split('::');
1989
		var previousServer = _previous.split('::');
1990
		var profile_selected = (_folder.indexOf('::') === -1);
1991
		if (server[0] != previousServer[0] && profile_selected)
1992
		{
1993
			// mail_changeProfile triggers a refresh, no need to do any more
1994
			return this.mail_changeProfile(_folder,_widget, _widget.getSelectedNode().childsCount == 0);
1995
		}
1996
1997
		// Apply new selected folder to list, which updates data
1998
		var nm = _widget.getRoot().getWidgetById(this.nm_index);
1999
		if(nm)
2000
		{
2001
			this.lock_tree();
2002
			nm.applyFilters({'selectedFolder': _folder});
2003
		}
2004
2005
		// Get nice folder name for message, if selected is not a profile
2006
		if(!profile_selected)
2007
		{
2008
			var displayname = _widget.getSelectedLabel();
2009
			var myMsg = (displayname?displayname:_folder).replace(this._unseen_regexp, '')+' '+this.egw.lang('selected');
2010
			this.egw.message(myMsg);
2011
		}
2012
2013
		// Update non-grid
2014
		this.mail_refreshFolderStatus(_folder,'forced',false,false);
2015
		this.mail_refreshQuotaDisplay(server[0]);
2016
		this.mail_preview();
2017
		if (server[0]!=previousServer[0])
2018
		{
2019
			this.mail_callRefreshVacationNotice(server[0]);
2020
			egw.jsonq('mail.mail_ui.ajax_refreshFilters',[server[0]]);
2021
		}
2022
	},
2023
2024
	/**
2025
	 * mail_checkAllSelected
2026
	 *
2027
	 * @param _action
2028
	 * @param _elems
2029
	 * @param _target
2030
	 * @param _confirm
2031
	 */
2032
	mail_checkAllSelected: function(_action, _elems, _target, _confirm)
2033
	{
2034
		if (typeof _confirm == 'undefined') _confirm = false;
2035
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2036
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2037
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2038
		var that = this;
2039
		var rvMain = false;
2040
		if ((obj_manager && _elems.length>1 && obj_manager.getAllSelected() && !_action.paste) || _action.id=='readall')
2041
		{
2042
			if (_confirm)
2043
			{
2044
				var buttons = [
2045
					{text: this.egw.lang("Yes"), id: "all", "class": "ui-priority-primary", "default": true, image: 'check'},
2046
					{text: this.egw.lang("Cancel"), id:"cancel"}
2047
				];
2048
				var messageToDisplay = '';
2049
				var actionlabel =_action.id;
2050
				switch (_action.id)
2051
				{
2052
					case "readall":
2053
						messageToDisplay = this.egw.lang("Do you really want to mark ALL messages as read in the current folder?")+" ";
2054
						break;
2055
					case "unlabel":
2056
						messageToDisplay = this.egw.lang("Do you really want to remove ALL labels from ALL messages in the current folder?")+" ";
2057
						break;
2058
					case "label1":
2059
						if (_action.id=="label1") actionlabel="important";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2060
					case "label2":
2061
						if (_action.id=="label2") actionlabel="job";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2062
					case "label3":
2063
						if (_action.id=="label3") actionlabel="personal";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2064
					case "label4":
2065
						if (_action.id=="label4") actionlabel="to do";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2066
					case "label5":
2067
						if (_action.id=="label5") actionlabel="later";
2068
					case "flagged":
2069
					case "read":
2070
					case "undelete":
2071
						messageToDisplay = this.egw.lang("Do you really want to toggle flag %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
2072
						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))+" ";
2073
						break;
2074
					default:
2075
						var type = null;
2076
						if (_action.id.substr(0,4)=='move' || _action.id === "drop_move_mail")
2077
						{
2078
							type = 'Move';
2079
						}
2080
						if (_action.id.substr(0,4)=='copy' || _action.id === "drop_copy_mail")
2081
						{
2082
							type = 'Copy';
2083
						}
2084
						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))+" ";
2085
				}
2086
				return et2_dialog.show_dialog(function(_button_id) {
2087
					var rv = false;
2088
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2089
					{
2090
						case "all":
2091
							rv = true;
2092
							break;
2093
						case "cancel":
2094
							rv = 'cancel';
2095
					}
2096
					if (rv !="cancel") that.lock_tree();
2097
					switch (_action.id)
2098
					{
2099
						case "delete":
2100
							that.mail_callDelete(_action, _elems,rv);
2101
							break;
2102
						case "readall":
2103
						case "unlabel":
2104
						case "label1":
2105
						case "label2":
2106
						case "label3":
2107
						case "label4":
2108
						case "label5":
2109
						case "flagged":
2110
						case "read":
2111
						case "undelete":
2112
							that.mail_callFlagMessages(_action, _elems,rv);
2113
							break;
2114
						case "drop_move_mail":
2115
							that.mail_callMove(_action, _elems,_target, rv);
2116
							break;
2117
						case "drop_copy_mail":
2118
							that.mail_callCopy(_action, _elems,_target, rv);
2119
							break;
2120
						default:
2121
							if (_action.id.substr(0,4)=='move') that.mail_callMove(_action, _elems,_target, rv);
2122
							if (_action.id.substr(0,4)=='copy') that.mail_callCopy(_action, _elems,_target, rv);
2123
					}
2124
				},
2125
				messageToDisplay,
2126
				this.egw.lang("Confirm"),
2127
				_action.id, buttons);
2128
			}
2129
			else
2130
			{
2131
				rvMain = true;
2132
			}
2133
		}
2134
		switch (_action.id)
2135
		{
2136
			case "delete":
2137
				this.mail_callDelete(_action, _elems,rvMain);
2138
				break;
2139
			case "unlabel":
2140
			case "label1":
2141
			case "label2":
2142
			case "label3":
2143
			case "label4":
2144
			case "label5":
2145
			case "flagged":
2146
			case "read":
2147
			case "undelete":
2148
				this.mail_callFlagMessages(_action, _elems,rvMain);
2149
				break;
2150
			case "drop_move_mail":
2151
				this.mail_callMove(_action, _elems,_target, rvMain);
2152
				break;
2153
			case "drop_copy_mail":
2154
				this.mail_callCopy(_action, _elems,_target, rvMain);
2155
				break;
2156
			default:
2157
				if (_action.id.substr(0,4)=='move') this.mail_callMove(_action, _elems,_target, rvMain);
2158
				if (_action.id.substr(0,4)=='copy') this.mail_callCopy(_action, _elems,_target, rvMain);
2159
		}
2160
	},
2161
2162
	/**
2163
	 * mail_doActionCall
2164
	 *
2165
	 * @param _action
2166
	 * @param _elems
2167
	 */
2168
	mail_doActionCall: function(_action, _elems)
2169
	{
2170
	},
2171
2172
	/**
2173
	 * mail_getActiveFilters
2174
	 *
2175
	 * @param _action
2176
	 * @return mixed boolean/activeFilters object
2177
	 */
2178
	mail_getActiveFilters: function(_action)
2179
	{
2180
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2181
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2182
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2183
		if (obj_manager && obj_manager.manager && obj_manager.manager.data && obj_manager.manager.data.nextmatch && obj_manager.manager.data.nextmatch.activeFilters)
2184
		{
2185
			var af = obj_manager.manager.data.nextmatch.activeFilters;
2186
			// merge startdate and enddate into the active filters (if set)
2187
			if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) af["startdate"] = this.et2.getWidgetById('startdate').date;
2188
			if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) af["enddate"] = this.et2.getWidgetById('enddate').date;
2189
			return af;
2190
		}
2191
		return false;
2192
	},
2193
2194
	/**
2195
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2196
	 *
2197
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2198
	 * @param _elems
2199
	 */
2200
	mail_flag: function(_action, _elems)
2201
	{
2202
		this.mail_checkAllSelected(_action,_elems,null,true);
2203
	},
2204
2205
	/**
2206
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2207
	 *
2208
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2209
	 * @param _elems
2210
	 * @param _allMessagesChecked
2211
	 */
2212
	mail_callFlagMessages: function(_action, _elems, _allMessagesChecked)
2213
	{
2214
		/**
2215
		 * vars
2216
		 */
2217
		var folder = '',
2218
			tree = {},
2219
			formData = {},
2220
			data = {
2221
				msg: [this.et2.getArrayMgr("content").getEntry('mail_id')] || '',
2222
				all: _allMessagesChecked || false,
2223
				popup: typeof this.et2_view!='undefined' || egw(window).is_popup() || false,
2224
				activeFilters: _action.id == 'readall'? false : this.mail_getActiveFilters(_action)
2225
			},
2226
			rowClass = _action.id;
2227
2228
		if (typeof _elems === 'undefined' || _elems.length == 0)
2229
		{
2230
			if (this.mail_isMainWindow && this.mail_currentlyFocussed)
2231
			{
2232
				data.msg = [this.mail_currentlyFocussed];
2233
				_elems = data;
2234
				data.msg = this.mail_getFormData(_elems).msg;
2235
			}
2236
		}
2237
		else // action called by contextmenu
2238
		{
2239
			data.msg = this.mail_getFormData(_elems).msg;
2240
		}
2241
		switch (_action.id)
2242
		{
2243
			case 'read':
2244
				rowClass = 'seen';
2245
				if (data.popup)
2246
				{
2247
					var et_2 = typeof this.et2_view!='undefined'? etemplate2:opener.etemplate2;
2248
					tree = et_2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
2249
				}
2250
				else
2251
				{
2252
					tree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
2253
				}
2254
				folder = tree.getSelectedNode().id;
2255
				break;
2256
			case 'readall':
2257
				rowClass = 'seen';
2258
				break;
2259
			case 'label1':
2260
				rowClass = 'labelone';
2261
				break;
2262
			case 'label2':
2263
				rowClass = 'labeltwo';
2264
				break;
2265
			case 'label3':
2266
				rowClass = 'labelthree';
2267
				break;
2268
			case 'label4':
2269
				rowClass = 'labelfour';
2270
				break;
2271
			case 'label5':
2272
				rowClass = 'labelfive';
2273
				break;
2274
			default:
2275
				break;
2276
		}
2277
		jQuery(data).extend({},data, formData);
2278
		if (data['all']=='cancel') return false;
2279
2280
		if (_action.id.substring(0,2)=='un') {
2281
			//old style, only available for undelete and unlabel (no toggle)
2282
			if ( _action.id=='unlabel') // this means all labels should be removed
2283
			{
2284
				var labels = ['labelone','labeltwo','labelthree','labelfour','labelfive'];
2285
				for (var i=0; i<labels.length; i++)	this.mail_removeRowClass(_elems,labels[i]);
2286
				this.mail_flagMessages(_action.id,data);
2287
			}
2288
			else
2289
			{
2290
				this.mail_removeRowClass(_elems,_action.id.substring(2));
2291
				this.mail_setRowClass(_elems,_action.id);
2292
				this.mail_flagMessages(_action.id,data);
2293
			}
2294
		}
2295
		else if (_action.id=='readall')
2296
		{
2297
			this.mail_flagMessages('read',data);
2298
		}
2299
		else
2300
		{
2301
			var msg_set = {msg:[]};
2302
			var msg_unset = {msg:[]};
2303
			var dataElem;
2304
			var flags;
2305
			var classes = '';
2306
			for (var i=0; i<data.msg.length; i++)
2307
			{
2308
				dataElem = egw.dataGetUIDdata(data.msg[i]);
2309
				if(typeof dataElem.data.flags == 'undefined')
2310
				{
2311
					dataElem.data.flags = {};
2312
				}
2313
				flags = dataElem.data.flags;
2314
				classes = dataElem.data['class'] || "";
2315
				classes = classes.split(' ');
2316
				// since we toggle we need to unset the ones already set, and set the ones not set
2317
				// flags is data, UI is done by class, so update both
2318
				// Flags are there or not, class names are flag or 'un'+flag
2319
				if(classes.indexOf(rowClass) >= 0)
2320
				{
2321
					classes.splice(classes.indexOf(rowClass),1);
2322
				}
2323
				if(classes.indexOf('un' + rowClass) >= 0)
2324
				{
2325
					classes.splice(classes.indexOf('un' + rowClass),1);
2326
				}
2327
				if (flags[_action.id])
2328
				{
2329
					msg_unset['msg'].push(data.msg[i]);
2330
					classes.push('un'+rowClass);
2331
					delete flags[_action.id];
2332
				}
2333
				else
2334
				{
2335
					msg_set['msg'].push(data.msg[i]);
2336
					flags[_action.id] = _action.id;
2337
					classes.push(rowClass);
2338
				}
2339
2340
				// Update cache & call callbacks - updates list
2341
				dataElem.data['class']  = classes.join(' ');
2342
				egw.dataStoreUID(data.msg[i],dataElem.data);
2343
2344
				//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
2345
				this.updateFilter_data(data.msg[i], _action.id, data.activeFilters);
2346
			}
2347
2348
			// Notify server of changes
2349
			if (msg_unset['msg'] && msg_unset['msg'].length)
2350
			{
2351
				if (!data['all']) this.mail_flagMessages('un'+_action.id,msg_unset);
2352
			}
2353
			if (msg_set['msg'] && msg_set['msg'].length)
2354
			{
2355
				if (!data['all']) this.mail_flagMessages(_action.id,msg_set);
2356
			}
2357
			//server must do the toggle, as we apply to ALL, not only the visible
2358
			if (data['all']) this.mail_flagMessages(_action.id,data);
2359
			// No further update needed, only in case of read, the counters should be refreshed
2360
			if (_action.id=='read') this.mail_refreshFolderStatus(folder,'thisfolderonly',false,true);
2361
			return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
2362
		}
2363
	},
2364
2365
	/**
2366
	 * Update changes on filtered mail rows in nm, triggers manual refresh
2367
	 *
2368
	 * @param {type} _uid mail uid
2369
	 * @param {type} _actionId action id sended by nm action
2370
	 * @param {type} _filters activefilters
2371
	 */
2372
	updateFilter_data: function (_uid, _actionId, _filters)
2373
	{
2374
		var uid = _uid.replace('mail::','');
2375
		var action = '';
2376
		switch (_actionId)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2377
		{
2378
			case 'flagged':
2379
				action = 'flagged';
2380
				break;
2381
			case 'read':
2382
				if (_filters.filter == 'seen')
2383
				{
2384
					action = 'seen';
2385
				}
2386
				else if (_filters.filter == 'unseen')
2387
				{
2388
					action = 'unseen';
2389
				}
2390
				break;
2391
			case 'label1':
2392
				action = 'keyword1';
2393
				break;
2394
			case 'label2':
2395
				action = 'keyword2';
2396
				break;
2397
			case 'label3':
2398
				action = 'keyword3';
2399
				break;
2400
			case 'label4':
2401
				action = 'keyword4';
2402
				break;
2403
			case 'label4':
2404
				action = 'keyword4';
2405
				break;
2406
		}
2407
		if (action == _filters.filter)
2408
		{
2409
			egw.refresh('','mail',uid, 'delete');
2410
		}
2411
	},
2412
2413
	/**
2414
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2415
	 *
2416
	 * @param {object} _flag
2417
	 * @param {object} _elems
2418
	 * @param {boolean} _isPopup
2419
	 */
2420
	mail_flagMessages: function(_flag, _elems,_isPopup)
2421
	{
2422
		egw.jsonq('mail.mail_ui.ajax_flagMessages',[_flag, _elems]);
2423
		//	.sendRequest(true);
2424
	},
2425
2426
	/**
2427
	 * display header lines, or source of mail, depending on the url given
2428
	 *
2429
	 * @param _url
2430
	 */
2431
	mail_displayHeaderLines: function(_url) {
2432
		// only used by right clickaction
2433
		egw_openWindowCentered(_url,'mail_display_headerLines','870','600',window.outerWidth/2,window.outerHeight/2);
2434
	},
2435
2436
	/**
2437
	 * View header of a message
2438
	 *
2439
	 * @param _action
2440
	 * @param _elems _elems[0].id is the row-id
2441
	 */
2442
	mail_header: function(_action, _elems)
2443
	{
2444
		if (typeof _elems == 'undefined'|| _elems.length==0)
2445
		{
2446
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2447
			{
2448
				var _elems = [];
2449
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2450
			}
2451
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2452
			{
2453
				if (this.mail_currentlyFocussed)
2454
				{
2455
					var _elems = [];
2456
					_elems.push({id:this.mail_currentlyFocussed});
2457
				}
2458
			}
2459
		}
2460
		//alert('mail_header('+_elems[0].id+')');
2461
		var url = window.egw_webserverUrl+'/index.php?';
2462
		url += 'menuaction=mail.mail_ui.displayHeader';	// todo compose for Draft folder
2463
		url += '&id='+_elems[0].id;
2464
		this.mail_displayHeaderLines(url);
2465
	},
2466
2467
	/**
2468
	 * View message source
2469
	 *
2470
	 * @param _action
2471
	 * @param _elems _elems[0].id is the row-id
2472
	 */
2473
	mail_mailsource: function(_action, _elems)
2474
	{
2475
		if (typeof _elems == 'undefined' || _elems.length==0)
2476
		{
2477
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2478
			{
2479
				var _elems = [];
2480
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2481
			}
2482
			if ((typeof _elems == 'undefined'|| _elems.length==0) && this.mail_isMainWindow)
2483
			{
2484
				if (this.mail_currentlyFocussed)
2485
				{
2486
					var _elems = [];
2487
					_elems.push({id:this.mail_currentlyFocussed});
2488
				}
2489
			}
2490
		}
2491
		//alert('mail_mailsource('+_elems[0].id+')');
2492
		var url = window.egw_webserverUrl+'/index.php?';
2493
		url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2494
		url += '&id='+_elems[0].id;
2495
		url += '&location=display';
2496
		this.mail_displayHeaderLines(url);
2497
	},
2498
2499
	/**
2500
	 * Save a message
2501
	 *
2502
	 * @param _action
2503
	 * @param _elems _elems[0].id is the row-id
2504
	 */
2505
	mail_save: function(_action, _elems)
2506
	{
2507
		if (typeof _elems == 'undefined' || _elems.length==0)
2508
		{
2509
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2510
			{
2511
				var _elems = [];
2512
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2513
			}
2514
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2515
			{
2516
				if (this.mail_currentlyFocussed)
2517
				{
2518
					var _elems = [];
2519
					_elems.push({id:this.mail_currentlyFocussed});
2520
				}
2521
			}
2522
		}
2523
2524
		for (var i in _elems)
2525
		{
2526
			//alert('mail_save('+_elems[0].id+')');
2527
			var url = window.egw_webserverUrl+'/index.php?';
2528
			url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2529
			url += '&id='+_elems[i].id;
2530
			var a = document.createElement('a');
2531
			a = jQuery(a)
2532
				.prop('href', url)
2533
				.prop('download',"")
2534
				.appendTo(this.et2.getDOMNode());
2535
			var evt = document.createEvent('MouseEvent');
2536
			evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
2537
			a[0].dispatchEvent(evt);
2538
			a.remove();
2539
		}
2540
	},
2541
2542
	/**
2543
	 * User clicked an address (FROM, TO, etc)
2544
	 *
2545
	 * @param {object} tag_info with values for attributes id, label, title, ...
2546
	 * @param {widget object} widget
2547
	 *
2548
	 * @todo seems this function is not implemented, need to be checked if it is neccessary at all
2549
	 */
2550
	address_click: function(tag_info, widget)
2551
	{
2552
2553
	},
2554
2555
	/**
2556
	 * displayAttachment
2557
	 *
2558
	 * @param {object} tag_info
2559
	 * @param {widget object} widget
2560
	 * @param {object} calledForCompose
2561
	 */
2562
	displayAttachment: function(tag_info, widget, calledForCompose)
2563
	{
2564
		var mailid;
2565
		var attgrid;
2566
		if (typeof calledForCompose == 'undefined' || typeof calledForCompose == 'object') calledForCompose=false;
2567
		if (calledForCompose===false)
2568
		{
2569
			if (this.mail_isMainWindow)
2570
			{
2571
				mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2572
				var p = widget.getParent();
2573
				var cont = p.getArrayMgr("content").data;
2574
				attgrid = cont[widget.id.replace(/\[filename\]/,'')];
2575
			}
2576
			else
2577
			{
2578
				mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2579
				attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[filename\]/,'')];
2580
			}
2581
		}
2582
		if (calledForCompose===true)
2583
		{
2584
			// CALLED FOR COMPOSE; processedmail_id could hold several IDs seperated by comma
2585
			attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2586
			var mailids = this.et2.getArrayMgr("content").getEntry('processedmail_id');
2587
			var mailida = mailids.split(',');
2588
			// either several attachments of one email, or multiple emlfiles
2589
			mailid = mailida.length==1 ? mailida[0] : mailida[widget.id.replace(/\[name\]/,'')];
2590
			if (typeof attgrid.uid != 'undefined' && attgrid.uid && mailid.indexOf(attgrid.uid)==-1)
2591
			{
2592
				for (var i=0; i<mailida.length; i++)
2593
				{
2594
					if (mailida[i].indexOf('::'+attgrid.uid)>-1) mailid = mailida[i];
2595
				}
2596
			}
2597
		}
2598
		var url = window.egw_webserverUrl+'/index.php?';
2599
		var width;
2600
		var height;
2601
		var windowName ='mail';
2602
		switch(attgrid.type.toUpperCase())
0 ignored issues
show
Bug introduced by
The variable attgrid does not seem to be initialized in case calledForCompose === false on line 2567 is false. Are you sure this can never be the case?
Loading history...
2603
		{
2604
			case 'MESSAGE/RFC822':
2605
				url += 'menuaction=mail.mail_ui.displayMessage';	// todo compose for Draft folder
2606
				url += '&mode=display';//message/rfc822 attachments should be opened in display mode
2607
				url += '&id='+mailid;
0 ignored issues
show
Bug introduced by
The variable mailid does not seem to be initialized in case calledForCompose === false on line 2567 is false. Are you sure this can never be the case?
Loading history...
2608
				url += '&part='+attgrid.partID;
2609
				url += '&is_winmail='+attgrid.winmailFlag;
2610
				windowName = windowName+'displayMessage_'+mailid+'_'+attgrid.partID;
2611
				width = 870;
2612
				height = egw_getWindowOuterHeight();
2613
				break;
2614
			case 'IMAGE/JPEG':
2615
			case 'IMAGE/PNG':
2616
			case 'IMAGE/GIF':
2617
			case 'IMAGE/BMP':
2618
			case 'APPLICATION/PDF':
2619
			case 'TEXT/PLAIN':
2620
			case 'TEXT/HTML':
2621
			case 'TEXT/DIRECTORY':
2622
/*
2623
				$sfxMimeType = $value['mimeType'];
2624
				$buff = explode('.',$value['name']);
2625
				$suffix = '';
2626
				if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime
2627
				if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix);
2628
				if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD')
2629
				{
2630
					$attachments[$key]['mimeType'] = $sfxMimeType;
2631
					$value['mimeType'] = strtoupper($sfxMimeType);
2632
				}
2633
*/
2634
			case 'TEXT/X-VCARD':
2635
			case 'TEXT/VCARD':
2636
			case 'TEXT/CALENDAR':
2637
			case 'TEXT/X-VCALENDAR':
2638
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2639
				url += '&id='+mailid;
2640
				url += '&part='+attgrid.partID;
2641
				url += '&is_winmail='+attgrid.winmailFlag;
2642
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2643
				var reg = '800x600';
2644
				var reg2;
2645
				// handle calendar/vcard
2646
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2647
				{
2648
					windowName = 'maildisplayEvent_'+mailid+'_'+attgrid.partID;
2649
					reg2 = egw.link_get_registry('calendar');
2650
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2651
					{
2652
						reg = reg2['view_popup'];
2653
					}
2654
				}
2655
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2656
				{
2657
					windowName = 'maildisplayContact_'+mailid+'_'+attgrid.partID;
2658
					reg2 = egw.link_get_registry('addressbook');
2659
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2660
					{
2661
						reg = reg2['add_popup'];
2662
					}
2663
				}
2664
				var w_h =reg.split('x');
2665
				width = w_h[0];
2666
				height = w_h[1];
2667
				break;
2668
			default:
2669
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2670
				url += '&id='+mailid;
2671
				url += '&part='+attgrid.partID;
2672
				url += '&is_winmail='+attgrid.winmailFlag;
2673
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2674
				width = 870;
2675
				height = 600;
2676
				break;
2677
		}
2678
		egw_openWindowCentered(url,windowName,width,height);
2679
	},
2680
2681
	/**
2682
	 * displayUploadedFile
2683
	 *
2684
	 * @param {object} tag_info
2685
	 * @param {widget object} widget
2686
	 */
2687
	displayUploadedFile: function(tag_info, widget)
2688
	{
2689
		var attgrid;
2690
		attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2691
2692
		if (attgrid.uid && (attgrid.partID||attgrid.folder))
2693
		{
2694
			this.displayAttachment(tag_info, widget, true);
2695
			return;
2696
		}
2697
		var get_param = {
2698
			menuaction: 'mail.mail_compose.getAttachment',	// todo compose for Draft folder
2699
			tmpname: attgrid.tmp_name,
2700
			etemplate_exec_id: this.et2._inst.etemplate_exec_id
2701
		};
2702
		var width;
2703
		var height;
2704
		var windowName ='maildisplayAttachment_'+attgrid.file.replace(/\//g,"_");
2705
		switch(attgrid.type.toUpperCase())
2706
		{
2707
			case 'IMAGE/JPEG':
2708
			case 'IMAGE/PNG':
2709
			case 'IMAGE/GIF':
2710
			case 'IMAGE/BMP':
2711
			case 'APPLICATION/PDF':
2712
			case 'TEXT/PLAIN':
2713
			case 'TEXT/HTML':
2714
			case 'TEXT/DIRECTORY':
2715
			case 'TEXT/X-VCARD':
2716
			case 'TEXT/VCARD':
2717
			case 'TEXT/CALENDAR':
2718
			case 'TEXT/X-VCALENDAR':
2719
				var reg = '800x600';
2720
				var reg2;
2721
				// handle calendar/vcard
2722
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2723
				{
2724
					windowName = 'maildisplayEvent_'+attgrid.file.replace(/\//g,"_");
2725
					reg2 = egw.link_get_registry('calendar');
2726
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2727
					{
2728
						reg = reg2['view_popup'];
2729
					}
2730
				}
2731
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2732
				{
2733
					windowName = 'maildisplayContact_'+attgrid.file.replace(/\//g,"_");
2734
					reg2 = egw.link_get_registry('addressbook');
2735
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2736
					{
2737
						reg = reg2['add_popup'];
2738
					}
2739
				}
2740
				var w_h =reg.split('x');
2741
				width = w_h[0];
2742
				height = w_h[1];
2743
				break;
2744
			case 'MESSAGE/RFC822':
2745
			default:
2746
				get_param.mode = 'save';
2747
				width = 870;
2748
				height = 600;
2749
				break;
2750
		}
2751
		egw.openPopup(egw.link('/index.php', get_param), width, height, windowName);
2752
	},
2753
2754
	saveAttachment: function(tag_info, widget)
2755
	{
2756
		var mailid;
2757
		var attgrid;
2758
		if (this.mail_isMainWindow)
2759
		{
2760
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2761
			var p = widget.getParent();
2762
			var cont = p.getArrayMgr("content").data;
2763
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2764
		}
2765
		else
2766
		{
2767
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2768
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2769
		}
2770
		var url = window.egw_webserverUrl+'/index.php?';
2771
		url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2772
		url += '&mode=save';
2773
		url += '&id='+mailid;
2774
		url += '&part='+attgrid.partID;
2775
		url += '&is_winmail='+attgrid.winmailFlag;
2776
		this.et2._inst.download(url);
2777
	},
2778
2779
	saveAllAttachmentsToZip: function(tag_info, widget)
2780
	{
2781
		var mailid;
2782
		var attgrid;
2783
		if (this.mail_isMainWindow)
2784
		{
2785
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2786
			var p = widget.getParent();
2787
			var cont = p.getArrayMgr("content").data;
2788
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2789
		}
2790
		else
2791
		{
2792
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2793
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2794
		}
2795
		var url = window.egw_webserverUrl+'/index.php?';
2796
		url += 'menuaction=mail.mail_ui.download_zip';	// todo compose for Draft folder
2797
		url += '&mode=save';
2798
		url += '&id='+mailid;
2799
		this.et2._inst.download(url);
2800
	},
2801
2802
	saveAttachmentToVFS: function(tag_info, widget)
2803
	{
2804
		var mailid;
2805
		var attgrid;
2806
		if (this.mail_isMainWindow)
2807
		{
2808
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2809
			var p = widget.getParent();
2810
			var cont = p.getArrayMgr("content").data;
2811
			attgrid = cont[widget.id.replace(/\[saveAsVFS\]/,'')];
2812
		}
2813
		else
2814
		{
2815
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2816
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[saveAsVFS\]/,'')];
2817
		}
2818
		var url = window.egw_webserverUrl+'/index.php?';
2819
		var width=640;
2820
		var height=570;
2821
		var windowName ='mail';
2822
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2823
		url += '&mode=saveas';
2824
		url += '&id='+mailid+'::'+attgrid.partID+'::'+attgrid.winmailFlag;
2825
		url += '&name='+attgrid.filename;
2826
		url += '&type='+attgrid.type.toLowerCase();
2827
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2828
		url += '&label='+egw.lang('Save');
2829
		egw_openWindowCentered(url,windowName,width,height);
2830
	},
2831
2832
	saveAllAttachmentsToVFS: function(tag_info, widget)
2833
	{
2834
		var mailid;
2835
		var attgrid;
2836
		if (this.mail_isMainWindow)
2837
		{
2838
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2839
			var p = widget.getParent();
2840
			attgrid = p.getArrayMgr("content").data;
2841
		}
2842
		else
2843
		{
2844
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2845
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments');
2846
		}
2847
		var url = window.egw_webserverUrl+'/index.php?';
2848
		var width=640;
2849
		var height=570;
2850
		var windowName ='mail';
2851
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2852
		url += '&mode=select-dir';
2853
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2854
		url += '&label='+egw.lang('Save all');
2855
		for (var i=0;i<attgrid.length;i++)
2856
		{
2857
			if (attgrid[i] != null) url += '&id['+i+']='+mailid+'::'+attgrid[i].partID+'::'+attgrid[i].winmailFlag+'::'+attgrid[i].filename;
2858
		}
2859
		egw_openWindowCentered(url,windowName,width,height);
2860
	},
2861
2862
	/**
2863
	 * Save a message to filemanager
2864
	 *
2865
	 * @param _action
2866
	 * @param _elems _elems[0].id is the row-id
2867
	 */
2868
	mail_save2fm: function(_action, _elems)
2869
	{
2870
		if (typeof _elems == 'undefined' || _elems.length==0)
2871
		{
2872
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2873
			{
2874
				var _elems = [];
2875
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2876
			}
2877
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2878
			{
2879
				if (this.mail_currentlyFocussed)
2880
				{
2881
					var _elems = [];
2882
					_elems.push({id:this.mail_currentlyFocussed});
2883
				}
2884
			}
2885
		}
2886
		var url = window.egw_webserverUrl+'/index.php?';
2887
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2888
		url += '&mode='+ (_elems.length>1?'select-dir':'saveas');
2889
		url += '&mime=message'+encodeURIComponent('/')+'rfc822';
2890
		url += '&method=mail.mail_ui.vfsSaveMessage';
2891
		url += '&label='+(_elems.length>1?egw.lang('Save all'):egw.lang('save'));
2892
2893
		for (var i in _elems)
2894
		{
2895
			var _id = _elems[i].id;
2896
			var dataElem = egw.dataGetUIDdata(_id);
2897
			var subject = dataElem? dataElem.data.subject: _elems[i].subject;
2898
			var filename = subject.replace(/[\f\n\t\v]/g,"_")|| 'unknown';
2899
			if (_elems.length>1)
2900
			{
2901
				url += '&id['+i+']='+_id;
2902
				url += '&name['+i+']='+encodeURIComponent(filename+'.eml');
2903
			}
2904
			else
2905
			{
2906
				url += '&id='+_id;
2907
				url += '&name='+encodeURIComponent(filename+'.eml');
2908
			}
2909
2910
		}
2911
		egw.openPopup(url,'680','400','vfs_save_messages', 'filemanager');
2912
	},
2913
2914
	/**
2915
	 * Integrate mail message into another app's entry
2916
	 *
2917
	 * @param _action
2918
	 * @param _elems _elems[0].id is the row-id
2919
	 */
2920
	mail_integrate: function(_action, _elems)
2921
	{
2922
		var app = _action.id;
2923
		var w_h = ['750','580']; // define a default wxh if there's no popup size registered
2924
2925
		if (typeof _action.data != 'undefined' )
2926
		{
2927
			if (typeof _action.data.popup != 'undefined' && _action.data.popup) w_h = _action.data.popup.split('x');
2928
			if (typeof _action.data.mail_import != 'undefined') var mail_import_hook = _action.data.mail_import;
2929
		}
2930
2931
		if (typeof _elems == 'undefined' || _elems.length==0)
2932
		{
2933
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2934
			{
2935
				var _elems = [];
2936
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2937
			}
2938
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2939
			{
2940
				if (this.mail_currentlyFocussed)
2941
				{
2942
					var _elems = [];
2943
					_elems.push({id:this.mail_currentlyFocussed});
2944
				}
2945
			}
2946
		}
2947
2948
		var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
2949
2950
		if (mail_import_hook && typeof mail_import_hook.app_entry_method != 'undefined')
2951
		{
2952
			var data = egw.dataGetUIDdata(_elems[0].id);
2953
			var subject = (data && typeof data.data != 'undefined')? data.data.subject : '';
2954
			this.integrate_checkAppEntry('Select '+ app + ' entry', app, subject, url,  mail_import_hook.app_entry_method, function (args){
2955
				egw_openWindowCentered(args.url+ (args.entryid ?'&entry_id=' + args.entryid: ''),'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2956
			});
2957
		}
2958
		else
2959
		{
2960
			egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2961
		}
2962
2963
	},
2964
2965
   /**
2966
	* Checks the application entry existance and offers user
2967
	* to select desire app id to append mail content into it,
2968
	* or add the mail content as a new app entry
2969
	*
2970
	* @param {string} _title select app entry title
2971
	* @param {string} _appName app to be integrated
2972
	* @param {string} _subject
2973
	* @param {string} _url
2974
	* @param {string} _appCheckCallback registered mail_import hook method
2975
	* @param {function} _execCallback function to get called on dialog actions
2976
	*/
2977
	integrate_checkAppEntry: function (_title, _appName, _subject ,_url, _appCheckCallback, _execCallback)
2978
	{
2979
	   var subject = _subject || '';
2980
	   var execCallback = _execCallback;
2981
	   egw.json(_appCheckCallback, subject,function(_entryId){
2982
2983
		   // if there's no entry saved already
2984
		   // open dialog in order to select one
2985
		   if (!_entryId)
2986
		   {
2987
			   var buttons = [
2988
				   {text: 'Append', id: 'append', image: 'check', default:true},
2989
				   {text: 'Add as new', id: 'new', image: 'check'},
2990
				   {text: 'Cancel', id: 'cancel', image: 'check'}
2991
			   ];
2992
			   et2_createWidget("dialog",
2993
			   {
2994
				   callback: function(_buttons, _value)
2995
				   {
2996
					   if (_buttons == 'cancel') return;
2997
					   if (_buttons == 'append' && _value)
2998
					   {
2999
						   _entryId = _value.id;
3000
					   }
3001
					   execCallback.call(this,{entryid:_entryId,url:_url});
3002
				   },
3003
				   title: egw.lang(_title),
3004
				   buttons: buttons||et2_dialog.BUTTONS_OK_CANCEL,
3005
				   value:{
3006
					   content:{
3007
						   appName:_appName // appName to search on its list later
3008
				   }},
3009
				   template: egw.webserverUrl+'/mail/templates/default/integration_to_entry_dialog.xet'
3010
			   },et2_dialog._create_parent('mail'));
3011
		   }
3012
		   else // there is an entry saved related to this mail's subject
3013
		   {
3014
			   execCallback.call(this,{entryid:_entryId,url:_url});
3015
		   }
3016
	   },this,true,this).sendRequest();
3017
	},
3018
3019
	/**
3020
	 * mail_getFormData
3021
	 *
3022
	 * @param {object} _actionObjects the senders
3023
	 *
3024
	 * @return structured array of message ids: array(msg=>message-ids)
3025
	 */
3026
	mail_getFormData: function(_actionObjects) {
3027
		var messages = {};
3028
		// if
3029
		if (typeof _actionObjects['msg'] != 'undefined' && _actionObjects['msg'].length>0) return _actionObjects;
3030
		if (_actionObjects.length>0)
3031
		{
3032
			messages['msg'] = [];
3033
		}
3034
3035
		for (var i = 0; i < _actionObjects.length; i++)
3036
		{
3037
			if (_actionObjects[i].id.length>0)
3038
			{
3039
				messages['msg'][i] = _actionObjects[i].id;
3040
			}
3041
		}
3042
3043
		return messages;
3044
	},
3045
3046
	/**
3047
	 * mail_setRowClass
3048
	 *
3049
	 * @param {object} _actionObjects the senders
3050
	 * @param {string} _class
3051
	 */
3052
	mail_setRowClass: function(_actionObjects,_class) {
3053
		if (typeof _class == 'undefined') return false;
3054
3055
		if (typeof _actionObjects['msg'] == 'undefined')
3056
		{
3057
			for (var i = 0; i < _actionObjects.length; i++)
3058
			{
3059
				// Check that the ID & interface is there.  Paste is missing iface.
3060
				if (_actionObjects[i].id.length>0 && _actionObjects[i].iface)
3061
				{
3062
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3063
					dataElem.addClass(_class);
3064
3065
				}
3066
			}
3067
		}
3068
		else
3069
		{
3070
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3071
			{
3072
				var mail_uid = _actionObjects['msg'][i];
3073
3074
				// Get the record from data cache
3075
				var dataElem = egw.dataGetUIDdata(mail_uid);
3076
				if(dataElem == null || typeof dataElem == undefined)
3077
				{
3078
					// Unknown ID, nothing to update
3079
					return;
3080
				}
3081
3082
				// Update class
3083
				dataElem.data['class']  += ' ' + _class;
3084
3085
				// need to update flags too
3086
				switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3087
				{
3088
					case 'unseen':
3089
						delete dataElem.data.flags.read;
3090
						break;
3091
				}
3092
3093
				// Update record, which updates all listeners (including nextmatch)
3094
				egw.dataStoreUID(mail_uid,dataElem.data);
3095
			}
3096
		}
3097
	},
3098
3099
	/**
3100
	 * mail_removeRowFlag
3101
	 * Removes a flag and updates the CSS class.  Updates the UI, but not the server.
3102
	 *
3103
	 * @param {action object} _actionObjects the senders, or a messages object
3104
	 * @param {string} _class the class to be removed
3105
	 */
3106
	mail_removeRowClass: function(_actionObjects,_class) {
3107
		if (typeof _class == 'undefined') return false;
3108
3109
		if (typeof _actionObjects['msg'] == 'undefined')
3110
		{
3111
			for (var i = 0; i < _actionObjects.length; i++)
3112
			{
3113
				if (_actionObjects[i].id.length>0)
3114
				{
3115
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3116
					dataElem.removeClass(_class);
3117
3118
				}
3119
			}
3120
		}
3121
		else
3122
		{
3123
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3124
			{
3125
				var mail_uid = _actionObjects['msg'][i];
3126
3127
				// Get the record from data cache
3128
				var dataElem = egw.dataGetUIDdata(mail_uid);
3129
				if(dataElem == null || typeof dataElem == undefined)
3130
				{
3131
					// Unknown ID, nothing to update
3132
					return;
3133
				}
3134
3135
				// Update class
3136
				var classes = dataElem.data['class'] || "";
3137
				classes = classes.split(' ');
3138
				if(classes.indexOf(_class) >= 0)
3139
				{
3140
					classes.splice(classes.indexOf(_class),1);
3141
					dataElem.data['class'] = classes.join(' ');
3142
3143
					// need to update flags too
3144
					switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3145
					{
3146
						case 'unseen':
3147
							dataElem.data.flags.read = true;
3148
							break;
3149
					}
3150
3151
					// Update record, which updates all listeners (including nextmatch)
3152
					egw.dataStoreUID(mail_uid,dataElem.data);
3153
				}
3154
			}
3155
		}
3156
	},
3157
3158
	/**
3159
	 * mail_move2folder - implementation of the move action from action menu
3160
	 *
3161
	 * @param _action _action.id holds folder target information
3162
	 * @param _elems - the representation of the elements to be affected
3163
	 */
3164
	mail_move2folder: function(_action, _elems) {
3165
		this.mail_move(_action, _elems, null);
3166
	},
3167
3168
	/**
3169
	 * mail_move - implementation of the move action from drag n drop
3170
	 *
3171
	 * @param _action
3172
	 * @param _senders - the representation of the elements dragged
3173
	 * @param _target - the representation of the target
3174
	 */
3175
	mail_move: function(_action,_senders,_target) {
3176
		this.mail_checkAllSelected(_action,_senders,_target,true);
3177
	},
3178
3179
	/**
3180
	 * mail_move - implementation of the move action from drag n drop
3181
	 *
3182
	 * @param _action
3183
	 * @param _senders - the representation of the elements dragged
3184
	 * @param _target - the representation of the target
3185
	 * @param _allMessagesChecked
3186
	 */
3187
	mail_callMove: function(_action,_senders,_target,_allMessagesChecked) {
3188
		var target = _action.id == 'drop_move_mail' ? _target.iface.id : _action.id.substr(5);
3189
		var messages = this.mail_getFormData(_senders);
3190
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3191
3192
		// Directly delete any cache for target
3193
		if(window.localStorage)
3194
		{
3195
			for(var i = 0; i < window.localStorage.length; i++)
3196
			{
3197
				var key = window.localStorage.key(i);
3198
3199
				// Find directly by what the key would look like
3200
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+target+'"') == 0)
3201
				{
3202
					window.localStorage.removeItem(key);
3203
				}
3204
			}
3205
		}
3206
		// TODO: Write move/copy function which cares about doing the same stuff
3207
		// as the "onNodeSelect" function!
3208
		messages['all'] = _allMessagesChecked;
3209
		if (messages['all']=='cancel') return false;
3210
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3211
3212
		// Make sure a default target folder is set in case of drop target is parent 0 (mail account name)
3213
		if (!target.match(/::/g)) target += '::INBOX';
3214
3215
		var self = this;
3216
		var nm = this.et2.getWidgetById(this.nm_index);
3217
		// thev 4th param indicates if it is a normal move messages action. if not the action is a move2.... (archiveFolder) action
3218
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages, 'move', (_action.id.substr(0,4)=='move'&&_action.id.substr(4,1)=='2'?'2':'_') ], function(){
3219
			self.unlock_tree();
3220
			// Nextmatch automatically selects the next row and calls preview.
3221
			// Unselect it and thanks to the timeout selectionMgr uses, preview
3222
			// will close when the selection callback fires instead of load the
3223
			// next message
3224
			nm.controller._selectionMgr.resetSelection();
3225
3226
			// Server response may contain refresh, but it's always delete
3227
			// Refresh list if current view is the target (happens when pasting)
3228
			var tree = self.et2.getWidgetById('nm[foldertree]');
3229
			if(nm && tree && target == tree.getValue())
3230
			{
3231
				// Can't trust the sorting, needs to be full refresh
3232
				nm.refresh();
3233
			}
3234
		})
3235
			.sendRequest();
3236
		this.mail_setRowClass(_senders,'deleted');
3237
		// Server response may contain refresh, not needed here
3238
	},
3239
3240
	/**
3241
	 * mail_copy - implementation of the move action from drag n drop
3242
	 *
3243
	 * @param _action
3244
	 * @param _senders - the representation of the elements dragged
3245
	 * @param _target - the representation of the target
3246
	 */
3247
	mail_copy: function(_action,_senders,_target) {
3248
		this.mail_checkAllSelected(_action,_senders,_target,true);
3249
	},
3250
3251
	/**
3252
	 * mail_callCopy - implementation of the copy action from drag n drop
3253
	 *
3254
	 * @param _action
3255
	 * @param _senders - the representation of the elements dragged
3256
	 * @param _target - the representation of the target
3257
	 * @param _allMessagesChecked
3258
	 */
3259
	mail_callCopy: function(_action,_senders,_target,_allMessagesChecked) {
3260
		var target = _action.id == 'drop_copy_mail' ? _target.iface.id : _action.id.substr(5);
3261
		var messages = this.mail_getFormData(_senders);
3262
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3263
		// TODO: Write move/copy function which cares about doing the same stuff
3264
		// as the "onNodeSelect" function!
3265
		messages['all'] = _allMessagesChecked;
3266
		if (messages['all']=='cancel') return false;
3267
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3268
		var self = this;
3269
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages],function (){self.unlock_tree();})
3270
			.sendRequest();
3271
		// Server response contains refresh
3272
	},
3273
3274
	/**
3275
	 * mail_AddFolder - implementation of the AddFolder action of right click options on the tree
3276
	 *
3277
	 * @param _action
3278
	 * @param _senders - the representation of the tree leaf to be manipulated
3279
	 */
3280
	mail_AddFolder: function(_action,_senders) {
3281
		//action.id == 'add'
3282
		//_senders.iface.id == target leaf / leaf to edit
3283
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3284
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3285
		var buttons = [
3286
			{text: this.egw.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
3287
			{text: this.egw.lang("Cancel"), id:"cancel"}
3288
		];
3289
		et2_dialog.show_prompt(function(_button_id, _value) {
3290
			var NewFolderName = null;
3291
			if (_value.length>0) NewFolderName = _value;
3292
			//alert(NewFolderName);
3293
			if (NewFolderName && NewFolderName.length>0)
3294
			{
3295
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3296
				{
3297
					case "add":
3298
						egw.json('mail.mail_ui.ajax_addFolder',[_senders[0].id, NewFolderName])
3299
							.sendRequest(true);
3300
						return;
3301
					case "cancel":
3302
				}
3303
			}
3304
		},
3305
		this.egw.lang("Enter the name for the new Folder:"),
3306
		this.egw.lang("Add a new Folder to %1:",OldFolderName),
3307
		'', buttons);
3308
	},
3309
3310
	/**
3311
	 * mail_RenameFolder - implementation of the RenameFolder action of right click options on the tree
3312
	 *
3313
	 * @param _action
3314
	 * @param _senders - the representation of the tree leaf to be manipulated
3315
	 */
3316
	mail_RenameFolder: function(_action,_senders) {
3317
		//action.id == 'rename'
3318
		//_senders.iface.id == target leaf / leaf to edit
3319
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3320
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3321
		var buttons = [
3322
			{text: this.egw.lang("Rename"), id: "rename", "class": "ui-priority-primary", image: 'edit', "default": true},
3323
			{text: this.egw.lang("Cancel"), id:"cancel"}
3324
		];
3325
		et2_dialog.show_prompt(function(_button_id, _value) {
3326
			var NewFolderName = null;
3327
			if (_value.length>0) NewFolderName = _value;
3328
			//alert(NewFolderName);
3329
			if (NewFolderName && NewFolderName.length>0)
3330
			{
3331
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3332
				{
3333
					case "rename":
3334
						egw.json('mail.mail_ui.ajax_renameFolder',[_senders[0].id, NewFolderName])
3335
							.sendRequest(true);
3336
						return;
3337
					case "cancel":
3338
				}
3339
			}
3340
		},
3341
		this.egw.lang("Rename Folder %1 to:",OldFolderName),
3342
		this.egw.lang("Rename Folder %1 ?",OldFolderName),
3343
		OldFolderName, buttons);
3344
	},
3345
3346
	/**
3347
	 * mail_MoveFolder - implementation of the MoveFolder action on the tree
3348
	 *
3349
	 * @param {egwAction} _action
3350
	 * @param {egwActionObject[]} _senders - the representation of the tree leaf to be manipulated
3351
	 * @param {egwActionObject} destination Drop target egwActionObject representing the destination
3352
	 */
3353
	mail_MoveFolder: function(_action,_senders,destination) {
3354
		if(!destination || !destination.id)
3355
		{
3356
			egw.debug('warn', "Move folder, but no target");
3357
			return;
3358
		}
3359
		var sourceProfile = _senders[0].id.split('::');
3360
		var targetProfile = destination.id.split('::');
3361
		if (sourceProfile[0]!=targetProfile[0])
3362
		{
3363
			egw.message(this.egw.lang('Moving Folders from one Mailaccount to another is not supported'),'error');
3364
			return;
3365
		}
3366
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3367
		var src_label = _senders[0].id.replace(/^[0-9]+::/,'');
3368
		var dest_label = destination.id.replace(/^[0-9]+::/,'');
3369
3370
		var callback = function (_button)
3371
		{
3372
			if (_button == et2_dialog.YES_BUTTON)
3373
			{
3374
				egw.appName='mail';
3375
				egw.message (egw.lang('Folder %1 is moving to folder %2',src_label,dest_label ));
3376
				egw.loading_prompt('mail_moveFolder', true,'','#egw_fw_basecontainer');
3377
				for(var i = 0; i < _senders.length; i++)
3378
				{
3379
					egw.jsonq('mail.mail_ui.ajax_MoveFolder',[_senders[i].id, destination.id],
3380
						// Move is done (successfully or not), remove loading
3381
						function() {
3382
							var id = destination.id.split('::');
3383
							//refersh the top parent
3384
							ftree.refreshItem(id[0],null);
3385
							egw.loading_prompt('mail_moveFolder', false);
3386
						}
3387
					);
3388
				}
3389
			}
3390
		};
3391
		et2_dialog.show_dialog(callback, this.egw.lang('Are you sure you want to move folder %1 to folder %2?',
3392
			src_label, dest_label), this.egw.lang('Move folder'), {},et2_dialog.BUTTONS_YES_NO,  et2_dialog.WARNING_MESSAGE);
3393
	},
3394
3395
	/**
3396
	 * mail_DeleteFolder - implementation of the DeleteFolder action of right click options on the tree
3397
	 *
3398
	 * @param _action
3399
	 * @param _senders - the representation of the tree leaf to be manipulated
3400
	 */
3401
	mail_DeleteFolder: function(_action,_senders) {
3402
		//action.id == 'delete'
3403
		//_senders.iface.id == target leaf / leaf to edit
3404
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3405
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3406
		var buttons = [
3407
			{text: this.egw.lang("Yes"), id: "delete", "class": "ui-priority-primary", "default": true},
3408
			{text: this.egw.lang("Cancel"), id:"cancel"}
3409
		];
3410
		et2_dialog.show_dialog(function(_button_id, _value) {
3411
			switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3412
			{
3413
				case "delete":
3414
					egw.json('mail.mail_ui.ajax_deleteFolder',[_senders[0].id])
3415
						.sendRequest(true);
3416
					return;
3417
				case "cancel":
3418
			}
3419
		},
3420
		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")),
3421
		this.egw.lang("DELETE Folder %1 ?",OldFolderName),
3422
		OldFolderName, buttons);
3423
	},
3424
3425
	/**
3426
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3427
	 *
3428
	 * @param _event
3429
	 * @param _file_count
3430
	 * @param {string?} _path where the file is uploaded to, default current directory
3431
	 */
3432
	uploadForImport: function(_event, _file_count, _path)
3433
	{
3434
		// path is probably not needed when uploading for file; maybe it is when from vfs
3435
		if(typeof _path == 'undefined')
3436
		{
3437
			//_path = this.get_path();
3438
		}
3439
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3440
		{
3441
			var widget = _event.data;
3442
//			var request = new egw_json_request('mail_ui::ajax_importMessage', ['upload', widget.getValue(), _path], this);
3443
//			widget.set_value('');
3444
//			request.sendRequest();//false, this._upload_callback, this);
3445
			this.et2_obj.submit();
3446
		}
3447
	},
3448
3449
	/**
3450
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3451
	 *
3452
	 * @param {event object} _event
3453
	 * @param {string} _file_count
3454
	 * @param {string} _path [_path=current directory] Where the file is uploaded to.
3455
	 */
3456
	uploadForCompose: function(_event, _file_count, _path)
3457
	{
3458
		// path is probably not needed when uploading for file; maybe it is when from vfs
3459
		if(typeof _path == 'undefined')
3460
		{
3461
			//_path = this.get_path();
3462
		}
3463
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3464
		{
3465
			var widget = _event.data;
3466
			this.et2_obj.submit();
3467
		}
3468
	},
3469
3470
	/**
3471
	 * Visible attachment box in compose dialog as soon as the file starts to upload
3472
	 */
3473
	composeUploadStart: function ()
3474
	{
3475
		var boxAttachment = this.et2.getWidgetById('attachments');
3476
		if (boxAttachment)
3477
		{
3478
			var groupbox = boxAttachment.getParent();
3479
			if (groupbox) groupbox.set_disabled(false);
3480
		}
3481
		//Resize the compose dialog
3482
		var self = this;
3483
		setTimeout(function(){self.compose_resizeHandler();}, 100);
3484
		return true;
3485
	},
3486
3487
	/**
3488
	* Upload for import (VFS)
3489
	*
3490
	* @param {egw object} _egw
3491
	* @param {widget object} _widget
3492
	* @param {window object} _window
3493
	*/
3494
	vfsUploadForImport: function(_egw, _widget, _window) {
3495
		if (jQuery.isEmptyObject(_widget)) return;
3496
		if (!jQuery.isEmptyObject(_widget.getValue()))
3497
		{
3498
			this.et2_obj.submit();
3499
		}
3500
	},
3501
3502
	/**
3503
	* Upload for compose (VFS)
3504
	*
3505
	* @param {egw object} _egw
3506
	* @param {widget object} _widget
3507
	* @param {window object} _window
3508
	*/
3509
	vfsUploadForCompose: function(_egw, _widget, _window)
3510
	{
3511
		if (jQuery.isEmptyObject(_widget)) return;
3512
		if (!jQuery.isEmptyObject(_widget.getValue()))
3513
		{
3514
			this.et2_obj.submit();
3515
		}
3516
	},
3517
3518
	/**
3519
	* Submit on change (VFS)
3520
	*
3521
	* @param {egw object} _egw
3522
	* @param {widget object} _widget
3523
	*/
3524
	submitOnChange: function(_egw, _widget)
3525
	{
3526
		if (!jQuery.isEmptyObject(_widget))
3527
		{
3528
			if (typeof _widget.id !== 'undefined') var widgetId = _widget.id;
3529
			switch (widgetId)
0 ignored issues
show
Bug introduced by
The variable widgetId does not seem to be initialized in case typeof _widget.id !== "undefined" on line 3528 is false. Are you sure this can never be the case?
Loading history...
3530
			{
3531
				case 'mimeType':
3532
					this.et2_obj.submit();
3533
					break;
3534
				default:
3535
					if (!jQuery.isEmptyObject(_widget.getValue()))
3536
					{
3537
						this.et2_obj.submit();
3538
					}
3539
			}
3540
		}
3541
	},
3542
3543
	/**
3544
	 * Save as Draft (VFS)
3545
	 * -handel both actions save as draft and save as draft and print
3546
	 *
3547
	 * @param {egwAction} _egw_action
3548
	 * @param {array|string} _action string "autosaving", if that triggered the action
3549
	 */
3550
	saveAsDraft: function(_egw_action, _action)
3551
	{
3552
		//this.et2_obj.submit();
3553
		var content = this.et2.getArrayMgr('content').data;
3554
		var action = _action;
3555
		if (_egw_action && _action !== 'autosaving')
3556
		{
3557
			action = _egw_action.id;
3558
		}
3559
3560
		var widgets = ['from','to','cc','bcc','subject','folder','replyto','mailaccount',
3561
			'mail_htmltext', 'mail_plaintext', 'lastDrafted', 'filemode', 'expiration', 'password'];
3562
		var widget = {};
3563
		for (var index in widgets)
3564
		{
3565
			widget = this.et2.getWidgetById(widgets[index]);
3566
			if (widget)
3567
			{
3568
				content[widgets[index]] = widget.get_value();
3569
			}
3570
		}
3571
		var self = this;
3572
		if (content)
3573
		{
3574
			// if we compose an encrypted message, we have to get the encrypted content
3575
			if (this.mailvelope_editor)
3576
			{
3577
				this.mailvelope_editor.encrypt([]).then(function(_armored)
3578
				{
3579
					content['mail_plaintext'] = _armored;
3580
					self.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3581
						self.savingDraft_response(_data,action);
3582
					}).sendRequest(true);
3583
				}, function(_err)
3584
				{
3585
					self.egw.message(_err.message, 'error');
3586
				});
3587
				return false;
3588
			}
3589
3590
			this.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3591
				self.savingDraft_response(_data,action);
3592
			}).sendRequest(true);
3593
		}
3594
	},
3595
3596
	/**
3597
	 * Set content of drafted message with new information sent back from server
3598
	 * This function would be used as callback of send request to ajax_saveAsDraft.
3599
	 *
3600
	 * @param {object} _responseData response data sent back from server by ajax_saveAsDraft function.
3601
	 *  the object conatins below items:
3602
	 *  -draftedId: new drafted id created by server
3603
	 *  -message: resault message
3604
	 *  -success: true if saving was successful otherwise false
3605
	 *  -draftfolder: Name of draft folder including its delimiter
3606
	 *
3607
	 * @param {string} _action action is the element which caused saving draft, it could be as such:
3608
	 *  -button[saveAsDraft]
3609
	 *  -button[saveAsDraftAndPrint]
3610
	 *  -autosaving
3611
	 */
3612
	savingDraft_response: function(_responseData, _action)
3613
	{
3614
		//Make sure there's a response from server otherwise shoot an error message
3615
		if (jQuery.isEmptyObject(_responseData))
3616
		{
3617
			this.egw.message('Could not saved the message. Because, the response from server failed.', 'error');
3618
			return false;
3619
		}
3620
3621
		if (_responseData.success)
3622
		{
3623
			var content = this.et2.getArrayMgr('content');
3624
			var lastDrafted = this.et2.getWidgetById('lastDrafted');
3625
			var folderTree = typeof opener.etemplate2.getByApplication('mail')[0] !='undefined'?
3626
								opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('nm[foldertree]'): null;
3627
			var activeFolder = folderTree?folderTree.getSelectedNode():null;
3628
			if (content)
3629
			{
3630
				var prevDraftedId = content.data.lastDrafted;
3631
				content.data.lastDrafted = _responseData.draftedId;
3632
				this.et2.setArrayMgr('content', content);
3633
				lastDrafted.set_value(_responseData.draftedId);
3634
				if (folderTree && activeFolder)
3635
				{
3636
					if (typeof activeFolder.id !='undefined' && _responseData.draftfolder == activeFolder.id)
3637
					{
3638
						if (prevDraftedId)
3639
						{
3640
							opener.egw_refresh(_responseData.message,'mail', prevDraftedId, 'delete');
3641
						}
3642
						this.egw.refresh(_responseData.message,'mail',_responseData.draftedId);
3643
					}
3644
				}
3645
				switch (_action)
3646
				{
3647
					case 'button[saveAsDraftAndPrint]':
3648
						this.mail_compose_print('mail::'+_responseData.draftedId);
3649
						this.egw.message(_responseData.message);
3650
						break;
3651
					case 'autosaving':
3652
						//Any sort of thing if it's an autosaving action
3653
					default:
3654
						this.egw.message(_responseData.message);
3655
				}
3656
			}
3657
		}
3658
		else
3659
		{
3660
			this.egw.message(_responseData.message, 'error');
3661
		}
3662
	},
3663
3664
	/**
3665
	 * Focus handler for folder, address, reject textbox/taglist to automatic check associated radio button
3666
	 *
3667
	 * @param {event} _ev
3668
	 * @param {object} _widget taglist
3669
	 *
3670
	 */
3671
	sieve_focus_radioBtn: function(_ev, _widget)
3672
	{
3673
		_widget.getRoot().getWidgetById('action').set_value(_widget.id.replace(/^action_([^_]+)_text$/, '$1'));
3674
	},
3675
3676
	/**
3677
	 * Select all aliases
3678
	 *
3679
	 */
3680
	sieve_vac_all_aliases: function()
3681
	{
3682
		var aliases = [];
3683
		var tmp = [];
3684
		var addr = this.et2.getWidgetById('addresses');
3685
		var addresses = this.et2.getArrayMgr('sel_options').data.addresses;
3686
3687
		for(var id in addresses) aliases.push(id);
3688
		if (addr)
3689
		{
3690
			tmp = aliases.concat(addr.get_value());
3691
3692
			// returns de-duplicate items of an array
3693
			var deDuplicator = function (item,pos)
3694
			{
3695
				return tmp.indexOf(item) == pos;
3696
			};
3697
3698
			aliases = tmp.filter(deDuplicator);
3699
			addr.set_value(aliases);
3700
		}
3701
	},
3702
3703
	/**
3704
	 * Disable/Enable date widgets on vacation seive rules form when status is "by_date"
3705
	 *
3706
	 */
3707
	vacationFilterStatusChange: function()
3708
	{
3709
		var status = this.et2.getWidgetById('status');
3710
		var s_date = this.et2.getWidgetById('start_date');
3711
		var e_date = this.et2.getWidgetById('end_date');
3712
		var by_date_label = this.et2.getWidgetById('by_date_label');
3713
3714
		if (status && s_date && e_date && by_date_label)
3715
		{
3716
			s_date.set_disabled(status.get_value() != "by_date");
3717
			e_date.set_disabled(status.get_value() != "by_date");
3718
			by_date_label.set_disabled(status.get_value() != "by_date");
3719
		}
3720
	},
3721
3722
	/**
3723
	 * action - handling actions on sieve rules
3724
	 *
3725
	 * @param _type - action name
3726
	 * @param _selected - selected row from the sieve rule list
3727
	 */
3728
	action: function(_type, _selected)
3729
	{
3730
		var  actionData ;
3731
		var that = this;
3732
		var typeId = _type.id;
3733
		var linkData = '';
3734
		var ruleID = ((_selected[0].id.split("_").pop()) - 1); // subtract the row id from 1 because the first row id is reserved by grid header
3735
		if (_type)
3736
		{
3737
3738
			switch (_type.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3739
			{
3740
				case 'delete':
3741
3742
					var callbackDeleteDialog = function (button_id)
3743
					{
3744
						if (button_id == et2_dialog.YES_BUTTON )
3745
						{
3746
							actionData = _type.parent.data.widget.getArrayMgr('content');
3747
							that._do_action(typeId, actionData['data'],ruleID);
3748
						}
3749
					};
3750
					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);
3751
3752
					break;
3753
				case 'add'	:
3754
					linkData = "mail.mail_sieve.edit";
3755
					this.egw.open_link(linkData,'_blank',"600x480");
3756
					break;
3757
				case 'edit'	:
3758
					linkData = "mail.mail_sieve.edit&ruleID="+ruleID;
3759
					this.egw.open_link(linkData,'_blank',"600x480");
3760
					break;
3761
				case 'enable':
3762
					actionData = _type.parent.data.widget.getArrayMgr('content');
3763
					this._do_action(typeId,actionData['data'],ruleID);
3764
					break;
3765
				case 'disable':
3766
					actionData = _type.parent.data.widget.getArrayMgr('content');
3767
					this._do_action(typeId,actionData['data'],ruleID);
3768
					break;
3769
3770
			}
3771
		}
3772
3773
	},
3774
3775
	/**
3776
	* Send back sieve action result to server
3777
	*
3778
	* @param {string} _typeID action name
3779
	* @param {object} _data content
3780
	* @param {string} _selectedID selected row id
3781
	* @param {string} _msg message
3782
	*
3783
	*/
3784
	_do_action: function(_typeID, _data,_selectedID,_msg)
3785
	{
3786
		if (_typeID && _data)
3787
		{
3788
			var request = this.egw.json('mail.mail_sieve.ajax_action', [_typeID,_selectedID,_msg],null,null,true);
3789
			request.sendRequest();
3790
		}
3791
	},
3792
3793
	/**
3794
	* Send ajax request to server to refresh the sieve grid
3795
	*/
3796
	sieve_refresh: function()
3797
	{
3798
		this.et2._inst.submit();
3799
	},
3800
3801
	/**
3802
	 * Select the right combination of the rights for radio buttons from the selected common right
3803
	 *
3804
	 * @@param {jQuery event} event
3805
	 * @param {widget} widget common right selectBox
3806
	 *
3807
	 */
3808
	acl_common_rights_selector: function(event,widget)
3809
	{
3810
		var rowId = widget.id.replace(/[^0-9.]+/g, '');
3811
		var rights = [];
3812
3813
		switch (widget.get_value())
3814
		{
3815
			case 'custom':
3816
				break;
3817
			case 'aeiklprstwx':
3818
				rights = widget.get_value().replace(/[k,x,t,e]/g,"cd").split("");
3819
				break;
3820
			default:
3821
				rights = widget.get_value().split("");
3822
		}
3823
		if (rights.length > 0)
3824
		{
3825
			for (var i=0;i<this.aclRights.length;i++)
3826
			{
3827
				var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3828
				rightsWidget.set_value((jQuery.inArray(this.aclRights[i],rights) != -1 )?true:false);
3829
			}
3830
		}
3831
	},
3832
3833
	/**
3834
	 *
3835
	 * Choose the right common right option for common ACL selecBox
3836
	 *
3837
	 * @param {jQuery event} event
3838
	 * @param {widget} widget radioButton rights
3839
	 *
3840
	 */
3841
	acl_common_rights: function(event, widget)
3842
	{
3843
	   var rowId = widget.id.replace(/[^0-9.]+/g, '');
3844
	   var aclCommonWidget = this.et2.getWidgetById(rowId + '[acl]');
3845
	   var rights = '';
3846
3847
	   for (var i=0;i<this.aclRights.length;i++)
3848
	   {
3849
		   var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3850
		   if (rightsWidget.get_value() == "true")
3851
			   rights += this.aclRights[i];
3852
3853
	   }
3854
3855
	   for (var i=0;i<this.aclCommonRights.length;i++)
3856
	   {
3857
		   if (rights.split("").sort().toString() == this.aclCommonRights[i].split("").sort().toString())
3858
			   rights = this.aclCommonRights[i];
3859
	   }
3860
	   if (jQuery.inArray(rights,this.aclCommonRights ) == -1 && rights !='lrswipcda')
3861
	   {
3862
		   aclCommonWidget.set_value('custom');
3863
	   }
3864
	   else if (rights =='lrswipcda')
3865
	   {
3866
           aclCommonWidget.set_value('aeiklprstwx');
3867
	   }
3868
	   else
3869
	   {
3870
		   aclCommonWidget.set_value(rights);
3871
	   }
3872
	},
3873
3874
	/**
3875
	 * Open seive filter list
3876
	 *
3877
	 * @param {action} _action
3878
	 * @param {sender} _senders
3879
	 *
3880
	 */
3881
	edit_sieve: function(_action, _senders)
3882
	{
3883
		var acc_id = parseInt(_senders[0].id);
3884
3885
		var url = this.egw.link('/index.php',{
3886
					'menuaction': 'mail.mail_sieve.index',
3887
					'acc_id': acc_id,
3888
					'ajax': 'true'
3889
		});
3890
3891
		// an ugly hack for idots to show up sieve rules not in an iframe
3892
		// but as new link, better to remove it after get rid of idots template
3893
		if (typeof window.framework == 'undefined')
3894
		{
3895
			this.egw.open_link(url);
3896
		}
3897
		else
3898
		{
3899
			this.loadIframe(url);
3900
		}
3901
	},
3902
3903
	/**
3904
	 * Load an url on an iframe
3905
	 *
3906
	 * @param {string} _url string egw url
3907
	 * @param {iframe widget} _iFrame an iframe to be set if non, extra_iframe is default
3908
	 *
3909
	 * @return {boolean} return TRUE if success, and FALSE if iframe not given
3910
	 */
3911
	loadIframe: function (_url, _iFrame)
3912
	{
3913
		var mailSplitter = this.et2.getWidgetById('splitter');
3914
		var quotaipercent = this.et2.getWidgetById('nm[quotainpercent]');
3915
		var iframe = _iFrame || this.et2.getWidgetById('extra_iframe');
3916
		if (typeof iframe != 'undefined' && iframe)
3917
		{
3918
			if (_url)
3919
			{
3920
				iframe.set_src(_url);
3921
			}
3922
			if (typeof mailSplitter != 'undefined' && mailSplitter && typeof quotaipercent != 'undefined')
3923
			{
3924
				mailSplitter.set_disabled(!!_url);
3925
				quotaipercent.set_disabled(!!_url);
3926
				iframe.set_disabled(!_url);
3927
			}
3928
			// extra_iframe used for showing up sieve rules
3929
			// need some special handling for mobile device
3930
			// as we wont have splitter, and also a fix for
3931
			// iframe with display none
3932
			if (iframe.id == "extra_iframe")
3933
			{
3934
				if (egwIsMobile())
3935
				{
3936
					var nm = this.et2.getWidgetById(this.nm_index);
3937
					nm.set_disabled(!!_url);
3938
					iframe.set_disabled(!_url);
3939
				}
3940
				// Set extra_iframe a class with height and width
3941
				// and position relative, seems iframe display none
3942
				// with 100% height/width covers mail tree and block
3943
				// therefore block the click handling
3944
				if (!iframe.disabled)
3945
				{
3946
					iframe.set_class('mail-index-extra-iframe');
3947
				}
3948
				else
3949
				{
3950
					iframe.set_class('');
3951
				}
3952
			}
3953
			return true;
3954
		}
3955
		return false;
3956
	},
3957
3958
	/**
3959
	 * Edit vacation message
3960
	 *
3961
	 * @param {action} _action
3962
	 * @param {sender} _senders
3963
	 */
3964
	edit_vacation: function(_action, _senders)
3965
	{
3966
		var acc_id = parseInt(_senders[0].id);
3967
		this.egw.open_link('mail.mail_sieve.editVacation&acc_id='+acc_id,'_blank','700x480');
3968
	},
3969
3970
	subscription_refresh: function(_data)
3971
	{
3972
		console.log(_data);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
3973
	},
3974
3975
	/**
3976
	 * Submit on apply button and save current tree state
3977
	 *
3978
	 * @param {type} _egw
3979
	 * @param {type} _widget
3980
	 * @returns {undefined}
3981
	 */
3982
	subscription_apply: function (_egw, _widget)
3983
	{
3984
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('foldertree');
3985
		if (tree)
3986
		{
3987
			tree.input._xfullXML = true;
3988
			this.subscription_treeLastState = tree.input.serializeTreeToJSON();
3989
		}
3990
		this.et2._inst.submit(_widget);
3991
	},
3992
3993
	/**
3994
	 * Show ajax-loader when the autoloading get started
3995
	 *
3996
	 * @param {type} _id item id
3997
	 * @param {type} _widget tree widget
3998
	 * @returns {Boolean}
3999
	 */
4000
	subscription_autoloadingStart: function (_id, _widget)
4001
	{
4002
		var node = _widget.input._globalIdStorageFind(_id);
4003
		if (node && typeof node.htmlNode != 'undefined')
4004
		{
4005
			var img = jQuery('img',node.htmlNode)[0];
4006
			img.src = egw.image('ajax-loader', 'admin');
4007
		}
4008
		return true;
4009
	},
4010
4011
	/**
4012
	 * Revert back the icon after autoloading is finished
4013
	 * @returns {Boolean}
4014
	 */
4015
	subscription_autoloadingEnd: function ()
4016
	{
4017
		return true;
4018
	},
4019
4020
	/**
4021
	 * Popup the subscription dialog
4022
	 *
4023
	 * @param {action} _action
4024
	 * @param {sender} _senders
4025
	 */
4026
	edit_subscribe: function (_action,_senders)
4027
	{
4028
		var acc_id = parseInt(_senders[0].id);
4029
		this.egw.open_link('mail.mail_ui.subscription&acc_id='+acc_id, '_blank', '720x500');
4030
	},
4031
4032
	/**
4033
	 * Subscribe selected unsubscribed folder
4034
	 *
4035
	 * @param {action} _action
4036
	 * @param {sender} _senders
4037
	 */
4038
	subscribe_folder: function(_action,_senders)
4039
	{
4040
		var mailbox = _senders[0].id.split('::');
4041
		var folder = mailbox[1], acc_id = mailbox[0];
4042
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4043
		this.egw.message(this.egw.lang('Subscribe to Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4044
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,true])
4045
			.sendRequest();
4046
	},
4047
4048
	/**
4049
	 * Unsubscribe selected subscribed folder
4050
	 *
4051
	 * @param {action} _action
4052
	 * @param {sender} _senders
4053
	 */
4054
	unsubscribe_folder: function(_action,_senders)
4055
	{
4056
		var mailbox = _senders[0].id.split('::');
4057
		var folder = mailbox[1], acc_id = mailbox[0];
4058
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4059
		this.egw.message(this.egw.lang('Unsubscribe from Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4060
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,false])
4061
			.sendRequest();
4062
	},
4063
4064
	/**
4065
	 * Onclick for node/foldername in subscription popup
4066
	 *
4067
	 * Used to (un)check node including all children
4068
	 *
4069
	 * @param {string} _id id of clicked node
4070
	 * @param {et2_tree} _widget reference to tree widget
4071
	 */
4072
	subscribe_onclick: function(_id, _widget)
4073
	{
4074
		_widget.setSubChecked(_id, "toggle");
4075
	},
4076
4077
	/**
4078
	 * Edit a folder acl for account(s)
4079
	 *
4080
	 * @param _action
4081
	 * @param _senders - the representation of the tree leaf to be manipulated
4082
	 */
4083
	edit_acl: function(_action, _senders)
4084
	{
4085
		var mailbox = _senders[0].id.split('::');
4086
		var folder = mailbox[1] || 'INBOX', acc_id = mailbox[0];
4087
		this.egw.open_link('mail.mail_acl.edit&mailbox='+ jQuery.base64Encode(folder)+'&acc_id='+acc_id, '_blank', '640x480');
4088
	},
4089
4090
	/**
4091
	 * Submit new selected folder back to server in order to read its acl's rights
4092
	 */
4093
	acl_folderChange: function ()
4094
	{
4095
		var mailbox = this.et2.getWidgetById('mailbox');
4096
4097
		if (mailbox)
4098
		{
4099
			if (mailbox.taglist.getValue().length > 0)
4100
			{
4101
				this.et2._inst.submit();
4102
			}
4103
		}
4104
	},
4105
4106
	/**
4107
	 * Edit a mail account
4108
	 *
4109
	 * @param _action
4110
	 * @param _senders - the representation of the tree leaf to be manipulated
4111
	 */
4112
	edit_account: function(_action, _senders)
4113
	{
4114
		var acc_id = parseInt(_senders[0].id);
4115
		this.egw.open_link('mail.mail_wizard.edit&acc_id='+acc_id, '_blank', '720x500');
4116
	},
4117
4118
	/**
4119
	 * Set expandable fields (Folder, Cc and Bcc) based on their content
4120
	 * - Only fields which have no content should get hidden
4121
	 */
4122
	compose_fieldExpander_init: function ()
4123
	{
4124
		var widgets = {
4125
			cc:{
4126
				widget:{},
4127
				jQClass: '.mailComposeJQueryCc'
4128
			},
4129
			bcc:{
4130
				widget:{},
4131
				jQClass: '.mailComposeJQueryBcc'
4132
			},
4133
			folder:{
4134
				widget:{},
4135
				jQClass: '.mailComposeJQueryFolder'
4136
			},
4137
			replyto:{
4138
				widget:{},
4139
				jQClass: '.mailComposeJQueryReplyto'
4140
			}};
4141
4142
		for(var widget in widgets)
4143
		{
4144
			var expanderBtn = widget + '_expander';
4145
			widgets[widget].widget = this.et2.getWidgetById(widget);
4146
			// Add expander button widget to the widgets object
4147
			widgets[expanderBtn] = {widget:this.et2.getWidgetById(expanderBtn)};
4148
4149
			if (typeof widgets[widget].widget != 'undefined'
4150
					&& typeof widgets[expanderBtn].widget != 'undefined'
4151
					&& widgets[widget].widget.get_value().length == 0)
4152
			{
4153
				widgets[expanderBtn].widget.set_disabled(false);
4154
				jQuery(widgets[widget].jQClass).hide();
4155
			}
4156
		}
4157
	},
4158
4159
	/**
4160
	 * Control textArea size based on available free space at the bottom
4161
	 *
4162
	 */
4163
	compose_resizeHandler: function()
4164
	{
4165
		// Do not resize compose dialog if it's running on mobile device
4166
		// in this case user would be able to edit mail body by scrolling down,
4167
		// which is more convenient on small devices. Also resize mailbody with
4168
		// ckeditor may causes performance regression, especially on devices with
4169
		// very limited resources and slow proccessor.
4170
		if (egwIsMobile()) return false;
4171
4172
		try {
4173
			var bodyH = egw_getWindowInnerHeight();
4174
			var textArea = this.et2.getWidgetById('mail_plaintext');
4175
			var $headerSec = jQuery('.mailComposeHeaderSection');
4176
			var attachments = this.et2.getWidgetById('attachments');
4177
			var content = this.et2.getArrayMgr('content').data;
4178
4179
			// @var arrbitary int represents px
4180
			// Visible height of attachment progress
4181
			var prgV_H = 150;
4182
4183
			// @var arrbitary int represents px
4184
			// Visible height of attchements list
4185
			var attchV_H = 68;
4186
4187
			if (typeof textArea != 'undefined' && textArea != null)
4188
			{
4189
				if (textArea.getParent().disabled)
4190
				{
4191
					textArea = this.et2.getWidgetById('mail_htmltext');
4192
				}
4193
				// Tolerate values base on plain text or html, in order to calculate freespaces
4194
				var textAreaDelta = textArea.id == "mail_htmltext"?20:40;
4195
4196
				// while attachments are in progress take progress visiblity into account
4197
				// otherwise the attachment progress is finished and consider attachments list
4198
				var delta = (attachments.table.find('li').length>0 && attachments.table.height() > 0)? prgV_H: (content.attachments? attchV_H: textAreaDelta);
4199
4200
				var bodySize = (bodyH  - Math.round($headerSec.height() + $headerSec.offset().top) - delta);
4201
4202
				if (textArea.id != "mail_htmltext")
4203
				{
4204
					textArea.getParent().set_height(bodySize);
4205
					textArea.set_height(bodySize);
4206
				}
4207
				else if (typeof textArea != 'undefined' && textArea.id == 'mail_htmltext')
4208
				{
4209
					textArea.ckeditor.resize('100%', bodySize);
4210
				}
4211
				else
4212
				{
4213
					textArea.set_height(bodySize - 90);
4214
				}
4215
			}
4216
		}
4217
		catch(e) {
4218
			// ignore errors causing compose to load twice
4219
		}
4220
	},
4221
4222
	/**
4223
	 * Display Folder,Cc or Bcc fields in compose popup
4224
	 *
4225
	 * @param {jQuery event} event
4226
	 * @param {widget object} widget clicked label (Folder, Cc or Bcc) from compose popup
4227
	 *
4228
	 */
4229
	compose_fieldExpander: function(event,widget)
4230
	{
4231
		var expWidgets = {cc:{},bcc:{},folder:{},replyto:{}};
4232
		for (var name in expWidgets)
4233
		{
4234
			expWidgets[name] = this.et2.getWidgetById(name+'_expander');
4235
		}
4236
4237
		if (typeof widget !='undefined')
4238
		{
4239
			switch (widget.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4240
			{
4241
				case 'cc_expander':
4242
					jQuery(".mailComposeJQueryCc").show();
4243
					if (typeof expWidgets.cc !='undefined')
4244
					{
4245
						expWidgets.cc.set_disabled(true);
4246
					}
4247
					break;
4248
				case 'bcc_expander':
4249
					jQuery(".mailComposeJQueryBcc").show();
4250
					if (typeof expWidgets.bcc !='undefined')
4251
					{
4252
						expWidgets.bcc.set_disabled(true);
4253
					}
4254
					break;
4255
				case 'folder_expander':
4256
					jQuery(".mailComposeJQueryFolder").show();
4257
					if (typeof expWidgets.folder !='undefined')
4258
					{
4259
						expWidgets.folder.set_disabled(true);
4260
					}
4261
					break;
4262
				case 'replyto_expander':
4263
					jQuery(".mailComposeJQueryReplyto").show();
4264
					if (typeof expWidgets.replyto !='undefined')
4265
					{
4266
						expWidgets.replyto.set_disabled(true);
4267
					}
4268
					break;
4269
			}
4270
		}
4271
		else if (typeof widget == "undefined")
4272
		{
4273
			var widgets = {cc:{},bcc:{},folder:{},replyto:{}};
4274
4275
			for(var widget in widgets)
4276
			{
4277
				widgets[widget] = this.et2.getWidgetById(widget);
4278
4279
				if (widgets[widget].get_value().length)
4280
				{
4281
					switch (widget)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4282
					{
4283
						case 'cc':
4284
							jQuery(".mailComposeJQueryCc").show();
4285
							if (typeof expWidgets.cc != 'undefiend')
4286
							{
4287
								expWidgets.cc.set_disabled(true);
4288
							}
4289
							break;
4290
						case 'bcc':
4291
							jQuery(".mailComposeJQueryBcc").show();
4292
							if (typeof expWidgets.bcc != 'undefiend')
4293
							{
4294
								expWidgets.bcc.set_disabled(true);
4295
							}
4296
							break;
4297
						case 'folder':
4298
							jQuery(".mailComposeJQueryFolder").show();
4299
							if (typeof expWidgets.folder != 'undefiend')
4300
							{
4301
								expWidgets.folder.set_disabled(true);
4302
							}
4303
							break;
4304
						case 'replyto':
4305
							jQuery(".mailComposeJQueryReplyto").show();
4306
							if (typeof expWidgets.replyto != 'undefiend')
4307
							{
4308
								expWidgets.replyto.set_disabled(true);
4309
							}
4310
							break;
4311
					}
4312
				}
4313
			}
4314
		}
4315
		this.compose_resizeHandler();
4316
	},
4317
4318
	/**
4319
	 * Lock tree so it does NOT receive any more mouse-clicks
4320
	 */
4321
	lock_tree: function()
4322
	{
4323
		if (!document.getElementById('mail_folder_lock_div'))
4324
		{
4325
			var parent = jQuery('#mail-index_nm\\[foldertree\\]');
4326
			var lock_div = jQuery(document.createElement('div'));
4327
			lock_div.attr('id', 'mail_folder_lock_div')
4328
				.addClass('mail_folder_lock');
4329
			parent.prepend(lock_div);
4330
		}
4331
	},
4332
4333
	/**
4334
	 * Unlock tree so it receives again mouse-clicks after calling lock_tree()
4335
	 */
4336
	unlock_tree: function()
4337
	{
4338
		jQuery('#mail_folder_lock_div').remove();
4339
	},
4340
4341
	/**
4342
	 * Called when tree opens up an account or folder
4343
	 *
4344
	 * @param {String} _id account-id[::folder-name]
4345
	 * @param {et2_widget_tree} _widget
4346
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4347
	 */
4348
	openstart_tree: function(_id, _widget, _hasChildren)
4349
	{
4350
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4351
			!_hasChildren)
4352
		{
4353
			this.lock_tree();
4354
		}
4355
		return true;	// allow opening of node
4356
	},
4357
4358
	/**
4359
	 * Called when tree opens up an account or folder
4360
	 *
4361
	 * @param {String} _id account-id[::folder-name]
4362
	 * @param {et2_widget_tree} _widget
4363
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4364
	 */
4365
	openend_tree: function(_id, _widget, _hasChildren)
4366
	{
4367
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4368
			_hasChildren == 1)
4369
		{
4370
			this.unlock_tree();
4371
		}
4372
	},
4373
4374
	/**
4375
	 * Print a mail from list
4376
4377
	 * @param _action
4378
	 * @param _senders - the representation of the tree leaf to be manipulated
4379
	 */
4380
	mail_print: function(_action, _senders)
4381
	{
4382
		var currentTemp = this.et2._inst.name;
4383
4384
		switch (currentTemp)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4385
		{
4386
			case 'mail.index':
4387
				this.mail_prev_print(_action, _senders);
4388
				break;
4389
			case 'mail.display':
4390
				this.mail_display_print();
4391
		}
4392
4393
	},
4394
4395
	/**
4396
	 * Print a mail from compose
4397
	 * @param {stirng} _id id of new draft
4398
	 */
4399
	mail_compose_print:function (_id)
4400
	{
4401
		this.egw.open(_id,'mail','view','&print='+_id+'&mode=print');
4402
	},
4403
4404
	/**
4405
	 * Bind special handler on print media.
4406
	 * -FF and IE have onafterprint event, and as Chrome does not have that event we bind afterprint function to onFocus
4407
	 */
4408
	print_for_compose: function()
4409
	{
4410
		var afterprint = function (){
4411
			egw(window).close();
4412
		};
4413
4414
		if (!window.onafterprint)
4415
		{
4416
			// For browsers which does not support onafterprint event, eg. Chrome
4417
			setTimeout(function() {
4418
				egw(window).close();
4419
			}, 2000);
4420
		}
4421
		else
4422
		{
4423
			window.onafterprint = afterprint;
4424
		}
4425
	},
4426
4427
	/**
4428
	 * Prepare display dialog for printing
4429
	 * copies iframe content to a DIV, as iframe causes
4430
	 * trouble for multipage printing
4431
	 * @param {jQuery object} _iframe mail body iframe
4432
	 * @returns {undefined}
4433
	 */
4434
	mail_prepare_print: function(_iframe)
4435
	{
4436
		var $mainIframe = _iframe || jQuery('#mail-display_mailDisplayBodySrc');
4437
		var tmpPrintDiv = jQuery('#tempPrintDiv');
4438
4439
		if (tmpPrintDiv.length == 0 && tmpPrintDiv.children())
4440
		{
4441
			tmpPrintDiv = jQuery(document.createElement('div'))
4442
							.attr('id', 'tempPrintDiv')
4443
							.addClass('tmpPrintDiv');
4444
			var notAttached = true;
4445
		}
4446
4447
		if ($mainIframe)
4448
		{
4449
			tmpPrintDiv[0].innerHTML = $mainIframe.contents().find('body').html();
4450
		}
4451
		// Attach the element to the DOM after maniupulation
4452
		if (notAttached) $mainIframe.after(tmpPrintDiv);
4453
		tmpPrintDiv.find('#divAppboxHeader').remove();
4454
4455
	},
4456
4457
	/**
4458
	 * Print a mail from Display
4459
	 */
4460
	mail_display_print: function ()
4461
	{
4462
		this.egw.message('Printing....');
4463
4464
		// Make sure the print happens after the content is loaded. Seems Firefox and IE can't handle timing for print command correctly
4465
		setTimeout(function(){
4466
			egw(window).window.print();
4467
		},100);
4468
	},
4469
4470
	/**
4471
	 * Print a mail from list
4472
	 *
4473
	 * @param {Object} _action
4474
	 * @param {Object} _elems
4475
	 *
4476
	 */
4477
	mail_prev_print: function (_action, _elems)
4478
	{
4479
		this.mail_open(_action, _elems, 'print');
4480
	},
4481
4482
	/**
4483
	 * Print a mail from list
4484
	 *
4485
	 * @param {egw object} _egw
4486
	 * @param {widget object} _widget mail account selectbox
4487
	 *
4488
	 */
4489
	vacation_change_account: function (_egw, _widget)
4490
	{
4491
		_widget.getInstanceManager().submit();
4492
	},
4493
4494
	/**
4495
	 * OnChange callback for recipients:
4496
	 * - make them draggable
4497
	 * - check if we have keys for recipients, if we compose an encrypted mail
4498
	 **/
4499
	recipients_onchange: function()
4500
	{
4501
		// if we compose an encrypted mail, check if we have keys for new recipient
4502
		if (this.mailvelope_editor)
4503
		{
4504
			var self = this;
4505
			this.mailvelopeGetCheckRecipients().catch(function(_err)
4506
			{
4507
				self.egw.message(_err.message, 'error');
4508
			});
4509
		}
4510
		this.set_dragging_dndCompose();
4511
	},
4512
4513
	/**
4514
	 * Make recipients draggable
4515
	 */
4516
	set_dragging_dndCompose: function ()
4517
	{
4518
		var zIndex = 100;
4519
		var dragItems = jQuery('div.ms-sel-item:not(div.ui-draggable)');
4520
		dragItems.each(function(i,item){
4521
				var $isErr = jQuery(item).find('.ui-state-error');
4522
				if ($isErr.length > 0)
4523
				{
4524
					delete dragItems.splice(i,1);
4525
				}
4526
			});
4527
		if (dragItems.length > 0)
4528
		{
4529
			dragItems.draggable({
4530
				appendTo:'body',
4531
				//Performance wise better to not add ui-draggable class to items since we are not using that class
4532
				containment:'document',
4533
				distance: 0,
4534
				cursor:'move',
4535
				cursorAt:{left:2},
4536
				//cancel dragging on close button to avoid conflict with close action
4537
				cancel:'.ms-close-btn',
4538
				delay: '300',
4539
				/**
4540
				 * function to act on draggable item on revert's event
4541
				 * @returns {Boolean} return true
4542
				 */
4543
				revert: function (){
4544
					this.parent().find('.ms-sel-item').css('position','relative');
4545
					var $input = this.parent().children('input');
4546
					// Make sure input field not getting into second line after revert
4547
					$input.width($input.width()-10);
4548
					return true;
4549
				},
4550
				/**
4551
				 * function to act as draggable starts dragging
4552
				 *
4553
				 * @param {type} event
4554
				 * @param {type} ui
4555
				 */
4556
				start:function(event, ui)
4557
				{
4558
					var dragItem = jQuery(this);
4559
					if (event.ctrlKey || event.metaKey)
4560
					{
4561
						dragItem.addClass('mailCompose_copyEmail')
4562
								.css('cursor','copy');
4563
					}
4564
					dragItem.css ('z-index',zIndex++);
4565
					dragItem.css('position','absolute');
4566
				},
4567
				/**
4568
				 *
4569
				 * @param {type} event
4570
				 * @param {type} ui
4571
				 */
4572
				create:function(event,ui)
4573
				{
4574
					jQuery(this).css('css','move');
4575
				}
4576
			}).draggable('disable');
4577
			window.setTimeout(function(){
4578
4579
				if(dragItems && dragItems.data() && typeof dragItems.data()['uiDraggable'] !== 'undefined') dragItems.draggable('enable');
4580
			},100);
4581
		}
4582
4583
	},
4584
4585
	/**
4586
	 * Initialize dropping targets for draggable emails
4587
	 * -
4588
	 */
4589
	init_dndCompose: function ()
4590
	{
4591
4592
		var self = this;
4593
		var emailTags = jQuery('#mail-compose_to,#mail-compose_cc,#mail-compose_bcc');
4594
		//Call to make new items draggable
4595
		emailTags.hover(function(){
4596
			self.set_dragging_dndCompose();
4597
		});
4598
		//Make used email-tag list widgets in mail compose droppable
4599
		emailTags.droppable({
4600
			accept:'.ms-sel-item',
4601
4602
			/**
4603
			 * Run after a draggable email item dropped over one of the email-taglists
4604
			 * -Set the dropped item to the dropped current target widget
4605
			 *
4606
			 * @param {type} event
4607
			 * @param {type} ui
4608
			 */
4609
			drop:function (event, ui)
4610
			{
4611
				var widget = self.et2.getWidgetById(this.getAttribute('name'));
4612
				var emails, distLists = [];
4613
				var fromWidget = {};
4614
4615
				var parentWidgetDOM = ui.draggable.parentsUntil('div[id^="mail-compoe_"]','.ui-droppable');
4616
				if (parentWidgetDOM != 'undefined' && parentWidgetDOM.length > 0)
4617
				{
4618
					fromWidget = self.et2.getWidgetById(parentWidgetDOM.attr('name'));
4619
				}
4620
4621
				var draggedValue = ui.draggable.text();
4622
4623
				// index of draggable item in selection list
4624
				var dValueKey = draggedValue;
4625
4626
				var distItem = ui.draggable.find('.mailinglist');
4627
				if (distItem.length>0)
4628
				{
4629
					var distItemId = parseInt(distItem.attr('data'));
4630
					if (distItemId)
4631
					{
4632
						var fromDistLists = resolveDistList(fromWidget);
4633
						for (var i=0;i<fromDistLists.length;i++)
4634
						{
4635
							if (distItemId == fromDistLists[i]['id'])
4636
							{
4637
								draggedValue = fromDistLists[i];
4638
								// dist list item index
4639
								dValueKey = fromDistLists[i]['id'];
4640
							}
4641
						}
4642
					}
4643
				}
4644
4645
				if (typeof widget != 'undefined')
4646
				{
4647
					emails = widget.get_value();
4648
					if (emails) emails = emails.concat([draggedValue]);
4649
4650
					// Resolve the dist list and normal emails
4651
					distLists = resolveDistList(widget, emails);
4652
4653
					// Add normal emails
4654
					if (emails) widget.set_value(emails);
4655
4656
					// check if there's any dist list to be added
4657
					if (distLists.length>0) widget.taglist.addToSelection(distLists);
4658
4659
					if (!jQuery.isEmptyObject(fromWidget)
4660
							&& !(ui.draggable.attr('class').search('mailCompose_copyEmail') > -1))
4661
					{
4662
						if (widget.node != fromWidget.node && !_removeDragged(fromWidget, dValueKey))
4663
						{
4664
							//Not successful remove, returns the item to its origin
4665
							jQuery(ui.draggable).draggable('option','revert',true);
4666
						}
4667
					}
4668
					else
4669
					{
4670
						ui.draggable
4671
								.removeClass('mailCompose_copyEmail')
4672
								.css('cursor','move');
4673
					}
4674
4675
					var dragItems = jQuery('div.ms-sel-item');
4676
					dragItems.each(function(i,item){
4677
						var $isErr = jQuery(item).find('.ui-state-error');
4678
						if ($isErr.length > 0)
4679
						{
4680
							delete dragItems.splice(i,1);
4681
						}
4682
					});
4683
				}
4684
			}
4685
		});
4686
4687
		/**
4688
		 * Remove dragged item from the widget which the item was dragged
4689
		 *
4690
		 * @param {type} _widget
4691
		 * @param {type} _value
4692
		 * @return {boolean} true if successul | false unsuccessul
4693
		 */
4694
		var _removeDragged = function (_widget, _value)
4695
		{
4696
			if (_widget && _value)
4697
			{
4698
				var emails = _widget.get_value();
4699
				var itemIndex = emails.indexOf(_value);
4700
				var dist = [];
4701
				if (itemIndex > -1)
4702
				{
4703
					emails.splice(itemIndex,1);
4704
					// Resolve the dist list and normal emails
4705
					var dist = resolveDistList(_widget, emails);
4706
4707
					// Add normal emails
4708
					_widget.set_value(emails);
4709
4710
					//check if there's any dist list to be added
4711
					if (dist)
4712
					{
4713
						for(var i=0;i<dist.length;i++)
4714
						{
4715
							if (dist[i]['id'] == _value) dist.splice(i,1);
4716
						}
4717
						_widget.taglist.addToSelection(dist);
4718
					}
4719
				}
4720
				else
4721
				{
4722
					return false;
4723
				}
4724
			}
4725
			return true;
4726
		};
4727
4728
		/**
4729
		 * Resolve taglist widget which has distribution list
4730
		 *
4731
		 * @param {type} _widget
4732
		 * @param {type} _emails
4733
		 * @returns {Array} returns an array of distribution lists in selected widget
4734
		 */
4735
		var resolveDistList = function (_widget, _emails)
4736
		{
4737
			var list = [];
4738
			var selectedList = _widget.taglist.getSelection();
4739
			// Make a list of distribution list from the selection
4740
			for (var i=0;i<selectedList.length;i++)
4741
			{
4742
				if (!isNaN(selectedList[i]['id']) && selectedList[i]['class'] === 'mailinglist')
4743
				{
4744
					list.push(selectedList[i]);
4745
				}
4746
			}
4747
4748
			// Remove dist list from emails list
4749
			for(var key in _emails)
4750
			{
4751
				if (!isNaN(_emails[key]))
4752
				{
4753
					_emails.splice(key,1);
4754
				}
4755
			}
4756
			// returns distlist
4757
			return list;
4758
		};
4759
	},
4760
4761
	/**
4762
	* Check sharing mode and disable not available options
4763
	*
4764
	* @param {DOMNode} _node
4765
	* @param {et2_widget} _widget
4766
	*/
4767
	check_sharing_filemode: function(_node, _widget)
4768
	{
4769
		if (!_widget) _widget = this.et2.getWidgetById('filemode');
4770
4771
		var extended_settings = _widget.get_value() != 'attach' && this.egw.app('stylite');
4772
		this.et2.getWidgetById('expiration').set_readonly(!extended_settings);
4773
		this.et2.getWidgetById('password').set_readonly(!extended_settings);
4774
4775
		if (_widget.get_value() == 'share_rw' && !this.egw.app('stylite'))
4776
		{
4777
			this.egw.message(this.egw.lang('Writable sharing requires EPL version!'), 'info');
4778
			_widget.set_value('share_ro');
4779
		}
4780
	},
4781
4782
	/**
4783
	 * Write / update compose window title with subject
4784
	 *
4785
	 * @param {DOMNode} _node
4786
	 * @param {et2_widget} _widget
4787
	 */
4788
	subject2title: function(_node, _widget)
4789
	{
4790
		if (!_widget) _widget = this.et2.getWidgetById('subject');
4791
4792
		if (_widget && _widget.get_value())
4793
		{
4794
			document.title = _widget.get_value();
4795
		}
4796
	},
4797
4798
	/**
4799
	 * Clear intervals stored in W_INTERVALS which assigned to window
4800
	 */
4801
	clearIntevals: function ()
4802
	{
4803
		for(var i=0;i<this.W_INTERVALS.length;i++)
4804
		{
4805
			clearInterval(this.W_INTERVALS[i]);
4806
			delete this.W_INTERVALS[i];
4807
		}
4808
	},
4809
4810
	/**
4811
	 * Window title getter function in order to set the window title
4812
	 *
4813
	 * @returns {string|undefined} window title
4814
	 */
4815
	getWindowTitle: function ()
4816
	{
4817
		var widget = {};
4818
		switch(this.et2._inst.name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4819
		{
4820
			case 'mail.display':
4821
				widget = this.et2.getWidgetById('mail_displaysubject');
4822
				if (widget) return widget.options.value;
4823
				break;
4824
			case 'mail.compose':
4825
				widget = this.et2.getWidgetById('subject');
4826
				if (widget) return widget.get_value();
4827
				break;
4828
		}
4829
		return undefined;
4830
	},
4831
4832
	/**
4833
	 *
4834
	 * @returns {undefined}
4835
	 */
4836
	prepareMailvelopePrint: function()
4837
	{
4838
		var tempPrint = jQuery('div#tempPrintDiv');
4839
		var mailvelopeTopContainer = jQuery('div.mailDisplayContainer');
4840
		var originFrame = jQuery('#mail-display_mailDisplayBodySrc');
4841
		var iframe = jQuery(this.mailvelope_iframe_selector);
4842
4843
		if (tempPrint.length >0)
4844
		{
4845
			// Mailvelope iframe height is approximately equal to the height of encrypted origin message
4846
			// we add an arbitary plus pixels to make sure it's covering the full content in print view and
4847
			// it is not getting acrollbar in normal view
4848
			// @TODO: after Mailvelope plugin provides a hieght value, we can replace the height with an accurate value
4849
			iframe.addClass('mailvelopeIframe').height(originFrame[0].contentWindow.document.body.scrollHeight + 400);
4850
			tempPrint.hide();
4851
			mailvelopeTopContainer.addClass('mailvelopeTopContainer');
4852
		}
4853
	},
4854
4855
	/**
4856
	 * Mailvelope (clientside PGP) integration:
4857
	 * - detect Mailvelope plugin and open "egroupware" keyring (app_base.mailvelopeAvailable and _mailvelopeOpenKeyring)
4858
	 * - display and preview of encrypted messages (mailvelopeDisplay)
4859
	 * - button to toggle between regular and encrypted mail (togglePgpEncrypt)
4860
	 * - compose encrypted messages (mailvelopeCompose, compose_submitAction)
4861
	 * - fix autosave and save as draft to store encrypted content (saveAsDraft)
4862
	 * - fix inline reply to encrypted message to clientside decrypt message and add signature (mailvelopeCompose)
4863
	 */
4864
4865
	/**
4866
	 * Called on load of preview or display iframe, if mailvelope is available
4867
	 *
4868
	 * @param {Keyring} _keyring Mailvelope keyring to use
4869
	 * @ToDo signatures
4870
	 */
4871
	mailvelopeDisplay: function(_keyring)
4872
	{
4873
		var self = this;
4874
		var mailvelope = window.mailvelope;
4875
		var iframe = jQuery('iframe#mail-display_mailDisplayBodySrc,iframe#mail-index_messageIFRAME');
4876
		var armored = iframe.contents().find('td.td_display > pre').text().trim();
4877
4878
		if (armored == "" || armored.indexOf(this.begin_pgp_message) === -1) return;
4879
4880
		var container = iframe.parent()[0];
4881
		var container_selector = container.id ? '#'+container.id : 'div.mailDisplayContainer';
4882
4883
		options = {
4884
			showExternalContent: this.egw.preference('allowExternalIMGs') == 1	// "1", or "0", undefined --> true or false
4885
		};
4886
		// get sender address, so Mailvelope can check signature
4887
		var from_widget = this.et2.getWidgetById('FROM_0') || this.et2.getWidgetById('previewFromAddress');
4888
		if (from_widget && from_widget.value)
4889
		{
4890
			options.senderAddress = from_widget.value.replace(/^.*<([^<>]+)>$/, '$1');
4891
		}
4892
		mailvelope.createDisplayContainer(container_selector, armored, _keyring, options).then(function()
4893
		{
4894
			// hide our iframe to give space for mailvelope iframe with encrypted content
4895
			iframe.hide();
4896
			self.prepareMailvelopePrint();
4897
		},
4898
		function(_err)
4899
		{
4900
			self.egw.message(_err.message, 'error');
4901
		});
4902
	},
4903
4904
	/**
4905
	 * Editor object of active compose
4906
	 *
4907
	 * @var {Editor}
4908
	 */
4909
	mailvelope_editor: undefined,
4910
4911
	/**
4912
	 * Called on compose, if mailvelope is available
4913
	 *
4914
	 * @param {Keyring} _keyring Mailvelope keyring to use
4915
	 */
4916
	mailvelopeCompose: function(_keyring)
4917
	{
4918
		delete this.mailvelope_editor;
4919
4920
		// currently Mailvelope only supports plain-text, to this is unnecessary
4921
		var mimeType = this.et2.getWidgetById('mimeType');
4922
		var is_html = mimeType.get_value();
4923
		var container = is_html ? '.mailComposeHtmlContainer' : '.mailComposeTextContainer';
4924
		var editor = this.et2.getWidgetById(is_html ? 'mail_htmltext' : 'mail_plaintext');
4925
		var options = { predefinedText: editor.get_value() };
4926
4927
		// check if we have some sort of reply to an encrypted message
4928
		// --> parse header, encrypted mail to quote and signature so Mailvelope understands it
4929
		var start_pgp = options.predefinedText.indexOf(this.begin_pgp_message);
4930
		if (start_pgp != -1)
4931
		{
4932
			var end_pgp = options.predefinedText.indexOf(this.end_pgp_message);
4933
			if (end_pgp != -1)
4934
			{
4935
				options = {
4936
					quotedMailHeader: options.predefinedText.slice(0, start_pgp).replace(/> /mg, '').trim()+"\n",
4937
					quotedMail: options.predefinedText.slice(start_pgp, end_pgp+this.end_pgp_message.length+1).replace(/> /mg, ''),
4938
					quotedMailIndent: start_pgp != 0,
4939
					predefinedText: options.predefinedText.slice(end_pgp+this.end_pgp_message.length+1).replace(/^> \s*/m,''),
4940
					signMsg: true	// for now (no UI) always sign, when we encrypt
4941
				};
4942
				// set encrypted checkbox, if not already set
4943
				var composeToolbar = this.et2.getWidgetById('composeToolbar');
4944
				if (!composeToolbar.checkbox('pgp'))
4945
				{
4946
					composeToolbar.checkbox('pgp',true);
4947
				}
4948
			}
4949
		}
4950
4951
		var self = this;
4952
		mailvelope.createEditorContainer(container, _keyring, options).then(function(_editor)
4953
		{
4954
			self.mailvelope_editor = _editor;
4955
			editor.set_disabled(true);
4956
			mimeType.set_readonly(true);
4957
		},
4958
		function(_err)
4959
		{
4960
			self.egw.message(_err.message, 'error');
4961
		});
4962
	},
4963
4964
	/**
4965
	 * Switch sending PGP encrypted mail on and off
4966
	 *
4967
	 * @param {object} _action toolbar action
4968
	 */
4969
	togglePgpEncrypt: function (_action)
4970
	{
4971
		var self = this;
4972
		if (_action.checked)
4973
		{
4974
			if (typeof mailvelope == 'undefined')
4975
			{
4976
				this.mailvelopeInstallationOffer();
4977
				// switch encrypt button off again
4978
				this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
4979
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
4980
				return;
4981
			}
4982
			// check if we have keys for all recipents, before switching
4983
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
4984
			{
4985
				var mimeType = self.et2.getWidgetById('mimeType');
4986
				// currently Mailvelope only supports plain-text, switch to it if necessary
4987
				if (mimeType.get_value())
4988
				{
4989
					mimeType.set_value(false);
4990
					self.et2._inst.submit();
4991
					return;	// ToDo: do that without reload
4992
				}
4993
				self.mailvelopeOpenKeyring().then(function(_keyring)
4994
				{
4995
					self.mailvelopeCompose(_keyring);
4996
				});
4997
			})
4998
			.catch(function(_err)
4999
			{
5000
				self.egw.message(_err.message, 'error');
5001
				self.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
5002
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
5003
				return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
5004
			});
5005
		}
5006
		else
5007
		{
5008
			// switch Mailvelop off again, but warn user he will loose his content
5009
			et2_dialog.show_dialog(function (_button_id)
5010
			{
5011
				if (_button_id == et2_dialog.YES_BUTTON )
5012
				{
5013
					self.et2.getWidgetById('mimeType').set_readonly(false);
5014
					self.et2.getWidgetById('mail_plaintext').set_disabled(false);
5015
					jQuery(self.mailvelope_iframe_selector).remove();
5016
				}
5017
				else
5018
				{
5019
					self.et2.getWidgetById('composeToolbar').checkbox('pgp',true);
5020
				}
5021
			},
5022
			this.egw.lang('You will loose current message body, unless you save it to your clipboard!'),
5023
			this.egw.lang('Switch off encryption?'),
5024
			{}, et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, this.egw);
5025
		}
5026
	},
5027
5028
	/**
5029
	 * Check if we have a key for all recipients
5030
	 *
5031
	 * @returns {Promise.<Array, Error>} Array of recipients or Error with recipients without key
5032
	 */
5033
	mailvelopeGetCheckRecipients: function()
5034
	{
5035
		// collect all recipients
5036
		var recipients = this.et2.getWidgetById('to').get_value();
5037
		recipients = recipients.concat(this.et2.getWidgetById('cc').get_value());
5038
		recipients = recipients.concat(this.et2.getWidgetById('bcc').get_value());
5039
5040
		return this._super.call(this, recipients);
5041
	},
5042
5043
	/**
5044
	 * Set the relevant widget to toolbar actions and submit
5045
	 *
5046
	 * @param {object|boolean} _action toolbar action or boolean value to stop extra call on
5047
	 * compose_integrated_submit
5048
	 */
5049
	compose_submitAction: function (_action)
5050
	{
5051
		if (this.compose_integrate_submit() && _action) return false;
5052
5053
		if (this.mailvelope_editor)
5054
		{
5055
			var self = this;
5056
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
5057
			{
5058
				return self.mailvelope_editor.encrypt(_recipients);
5059
			}).then(function(_armored)
5060
			{
5061
				self.et2.getWidgetById('mimeType').set_value(false);
5062
				self.et2.getWidgetById('mail_plaintext').set_disabled(false);
5063
				self.et2.getWidgetById('mail_plaintext').set_value(_armored);
5064
				self.et2._inst.submit(null,null,true);
5065
			}).catch(function(_err)
5066
			{
5067
				self.egw.message(_err.message, 'error');
5068
			});
5069
			return false;
5070
		}
5071
		this.et2._inst.submit(null,null,true);
5072
	},
5073
5074
	/**
5075
	 * This function runs before client submit (send) mail to server
5076
	 * and takes care of mail integration modules to popup entry selection
5077
	 * dialog to give user a choice to which entry of selected app the compose
5078
	 * should be integereated.
5079
	 * @param {int|boolean} _integIndex
5080
	 *
5081
	 * @returns {Boolean} return true if to_tracker is checked otherwise false
5082
	 */
5083
	compose_integrate_submit: function (_integIndex)
5084
	{
5085
		if (_integIndex == false) return false;
5086
		var index = _integIndex || 0;
5087
		var integApps = ['to_tracker', 'to_infolog', 'to_calendar'];
5088
		var subject = this.et2.getWidgetById('subject');
5089
		var toolbar = this.et2.getWidgetById('composeToolbar');
5090
		var to_integrate_ids = this.et2.getWidgetById('to_integrate_ids');
5091
		var integWidget= {};
5092
		var self = this;
5093
5094
		integWidget = this.et2.getWidgetById(integApps[index]);
5095
		if (toolbar.options.actions[integApps[index]] &&
5096
				typeof toolbar.options.actions[integApps[index]]['mail_import'] != 'undefined' &&
5097
				typeof toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'] != 'unefined')
5098
		{
5099
			var mail_import_hook = toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'];
5100
			if (integWidget.get_value() == 'on')
5101
			{
5102
				this.integrate_checkAppEntry(egw.lang('Select %1 entry',integApps[index]), integApps[index].substr(3), subject.get_value(), '', mail_import_hook , function (args){
5103
					var value = {};
5104
					value[integApps[index]] = args.entryid;
5105
					var oldValue = to_integrate_ids.get_value()[0];
5106
					to_integrate_ids.set_value(jQuery.extend(value,oldValue));
5107
					index = index<integApps.length? ++index:false;
5108
					self.compose_integrate_submit(index);
5109
				});
5110
				return true;
5111
			}
5112
		}
5113
		else if(index<integApps.length)
5114
		{
5115
			this.compose_integrate_submit(++index);
5116
		}
5117
		else
5118
		{
5119
			this.compose_submitAction(false);
5120
		}
5121
		return false;
5122
	},
5123
5124
	/**
5125
	 * Set the selected checkbox action
5126
	 *
5127
	 * @param {type} _action selected toolbar action with checkbox
5128
	 * @returns {undefined}
5129
	 */
5130
	compose_setToggle: function (_action)
5131
	{
5132
		var widget = this.et2.getWidgetById (_action.id);
5133
		if (widget && typeof _action.checkbox != 'undefined' && _action.checkbox)
5134
		{
5135
			widget.set_value(_action.checked?"on":"off");
5136
		}
5137
	},
5138
5139
	/**
5140
	 * Set the selected priority value
5141
	 * @param {type} _action selected action
5142
	 * @returns {undefined}
5143
	 */
5144
	compose_priorityChange: function (_action)
5145
	{
5146
		var widget = this.et2.getWidgetById ('priority');
5147
		if (widget)
5148
		{
5149
			widget.set_value(_action.id);
5150
		}
5151
	},
5152
5153
	/**
5154
	 * Triger relative widget via its toolbar identical action
5155
	 * @param {type} _action toolbar action
5156
	 */
5157
	compose_triggerWidget:function (_action)
5158
	{
5159
		var widget = this.et2.getWidgetById(_action.id);
5160
		if (widget)
5161
		{
5162
			switch(widget.id)
5163
			{
5164
				case 'uploadForCompose':
5165
					document.getElementById('mail-compose_uploadForCompose').click();
5166
					break;
5167
				default:
5168
					widget.click();
5169
			}
5170
		}
5171
	},
5172
5173
	/**
5174
	 * Save drafted compose as eml file into VFS
5175
	 * @param {type} _action action
5176
	 */
5177
	compose_saveDraft2fm: function (_action)
5178
	{
5179
		var content = this.et2.getArrayMgr('content').data;
5180
		var subject = this.et2.getWidgetById('subject');
5181
		var elem = {0:{id:"", subject:""}};
5182
		if (typeof content != 'undefined' && content.lastDrafted && subject)
5183
		{
5184
			elem[0].id = content.lastDrafted;
5185
			elem[0].subject = subject.get_value();
5186
			this.mail_save2fm(_action, elem);
5187
		}
5188
		else
5189
		{
5190
			et2_dialog.alert('You need to save the message as draft first before to be able to save it into VFS','Save to filemanager','info');
5191
		}
5192
	},
5193
5194
	/**
5195
	 * Folder Management, opens the folder magnt. dialog
5196
	 * with the selected acc_id from index tree
5197
	 *
5198
	 * @param {egw action object} _action actions
5199
	 * @param {object} _senders selected node
5200
	 */
5201
	folderManagement: function (_action,_senders)
5202
	{
5203
		var acc_id = parseInt(_senders[0].id);
5204
		this.egw.open_link('mail.mail_ui.folderManagement&acc_id='+acc_id, '_blank', '720x500');
5205
	},
5206
5207
	/**
5208
	 * Show ajax-loader when the autoloading get started
5209
	 *
5210
	 * @param {type} _id item id
5211
	 * @param {type} _widget tree widget
5212
	 * @returns {Boolean}
5213
	 */
5214
	folderMgmt_autoloadingStart: function(_id, _widget)
5215
	{
5216
		return this.subscription_autoloadingStart (_id, _widget);
5217
	},
5218
5219
	/**
5220
	 * Revert back the icon after autoloading is finished
5221
	 * @param {type} _id item id
5222
	 * @param {type} _widget tree widget
5223
	 * @returns {Boolean}
5224
	 */
5225
	folderMgmt_autoloadingEnd: function(_id, _widget)
5226
	{
5227
		return true;
5228
	},
5229
5230
	/**
5231
	 *
5232
	 * @param {type} _ids
5233
	 * @param {type} _widget
5234
	 * @returns {undefined}
5235
	 */
5236
	folderMgmt_onSelect: function(_ids, _widget)
5237
	{
5238
		// Flag to reset selected items
5239
		var resetSelection = false;
5240
5241
		var self = this;
5242
5243
		/**
5244
		 * helper function to multiselect range of nodes in same level
5245
		 *
5246
		 * @param {string} _a start node id
5247
		 * @param {string} _b end node id
5248
		 * @param {string} _branch totall node ids in the level
5249
		 */
5250
		var rangeSelector = function(_a,_b, _branch)
5251
		{
5252
			var branchItems = _branch.split(_widget.input.dlmtr);
5253
			var _aIndex = _widget.input.getIndexById(_a);
5254
			var _bIndex = _widget.input.getIndexById(_b);
5255
			if (_bIndex<_aIndex)
5256
			{
5257
				var tmpIndex = _aIndex;
5258
				_aIndex = _bIndex;
5259
				_bIndex = tmpIndex;
5260
			}
5261
			for(var i =_aIndex;i<=_bIndex;i++)
5262
			{
5263
				self.folderMgmt_setCheckbox(_widget, branchItems[i], !_widget.input.isItemChecked(branchItems[i]));
5264
			}
5265
		};
5266
5267
		// extract items ids
5268
		var itemIds = _ids.split(_widget.input.dlmtr);
5269
5270
		if(itemIds.length == 2) // there's a range selected
5271
		{
5272
			var branch = _widget.input.getSubItems(_widget.input.getParentId(itemIds[0]));
5273
			// Set range of selected/unselected
5274
			rangeSelector(itemIds[0], itemIds[1], branch);
5275
		}
5276
		else if(itemIds.length != 1)
5277
		{
5278
			resetSelection = true;
5279
		}
5280
5281
		if (resetSelection)
5282
		{
5283
			_widget.input._unselectItems();
5284
		}
5285
	},
5286
5287
	/**
5288
	 * Set enable/disable checkbox
5289
	 *
5290
	 * @param {object} _widget tree widget
5291
	 * @param {string} _itemId item tree id
5292
	 * @param {boolean} _stat - status to be set on checkbox true/false
5293
	 */
5294
	folderMgmt_setCheckbox: function (_widget, _itemId, _stat)
5295
	{
5296
		if (_widget)
5297
		{
5298
			_widget.input.setCheck(_itemId, _stat);
5299
			_widget.input.setSubChecked(_itemId,_stat);
5300
		}
5301
	},
5302
5303
	/**
5304
	 *
5305
	 * @param {type} _id
5306
	 * @param {type} _widget
5307
	 * @TODO: Implement onCheck handler in order to select or deselect subItems
5308
	 *	of a checked parent node
5309
	 */
5310
	folderMgmt_onCheck: function (_id, _widget)
5311
	{
5312
		var selected = _widget.input.getAllChecked();
5313
		if (selected && selected.split(_widget.input.dlmtr).length > 5)
5314
		{
5315
			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.'));
5316
		}
5317
	},
5318
5319
	/**
5320
	 * Detele button handler
5321
	 * triggers longTask dialog and send delete operation url
5322
	 *
5323
	 */
5324
	folderMgmt_deleteBtn: function ()
5325
	{
5326
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('tree');
5327
		var menuaction= 'mail.mail_ui.ajax_folderMgmt_delete';
5328
5329
		var callbackDialog = function(_btn)
5330
		{
5331
			egw.appName='mail';
5332
			if (_btn === et2_dialog.YES_BUTTON)
5333
			{
5334
				if (tree)
5335
				{
5336
					var selFolders = tree.input.getAllChecked();
5337
					if (selFolders)
5338
					{
5339
						var selFldArr = selFolders.split(tree.input.dlmtr);
5340
						var msg = egw.lang('Deleting %1 folders in progress ...', selFldArr.length);
5341
						et2_dialog.long_task(function(_val, _resp){
5342
							console.log(_val, _resp);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
5343
							if (_val && _resp.type !== 'error')
5344
							{
5345
								var stat = [];
5346
								var folderName = '';
5347
								for(var i=0;i<selFldArr.length;i++)
5348
								{
5349
									folderName = selFldArr[i].split('::');
5350
									stat[selFldArr[i]] = folderName[1];
5351
								}
5352
								// delete the item from index folderTree
5353
								egw.window.app.mail.mail_removeLeaf(stat);
5354
							}
5355
							else
5356
							{
5357
								// submit
5358
								etemplate2.getByApplication('mail')[0].widgetContainer._inst.submit();
5359
							}
5360
						}, msg, egw.lang('Deleting folders'), menuaction, selFldArr, 'mail');
5361
						return true;
5362
					}
5363
				}
5364
			}
5365
		};
5366
		et2_dialog.show_dialog(callbackDialog, this.egw.lang('Are you sure you want to delete all selected folders?'), this.egw.lang('Delete folder'), {},
5367
			et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, egw);
5368
	},
5369
5370
	/**
5371
	 * Spam Actions handler
5372
	 *
5373
	 * @param {object} _action egw action
5374
	 * @param {object} _sender nm row
5375
	 */
5376
	spam_actions: function (_action, _sender)
5377
	{
5378
		var id = '';
5379
		if (_sender.length == 0)
5380
		{
5381
			var nm = this.et2.getWidgetById(this.nm_index);
5382
			id = nm.getSelection().ids[0];
5383
		}
5384
		else
5385
		{
5386
			id = _sender[0].id;
5387
		}
5388
		var data = egw.dataGetUIDdata(id);
5389
		var fromaddress = data.data.fromaddress.match(/<([^\'\" <>]+)>$/);
5390
		var email = (fromaddress && fromaddress[1])?fromaddress[1]:data.data.fromaddress;
5391
		var domain = '@'+email.split('@')[1];
5392
		this.egw.json('mail.mail_ui.ajax_spamAction', [
5393
			_action.id,
5394
			{
5395
				'acc_id':id.split('::')[2],
5396
				'row_id':data.data.row_id,
5397
				'uid': data.data.uid,
5398
				'sender': _action.id.match(/domain/)? domain : email
5399
			}
5400
		]).sendRequest(true);
5401
	},
5402
5403
	spamTitan_setActionTitle: function (_action, _sender)
5404
	{
5405
		var id = _sender[0].id;
5406
		var data = egw.dataGetUIDdata(id);
5407
		var fromaddress = data.data.fromaddress.match(/<([^\'\" <>]+)>$/);
5408
		var email = (fromaddress && fromaddress[1]) ?fromaddress[1]:data.data.fromaddress;
5409
		var domain = email.split('@')[1];
5410
		switch (_action.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
5411
		{
5412
			case 'whitelist_email_add':
5413
				_action.set_caption(this.egw.lang('Add "%1" into whitelisted emails', email));
5414
				break;
5415
			case 'whitelist_email_remove':
5416
				_action.set_caption(this.egw.lang('Remove "%1" from whiltelisted emails', email));
5417
				break;
5418
			case 'whitelist_domain_add':
5419
				_action.set_caption(this.egw.lang('Add "%1" into whiltelisted domains', domain));
5420
				break;
5421
			case 'whitelist_domain_remove':
5422
				_action.set_caption(this.egw.lang('Remove "%1" from whiltelisted domains', domain));
5423
				break;
5424
			case 'blacklist_email_add':
5425
				_action.set_caption(this.egw.lang('Add "%1" into blacklisted emails', email));
5426
				break;
5427
			case 'blacklist_email_remove':
5428
				_action.set_caption(this.egw.lang('Remove "%1" from blacklisted emails', email));
5429
				break;
5430
			case 'blacklist_domain_add':
5431
				_action.set_caption(this.egw.lang('Add "%1" into blacklisted domains', domain));
5432
				break;
5433
			case 'blacklist_domain_remove':
5434
				_action.set_caption(this.egw.lang('Remove "%1" from blacklisted domains', domain));
5435
				break;
5436
5437
		}
5438
5439
		return true;
5440
	},
5441
	/**
5442
	 * Implement mobile view
5443
	 *
5444
	 * @param {type} _action
5445
	 * @param {type} _sender
5446
	 */
5447
	mobileView: function(_action, _sender)
5448
	{
5449
		// row id in nm
5450
		var id = _sender[0].id;
5451
5452
		var defaultActions= {
5453
			actions:['delete', 'forward','reply','flagged'], // default actions to display
5454
			check:function(_action){
5455
				for (var i=0;i<= this.actions.length;i++)
5456
				{
5457
					if (_action == this.actions[i]) return true;
5458
				}
5459
				return false;
5460
			}
5461
		};
5462
5463
		var content = {};
5464
		var self = this;
5465
5466
		if (id){
5467
			content = egw.dataGetUIDdata(id);
5468
			content.data['toolbar'] = this.et2.getArrayMgr('sel_options').getEntry('toolbar');
5469
			// Set default actions
5470
			for(var action in content.data['toolbar'])
5471
			{
5472
				content.data.toolbar[action]['toolbarDefault'] = defaultActions.check(action);
5473
			}
5474
			// update local storage with added toolbar actions
5475
			egw.dataStoreUID(id,content.data);
5476
		}
5477
5478
		this.viewEntry(_action, _sender, true, function(etemplate){
5479
			// et2 object in view
5480
			var et2 = etemplate.widgetContainer;
5481
			// iframe to load message
5482
			var iframe = et2.getWidgetById('iframe');
5483
			// toolbar widget
5484
			var toolbar = et2.getWidgetById('toolbar');
5485
			// attachments details title DOM node
5486
			var $attachment = jQuery('.attachments span.et2_details_title');
5487
			// details DOM
5488
			var $details = jQuery('.et2_details.details');
5489
			// Content
5490
			var content = et2.getArrayMgr('content').data;
5491
5492
			// set the current selected row
5493
			et2.mail_currentlyFocussed = id;
5494
5495
			if (content.attachmentsBlock.length>0 && content.attachmentsBlock[0].filename)
5496
			{
5497
				$attachment.text(self.egw.lang('%1 attachments', content.attachmentsBlock.length));
5498
			}
5499
			else
5500
			{
5501
				// disable attachments area if there's no attachments
5502
				$attachment.parent().hide();
5503
			}
5504
			// disable the detials if there's no details
5505
			if (!content.ccaddress && !content.additionaltoaddress) $details.hide();
5506
5507
			toolbar.set_actions(content.toolbar);
5508
			var toaddressdetails = self.et2_view.widgetContainer.getWidgetById('toaddressdetails');
5509
			if (toaddressdetails && content.additionaltoaddress)
5510
			{
5511
				toaddressdetails.set_value('... ' +content.additionaltoaddress.length + egw.lang(' more'));
5512
				jQuery(toaddressdetails.getDOMNode()).off().on('click', function(){
5513
					$details.find('.et2_details_toggle').click();
5514
				});
5515
			}
5516
5517
			// Request email body from server
5518
			iframe.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:id}));
5519
			jQuery(iframe.getDOMNode()).on('load',function(){
5520
5521
				if (jQuery(this.contentWindow.document.body).find('#calendar-meeting').length > 0)
5522
				{
5523
					var frame = this;
5524
					jQuery(this).show();
5525
					// calendar meeting mails still need to be in iframe, therefore, we calculate the height
5526
					// and set the iframe with a fixed height to be able to see all content without getting
5527
					// scrollbar becuase of scrolling issue in iframe
5528
					window.setTimeout(function(){jQuery(frame).height(frame.contentWindow.document.body.scrollHeight);}, 500);
5529
				}
5530
				else
5531
				{
5532
					// Use prepare print function to copy iframe content into div
5533
					// as we don't want to show content in iframe (scrolling problem).
5534
					self.mail_prepare_print(jQuery(this));
5535
				}
5536
5537
5538
			});
5539
		});
5540
	}
5541
});
5542