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 32KB

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