Aleksander Machniak
2016-05-16 0b7e26c1bf6bc7a684eb3a214d92d3927306cd8a
commit | author | age
b34d67 1 /**
TB 2  * (Manage)Sieve Filters plugin
3  *
4  * @licstart  The following is the entire license notice for the
5  * JavaScript code in this file.
6  *
7  * Copyright (c) 2012-2014, The Roundcube Dev Team
8  *
9  * The JavaScript code in this page is free software: you can redistribute it
10  * and/or modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation, either version 3 of
12  * the License, or (at your option) any later version.
13  *
14  * @licend  The above is the entire license notice
15  * for the JavaScript code in this file.
16  */
48e9c1 17
T 18 if (window.rcmail) {
19   rcmail.addEventListener('init', function(evt) {
20     // add managesieve-create command to message_commands array,
21     // so it's state will be updated on message selection/unselection
22     if (rcmail.env.task == 'mail') {
23       if (rcmail.env.action != 'show')
24         rcmail.env.message_commands.push('managesieve-create');
25       else
26         rcmail.enable_command('managesieve-create', true);
27     }
28
27f0c2 29     if (rcmail.env.task == 'mail' || rcmail.env.action.startsWith('plugin.managesieve')) {
48e9c1 30       // Create layer for form tips
T 31       if (!rcmail.env.framed) {
32         rcmail.env.ms_tip_layer = $('<div id="managesieve-tip" class="popupmenu"></div>');
33         rcmail.env.ms_tip_layer.appendTo(document.body);
34       }
35     }
36
37     // register commands
38     rcmail.register_command('plugin.managesieve-save', function() { rcmail.managesieve_save() });
39     rcmail.register_command('plugin.managesieve-act', function() { rcmail.managesieve_act() });
40     rcmail.register_command('plugin.managesieve-add', function() { rcmail.managesieve_add() });
41     rcmail.register_command('plugin.managesieve-del', function() { rcmail.managesieve_del() });
42     rcmail.register_command('plugin.managesieve-move', function() { rcmail.managesieve_move() });
43     rcmail.register_command('plugin.managesieve-setadd', function() { rcmail.managesieve_setadd() });
44     rcmail.register_command('plugin.managesieve-setdel', function() { rcmail.managesieve_setdel() });
45     rcmail.register_command('plugin.managesieve-setact', function() { rcmail.managesieve_setact() });
46     rcmail.register_command('plugin.managesieve-setget', function() { rcmail.managesieve_setget() });
47
27f0c2 48     if (rcmail.env.action.startsWith('plugin.managesieve')) {
48e9c1 49       if (rcmail.gui_objects.sieveform) {
T 50         rcmail.enable_command('plugin.managesieve-save', true);
581b6b 51         sieve_form_init();
48e9c1 52       }
T 53       else {
54         rcmail.enable_command('plugin.managesieve-add', 'plugin.managesieve-setadd', !rcmail.env.sieveconnerror);
55       }
56
13b33d 57       var setcnt, set = rcmail.env.currentset;
48e9c1 58
T 59       if (rcmail.gui_objects.filterslist) {
60         rcmail.filters_list = new rcube_list_widget(rcmail.gui_objects.filterslist,
13b33d 61           {multiselect:false, draggable:true, keyboard:true});
a2e09c 62
AM 63         rcmail.filters_list
13b33d 64           .addEventListener('select', function(e) { rcmail.managesieve_select(e); })
AM 65           .addEventListener('dragstart', function(e) { rcmail.managesieve_dragstart(e); })
66           .addEventListener('dragend', function(e) { rcmail.managesieve_dragend(e); })
a2e09c 67           .addEventListener('initrow', function(row) {
13b33d 68             row.obj.onmouseover = function() { rcmail.managesieve_focus_filter(row); };
AM 69             row.obj.onmouseout = function() { rcmail.managesieve_unfocus_filter(row); };
a2e09c 70           })
13b33d 71           .init();
48e9c1 72       }
T 73
74       if (rcmail.gui_objects.filtersetslist) {
a2e09c 75         rcmail.filtersets_list = new rcube_list_widget(rcmail.gui_objects.filtersetslist,
13b33d 76           {multiselect:false, draggable:false, keyboard:true});
a2e09c 77
13b33d 78         rcmail.filtersets_list.init().focus();
48e9c1 79
T 80         if (set != null) {
81           set = rcmail.managesieve_setid(set);
13b33d 82           rcmail.filtersets_list.select(set);
48e9c1 83         }
13b33d 84
AM 85         // attach select event after initial record was selected
86         rcmail.filtersets_list.addEventListener('select', function(e) { rcmail.managesieve_setselect(e); });
48e9c1 87
T 88         setcnt = rcmail.filtersets_list.rowcount;
89         rcmail.enable_command('plugin.managesieve-set', true);
90         rcmail.enable_command('plugin.managesieve-setact', 'plugin.managesieve-setget', setcnt);
91         rcmail.enable_command('plugin.managesieve-setdel', setcnt > 1);
92
93         // Fix dragging filters over sets list
13b33d 94         $('tr', rcmail.gui_objects.filtersetslist).each(function (i, e) { rcmail.managesieve_fixdragend(e); });
48e9c1 95       }
T 96     }
13b33d 97
48e9c1 98     if (rcmail.gui_objects.sieveform && rcmail.env.rule_disabled)
T 99       $('#disabled').attr('checked', true);
100   });
101 };
102
103 /*********************************************************/
104 /*********       Managesieve UI methods          *********/
105 /*********************************************************/
106
107 rcube_webmail.prototype.managesieve_add = function()
108 {
109   this.load_managesieveframe();
110   this.filters_list.clear_selection();
111 };
112
113 rcube_webmail.prototype.managesieve_del = function()
114 {
115   var id = this.filters_list.get_single_selection();
116   if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) {
117     var lock = this.set_busy(true, 'loading');
27f0c2 118     this.http_post('plugin.managesieve-action',
48e9c1 119       '_act=delete&_fid='+this.filters_list.rows[id].uid, lock);
T 120   }
121 };
122
123 rcube_webmail.prototype.managesieve_act = function()
124 {
125   var id = this.filters_list.get_single_selection(),
126     lock = this.set_busy(true, 'loading');
127
27f0c2 128   this.http_post('plugin.managesieve-action',
48e9c1 129     '_act=act&_fid='+this.filters_list.rows[id].uid, lock);
T 130 };
131
132 // Filter selection
133 rcube_webmail.prototype.managesieve_select = function(list)
134 {
135   var id = list.get_single_selection();
136   if (id != null)
137     this.load_managesieveframe(list.rows[id].uid);
138 };
139
140 // Set selection
141 rcube_webmail.prototype.managesieve_setselect = function(list)
142 {
143   this.show_contentframe(false);
144   this.filters_list.clear(true);
145   this.enable_command('plugin.managesieve-setdel', list.rowcount > 1);
27f0c2 146   this.enable_command('plugin.managesieve-setact', 'plugin.managesieve-setget', true);
48e9c1 147
T 148   var id = list.get_single_selection();
149   if (id != null)
150     this.managesieve_list(this.env.filtersets[id]);
151 };
152
153 rcube_webmail.prototype.managesieve_rowid = function(id)
154 {
155   var i, rows = this.filters_list.rows;
156
78ef00 157   for (i in rows)
48e9c1 158     if (rows[i] != null && rows[i].uid == id)
T 159       return i;
160 };
161
162 // Returns set's identifier
163 rcube_webmail.prototype.managesieve_setid = function(name)
164 {
165   for (var i in this.env.filtersets)
166     if (this.env.filtersets[i] == name)
167       return i;
168 };
169
170 // Filters listing request
171 rcube_webmail.prototype.managesieve_list = function(script)
172 {
173   var lock = this.set_busy(true, 'loading');
174
27f0c2 175   this.http_post('plugin.managesieve-action', '_act=list&_set='+urlencode(script), lock);
48e9c1 176 };
T 177
178 // Script download request
179 rcube_webmail.prototype.managesieve_setget = function()
180 {
181   var id = this.filtersets_list.get_single_selection(),
182     script = this.env.filtersets[id];
183
4a4088 184   this.goto_url('plugin.managesieve-action', {_act: 'setget', _set: script}, false, true);
48e9c1 185 };
T 186
187 // Set activate/deactivate request
188 rcube_webmail.prototype.managesieve_setact = function()
189 {
190   var id = this.filtersets_list.get_single_selection(),
191    lock = this.set_busy(true, 'loading'),
192     script = this.env.filtersets[id],
193     action = $('#rcmrow'+id).hasClass('disabled') ? 'setact' : 'deact';
194
27f0c2 195   this.http_post('plugin.managesieve-action', '_act='+action+'&_set='+urlencode(script), lock);
48e9c1 196 };
T 197
198 // Set delete request
199 rcube_webmail.prototype.managesieve_setdel = function()
200 {
201   if (!confirm(this.get_label('managesieve.setdeleteconfirm')))
202     return false;
203
204   var id = this.filtersets_list.get_single_selection(),
205     lock = this.set_busy(true, 'loading'),
206     script = this.env.filtersets[id];
207
27f0c2 208   this.http_post('plugin.managesieve-action', '_act=setdel&_set='+urlencode(script), lock);
48e9c1 209 };
T 210
211 // Set add request
212 rcube_webmail.prototype.managesieve_setadd = function()
213 {
214   this.filters_list.clear_selection();
215   this.enable_command('plugin.managesieve-act', 'plugin.managesieve-del', false);
216
217   if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
218     var lock = this.set_busy(true, 'loading');
219     target = window.frames[this.env.contentframe];
27f0c2 220     target.location.href = this.env.comm_path+'&_action=plugin.managesieve-action&_framed=1&_newset=1&_unlock='+lock;
48e9c1 221   }
T 222 };
223
224 rcube_webmail.prototype.managesieve_updatelist = function(action, o)
225 {
226   this.set_busy(true);
227
228   switch (action) {
229     // Delete filter row
230     case 'del':
022f51 231       var id = o.id, list = this.filters_list;
48e9c1 232
T 233       list.remove_row(this.managesieve_rowid(o.id));
234       list.clear_selection();
235       this.show_contentframe(false);
236       this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', false);
237
da7905 238       // filter identifiers changed, fix the list
AM 239       $('tr', this.filters_list.list).each(function() {
240         // remove hidden (deleted) rows
241         if (this.style.display == 'none') {
242           $(this).detach();
243           return;
244         }
245
022f51 246         var rowid = this.id.substr(6);
AM 247
248         // remove all attached events
d9ff47 249         $(this).off();
022f51 250
AM 251         // update row id
224a1b 252         if (rowid > id) {
AM 253           this.uid = rowid - 1;
254           $(this).attr('id', 'rcmrow' + this.uid);
255         }
da7905 256       });
AM 257       list.init();
48e9c1 258
T 259       break;
260
261     // Update filter row
262     case 'update':
da7905 263       var i, row = $('#rcmrow'+this.managesieve_rowid(o.id));
48e9c1 264
T 265       if (o.name)
d6b592 266         $('td', row).text(o.name);
48e9c1 267       if (o.disabled)
T 268         row.addClass('disabled');
269       else
270         row.removeClass('disabled');
271
272       $('#disabled', $('iframe').contents()).prop('checked', o.disabled);
273
274       break;
275
276     // Add filter row to the list
277     case 'add':
278       var list = this.filters_list,
279         row = $('<tr><td class="name"></td></tr>');
280
d6b592 281       $('td', row).text(o.name);
48e9c1 282       row.attr('id', 'rcmrow'+o.id);
T 283       if (o.disabled)
284         row.addClass('disabled');
285
286       list.insert_row(row.get(0));
287       list.highlight_row(o.id);
288
289       this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', true);
290
291       break;
292
293     // Filling rules list
294     case 'list':
295       var i, tr, td, el, list = this.filters_list;
296
297       if (o.clear)
298         list.clear();
299
300       for (i in o.list) {
301         el = o.list[i];
302         tr = document.createElement('TR');
303         td = document.createElement('TD');
304
d6b592 305         $(td).text(el.name);
48e9c1 306         td.className = 'name';
T 307         tr.id = 'rcmrow' + el.id;
308         if (el['class'])
309             tr.className = el['class'];
310         tr.appendChild(td);
311
312         list.insert_row(tr);
313       }
314
315       if (o.set)
316         list.highlight_row(o.set);
317       else
318         this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', false);
319
320       break;
321
322     // Sactivate/deactivate set
323     case 'setact':
324       var id = this.managesieve_setid(o.name), row = $('#rcmrow' + id);
325       if (o.active) {
326         if (o.all)
327           $('tr', this.gui_objects.filtersetslist).addClass('disabled');
328         row.removeClass('disabled');
329       }
330       else
331         row.addClass('disabled');
332
333       break;
334
335     // Delete set row
336     case 'setdel':
337       var id = this.managesieve_setid(o.name);
338
339       this.filtersets_list.remove_row(id);
340       this.filters_list.clear();
341       this.show_contentframe(false);
342       this.enable_command('plugin.managesieve-setdel', 'plugin.managesieve-setact', 'plugin.managesieve-setget', false);
343
344       delete this.env.filtersets[id];
345
346       break;
347
348     // Create set row
349     case 'setadd':
350       var id = 'S' + new Date().getTime(),
351         list = this.filtersets_list,
352         row = $('<tr class="disabled"><td class="name"></td></tr>');
353
d6b592 354       $('td', row).text(o.name);
48e9c1 355       row.attr('id', 'rcmrow'+id);
T 356
357       this.env.filtersets[id] = o.name;
358       list.insert_row(row.get(0));
359
360       // move row into its position on the list
361       if (o.index != list.rowcount-1) {
362         row.detach();
363         var elem = $('tr:visible', list.list).get(o.index);
364         row.insertBefore(elem);
365       }
366
367       list.select(id);
368
369       // Fix dragging filters over sets list
370       this.managesieve_fixdragend(row);
371
372       break;
373   }
374
375   this.set_busy(false);
376 };
377
378 // load filter frame
379 rcube_webmail.prototype.load_managesieveframe = function(id)
380 {
381   var has_id = typeof(id) != 'undefined' && id != null;
382   this.enable_command('plugin.managesieve-act', 'plugin.managesieve-del', has_id);
383
384   if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) {
385     target = window.frames[this.env.contentframe];
386     var msgid = this.set_busy(true, 'loading');
27f0c2 387     target.location.href = this.env.comm_path+'&_action=plugin.managesieve-action&_framed=1'
a648ba 388       +(has_id ? '&_fid='+id : '')+'&_unlock='+msgid;
48e9c1 389   }
T 390 };
391
392 // load filter frame
393 rcube_webmail.prototype.managesieve_dragstart = function(list)
394 {
395   var id = this.filters_list.get_single_selection();
396
397   this.drag_active = true;
398   this.drag_filter = id;
399 };
400
401 rcube_webmail.prototype.managesieve_dragend = function(e)
402 {
403   if (this.drag_active) {
404     if (this.drag_filter_target) {
405       var lock = this.set_busy(true, 'loading');
406
407       this.show_contentframe(false);
27f0c2 408       this.http_post('plugin.managesieve-action', '_act=move&_fid='+this.drag_filter
48e9c1 409         +'&_to='+this.drag_filter_target, lock);
T 410     }
411     this.drag_active = false;
412   }
413 };
414
415 // Fixes filters dragging over sets list
416 // @TODO: to be removed after implementing copying filters
417 rcube_webmail.prototype.managesieve_fixdragend = function(elem)
418 {
419   var p = this;
d9ff47 420   $(elem).on('mouseup' + ((bw.iphone || bw.ipad) ? ' touchend' : ''), function(e) {
48e9c1 421     if (p.drag_active)
T 422       p.filters_list.drag_mouse_up(e);
423   });
424 };
425
426 rcube_webmail.prototype.managesieve_focus_filter = function(row)
427 {
428   var id = row.id.replace(/^rcmrow/, '');
429   if (this.drag_active && id != this.drag_filter) {
430     this.drag_filter_target = id;
431     $(row.obj).addClass(id < this.drag_filter ? 'filtermoveup' : 'filtermovedown');
432   }
433 };
434
435 rcube_webmail.prototype.managesieve_unfocus_filter = function(row)
436 {
437   if (this.drag_active) {
438     $(row.obj).removeClass('filtermoveup filtermovedown');
439     this.drag_filter_target = null;
440   }
441 };
442
443 /*********************************************************/
444 /*********          Filter Form methods          *********/
445 /*********************************************************/
446
447 // Form submition
448 rcube_webmail.prototype.managesieve_save = function()
449 {
50a57e 450   if (this.env.action == 'plugin.managesieve-vacation') {
AM 451     var data = $(this.gui_objects.sieveform).serialize();
452     this.http_post('plugin.managesieve-vacation', data, this.display_message(this.get_label('managesieve.vacation.saving'), 'loading'));
453     return;
454   }
455
48e9c1 456   if (parent.rcmail && parent.rcmail.filters_list && this.gui_objects.sieveform.name != 'filtersetform') {
T 457     var id = parent.rcmail.filters_list.get_single_selection();
458     if (id != null)
459       this.gui_objects.sieveform.elements['_fid'].value = parent.rcmail.filters_list.rows[id].uid;
460   }
461   this.gui_objects.sieveform.submit();
462 };
463
464 // Operations on filters form
465 rcube_webmail.prototype.managesieve_ruleadd = function(id)
466 {
27f0c2 467   this.http_post('plugin.managesieve-action', '_act=ruleadd&_rid='+id);
48e9c1 468 };
T 469
470 rcube_webmail.prototype.managesieve_rulefill = function(content, id, after)
471 {
472   if (content != '') {
473     // create new element
474     var div = document.getElementById('rules'),
475       row = document.createElement('div');
476
477     this.managesieve_insertrow(div, row, after);
478     // fill row after inserting (for IE)
479     row.setAttribute('id', 'rulerow'+id);
480     row.className = 'rulerow';
481     row.innerHTML = content;
482
c6f075 483     // initialize smart list inputs
AM 484     $('textarea[data-type="list"]', row).each(function() {
485       smart_field_init(this);
486     });
487
48e9c1 488     this.managesieve_formbuttons(div);
T 489   }
490 };
491
492 rcube_webmail.prototype.managesieve_ruledel = function(id)
493 {
494   if ($('#ruledel'+id).hasClass('disabled'))
495     return;
496
497   if (confirm(this.get_label('managesieve.ruledeleteconfirm'))) {
498     var row = document.getElementById('rulerow'+id);
499     row.parentNode.removeChild(row);
500     this.managesieve_formbuttons(document.getElementById('rules'));
501   }
502 };
503
504 rcube_webmail.prototype.managesieve_actionadd = function(id)
505 {
27f0c2 506   this.http_post('plugin.managesieve-action', '_act=actionadd&_aid='+id);
48e9c1 507 };
T 508
509 rcube_webmail.prototype.managesieve_actionfill = function(content, id, after)
510 {
511   if (content != '') {
512     var div = document.getElementById('actions'),
513       row = document.createElement('div');
514
515     this.managesieve_insertrow(div, row, after);
516     // fill row after inserting (for IE)
517     row.className = 'actionrow';
518     row.setAttribute('id', 'actionrow'+id);
519     row.innerHTML = content;
520
9a0900 521     // initialize smart list inputs
AM 522     $('textarea[data-type="list"]', row).each(function() {
523       smart_field_init(this);
524     });
525
48e9c1 526     this.managesieve_formbuttons(div);
T 527   }
528 };
529
530 rcube_webmail.prototype.managesieve_actiondel = function(id)
531 {
532   if ($('#actiondel'+id).hasClass('disabled'))
533     return;
534
535   if (confirm(this.get_label('managesieve.actiondeleteconfirm'))) {
536     var row = document.getElementById('actionrow'+id);
537     row.parentNode.removeChild(row);
538     this.managesieve_formbuttons(document.getElementById('actions'));
539   }
540 };
541
542 // insert rule/action row in specified place on the list
543 rcube_webmail.prototype.managesieve_insertrow = function(div, row, after)
544 {
545   for (var i=0; i<div.childNodes.length; i++) {
546     if (div.childNodes[i].id == (div.id == 'rules' ? 'rulerow' : 'actionrow')  + after)
547       break;
548   }
549
550   if (div.childNodes[i+1])
551     div.insertBefore(row, div.childNodes[i+1]);
552   else
553     div.appendChild(row);
554 };
555
556 // update Delete buttons status
557 rcube_webmail.prototype.managesieve_formbuttons = function(div)
558 {
559   var i, button, buttons = [];
560
561   // count and get buttons
562   for (i=0; i<div.childNodes.length; i++) {
563     if (div.id == 'rules' && div.childNodes[i].id) {
564       if (/rulerow/.test(div.childNodes[i].id))
565         buttons.push('ruledel' + div.childNodes[i].id.replace(/rulerow/, ''));
566     }
567     else if (div.childNodes[i].id) {
568       if (/actionrow/.test(div.childNodes[i].id))
569         buttons.push( 'actiondel' + div.childNodes[i].id.replace(/actionrow/, ''));
570     }
571   }
572
573   for (i=0; i<buttons.length; i++) {
574     button = document.getElementById(buttons[i]);
575     if (i>0 || buttons.length>1) {
576       $(button).removeClass('disabled');
577     }
578     else {
579       $(button).addClass('disabled');
580     }
581   }
582 };
583
9c38c5 584 // update vacation addresses field with user identities
AM 585 rcube_webmail.prototype.managesieve_vacation_addresses = function(id)
586 {
587   var lock = this.set_busy(true, 'loading');
588   this.http_post('plugin.managesieve-action', {_act: 'addresses', _aid: id}, lock);
589 };
590
591 // update vacation addresses field with user identities
592 rcube_webmail.prototype.managesieve_vacation_addresses_update = function(id, addresses)
593 {
594   var field = $('#vacation_addresses,#action_addresses' + (id || ''));
595   smart_field_reset(field.get(0), addresses);
596 };
597
48e9c1 598 function rule_header_select(id)
T 599 {
600   var obj = document.getElementById('header' + id),
601     size = document.getElementById('rule_size' + id),
e499a1 602     msg = document.getElementById('rule_message' + id),
48e9c1 603     op = document.getElementById('rule_op' + id),
a1679c 604     header = document.getElementById('custom_header' + id + '_list'),
48e9c1 605     mod = document.getElementById('rule_mod' + id),
T 606     trans = document.getElementById('rule_trans' + id),
0185a2 607     comp = document.getElementById('rule_comp' + id),
AM 608     datepart = document.getElementById('rule_date_part' + id),
609     dateheader = document.getElementById('rule_date_header_div' + id),
610     h = obj.value;
48e9c1 611
0185a2 612   if (h == 'size') {
48e9c1 613     size.style.display = 'inline';
e499a1 614     $.each([op, header, mod, trans, comp, msg], function() { this.style.display = 'none'; });
AM 615   }
616   else if (h == 'message') {
617     msg.style.display = 'inline';
618     $.each([op, header, mod, trans, comp, size], function() { this.style.display = 'none'; });
48e9c1 619   }
T 620   else {
0185a2 621     header.style.display = h != '...' ? 'none' : 'inline-block';
48e9c1 622     size.style.display = 'none';
T 623     op.style.display = 'inline';
624     comp.style.display = '';
0185a2 625     mod.style.display = h == 'body' || h == 'currentdate' || h == 'date' ? 'none' : 'block';
AM 626     trans.style.display = h == 'body' ? 'block' : 'none';
e499a1 627     msg.style.display = h == 'message' ? 'block' : 'none';
48e9c1 628   }
T 629
0185a2 630   if (datepart)
AM 631     datepart.style.display = h == 'currentdate' || h == 'date' ? 'inline' : 'none';
632   if (dateheader)
633     dateheader.style.display = h == 'date' ? '' : 'none';
634
635   rule_op_select(op, id, h);
636   rule_mod_select(id, h);
637   obj.style.width = h == '...' ? '40px' : '';
48e9c1 638 };
T 639
c6f075 640 function rule_op_select(obj, id, header)
48e9c1 641 {
5c6e74 642   var target = document.getElementById('rule_target' + id + '_list');
48e9c1 643
5c6e74 644   if (!header)
AM 645     header = document.getElementById('header' + id).value;
646
e499a1 647   target.style.display = obj.value.match(/^(exists|notexists)$/) || header.match(/^(size|message)$/) ? 'none' : 'inline-block';
48e9c1 648 };
T 649
650 function rule_trans_select(id)
651 {
652   var obj = document.getElementById('rule_trans_op' + id),
653     target = document.getElementById('rule_trans_type' + id);
654
655   target.style.display = obj.value != 'content' ? 'none' : 'inline';
656 };
657
0185a2 658 function rule_mod_select(id, header)
48e9c1 659 {
T 660   var obj = document.getElementById('rule_mod_op' + id),
0185a2 661     target = document.getElementById('rule_mod_type' + id),
e499a1 662     duplicate = document.getElementById('rule_duplicate_div' + id),
0185a2 663     index = document.getElementById('rule_index_div' + id);
AM 664
665   if (!header)
666     header = document.getElementById('header' + id).value;
48e9c1 667
T 668   target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline';
0185a2 669
AM 670   if (index)
e499a1 671     index.style.display = !header.match(/^(body|currentdate|size|message)$/) && obj.value != 'envelope'  ? '' : 'none';
AM 672
673   if (duplicate)
674     duplicate.style.display = header == 'message' ? '' : 'none';
48e9c1 675 };
T 676
677 function rule_join_radio(value)
678 {
679   $('#rules').css('display', value == 'any' ? 'none' : 'block');
680 };
681
682 function rule_adv_switch(id, elem)
683 {
684   var elem = $(elem), enabled = elem.hasClass('hide'), adv = $('#rule_advanced'+id);
685
686   if (enabled) {
687     adv.hide();
688     elem.removeClass('hide').addClass('show');
689   }
690   else {
691     adv.show();
692     elem.removeClass('show').addClass('hide');
693   }
694 }
695
696 function action_type_select(id)
697 {
698   var obj = document.getElementById('action_type' + id),
f001af 699     v = obj.value, enabled = {},
48e9c1 700     elems = {
T 701       mailbox: document.getElementById('action_mailbox' + id),
0f4806 702       target: document.getElementById('redirect_target' + id),
48e9c1 703       target_area: document.getElementById('action_target_area' + id),
T 704       flags: document.getElementById('action_flags' + id),
ebb204 705       vacation: document.getElementById('action_vacation' + id),
2e7bd6 706       set: document.getElementById('action_set' + id),
PS 707       notify: document.getElementById('action_notify' + id)
48e9c1 708     };
T 709
0185a2 710   if (v == 'fileinto' || v == 'fileinto_copy') {
48e9c1 711     enabled.mailbox = 1;
T 712   }
0185a2 713   else if (v == 'redirect' || v == 'redirect_copy') {
48e9c1 714     enabled.target = 1;
T 715   }
0185a2 716   else if (v.match(/^reject|ereject$/)) {
48e9c1 717     enabled.target_area = 1;
T 718   }
0185a2 719   else if (v.match(/^(add|set|remove)flag$/)) {
48e9c1 720     enabled.flags = 1;
T 721   }
0185a2 722   else if (v == 'vacation') {
48e9c1 723     enabled.vacation = 1;
T 724   }
0185a2 725   else if (v == 'set') {
ebb204 726     enabled.set = 1;
AM 727   }
0185a2 728   else if (v == 'notify') {
2e7bd6 729     enabled.notify = 1;
PS 730   }
48e9c1 731
T 732   for (var x in elems) {
733     elems[x].style.display = !enabled[x] ? 'none' : 'inline';
734   }
735 };
736
c883f6 737 function vacation_action_select()
AM 738 {
739   var selected = $('#vacation_action').val();
740
741   $('#action_target_span')[selected == 'discard' || selected == 'keep' ? 'hide' : 'show']();
742 };
743
c6f075 744 // Inititalizes smart list input
AM 745 function smart_field_init(field)
746 {
747   var id = field.id + '_list',
748     area = $('<span class="listarea"></span>'),
749     list = field.value ? field.value.split("\n") : [''];
750
751   if ($('#'+id).length)
752     return;
753
754   // add input rows
755   $.each(list, function(i, v) {
756     area.append(smart_field_row(v, field.name, i, $(field).data('size')));
757   });
758
759   area.attr('id', id);
760   field = $(field);
761
762   if (field.attr('disabled'))
763     area.hide();
8b5038 764   // disable the original field anyway, we don't want it in POST
AM 765   else
766     field.prop('disabled', true);
c6f075 767
AM 768   field.after(area);
769
770   if (field.hasClass('error')) {
771     area.addClass('error');
772     rcmail.managesieve_tip_register([[id, field.data('tip')]]);
773   }
774 };
775
776 function smart_field_row(value, name, idx, size)
777 {
778   // build row element content
779   var input, content = '<span class="listelement">'
bba781 780       + '<span class="reset"></span><input type="text"></span>',
c6f075 781     elem = $(content),
AM 782     attrs = {value: value, name: name + '[]'};
783
784   if (size)
785     attrs.size = size;
786
bba781 787   input = $('input', elem).attr(attrs).keydown(function(e) {
AM 788     var input = $(this);
13b33d 789
bba781 790     // element creation event (on Enter)
AM 791     if (e.which == 13) {
792       var name = input.attr('name').replace(/\[\]$/, ''),
793         dt = (new Date()).getTime(),
794         elem = smart_field_row('', name, dt, size);
c6f075 795
bba781 796       input.parent().after(elem);
AM 797       $('input', elem).focus();
798     }
13b33d 799     // backspace or delete: remove input, focus previous one
AM 800     else if ((e.which == 8 || e.which == 46) && input.val() == '') {
801
802       var parent = input.parent(), siblings = parent.parent().children();
803
804       if (siblings.length > 1) {
805         if (parent.prev().length)
806           parent.prev().children('input').focus();
807         else
808           parent.next().children('input').focus();
809
810         parent.remove();
811         return false;
812       }
813     }
c6f075 814   });
AM 815
816   // element deletion event
817   $('span[class="reset"]', elem).click(function() {
bba781 818     var span = $(this.parentNode);
c6f075 819
AM 820     if (span.parent().children().length > 1)
821       span.remove();
822     else
823       $('input', span).val('').focus();
824   });
825
826   return elem;
827 }
828
9c38c5 829 // Reset and fill the smart list input with new data
AM 830 function smart_field_reset(field, data)
831 {
832   var id = field.id + '_list',
833     list = data.length ? data : [''];
834     area = $('#' + id);
835
836   area.empty();
837
838   // add input rows
839   $.each(list, function(i, v) {
840     area.append(smart_field_row(v, field.name, i, $(field).data('size')));
841   });
842 }
843
48e9c1 844 // Register onmouse(leave/enter) events for tips on specified form element
T 845 rcube_webmail.prototype.managesieve_tip_register = function(tips)
846 {
847   var n, framed = parent.rcmail,
848     tip = framed ? parent.rcmail.env.ms_tip_layer : rcmail.env.ms_tip_layer;
849
d9ff47 850   for (n in tips) {
48e9c1 851     $('#'+tips[n][0])
c6f075 852       .data('tip', tips[n][1])
d9ff47 853       .mouseleave(function(e) { tip.hide(); })
AM 854       .mouseenter(function(e) {
c6f075 855         var elem = $(this),
AM 856           offset = elem.offset(),
857           left = offset.left,
858           top = offset.top - 12,
859           minwidth = elem.width();
48e9c1 860
c6f075 861         if (framed) {
AM 862           offset = $((rcmail.env.task == 'mail'  ? '#sievefilterform > iframe' : '#filter-box'), parent.document).offset();
863           top  += offset.top;
864           left += offset.left;
865         }
48e9c1 866
c6f075 867         tip.html(elem.data('tip'));
AM 868         top -= tip.height();
48e9c1 869
c6f075 870         tip.css({left: left, top: top, minWidth: (minwidth-2) + 'px'}).show();
d9ff47 871       });
48e9c1 872   }
T 873 };
874
581b6b 875 // format time string
AM 876 function sieve_formattime(hour, minutes)
877 {
878   var i, c, h, time = '', format = rcmail.env.time_format || 'H:i';
879
880   for (i=0; i<format.length; i++) {
881     c = format.charAt(i);
882     switch (c) {
883       case 'a': time += hour > 12 ? 'am' : 'pm'; break;
884       case 'A': time += hour > 12 ? 'AM' : 'PM'; break;
885       case 'g':
886       case 'h':
887         h = hour == 0 ? 12 : hour > 12 ? hour - 12 : hour;
888         time += (c == 'h' && hour < 10 ? '0' : '') + hour;
889         break;
890       case 'G': time += hour; break;
891       case 'H': time += (hour < 10 ? '0' : '') + hour; break;
892       case 'i': time += (minutes < 10 ? '0' : '') + minutes; break;
893       case 's': time += '00';
894       default: time += c;
895     }
896   }
897
898   return time;
899 }
900
901 function sieve_form_init()
902 {
903   // small resize for header element
904   $('select[name="_header[]"]', rcmail.gui_objects.sieveform).each(function() {
905     if (this.value == '...') this.style.width = '40px';
906   });
907
908   // resize dialog window
909   if (rcmail.env.action == 'plugin.managesieve' && rcmail.env.task == 'mail') {
910     parent.rcmail.managesieve_dialog_resize(rcmail.gui_objects.sieveform);
911   }
912
913   $('input[type="text"]:first', rcmail.gui_objects.sieveform).focus();
914
915   // initialize smart list inputs
916   $('textarea[data-type="list"]', rcmail.gui_objects.sieveform).each(function() {
917     smart_field_init(this);
918   });
919
920   // enable date pickers on date fields
921   if ($.datepicker && rcmail.env.date_format) {
922     $.datepicker.setDefaults({
923       dateFormat: rcmail.env.date_format,
924       changeMonth: true,
925       showOtherMonths: true,
926       selectOtherMonths: true,
927       onSelect: function(dateText) { $(this).focus().val(dateText); }
928     });
929     $('input.datepicker').datepicker();
930   }
931
932   // configure drop-down menu on time input fields based on jquery UI autocomplete
933   $('#vacation_timefrom, #vacation_timeto')
934     .attr('autocomplete', "off")
935     .autocomplete({
936       delay: 100,
937       minLength: 1,
938       source: function(p, callback) {
939         var h, result = [];
940         for (h = 0; h < 24; h++)
941           result.push(sieve_formattime(h, 0));
942         result.push(sieve_formattime(23, 59));
943
944         return callback(result);
945       },
946       open: function(event, ui) {
947         // scroll to current time
948         var $this = $(this), val = $this.val(),
949           widget = $this.autocomplete('widget').css('width', '10em'),
950           menu = $this.data('ui-autocomplete').menu;
951
952         if (val && val.length)
953           widget.children().each(function() {
954             var li = $(this);
955             if (li.text().indexOf(val) == 0)
956               menu._scrollIntoView(li);
957           });
958       },
959       select: function(event, ui) {
960         $(this).val(ui.item.value);
961         return false;
962       }
963     })
964     .click(function() {  // show drop-down upon clicks
965       $(this).autocomplete('search', $(this).val() || ' ');
966     })
e499a1 967
AM 968   // display advanced controls when contain errors
969   $('input.error').each(function() {
970     if (String(this.id).match(/([0-9]+)$/)) {
971       $('#ruleadv' + RegExp.$1 + '.show').click();
972     }
973   });
581b6b 974 }
AM 975
976
48e9c1 977 /*********************************************************/
T 978 /*********           Mail UI methods             *********/
979 /*********************************************************/
980
fb5255 981 rcube_webmail.prototype.managesieve_create = function(force)
48e9c1 982 {
6e6f9c 983   if (!force && this.env.action != 'show') {
fb5255 984     var uid = this.message_list.get_single_selection(),
AM 985       lock = this.set_busy(true, 'loading');
986
987     this.http_post('plugin.managesieve-action', {_uid: uid}, lock);
988     return;
989   }
990
991   if (!this.env.sieve_headers || !this.env.sieve_headers.length)
48e9c1 992     return;
T 993
994   var i, html, buttons = {}, dialog = $("#sievefilterform");
995
996   // create dialog window
997   if (!dialog.length) {
998     dialog = $('<div id="sievefilterform"></div>');
999     $('body').append(dialog);
1000   }
1001
1002   // build dialog window content
8f8bea 1003   html = '<fieldset><legend>'+this.get_label('managesieve.usedata')+'</legend><ul>';
fb5255 1004   for (i in this.env.sieve_headers)
48e9c1 1005     html += '<li><input type="checkbox" name="headers[]" id="sievehdr'+i+'" value="'+i+'" checked="checked" />'
fb5255 1006       +'<label for="sievehdr'+i+'">'+this.env.sieve_headers[i][0]+':</label> '+this.env.sieve_headers[i][1]+'</li>';
48e9c1 1007   html += '</ul></fieldset>';
T 1008
1009   dialog.html(html);
1010
1011   // [Next Step] button action
8f8bea 1012   buttons[this.get_label('managesieve.nextstep')] = function () {
48e9c1 1013     // check if there's at least one checkbox checked
T 1014     var hdrs = $('input[name="headers[]"]:checked', dialog);
1015     if (!hdrs.length) {
8f8bea 1016       alert(rcmail.get_label('managesieve.nodata'));
48e9c1 1017       return;
T 1018     }
1019
1020     // build frame URL
1021     var url = rcmail.get_task_url('mail');
1022     url = rcmail.add_url(url, '_action', 'plugin.managesieve');
1023     url = rcmail.add_url(url, '_framed', 1);
1024
1025     hdrs.map(function() {
1026       var val = rcmail.env.sieve_headers[this.value];
1027       url = rcmail.add_url(url, 'r['+this.value+']', val[0]+':'+val[1]);
1028     });
1029
1030     // load form in the iframe
1031     var frame = $('<iframe>').attr({src: url, frameborder: 0})
46f06c 1032     dialog.empty().append(frame).dialog('widget').resize();
48e9c1 1033
T 1034     // Change [Next Step] button with [Save] button
1035     buttons = {};
8f8bea 1036     buttons[rcmail.get_label('save')] = function() {
48e9c1 1037       var win = $('iframe', dialog).get(0).contentWindow;
T 1038       win.rcmail.managesieve_save();
1039     };
1040     dialog.dialog('option', 'buttons', buttons);
1041   };
1042
1043   // show dialog window
1044   dialog.dialog({
1045     modal: false,
64542f 1046     resizable: true,
AM 1047     closeOnEscape: !bw.ie7,  // disable for performance reasons
8f8bea 1048     title: this.get_label('managesieve.newfilter'),
48e9c1 1049     close: function() { rcmail.managesieve_dialog_close(); },
T 1050     buttons: buttons,
1051     minWidth: 600,
1052     minHeight: 300,
1053     height: 250
1054   }).show();
1055
1056   this.env.managesieve_dialog = dialog;
1057 }
1058
1059 rcube_webmail.prototype.managesieve_dialog_close = function()
1060 {
1061   var dialog = this.env.managesieve_dialog;
1062
1063   // BUG(?): if we don't remove the iframe first, it will be reloaded
1064   dialog.html('');
1065   dialog.dialog('destroy').hide();
1066 }
1067
1068 rcube_webmail.prototype.managesieve_dialog_resize = function(o)
1069 {
1070   var dialog = this.env.managesieve_dialog,
1071     win = $(window), form = $(o);
1072     width = $('fieldset:first', o).width(), // fieldset width is more appropriate here
1073     height = form.height(),
1074     w = win.width(), h = win.height();
1075
1076   dialog.dialog('option', { height: Math.min(h-20, height+120), width: Math.min(w-20, width+65) })
1077     .dialog('option', 'position', ['center', 'center']);  // works in a separate call only (!?)
1078 }