comparison plugins/managesieve/managesieve.js @ 0:1e000243b222

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