You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

managesieve.js 35KB

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