Thomas Bruederli
2014-04-25 6c7452d667159d99d36103fbeae1f19acf64e05e
commit | author | age
5f660c 1 /**
e019f2 2  * Roundcube functions for default skin interface
5f660c 3  */
A 4
5 /**
6  * Settings
7  */
8
9 function rcube_init_settings_tabs()
10 {
a3ed96 11   var el, cl, container = $('#tabsbar'),
A 12     last_tab = $('span:last', container),
c49c35 13     tab = '#settingstabpreferences',
a3ed96 14     action = window.rcmail && rcmail.env.action ? rcmail.env.action : null;
A 15
16   // move About tab to the end
17   if (last_tab && last_tab.attr('id') != 'settingstababout' && (el = $('#settingstababout'))) {
18     cl = el.clone(true);
19     el.remove();
20     last_tab.after(cl);
21   }
22
23   // get selected tab
24   if (action)
c49c35 25     tab = '#settingstab' + (action.indexOf('identity')>0 ? 'identities' : action.replace(/\./g, ''));
cc97ea 26
T 27   $(tab).addClass('tablink-selected');
9489a2 28   $('a', tab).removeAttr('onclick').click(function() { return false; });
5f660c 29 }
A 30
6769ba 31 // Fieldsets-to-tabs converter
A 32 // Warning: don't place "caller" <script> inside page element (id)
33 function rcube_init_tabs(id, current)
34 {
0501b6 35   var content = $('#'+id),
T 36     fs = content.children('fieldset');
7403ab 37
A 38   if (!fs.length)
39     return;
6769ba 40
A 41   current = current ? current : 0;
42
43   // first hide not selected tabs
44   fs.each(function(idx) { if (idx != current) $(this).hide(); });
45
46   // create tabs container
5744bf 47   var tabs = $('<div>').addClass('tabsbar').appendTo(content);
6769ba 48
A 49   // convert fildsets into tabs
50   fs.each(function(idx) {
0501b6 51     var tab, a, elm = $(this), legend = elm.children('legend');
6769ba 52
A 53     // create a tab
54     a   = $('<a>').text(legend.text()).attr('href', '#');
55     tab = $('<span>').attr({'id': 'tab'+idx, 'class': 'tablink'})
361ce6 56         .click(function() { rcube_show_tab(id, idx); return false })
6769ba 57
A 58     // remove legend
59     legend.remove();
60     // style fieldset
61     elm.addClass('tabbed');
62     // style selected tab
63     if (idx == current)
64       tab.addClass('tablink-selected');
65
66     // add the tab to container
67     tab.append(a).appendTo(tabs);
68   });
69 }
70
71 function rcube_show_tab(id, index)
72 {
0501b6 73   var fs = $('#'+id).children('fieldset');
6769ba 74
A 75   fs.each(function(idx) {
76     // Show/hide fieldset (tab content)
77     $(this)[index==idx ? 'show' : 'hide']();
78     // Select/unselect tab
79     $('#tab'+idx).toggleClass('tablink-selected', idx==index);
80   });
81 }
82
5f660c 83 /**
3940ba 84  * Mail UI
5f660c 85  */
A 86
87 function rcube_mail_ui()
88 {
9e5550 89   this.popups = {
A 90     markmenu:       {id:'markmessagemenu'},
e25a35 91     replyallmenu:   {id:'replyallmenu'},
d145f7 92     forwardmenu:    {id:'forwardmenu', editable:1},
9e5550 93     searchmenu:     {id:'searchmenu', editable:1},
A 94     messagemenu:    {id:'messagemenu'},
bc2c43 95     attachmentmenu: {id:'attachmentmenu'},
9e5550 96     listmenu:       {id:'listmenu', editable:1},
a45f9b 97     dragmenu:       {id:'dragmenu', sticky:1},
9e5550 98     groupmenu:      {id:'groupoptionsmenu', above:1},
A 99     mailboxmenu:    {id:'mailboxoptionsmenu', above:1},
d145f7 100     composemenu:    {id:'composeoptionsmenu', editable:1, overlap:1},
4be86f 101     spellmenu:      {id:'spellmenu'},
71f60c 102     // toggle: #1486823, #1486930
0501b6 103     uploadmenu:     {id:'attachment-form', editable:1, above:1, toggle:!bw.ie&&!bw.linux },
T 104     uploadform:     {id:'upload-form', editable:1, toggle:!bw.ie&&!bw.linux }
a61bbb 105   };
3940ba 106
a61bbb 107   var obj;
9e5550 108   for (var k in this.popups) {
A 109     obj = $('#'+this.popups[k].id)
a61bbb 110     if (obj.length)
9e5550 111       this.popups[k].obj = obj;
A 112     else {
113       delete this.popups[k];
114     }
a61bbb 115   }
5f660c 116 }
A 117
118 rcube_mail_ui.prototype = {
119
4b09fb 120 show_popup: function(popup, show, config)
5f660c 121 {
4b09fb 122   var obj;
A 123   // auto-register menu object
124   if (!this.popups[popup] && (obj = $('#'+popup)) && obj.length)
125     this.popups[popup] = $.extend(config, {id: popup, obj: obj});
126
9e5550 127   if (typeof this[popup] == 'function')
A 128     return this[popup](show);
129   else
130     return this.show_popupmenu(popup, show);
131 },
132
133 show_popupmenu: function(popup, show)
134 {
135   var obj = this.popups[popup].obj,
136     above = this.popups[popup].above,
bc2c43 137     ref = $(this.popups[popup].link ? this.popups[popup].link : rcube_find_object(popup+'link'));
9e5550 138
5f660c 139   if (typeof show == 'undefined')
a61bbb 140     show = obj.is(':visible') ? false : true;
0e2ccb 141   else if (this.popups[popup].toggle && show && this.popups[popup].obj.is(':visible') )
T 142     show = false;
6c9d49 143
bc2c43 144   if (show && ref.length) {
AM 145     var parent = ref.parent(),
26e76d 146       win = $(window),
bc2c43 147       pos = parent.hasClass('dropbutton') ? parent.offset() : ref.offset();
8431a7 148
bc2c43 149     if (!above && pos.top + ref.height() + obj.height() > win.height())
b218aa 150       above = true;
26e76d 151     if (pos.left + obj.width() > win.width())
T 152       pos.left = win.width() - obj.width() - 30;
8431a7 153
bc2c43 154     obj.css({ left:pos.left, top:(pos.top + (above ? -obj.height() : ref.height())) });
a61bbb 155   }
3940ba 156
a61bbb 157   obj[show?'show':'hide']();
4b09fb 158
d145f7 159   if (bw.ie6 && this.popups[popup].overlap) {
T 160     $('select').css('visibility', show?'hidden':'inherit');
161     $('select', obj).css('visibility', 'inherit');
162   }
a61bbb 163 },
T 164
a45f9b 165 dragmenu: function(show)
a61bbb 166 {
a45f9b 167   this.popups.dragmenu.obj[show?'show':'hide']();
511420 168 },
A 169
a509bb 170 forwardmenu: function(show)
A 171 {
172   $("input[name='forwardtype'][value="+(rcmail.env.forward_attachment ? 1 : 0)+"]", this.popups.forwardmenu.obj)
173     .prop('checked', true);
174   this.show_popupmenu('forwardmenu', show);
175 },
176
9e5550 177 uploadmenu: function(show)
087c7d 178 {
A 179   if (typeof show == 'object') // called as event handler
180     show = false;
64fa95 181
T 182   // clear upload form
183   if (!show) {
184     try { $('#attachment-form form')[0].reset(); }
185     catch(e){}  // ignore errors
186   }
b218aa 187
9e5550 188   this.show_popupmenu('uploadmenu', show);
b218aa 189
9a4fd7 190   if (!document.all && this.popups.uploadmenu.obj.is(':visible'))
b218aa 191     $('#attachment-form input[type=file]').click();
5f660c 192 },
A 193
9e5550 194 searchmenu: function(show)
30b152 195 {
9e5550 196   var obj = this.popups.searchmenu.obj,
A 197     ref = rcube_find_object('searchmenulink');
30b152 198
9e5550 199   if (typeof show == 'undefined')
A 200     show = obj.is(':visible') ? false : true;
201
30b152 202   if (show && ref) {
A 203     var pos = $(ref).offset();
3e5c70 204     obj.css({left:pos.left, top:(pos.top + ref.offsetHeight + 2)});
30b152 205
A 206     if (rcmail.env.search_mods) {
3e5c70 207       var n, all,
A 208         list = $('input:checkbox[name="s_mods[]"]', obj),
209         mbox = rcmail.env.mailbox,
210         mods = rcmail.env.search_mods;
3cacf9 211
3e5c70 212       if (rcmail.env.task == 'mail') {
3cacf9 213         mods = mods[mbox] ? mods[mbox] : mods['*'];
3e5c70 214         all = 'text';
3cacf9 215       }
A 216       else {
3e5c70 217         all = '*';
A 218       }
219
220       if (mods[all])
221         list.map(function() {
222           this.checked = true;
223           this.disabled = this.value != all;
224         });
225       else {
226         list.prop('disabled', false).prop('checked', false);
227         for (n in mods)
228           $('#s_mod_' + n).prop('checked', true);
3cacf9 229       }
30b152 230     }
A 231   }
9e5550 232   obj[show?'show':'hide']();
30b152 233 },
3940ba 234
30b152 235 set_searchmod: function(elem)
A 236 {
3e5c70 237   var all, m, task = rcmail.env.task,
3cacf9 238     mods = rcmail.env.search_mods,
A 239     mbox = rcmail.env.mailbox;
3940ba 240
3cacf9 241   if (!mods)
A 242     mods = {};
3940ba 243
3cacf9 244   if (task == 'mail') {
A 245     if (!mods[mbox])
246       mods[mbox] = rcube_clone_object(mods['*']);
3e5c70 247     m = mods[mbox];
A 248     all = 'text';
3cacf9 249   }
A 250   else { //addressbook
3e5c70 251     m = mods;
A 252     all = '*';
3cacf9 253   }
A 254
3e5c70 255   if (!elem.checked)
A 256     delete(m[elem.value]);
257   else
258     m[elem.value] = 1;
259
260   // mark all fields
261   if (elem.value != all)
262     return;
263
264   $('input:checkbox[name="s_mods[]"]').map(function() {
265     if (this == elem)
266       return;
267
268     this.checked = true;
269     if (elem.checked) {
270       this.disabled = true;
271       delete m[this.value];
272     }
273     else {
274       this.disabled = false;
275       m[this.value] = 1;
276     }
277   });
30b152 278 },
A 279
9e5550 280 listmenu: function(show)
f52c93 281 {
9e5550 282   var obj = this.popups.listmenu.obj,
A 283     ref = rcube_find_object('listmenulink');
f52c93 284
9e5550 285   if (typeof show == 'undefined')
A 286     show = obj.is(':visible') ? false : true;
287
f52c93 288   if (show && ref) {
6c9d49 289     var pos = $(ref).offset(),
9e5550 290       menuwidth = obj.width(),
6c9d49 291       pagewidth = $(document).width();
A 292
293     if (pagewidth - pos.left < menuwidth && pos.left > menuwidth)
294       pos.left = pos.left - menuwidth;
295
9e5550 296     obj.css({ left:pos.left, top:(pos.top + ref.offsetHeight + 2)});
e0efd8 297
f52c93 298     // set form values
491133 299     $('input[name="sort_col"][value="'+rcmail.env.sort_col+'"]').prop('checked', true);
A 300     $('input[name="sort_ord"][value="DESC"]').prop('checked', rcmail.env.sort_order == 'DESC');
301     $('input[name="sort_ord"][value="ASC"]').prop('checked', rcmail.env.sort_order != 'DESC');
302     $('input[name="view"][value="thread"]').prop('checked', rcmail.env.threading ? true : false);
303     $('input[name="view"][value="list"]').prop('checked', rcmail.env.threading ? false : true);
e0efd8 304
AM 305     // set checkboxes
306     $('input[name="list_col[]"]').each(function() {
307       $(this).prop('checked', jQuery.inArray(this.value, rcmail.env.coltypes) != -1);
308     });
f52c93 309   }
T 310
9e5550 311   obj[show?'show':'hide']();
f52c93 312
T 313   if (show) {
314     var maxheight=0;
315     $('#listmenu fieldset').each(function() {
316       var height = $(this).height();
317       if (height > maxheight) {
318         maxheight = height;
319       }
320     });
321     $('#listmenu fieldset').css("min-height", maxheight+"px")
322     // IE6 complains if you set this attribute using either method:
323     //$('#listmenu fieldset').css({'height':'auto !important'});
324     //$('#listmenu fieldset').css("height","auto !important");
325       .height(maxheight);
326   };
327 },
328
bc2c43 329 open_listmenu: function()
f52c93 330 {
9e5550 331   this.listmenu();
f52c93 332 },
T 333
334 save_listmenu: function()
335 {
9e5550 336   this.listmenu();
f52c93 337
a80405 338   var sort = $('input[name="sort_col"]:checked').val(),
A 339     ord = $('input[name="sort_ord"]:checked').val(),
340     thread = $('input[name="view"]:checked').val(),
341     cols = $('input[name="list_col[]"]:checked')
342       .map(function(){ return this.value; }).get();
f52c93 343
T 344   rcmail.set_list_options(cols, sort, ord, thread == 'thread' ? 1 : 0);
345 },
346
4be86f 347 spellmenu: function(show)
A 348 {
349   var link, li,
350     lang = rcmail.spellcheck_lang(),
351     menu = this.popups.spellmenu.obj,
352     ul = $('ul', menu);
353
354   if (!ul.length) {
355     ul = $('<ul>');
356
357     for (i in rcmail.env.spell_langs) {
358       li = $('<li>');
a27b87 359       link = $('<a href="#"></a>').text(rcmail.env.spell_langs[i])
4be86f 360         .addClass('active').data('lang', i)
A 361         .click(function() {
362           rcmail.spellcheck_lang_set($(this).data('lang'));
363         });
364
365       link.appendTo(li);
366       li.appendTo(ul);
367     }
368
369     ul.appendTo(menu);
370   }
371
372   // select current language
373   $('li', ul).each(function() {
374     var el = $('a', this);
375     if (el.data('lang') == lang)
376       el.addClass('selected');
377     else if (el.hasClass('selected'))
378       el.removeClass('selected');
379   });
380
381   this.show_popupmenu('spellmenu', show);
bc2c43 382 },
AM 383
384 show_attachmentmenu: function(elem)
385 {
386   var id = elem.parentNode.id.replace(/^attach/, '');
387
388   $('#attachmenuopen').unbind('click').attr('onclick', '').click(function(e) {
389     return rcmail.command('open-attachment', id, this);
390   });
391
392   $('#attachmenudownload').unbind('click').attr('onclick', '').click(function() {
393     rcmail.command('download-attachment', id, this);
394   });
395
396   this.popups.attachmentmenu.link = elem;
397   rcmail.command('menu-open', {menu: 'attachmentmenu', id: id});
398 },
399
400 menu_open: function(p)
401 {
402   if (p && p.props && p.props.menu == 'attachmentmenu')
403     this.show_popup('attachmentmenu');
404   else
405     this.open_listmenu();
406 },
407
408 menu_save: function(prop)
409 {
410   this.save_listmenu();
4be86f 411 },
A 412
ec581c 413 body_mouseup: function(evt, p)
5f660c 414 {
9e5550 415   var i, target = rcube_event.get_target(evt);
f52c93 416
9e5550 417   for (i in this.popups) {
A 418     if (this.popups[i].obj.is(':visible') && target != rcube_find_object(i+'link')
0e2ccb 419       && !this.popups[i].toggle
6c7452 420       && target != this.popups[i].obj.get(0)  // check if scroll bar was clicked (#1489832)
9e5550 421       && (!this.popups[i].editable || !this.target_overlaps(target, this.popups[i].id))
A 422       && (!this.popups[i].sticky || !rcube_mouse_is_over(evt, rcube_find_object(this.popups[i].id)))
9a0153 423       && !$(target).is('.folder-selector-link') && !$(target).children('.folder-selector-link').length
9e5550 424     ) {
d145f7 425       window.setTimeout('rcmail_ui.show_popup("'+i+'",false);', 50);
9e5550 426     }
30b152 427   }
087c7d 428 },
A 429
430 target_overlaps: function (target, elementid)
431 {
432   var element = rcube_find_object(elementid);
433   while (target.parentNode) {
434     if (target.parentNode == element)
435       return true;
436     target = target.parentNode;
437   }
438   return false;
5f660c 439 },
A 440
0a36c3 441 body_keydown: function(evt, p)
5f660c 442 {
30b152 443   if (rcube_event.get_keycode(evt) == 27) {
9e5550 444     for (var k in this.popups) {
A 445       if (this.popups[k].obj.is(':visible'))
446         this.show_popup(k, false);
a61bbb 447     }
30b152 448   }
ce06d3 449 },
A 450
451 switch_preview_pane: function(elem)
452 {
453   var uid, prev_frm = $('#mailpreviewframe');
454
455   if (elem.checked) {
456     rcmail.env.contentframe = 'messagecontframe';
457     if (mailviewsplit.layer) {
458       mailviewsplit.resize();
459       mailviewsplit.layer.elm.style.display = '';
129997 460     }
A 461     else
ce06d3 462       mailviewsplit.init();
129997 463
A 464     if (bw.opera) {
465       $('#messagelistcontainer').css({height: ''});
466     }
ce06d3 467     prev_frm.show();
129997 468
ce06d3 469     if (uid = rcmail.message_list.get_single_selection())
A 470       rcmail.show_message(uid, false, true);
129997 471   }
A 472   else {
ce06d3 473     prev_frm.hide();
A 474     if (bw.ie6 || bw.ie7) {
475       var fr = document.getElementById('mailcontframe');
476       fr.style.bottom = 0;
129997 477       fr.style.height = parseInt(fr.parentNode.offsetHeight)+'px';
ce06d3 478     }
129997 479     else {
ce06d3 480       $('#mailcontframe').css({height: 'auto', bottom: 0});
129997 481       if (bw.opera)
A 482         $('#messagelistcontainer').css({height: 'auto'});
483     }
ce06d3 484     if (mailviewsplit.layer)
A 485       mailviewsplit.layer.elm.style.display = 'none';
129997 486
ce06d3 487     rcmail.env.contentframe = null;
A 488     rcmail.show_contentframe(false);
489   }
9b6c82 490
A 491   rcmail.command('save-pref', {name: 'preview_pane', value: (elem.checked?1:0)});
3940ba 492 },
A 493
494 /* Message composing */
495 init_compose_form: function()
496 {
15482b 497   var f, v, field, fields = ['cc', 'bcc', 'replyto', 'followupto'],
3940ba 498     div = document.getElementById('compose-div'),
A 499     headers_div = document.getElementById('compose-headers-div');
500
e25a35 501   // Show input elements with non-empty value
A 502   for (f=0; f<fields.length; f++) {
15482b 503     v = fields[f]; field = $('#_'+v);
AM 504     if (field.length) {
505       field.on('change', {v:v}, function(e) { if (this.value) rcmail_ui.show_header_form(e.data.v); });
506       if (field.val() != '')
507         rcmail_ui.show_header_form(v);
508     }
e25a35 509   }
3940ba 510
A 511   // prevent from form data loss when pressing ESC key in IE
512   if (bw.ie) {
513     var form = rcube_find_object('form');
514     form.onkeydown = function (e) {
515       if (rcube_event.get_keycode(e) == 27)
516         rcube_event.cancel(e);
517     };
518   }
519
520   $(window).resize(function() {
521     rcmail_ui.resize_compose_body();
522   });
523
524   $('#compose-container').resize(function() {
525     rcmail_ui.resize_compose_body();
526   });
527
b218aa 528   div.style.top = (parseInt(headers_div.offsetHeight, 10) + 3) + 'px';
3940ba 529   $(window).resize();
a27b87 530
bd3d68 531   // fixes contacts-table position when there's more than one addressbook
AM 532   $('#contacts-table').css('top', $('#directorylist').height() + 24 + 'px');
533
a27b87 534   // contacts search submit
AM 535   $('#quicksearchbox').keydown(function(e) {
536     if (rcube_event.get_keycode(e) == 13)
537       rcmail.command('search');
538   });
3940ba 539 },
A 540
541 resize_compose_body: function()
542 {
a27b87 543   var div = $('#compose-div .boxlistcontent'),
AM 544     w = div.width() - 2, h = div.height(),
532bc5 545     x = bw.ie || bw.opera ? 4 : 0;
3940ba 546
a27b87 547   $('#compose-body_tbl').width((w+3)+'px').height('');
AM 548   $('#compose-body_ifr').width((w+3)+'px').height((h-54)+'px');
549   $('#compose-body').width((w-x)+'px').height(h+'px');
269b14 550   $('#googie_edit_layer').height(h+'px');
7534f6 551 },
A 552
553 resize_compose_body_ev: function()
554 {
555   window.setTimeout(function(){rcmail_ui.resize_compose_body();}, 100);
3940ba 556 },
A 557
558 show_header_form: function(id)
559 {
560   var row, s,
561     link = document.getElementById(id + '-link');
562
563   if ((s = this.next_sibling(link)))
564     s.style.display = 'none';
565   else if ((s = this.prev_sibling(link)))
566     s.style.display = 'none';
567
568   link.style.display = 'none';
569
570   if ((row = document.getElementById('compose-' + id))) {
571     var div = document.getElementById('compose-div'),
572       headers_div = document.getElementById('compose-headers-div');
88b301 573     $(row).show();
b218aa 574     div.style.top = (parseInt(headers_div.offsetHeight, 10) + 3) + 'px';
3940ba 575     this.resize_compose_body();
A 576   }
577
578   return false;
579 },
580
581 hide_header_form: function(id)
582 {
583   var row, ns,
584     link = document.getElementById(id + '-link'),
585     parent = link.parentNode,
586     links = parent.getElementsByTagName('a');
587
588   link.style.display = '';
589
590   for (var i=0; i<links.length; i++)
591     if (links[i].style.display != 'none')
592       for (var j=i+1; j<links.length; j++)
88b301 593         if (links[j].style.display != 'none')
3940ba 594           if ((ns = this.next_sibling(links[i]))) {
88b301 595             ns.style.display = '';
AM 596             break;
597           }
3940ba 598
A 599   document.getElementById('_' + id).value = '';
600
601   if ((row = document.getElementById('compose-' + id))) {
602     var div = document.getElementById('compose-div'),
603       headers_div = document.getElementById('compose-headers-div');
604     row.style.display = 'none';
605     div.style.top = (parseInt(headers_div.offsetHeight, 10) + 1) + 'px';
606     this.resize_compose_body();
607   }
608
609   return false;
610 },
611
612 next_sibling: function(elm)
613 {
614   var ns = elm.nextSibling;
615   while (ns && ns.nodeType == 3)
616     ns = ns.nextSibling;
617   return ns;
618 },
619
620 prev_sibling: function(elm)
621 {
622   var ps = elm.previousSibling;
623   while (ps && ps.nodeType == 3)
624     ps = ps.previousSibling;
625   return ps;
235504 626 },
AM 627
628 enable_command: function(p)
629 {
b972b4 630   if (p.command == 'reply-list' && rcmail.env.reply_all_mode == 1) {
235504 631     var label = rcmail.gettext(p.status ? 'replylist' : 'replyall');
AM 632     $('a.button.replyAll').attr('title', label);
633   }
5f660c 634 }
A 635
636 };
3940ba 637
e97f01 638 /**
3d78d5 639  * Roundcube generic layer (floating box) class
AM 640  *
641  * @constructor
642  */
643 function rcube_layer(id, attributes)
644 {
645   this.name = id;
646
647   // create a new layer in the current document
648   this.create = function(arg)
649   {
650     var l = (arg.x) ? arg.x : 0,
651       t = (arg.y) ? arg.y : 0,
652       w = arg.width,
653       h = arg.height,
654       z = arg.zindex,
655       vis = arg.vis,
656       parent = arg.parent,
657       obj = document.createElement('DIV');
658
659     obj.id = this.name;
660     obj.style.position = 'absolute';
661     obj.style.visibility = (vis) ? (vis==2) ? 'inherit' : 'visible' : 'hidden';
662     obj.style.left = l+'px';
663     obj.style.top = t+'px';
664     if (w)
665       obj.style.width = w.toString().match(/\%$/) ? w : w+'px';
666     if (h)
667       obj.style.height = h.toString().match(/\%$/) ? h : h+'px';
668     if (z)
669       obj.style.zIndex = z;
670
671     if (parent)
672       parent.appendChild(obj);
673     else
674       document.body.appendChild(obj);
675
676     this.elm = obj;
677   };
678
679   // create new layer
680   if (attributes != null) {
681     this.create(attributes);
682     this.name = this.elm.id;
683   }
684   else  // just refer to the object
685     this.elm = document.getElementById(id);
686
687   if (!this.elm)
688     return false;
689
690
691   // ********* layer object properties *********
692
693   this.css = this.elm.style;
694   this.event = this.elm;
695   this.width = this.elm.offsetWidth;
696   this.height = this.elm.offsetHeight;
697   this.x = parseInt(this.elm.offsetLeft);
698   this.y = parseInt(this.elm.offsetTop);
699   this.visible = (this.css.visibility=='visible' || this.css.visibility=='show' || this.css.visibility=='inherit') ? true : false;
700
701
702   // ********* layer object methods *********
703
704   // move the layer to a specific position
705   this.move = function(x, y)
706   {
707     this.x = x;
708     this.y = y;
709     this.css.left = Math.round(this.x)+'px';
710     this.css.top = Math.round(this.y)+'px';
711   };
712
713   // change the layers width and height
714   this.resize = function(w,h)
715   {
716     this.css.width  = w+'px';
717     this.css.height = h+'px';
718     this.width = w;
719     this.height = h;
720   };
721
722   // show or hide the layer
723   this.show = function(a)
724   {
725     if(a == 1) {
726       this.css.visibility = 'visible';
727       this.visible = true;
728     }
729     else if(a == 2) {
730       this.css.visibility = 'inherit';
731       this.visible = true;
732     }
733     else {
734       this.css.visibility = 'hidden';
735       this.visible = false;
736     }
737   };
738
739   // write new content into a Layer
740   this.write = function(cont)
741   {
742     this.elm.innerHTML = cont;
743   };
744
745 };
746
747 /**
e97f01 748  * Scroller
A 749  */
750 function rcmail_scroller(list, top, bottom)
751 {
752   var ref = this;
753
754   this.list = $(list);
755   this.top = $(top);
756   this.bottom = $(bottom);
757   this.step_size = 6;
758   this.step_time = 20;
759   this.delay = 500;
760
761   this.top
762     .mouseenter(function() { ref.ts = window.setTimeout(function() { ref.scroll('down'); }, ref.delay); })
763     .mouseout(function() { if (ref.ts) window.clearTimeout(ref.ts); });
764
765   this.bottom
766     .mouseenter(function() { ref.ts = window.setTimeout(function() { ref.scroll('up'); }, ref.delay); })
767     .mouseout(function() { if (ref.ts) window.clearTimeout(ref.ts); });
768
769   this.scroll = function(dir)
770   {
771     var ref = this, size = this.step_size;
772
773     if (!rcmail.drag_active)
774       return;
775
776     if (dir == 'down')
777       size *= -1;
778
779     this.list.get(0).scrollTop += size;
780     this.ts = window.setTimeout(function() { ref.scroll(dir); }, this.step_time);
781   };
782 };
783
5f660c 784
e2b0a0 785 // Events handling in iframes (eg. preview pane)
A 786 function iframe_events()
787 {
788   // this==iframe
c95845 789   try {
AM 790     var doc = this.contentDocument ? this.contentDocument : this.contentWindow ? this.contentWindow.document : null;
791     rcube_event.add_listener({ element: doc, object:rcmail_ui, method:'body_mouseup', event:'mouseup' });
792   }
793   catch (e) {
794     // catch possible "Permission denied" error in IE
795   };
e97f01 796 };
e2b0a0 797
9e1daa 798 // Abbreviate mailbox names to fit width of the container
T 799 function rcube_render_mailboxlist()
800 {
c3762a 801   var list = $('#mailboxlist > li > a, #mailboxlist ul:visible > li > a');
79db33 802
A 803   // it's too slow with really big number of folders, especially on IE
c3762a 804   if (list.length > (bw.ie && bw.vendver < 9 ? 40 : 100))
9e1daa 805     return;
T 806
c3762a 807   list.each(function() {
79db33 808     var elem = $(this),
A 809       text = elem.data('text');
810
9e1daa 811     if (!text) {
c3762a 812       text = elem.text().replace(/\s+\([0-9]+\)$/, '');
9e1daa 813       elem.data('text', text);
T 814     }
c3762a 815
9e1daa 816     if (text.length < 6)
T 817       return;
818
c3762a 819     var abbrev = fit_string_to_size(text, elem, elem.width() - elem.children('span.unreadcount').width() - 16);
9e1daa 820     if (abbrev != text)
T 821       elem.attr('title', text);
822     elem.contents().filter(function(){ return (this.nodeType == 3); }).get(0).data = abbrev;
823   });
e97f01 824 };
9e1daa 825
T 826 // inspired by https://gist.github.com/24261/7fdb113f1e26111bd78c0c6fe515f6c0bf418af5
827 function fit_string_to_size(str, elem, len)
828 {
c3762a 829   var w, span, $span, result = str, ellip = '...';
9e1daa 830
79db33 831   if (!rcmail.env.tmp_span) {
A 832     // it should be appended to elem to use the same css style
833     // but for performance reasons we'll append it to body (once)
c3762a 834     span = $('<b>').css({visibility: 'hidden', padding: '0px',
AM 835       'font-family': elem.css('font-family'),
836       'font-size': elem.css('font-size')})
79db33 837       .appendTo($('body', document)).get(0);
A 838     rcmail.env.tmp_span = span;
839   }
840   else {
841     span = rcmail.env.tmp_span;
842   }
c3762a 843
AM 844   $span = $(span);
845   $span.text(result);
9e1daa 846
79db33 847   // on first run, check if string fits into the length already.
A 848   w = span.offsetWidth;
849   if (w > len) {
850     var cut = Math.max(1, Math.floor(str.length * ((w - len) / w) / 2)),
851       mid = Math.floor(str.length / 2),
852       offLeft = mid,
853       offRight = mid;
9e1daa 854
79db33 855     while (true) {
A 856       offLeft = mid - cut;
857       offRight = mid + cut;
c3762a 858       $span.text(str.substring(0,offLeft) + ellip + str.substring(offRight));
9e1daa 859
79db33 860       // break loop if string fits size
A 861       if (offLeft < 3 || span.offsetWidth)
862         break;
863
864       cut++;
9e1daa 865     }
79db33 866
A 867     // build resulting string
868     result = str.substring(0,offLeft) + ellip + str.substring(offRight);
869   }
870
871   return result;
e97f01 872 };
90550b 873
2c1937 874 function update_quota(data)
A 875 {
876   percent_indicator(rcmail.gui_objects.quotadisplay, data);
e97f01 877 };
2c1937 878
A 879 // percent (quota) indicator
880 function percent_indicator(obj, data)
881 {
882   if (!data || !obj)
883     return false;
884
885   var limit_high = 80,
886     limit_mid  = 55,
887     width = data.width ? data.width : rcmail.env.indicator_width ? rcmail.env.indicator_width : 100,
888     height = data.height ? data.height : rcmail.env.indicator_height ? rcmail.env.indicator_height : 14,
889     quota = data.percent ? Math.abs(parseInt(data.percent)) : 0,
890     quota_width = parseInt(quota / 100 * width),
891     pos = $(obj).position();
892
893   // workarounds for Opera and Webkit bugs
894   pos.top = Math.max(0, pos.top);
895   pos.left = Math.max(0, pos.left);
896
897   rcmail.env.indicator_width = width;
898   rcmail.env.indicator_height = height;
899
900   // overlimit
901   if (quota_width > width) {
902     quota_width = width;
903     quota = 100;
904   }
905
906   if (data.title)
907     data.title = rcmail.get_label('quota') + ': ' +  data.title;
908
909   // main div
910   var main = $('<div>');
911   main.css({position: 'absolute', top: pos.top, left: pos.left,
912       width: width + 'px', height: height + 'px', zIndex: 100, lineHeight: height + 'px'})
913     .attr('title', data.title).addClass('quota_text').html(quota + '%');
914   // used bar
915   var bar1 = $('<div>');
916   bar1.css({position: 'absolute', top: pos.top + 1, left: pos.left + 1,
917       width: quota_width + 'px', height: height + 'px', zIndex: 99});
918   // background
919   var bar2 = $('<div>');
920   bar2.css({position: 'absolute', top: pos.top + 1, left: pos.left + 1,
921       width: width + 'px', height: height + 'px', zIndex: 98})
235504 922     .addClass('quota_bg');
2c1937 923
A 924   if (quota >= limit_high) {
925     main.addClass(' quota_text_high');
926     bar1.addClass('quota_high');
927   }
928   else if(quota >= limit_mid) {
929     main.addClass(' quota_text_mid');
930     bar1.addClass('quota_mid');
931   }
932   else {
933     main.addClass(' quota_text_low');
934     bar1.addClass('quota_low');
935   }
936
937   // replace quota image
938   $(obj).html('').append(bar1).append(bar2).append(main);
939   // update #quotaimg title
940   $('#quotaimg').attr('title', data.title);
e97f01 941 };
2c1937 942
90550b 943 // Optional parameters used by TinyMCE
V 944 var rcmail_editor_settings = {
c3762a 945   skin: "default", // "default", "o2k7"
AM 946   skin_variant: "" // "", "silver", "black"
90550b 947 };
2c1937 948
A 949 var rcmail_ui;
950
951 function rcube_init_mail_ui()
952 {
953   rcmail_ui = new rcube_mail_ui();
954   rcube_event.add_listener({ object:rcmail_ui, method:'body_mouseup', event:'mouseup' });
955   rcube_event.add_listener({ object:rcmail_ui, method:'body_keydown', event:'keydown' });
956
c3762a 957   rcmail.addEventListener('init', function() {
AM 958     if (rcmail.env.quota_content)
959       update_quota(rcmail.env.quota_content);
960     rcmail.addEventListener('setquota', update_quota);
2c1937 961
c3762a 962     $('iframe').load(iframe_events)
AM 963       .contents().mouseup(function(e){rcmail_ui.body_mouseup(e)});
2c1937 964
c3762a 965     if (rcmail.env.task == 'mail') {
AM 966       rcmail.addEventListener('enable-command', 'enable_command', rcmail_ui);
967       rcmail.addEventListener('menu-open', 'menu_open', rcmail_ui);
968       rcmail.addEventListener('menu-save', 'menu_save', rcmail_ui);
969       rcmail.addEventListener('aftersend-attachment', 'uploadmenu', rcmail_ui);
970       rcmail.addEventListener('aftertoggle-editor', 'resize_compose_body_ev', rcmail_ui);
971       rcmail.gui_object('dragmenu', 'dragmenu');
2c1937 972
c3762a 973       if (rcmail.gui_objects.mailboxlist) {
AM 974         rcmail.treelist.addEventListener('expand', rcube_render_mailboxlist);
975         rcmail.addEventListener('responseaftermark', rcube_render_mailboxlist);
976         rcmail.addEventListener('responseaftergetunread', rcube_render_mailboxlist);
977         rcmail.addEventListener('responseaftercheck-recent', rcube_render_mailboxlist);
978         rcmail.addEventListener('responseafterrefresh', rcube_render_mailboxlist);
979         rcmail.addEventListener('afterimport-messages', function(){ rcmail_ui.show_popup('uploadform', false); });
980       }
981
982       if (rcmail.env.action == 'compose')
983         rcmail_ui.init_compose_form();
984       else if (rcmail.env.action == 'show' || rcmail.env.action == 'preview')
985         // add menu link for each attachment
986         $('#attachment-list > li[id^="attach"]').each(function() {
ba2d42 987           $(this).append($('<a class="drop"></a>').click(function() { rcmail_ui.show_attachmentmenu(this); }));
c3762a 988         });
2c1937 989     }
c3762a 990     else if (rcmail.env.task == 'addressbook') {
AM 991       rcmail.addEventListener('afterupload-photo', function(){ rcmail_ui.show_popup('uploadform', false); });
e97f01 992
c3762a 993       rcmail.gui_object('dragmenu', 'dragmenu');
AM 994     }
995     else if (rcmail.env.task == 'settings') {
996       if (rcmail.gui_objects.subscriptionlist)
997         new rcmail_scroller('#folderlist-content', '#folderlist-title', '#folderlist-footer');
998     }
999   });
2c1937 1000 }