diff --git a/modoboa/extensions/webmail/lib/imapheader.py b/modoboa/extensions/webmail/lib/imapheader.py index ffc8cafb6..1e1f4dac9 100644 --- a/modoboa/extensions/webmail/lib/imapheader.py +++ b/modoboa/extensions/webmail/lib/imapheader.py @@ -89,7 +89,7 @@ def parse_date(value, **kwargs): ndate = datetime.datetime(*(tmp)[:7]) now = datetime.datetime.now() if now - ndate > datetime.timedelta(7): - return ndate.strftime("%d.%m.%Y %H:%M") + return ndate.strftime("%d/%m/%Y %H:%M") return ndate.strftime("%a %H:%M") except ValueError: return value diff --git a/modoboa/extensions/webmail/lib/imaputils.py b/modoboa/extensions/webmail/lib/imaputils.py index 86b1d4904..0a306dd74 100644 --- a/modoboa/extensions/webmail/lib/imaputils.py +++ b/modoboa/extensions/webmail/lib/imaputils.py @@ -649,15 +649,12 @@ class IMAPconnector(object): if not r'\Seen' in data[int(uid)]['FLAGS']: msg['style'] = 'unseen' if r'\Answered' in data[int(uid)]['FLAGS']: - msg['img_flags'] = [static_url('pics/answered.png')] + msg['answered'] = True if r'$Forwarded' in data[int(uid)]['FLAGS']: - if 'img_flags' in msg: - msg['img_flags'] += [static_url('pics/forwarded.png')] - else: - msg['img_flags'] = [static_url('pics/forwarded.png')] + msg['forwarded'] = True bs = BodyStructure(data[int(uid)]['BODYSTRUCTURE']) if bs.has_attachments(): - msg['img_withatts'] = static_url('pics/attachment.png') + msg['attachments'] = True result += [msg] return result diff --git a/modoboa/extensions/webmail/lib/listing.py b/modoboa/extensions/webmail/lib/listing.py index c17f544b6..80d0927d4 100644 --- a/modoboa/extensions/webmail/lib/listing.py +++ b/modoboa/extensions/webmail/lib/listing.py @@ -14,25 +14,25 @@ class WMtable(tables.Table): styles = "table-hover" idkey = "imapid" drag = tables.ImgColumn( - "drag", cssclass="draggable left", width="1%", + "drag", cssclass="draggable left", defvalue="%spics/grippy.png" % settings.STATIC_URL, header="" ) selection = tables.SelectionColumn( - "selection", safe=True, width='1%', header=None, sortable=False + "selection", safe=True, header=None, sortable=False ) - flags = tables.ImgColumn("flags", width="3%") - withatts = tables.ImgColumn("withatts", width="2%") + flags = tables.ImgColumn("flags") + withatts = tables.ImgColumn("withatts") subject = tables.Column( "subject", label=ugettext_lazy("Subject"), limit=60, cssclass="openable" ) from_ = tables.Column( - "from", width="20%", label=ugettext_lazy("From"), limit=30, + "from", label=ugettext_lazy("From"), limit=30, cssclass="openable" ) date = tables.Column( - "date", width="15%", label=ugettext_lazy("Date"), cssclass="openable" + "date", label=ugettext_lazy("Date"), cssclass="openable" ) cols_order = [ diff --git a/modoboa/extensions/webmail/static/webmail/css/webmail.css b/modoboa/extensions/webmail/static/webmail/css/webmail.css index 1ff81f3e1..59cace3c2 100644 --- a/modoboa/extensions/webmail/static/webmail/css/webmail.css +++ b/modoboa/extensions/webmail/static/webmail/css/webmail.css @@ -1,10 +1,16 @@ /* MEDIA */ #listing { position: absolute; - overflow: auto; - top: 60px; - padding: 0; + top: 75px; + bottom: 0; margin: 0; + overflow: auto; + padding-left: 15px; + padding-right: 15px; +} + +td[name=drag], td[name=selection] { + width: 1%; } @media (max-width: 400px) { @@ -21,7 +27,7 @@ @media (max-width: 500px) { th#date, td[name="date"], - #menubar .Actions{ + #menubar .actions { display: none; } } @@ -38,7 +44,7 @@ @media (min-width: 768px) { td[name=from] { - width: 20%; + width: 25%; } } @@ -48,7 +54,7 @@ } th#date, td[name="date"]{ - max-width: 60px; + max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -71,9 +77,6 @@ @media (min-width: 1198px) { - #listing { - padding-left: 15px; - } } /* GENERAL */ @@ -82,14 +85,18 @@ body, html { } #rightcol { - position: relative; + position: fixed; + top: 51px; + bottom: 0; } #folders { - /*position: fixed; - top: 73px;*/ + position: absolute; + top: 73px; + left: 15px; + right: 15px; + overflow-x: hidden; overflow-y: auto; - margin-bottom: 5px; } #folders .ui-resizable-handle { @@ -149,9 +156,19 @@ td[name="date"] { text-align: right; } +#left-toolbar { + position: absolute; + width: 100%; + bottom: 0; +} + +#quotabox { + padding-top: 15px; +} + #quotabar { - margin: 15px 0 0; - width: 190px; + height: 5px; + margin-bottom: 0; } #quotaraw { @@ -160,7 +177,7 @@ td[name="date"] { /* - *TOP NAVBAR + * TOP NAVBAR */ .navbar-header{ @@ -170,9 +187,26 @@ td[name="date"] { /* * Mailboxes list */ +.email { + border-top: 1px solid #ddd; + padding-top: 10px; + +} + +div.email:hover { + background-color: #f5f5f5; +} + +.openable { + cursor: pointer; +} + +.leftcol-heading { + margin-bottom: 15px; +} + #mboxactions { - position: fixed; - padding-left: 30px; + margin: 5px 0; } div.clickbox { @@ -216,9 +250,9 @@ li.droppable li{ padding: 2px 0; } -#mailheader label { - text-align: left; -} +/* #mailheader label { */ +/* text-align: left; */ +/* } */ #mailheader .options { margin-bottom: 8px; @@ -240,7 +274,7 @@ li.droppable li{ float: left; } -#list { +list { position: absolute; top: 5px; left: 180px; @@ -308,16 +342,13 @@ li.droppable li{ * Table */ -td[class*=openable] { - cursor: pointer; -} + /* *Action buttons */ #menubar { - /*background-color: #fff;*/ position: absolute; top: 0; padding-top: 20px; diff --git a/modoboa/extensions/webmail/static/webmail/js/webmail.js b/modoboa/extensions/webmail/static/webmail/js/webmail.js index 4c422f657..683ee4cc4 100644 --- a/modoboa/extensions/webmail/static/webmail/js/webmail.js +++ b/modoboa/extensions/webmail/static/webmail/js/webmail.js @@ -20,8 +20,6 @@ Webmail.prototype = { mboxes_col_width: 200 }, - - initialize: function(options) { this.options = $.extend({}, this.defaults, options); this.rtimer = null; @@ -38,88 +36,116 @@ Webmail.prototype = { }); this.record_unseen_messages(); + $("#mboxactions").on("shown.bs.dropdown", function() { + var $menu = $("ul", this); + var offset = $menu.offset(); - $("#mboxactions").css({ - bottom: $("#bottom-bar").outerHeight(true) + "px" + $("body").append($menu); + $menu.show(); + $menu.css("position", "absolute"); + $menu.css("top", offset.top + "px"); + $menu.css("left", offset.left + "px"); + $(this).data("original_menu", $menu); + }).on("hide.bs.dropdown", function() { + var $this = $(this); + $this.append($this.data("original_menu")); + $this.data("original_menu").removeAttr("style"); }); + /*$("#mboxactions").css({ + bottom: $("#bottom-bar").outerHeight(true) + "px" + });*/ + /* Responsive -> on resizing folders (leftcol) */ - $("#folders").resizable({ - start: function(event, ui) { - $('#listing iframe').css('pointer-events','none'); - }, - handles: "e", - minWidth: parseInt($("#folders").css("width").replace("px", "")), - maxWidth: 400, - stop: function(event, ui) { - $('#listing iframe').css('pointer-events','auto'); - } - }); + // $("#folders").resizable({ + // start: function(event, ui) { + // $('#listing iframe').css('pointer-events','none'); + // }, + // handles: "e", + // minWidth: $("#folders").width(), + // maxWidth: 400, + // stop: function(event, ui) { + // $('#listing iframe').css('pointer-events','auto'); + // } + // }); - $("#folders").resizable({ - resize: function(event, ui) { - if ($(window).width() > 1198) { - var width = ui.size.width; - /*$("#rightcol").css({ - marginLeft: width + 'px' - });*/ - $("#folders").css({ - width : width + 'px' - }); - /*$("#rightcol").css({ - paddingRight: width - 110 + 'px' - }); - if ($(window).width() < 1800) { - $("#rightcol").css({ - paddingRight: width - 110 + 'px' - }); - }*/ - } - } - }); + // $("#folders").resizable({ + // resize: function(event, ui) { + // if ($(window).width() > 1198) { + // var width = ui.size.width; + // /*$("#rightcol").css({ + // marginLeft: width + 'px' + // });*/ + // $("#folders").css({ + // width : width + 'px' + // }); + // /*$("#rightcol").css({ + // paddingRight: width - 110 + 'px' + // }); + // if ($(window).width() < 1800) { + // $("#rightcol").css({ + // paddingRight: width - 110 + 'px' + // }); + // }*/ + // } + // } + // }); /* end Responsive */ this.resize(); + this.setup_infinite_scroll(); this.init_droppables(); this.register_navcallbacks(); this.listen(); }, register_navcallbacks: function() { - this.navobject.register_callback("listmailbox", $.proxy(this.listmailbox_callback, this)); - this.navobject.register_callback("compose", $.proxy(this.compose_callback, this)); - this.navobject.register_callback("viewmail", $.proxy(this.viewmail_callback, this)); + this.navobject.register_callback( + "listmailbox", $.proxy(this.listmailbox_callback, this)); + this.navobject.register_callback( + "compose", $.proxy(this.compose_callback, this)); + this.navobject.register_callback( + "viewmail", $.proxy(this.viewmail_callback, this)); - this.navobject.register_callback("reply", $.proxy(this.compose_callback, this)); - this.navobject.register_callback("replyall", $.proxy(this.compose_callback, this)); - this.navobject.register_callback("forward", $.proxy(this.compose_callback, this)); + this.navobject.register_callback( + "reply", $.proxy(this.compose_callback, this)); + this.navobject.register_callback( + "replyall", $.proxy(this.compose_callback, this)); + this.navobject.register_callback( + "forward", $.proxy(this.compose_callback, this)); }, listen: function() { $(window).resize($.proxy(this.resize, this)); - $(document).on("click", "a[name=compose]", $.proxy(this.compose_loader, this)); - $(document).on("click", "a[name=totrash]", $.proxy(this.delete_messages, this)); - $(document).on("click", "a[name*=mark-]", $.proxy(this.send_mark_request, this)); + $(document).on( + "click", "a[name=compose]", $.proxy(this.compose_loader, this)); + $(document).on( + "click", "a[name=totrash]", $.proxy(this.delete_messages, this)); + $(document).on( + "click", "a[name*=mark-]", $.proxy(this.send_mark_request, this)); $(document).on("click", "a[name=compress]", $.proxy(this.compress, this)); $(document).on("click", "a[name=empty]", $.proxy(this.empty, this)); $(document).on("click", "#bottom-bar a", $.proxy(this.getpage_loader, this)); - $(document).on("click", "a[name=loadfolder]", $.proxy(this.listmailbox_loader, this)); + $(document).on( + "click", "a[name=loadfolder]", $.proxy(this.listmailbox_loader, this)); $(document).on("click", "a[name=selectfolder]", this.select_parent_mailbox); - $(document).on("click", "div[class*=clickbox]", $.proxy(this.mbox_state_callback, this)); + $(document).on( + "click", "div[class*=clickbox]", $.proxy(this.mbox_state_callback, this)); $(document).on("click", "a[name=newmbox]", $.proxy(this.new_mailbox, this)); $(document).on("click", "a[name=editmbox]", $.proxy(this.edit_mbox, this)); $(document).on("click", "a[name=removembox]", $.proxy(this.remove_mbox, this)); - $(document).on("click", "td[class*=openable]", $.proxy(this.viewmail_loader, this)); + $(document).on("click", "div.openable", $.proxy(this.viewmail_loader, this)); $(document).on("click", "a[name=reply]", $.proxy(this.reply_loader, this)); $(document).on("click", "a[name=replyall]", $.proxy(this.reply_loader, this)); $(document).on("click", "a[name=forward]", $.proxy(this.reply_loader, this)); $(document).on("click", "a[name=delete]", $.proxy(this.delete_message, this)); - $(document).on("click", "a[name=activate_links]", $.proxy(function(e) { this.display_mode(e, "1"); }, this)); + $(document).on( + "click", "a[name=activate_links]", $.proxy(function(e) { this.display_mode(e, "1"); }, this)); $(document).on("click", "a[name=disable_links]", $.proxy(function(e) { this.display_mode(e, "0"); }, this)); $(document).on("click", "a[name=sendmail]", $.proxy(this.sendmail, this)); @@ -130,6 +156,28 @@ Webmail.prototype = { }, this)); }, + /** + * Setup an "infinite scroll" behaviour for the email list. + */ + setup_infinite_scroll: function() { + var that = this; + + $("#listing").infinite_scroll({ + url: this.options.listing_url, + calculate_bottom: function($element) { + return $("#emails").height() - $element.height(); + }, + get_args: function() { + return that.navparams; + }, + process_results: function(data) { + var content = $("#emails").html() + data.listing; + + $("#emails").html(content); + } + }); + }, + record_unseen_messages: function() { var unseen_counters = {}; @@ -144,37 +192,23 @@ Webmail.prototype = { * Global resize event callback. */ resize: function() { - /*$("#mboxes_container").height( - $("#folders").height() - $("#mboxactions").height());*/ var $window = $(window); var current_action = this.navobject.getparam("action"); + $("#folders").height( + $("#left-toolbar").offset().top - $("#folders").offset().top + ); + if ($window.width() > 1198) { - $("#folders").css({ - /*bottom: $("#bottom-bar").outerHeight(true) + 10,*/ - width: this.options.mboxes_col_width + 'px' - }); + // $("#folders").css({ + // width: this.options.mboxes_col_width + 'px' + // }); } - if (current_action == "listmailbox") { - this.resize_listing("auto"); - } else if (current_action == "viewmail") { - this.resize_listing("hidden"); - } else if (current_action == "compose") { + if (current_action == "compose") { this.resize_compose_body(); } }, - /** - * Resize the "listing" div. - */ - resize_listing: function(overflow) { - $("#listing").css("overflow", overflow); - $("#listing").height( - $("#bottom-bar").offset().top - - ($("#menubar").offset().top + $("#menubar").outerHeight()) - ); - }, - /** * Resize the textarea used to write plain/text messages. */ @@ -183,13 +217,12 @@ Webmail.prototype = { if ($container.length) { var top = $container.offset().top; - var bottom = $("#bottom-bar").offset().top; - $("#body_container").innerHeight(bottom - top - 10); + $("#body_container").innerHeight($(window).height() - top - 10); } }, - /* + /** * Callback of the 'compose' action. * * It is also shared with other similar actions : reply, forward. @@ -199,14 +232,14 @@ Webmail.prototype = { $("#body_container").outerHeight(true)); }, - /* + /** * Simple helper to retrieve the currently selected mailbox. */ get_current_mailbox: function() { return this.navobject.getparam("mbox", "INBOX"); }, - /* + /** * Keep track of interesting navigation parameters in order to * restore them later. */ @@ -276,10 +309,10 @@ Webmail.prototype = { $("#menubar").html(response.menu); $("#searchfield").searchbar({navobj: this.navobject}); } - if (response.navbar) { - $("#bottom-bar-right").html(response.navbar); + /*if (response.navbar) { + $("#pagination").html(response.navbar); $("#pagination-responsive").html(response.navbar); - } + }*/ $("#listing").html(response.listing); }, @@ -832,22 +865,22 @@ Webmail.prototype = { * Loader of the 'viewmail' action */ viewmail_loader: function(e) { - var $tr = $(e.target).parent(); + var $div = $(e.target).parents(".email"); var curmb = this.get_current_mailbox(); e.preventDefault(); - if ($tr.hasClass("disabled")) { + if ($div.hasClass("disabled")) { return; } - $tr.addClass("disabled"); - if ($tr.hasClass("unseen")) { + $div.addClass("disabled"); + if ($div.hasClass("unseen")) { var mb = this.get_current_mailbox(); this.change_unseen_messages(mb, -1); } this.navobject.reset().setparams({ action: "viewmail", mbox: curmb, - mailid: $tr.attr("id") + mailid: $div.attr("id") }).update(); }, @@ -861,14 +894,14 @@ Webmail.prototype = { listmailbox_callback: function(resp) { this.store_nav_params(); this.page_update(resp); - $("#emails").htmltable(); + $("#emails").htmltable({ + row_selector: "div.email" + }); this.htmltable = $("#emails").data("htmltable"); this.init_draggables(); - this.resize_listing("auto"); + $("#listing").css("overflow", "auto"); }, - - add_field: function(e, name) { e.preventDefault(); $("label[for=id_" + name + "]").parent().show(); @@ -912,7 +945,7 @@ Webmail.prototype = { */ viewmail_callback: function(resp) { this.page_update(resp); - this.resize_listing("hidden"); + $("#listing").css("overflow", "hidden"); $("a[name=back]").click($.proxy(function(e) { e.preventDefault(); this.go_back_to_listing(); diff --git a/modoboa/extensions/webmail/templates/webmail/compose.html b/modoboa/extensions/webmail/templates/webmail/compose.html index 01d4ad244..8dc67a5f1 100644 --- a/modoboa/extensions/webmail/templates/webmail/compose.html +++ b/modoboa/extensions/webmail/templates/webmail/compose.html @@ -1,17 +1,19 @@ {% load i18n form_tags %}{% load url from future %}