* Some fixes about *unseen messages* counters (see #204)

* Disable mailbox actions for RO mailboxes (fixes #239)
This commit is contained in:
Antoine Nguyen
2012-04-17 12:31:30 +02:00
parent c201d25e09
commit fa95284944
8 changed files with 891 additions and 1375 deletions
+150 -204
View File
@@ -1,114 +1,128 @@
#listing {
position: absolute;
left: 160px;
right: 0px;
top: 130px;
height: expression(document.body.clientHeight - 35 + "px");
body, html {
overflow: hidden;
height: 100%;
}
#leftcol {
/*position: fixed;
top: 60px;
left: 0;
width: 200px;
padding-left: 15px;
overflow: hidden;*/
}
#folders {
position: fixed;
top: 60px;
left: 15px;
width: 200px;
overflow-y: auto;
margin-bottom: 5px;
}
#mboxes_container {
overflow: auto;
}
html > body #listing {
#menubar {
position: fixed;
bottom: 35px;
left: 215px;
padding-left: 15px;
}
body.loading {
display: block;
filter: alpha(opacity=50);
opacity: 0.5;
z-index: 3;
background: #FFF url("../../css/spinner.gif") center center no-repeat;
#listing {
position: fixed;
left: 215px;
right: 0;
padding-left: 15px;
}
.clearfix:after {
content: ".";
display: block;
clear: both;
visibility: hidden;
overflow: hidden;
line-height: 0;
height: 0;
}
.clearfix {
display: inline-block;
}
html[xmlns] .clearfix {
display: block;
}
* html .clearfix {
height: 1%;
overflow: visible;
}
/*thead tr {
position: relative;
top: expression(offsetParent.scrollTop);
z-index: 1;
padding: 0;
}*/
/*table#emails > tbody {
position: fixed;
bottom: 35px;
top: 155px;
left: 155px;
right: 0px;
overflow-x: hidden;
overflow-y: auto;
}*/
#emails th {
/*position: relative;*/
}
#emails th input {
margin: 0;
}
#emails tr {
width: 100%;
border-bottom: 1px solid #C8D6E8;
user-select: none; /* CSS3 */
-moz-user-select: none; /* Gecko (Firefox) */
-khtml-user-select: none; /* Webkit (Safari, Chrome) */
}
.draggable {
cursor: move;
/*position: relative;*/
#mailcontent {
border: 0;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.draggable img {
position: static;
.unseen {
font-weight: bold;
}
ul.hidden {
display: none;
td[name="date"] {
text-align: right;
}
ul.visible {
display: block;
padding-bottom: 0;
#quotabar {
margin: 12px 0 0 15px;
width: 200px;
}
/* Compose mail page */
#compose-container {
#quotaraw {
margin-left: 10px;
}
/*
* Mailboxes list
*/
#mboxactions {
position: fixed;
padding-left: 14px;
}
#mboxactions .btn-toolbar {
margin-bottom: 0px;
}
#folders li {
position: relative;
}
div.clickbox {
position: absolute;
left: 0px;
right: 10px;
top: 0;
bottom: 0;
top: 2px;
width: 14px;
height: 14px;
}
div.collapsed {
background-image: url("/static/pics/collapsed.png");
background-repeat: no-repeat;
}
div.expanded {
background-image: url("/static/pics/expanded.png");
background-repeat: no-repeat;
}
/*
* Compose form
*/
#mailheader {
position: relative;
padding-bottom: 5px;
}
#mailheader input {
width: 99%;
padding: 2px 0;
}
#mailheader textarea {
width: 99%;
height: 40px;
padding: 2px 0;
}
#mailheader label {
text-align: left;
}
#attachments {
position: relative;
border: 1px solid #cccccc;
background-color: #eee;
margin: 10px 0 5px 0;
margin: 1px 0 5px 0;
padding: 5px 0;
cursor: pointer;
width: 100%;
@@ -121,133 +135,65 @@ ul.visible {
#list {
position: absolute;
top: 5px;
left: 130px;
left: 160px;
font-weight: bold;
}
#body_container {
position: absolute;
left: 15px;
right: 0px;
bottom: 15px;
}
#id_body {
width: 99%;
height: 100%;
}
/*
* Attachments form
*/
#submit {
margin: 0 auto;
}
#attachment_list {
margin-top: 20px;
height: 150px;
overflow-x: hidden;
overflow-y: auto;
padding: 2px;
}
#attachment_list i,
#attachment_list label {
float: left;
}
.shortlist {
font-weight: normal !important;
font-style: italic;
}
div.row {
width: 100%;
margin: 5px 0;
}
div.row label {
width: 120px;
font-size: small;
padding: 3px 0;
}
div.input_container {
position: static;
margin-left: 130px;
}
textarea {
border: 1px solid #cccccc;
background-color: #eee;
width: 100%;
height: 40px;
word-wrap: break-word;
resize: none;
padding: 2px 0;
}
textarea:hover {
background-color: #ffffcc;
}
#body_container {
position: absolute;
top: 205px;
left: 0;
right: 0px;
bottom: 15px;
}
#id_body {
background: white;
width: 100%;
height: 100%;
}
#mailheader input {
width: 100%;
padding: 2px 0;
}
#mailheader {
position: relative;
padding-bottom: 5px;
}
/* Progress bar */
#quotalabel {
float: left;
padding: 7px 2px 0 5px;
display: none;
}
#quotabox {
display: none;
float: left;
margin: 5px;
width: 300px;
padding: 0;
}
#box {
/*border: 1px solid #ccc; */
width: 200px;
background: url(../../pics/progressbar_bg.gif) right center no-repeat;
height: 19px;
float: left;
}
#perc {
background: url(../../pics/progressbar.gif) right center no-repeat;
height: 19px;
}
#quotatext {
padding: 2px 0 0 2px;
float: left;
}
#fdmenu { border:1px solid #999; padding:0; background:#eee; width:150px; display:none; }
#fdmenu .separator { border-top:1px solid #999; }
#fdmenu ul { list-style-type:none; margin:0; padding:0; }
#fdmenu li { margin:0; padding:0; }
#fdmenu li a { display:block; padding:5px 10px 5px 5px; font-size:12px; text-decoration:none; font-family:tahoma,arial,sans-serif; color:#000; }
#fdmenu li a:hover { background-color:#ddd; }
#fdmenu img { float:left; margin: 0 5px 0 0; }
.folder_menu {
float: right;
opacity: 0.8;
}
.folder_btn {
float: right;
margin: 3px;
}
.folder_menubar {
clear: both;
}
/*
* Drap & Drop
*/
.dragbox {
position : absolute;
opacity : 0.8;
width : 200px;
padding : 5px;
text-align : center;
height : 25px;
border : 1px solid #333;
background : white;
display: none;
z-index : 3;
}
/*
* Folder form
*/
.modal-body {
max-height: 300px;
overflow-y: auto;
}
#folders2 li {
position: relative;
}
-111
View File
@@ -1,111 +0,0 @@
/*
* Simple dropdown menu plugin used for folders manipulation.
*
*/
var FdMenu = new Class({
Implements: [Options],
options: {
modify_url: "",
delete_url: ""
},
add_entry: function(name, label, pic, url, onclick) {
var item = new Element("li");
var picpath = static_url("pics/" + pic);
this[name] = new Element("a")
.set("html", "<img src='" + picpath + "' /> " + label)
.addEvent("click", onclick.bind(this))
.inject(item);
item.inject(this.list);
},
initialize: function(options) {
this.setOptions(options);
this.container = new Element("div", {"id" : "fdmenu"})
.addClass("fdmenu");
this.list = new Element("ul");
this.add_entry("modbutton", gettext("Edit folder"),
"edit.png", this.options.modify_url, function(evt) {
evt.stop();
SqueezeBox.open(evt.target.get("href"), {
handler: "iframe",
size: {x: 350, y: 400},
closeBtn: true
});
$(document.body).fireEvent("click");
});
this.add_entry("delbutton", gettext("Delete folder"), "remove.png",
this.options.delete_url, function(evt) {
evt.stop();
$(document.body).fireEvent("click");
if (!confirm(gettext("Delete folder?"))) {
return;
}
new Request.JSON.mdb({
url: evt.target.get("href"),
method: "GET",
onSuccess: function(resp) {
if (resp.status == "ok") {
var dfolder = this.current_folder + "/";
if (dfolder == current_anchor.base) {
var pfolder = ((this.current_folder.split(".")).slice(0, -1)).join(".");
if (pfolder == "") {
pfolder = "INBOX";
}
current_anchor.baseurl(pfolder, 1);
}
current_anchor.loading_message = gettext("Folder deleted");
current_anchor.loading_color = "green";
current_anchor.update(1);
} else {
infobox.error(resp.error);
infobox.hide(2);
}
}.bind(this)
}).send();
}
);
this.list.inject(this.container);
this.shown = false;
$(document.body).addEvent("click", function() {
if (this.shown) {
this.hide();
}
}.bind(this));
},
show: function(origin, folder) {
var position = origin.getPosition();
this.container.setStyles({
position: "absolute",
top: position.y + 5,
left: position.x + 5,
display: "block"
});
this.container.inject(document.body);
this.shown = true;
this.current_folder = folder;
this.modbutton.set("href", this.options.modify_url + "?name=" + folder);
this.delbutton.set("href", this.options.delete_url + "?name=" + folder);
},
hide: function() {
this.container.setStyles({
display: "none"
});
this.container = this.container.dispose();
this.shown = false;
},
toggle: function(origin, folder) {
return (!this.shown) ? this.show(origin, folder) : this.hide();
}
});
File diff suppressed because it is too large Load Diff
@@ -1,49 +1,10 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}webmail/css/folders.css" />
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}webmail/js/webmail.js" type="text/javascript"></script>
<script type="text/javascript">
window.addEvent("domready", function() {
var form = new Form();
init_folders_browsing();
$$("a[name=loadfolder]").addEvent("click", function(evt) {
evt.stop();
$$("a[name=loadfolder]").each(function(item) {
item.getParent().removeClass("selected");
});
this.getParent().addClass("selected");
});
form.register_extra_data_callback("{{ fname }}", function() {
var result = "";
$$("li[class*=selected]").each(function(item) {
var atag = item.getFirst("a");
result = atag.get("href");
});
return "parent_folder=" + result;
});
});
</script>
{% endblock %}
{% block content %}
<div class="title"><h1>{{ title }}</h1></div>
<div id="error" class="error">{{ error }}</div>
<form action="{% url modoboa.extensions.webmail.views.newfolder %}"
method="POST" id="{{ fname }}" name="{{ fname }}">
<input type="hidden" name="oldname" value="{{ oldname }}" />
{% include "common/genericform.html" %}
<div class="row">
<label>{% trans "Parent folder" %}</label>
</div>
<div id="folders2" class="box">
{% include "webmail/folders.html" %}
</div>
<div id="fdcreate">
<input type="submit" name="submit" value='{{ submit_label }}'/>
</div>
</form>
{% extends "common/generic_modal_form.html" %}
{% load i18n webextras %}
{% block extrafields %}
<div id="folders2" class="well">
<ul class="nav nav-list">
<li class="nav-header">{% trans "Parent mailbox" %}</li>
{% print_folders folders selected withunseen selectonly %}
</ul>
</div>
{% endblock %}
+32 -220
View File
@@ -1,230 +1,42 @@
{% extends "common/email_listing.html" %}
{% load i18n %}
{% extends "fixed.html" %}
{% load i18n libextras %}
{% block html_head %}
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}webmail/css/webmail.css" />
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}webmail/css/folders.css" />
<script type="text/javascript" src="{{ MEDIA_URL }}js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}webmail/js/fdmenu.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-ui.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.htmltable.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/searchbar.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}webmail/js/webmail.js"></script>
{{ block.super }}
<script type="text/javascript">
var webmail = undefined;
function wm_updatelisting(resp) {
window.removeEvents("resize");
updatelisting(resp);
if ($defined(resp.folders)) {
$("folders").set("html", resp.folders);
$$("li[class*=clickable]").removeEvents();
SqueezeBox.assign($("folders").getElements('a[class=boxed]'), {
parse: 'rel'
$(document).ready(function() {
webmail = new Webmail({
poller_interval: {{ refreshrate }},
poller_url: "{% url modoboa.extensions.webmail.views.check_unseen_messages %}",
move_url: "{% url modoboa.extensions.webmail.views.move %}",
submboxes_url: "{% url modoboa.extensions.webmail.views.submailboxes %}",
deflocation: "{{ deflocation }}",
defcallback: "{{ defcallback }}",
ro_mboxes: {% tolist ro_mboxes %}
});
var fdbuttons = $$("img[class*=footer]");
var fdmenu = new FdMenu({
modify_url: "{% url modoboa.extensions.webmail.views.editfolder %}",
delete_url: "{% url modoboa.extensions.webmail.views.delfolder %}"
});
fdbuttons.addEvents({
click: function(evt) {
var parent = this.getParent();
var fdname = parent.getFirst("a[name=loadfolder]").get("href");
fdmenu.toggle(this, fdname);
evt.stop();
}
});
}
select_folder($$("a[href=" + current_anchor.getbaseurl() + "]"));
init_folders_browsing();
if ($defined(resp.quota) && resp.quota != "-1") {
quota_pb.set(resp.quota);
$("quotabox").setStyle("display", "block");
$("quotalabel").setStyle("display", "block");
}
$$("a[name=loadfolder]").addEvent("click", foldercallback);
$$("a[name=compose]").addEvent("click", compose_loader);
}
});
</script>
{% endblock %}
{% block js %}
/*quota_pb = new ProgressBar({
container: $("quotabox"),
startPercentage: 0,
boxID: "box",
percentageID: "perc",
displayText: true,
displayID: "quotatext"
});
current_anchor.register_callback("viewmail", viewmail_cb);
current_anchor.register_callback("compose", compose_callback);
current_anchor.register_callback("reply", compose_callback);
current_anchor.register_callback("replyall", compose_callback);
current_anchor.register_callback("forward", compose_callback);
window.addEvent("pageRefresh", function() {
if (rtimer) {
clearInterval(rtimer);
rtimer = null;
}
});*/
new Webmail({
refreshRate: {{ refreshrate }},
modify_url: "{% url modoboa.extensions.webmail.views.editfolder %}",
delete_url: "{% url modoboa.extensions.webmail.views.delfolder %}",
move_url: "{% url modoboa.extensions.webmail.views.move %}",
submboxes_url: "{% url modoboa.extensions.webmail.views.submailboxes %}"
});
current_anchor.register_callback("folder", function(resp) {
wm_updatelisting(resp);
rtimer = refreshFolder.periodical({{ refreshrate }});
searchbox_init();
update_sortable_column();
var emails_table = new HtmlTable($("emails"), {
selectable: true,
shiftForMultiSelect: true
}).addEvents({
rowFocus: function(tr) {
clearInterval(rtimer);
},
rowUnfocus: function(tr) {
if (this._selectedRows.length == 0) {
rtimer = refreshFolder.periodical({{ refreshrate }});
}
}
});
/* The IE way for disabling default selection */
/* Actually it doesn't work :p */
$$("tbody>tr").set("unselectable", "on");
bstart_dragging = function(item) {
var block = new Element("div", {id: "draggeditems"})
.setStyles({"position" : "absolute",
"opacity" : 0.8,
"width" : "200px",
"padding" : "5px",
"text-align" : "center",
"height" : "25px",
"border" : "1px solid #333",
"background" : "white",
display: "none",
"z-index" : 3,
top : this.element.getCoordinates()['top'],
left : this.element.getCoordinates()['left']})
.inject(document.body);
block.store("parent", this.element);
this.element = block;
clearInterval(rtimer);
};
start_dragging = function(item) {
var tr = this.element.retrieve("parent").getParent();
if (!emails_table.isSelected(tr)) {
emails_table.selectNone();
emails_table.selectRow(tr);
}
item.set("html", "Moving " + emails_table._selectedRows.length + " messages");
this.element.setStyle("display", "block");
};
enter_droppable = function(item, droppable) {
droppable.addClass("dragging");
};
leave_droppable = function(item, droppable) {
droppable.removeClass("dragging");
};
restore_parent = function(drag, item) {
var parent = item.retrieve("parent");
drag.element = parent;
rtimer = refreshFolder.periodical({{ refreshrate }});
};
drop_element = function(item, droppable, event) {
this.element.dispose();
delete(this.element);
if (!droppable) {
restore_parent(this, item);
return;
}
droppable.removeClass("dragging");
dest = gethref(droppable.getFirst("a"));
msgset = new Array();
emails_table._selectedRows.each(function(item, index) {
msgset.include(item.get("id"));
});
{% url modoboa.extensions.webmail.views.move as moveurl %}
simple_request("{{ moveurl }}", {msgset : msgset.join(), to : dest});
};
cancel_dragging = function(item) {
this.element.dispose();
delete(this.element);
restore_parent(this, item);
};
$$("td[class*=draggable]").each(function(item) {
new Drag.Move(item, {
droppables: ".droppable"
}).addEvents({
beforeStart: bstart_dragging,
start: start_dragging,
enter: enter_droppable,
leave: leave_droppable,
drop: drop_element,
cancel: cancel_dragging
});
});
buildmarkrequest = function(evt) {
evt.stop();
if (!emails_table._selectedRows.length) {
return;
}
var ids = new Array();
emails_table._selectedRows.each(function(item, index) {
ids.include(item.get("id"));
});
simple_request(evt.target.get("href"), {ids : ids.join()});
};
$$("a[name=mark-read]").addEvent("click", buildmarkrequest);
$$("a[name=mark-unread]").addEvent("click", buildmarkrequest);
$$("a[name=fdaction]").addEvent("click", function(evt) {
simple_request(evt.target.get("href"), {});
evt.stop();
});
if ($("toggleselect")) {
$("toggleselect").addEvent("click", function(evt) {
if (evt.target.checked) {
emails_table.selectAll();
} else {
emails_table.selectNone();
}
});
}
init_sortable_columns();
$$("tbody>tr").addEvent("dblclick", viewmail);
});
{% block fixed_content %}
<div id="leftcol">
<div id="folders" class="well sidebar-nav">{{ mboxes }}</div>
</div>
<div id="menubar"></div>
<div id="listing"></div>
{% endblock %}
{% block middletitle %}{% trans "Webmail" %}{% endblock %}
{% block leftcol %}
<div id="folders" class="box">{{ mboxes }}</div>
{% endblock %}
{% block menu %}{{ menu }}{% endblock %}
{% block footer %}
<div id="quotalabel">{% trans "Mailbox quota" %}</div>
<div id="quotabox">{{ quota }}</div>
{{ block.super }}
{% block footerleft %}
<div id="quotabox">
<label class="pull-left navbar-text">{% trans "Mailbox quota" %}</label>
<div id="quotabar" class="pull-left progress {% progress_color quota %}">
<div class="bar" style="width: {{ quota }}%"></div>
</div>
<label id="quotaraw" class="pull-left navbar-text">{{ quota }}%</label>
</div>
{% endblock %}
+4 -5
View File
@@ -105,9 +105,8 @@ def listmailbox_menu(selection, folder, user):
]
if folder == parameters.get_user(user, "TRASH_FOLDER"):
entries[2]["menu"] += [
{"name" : "fdaction",
{"name" : "empty",
"label" : _("Empty folder"),
"img" : static_url("pics/clear.png"),
"url" : reverse(webmail.views.empty, args=[folder])}
]
searchbar = render_to_string('common/email_searchbar.html', {
@@ -167,19 +166,19 @@ def mboxes_menu():
{"name" : "newmbox",
"url" : reverse(webmail.views.newfolder),
"img" : "icon-plus",
"label" : "",
"title" : _("Create a new mailbox"),
"modal" : True,
"modalcb" : "webmail.mboxform_cb",
"class" : "btn btn-mini"},
{"name" : "editmbox",
"url" : reverse(webmail.views.editfolder),
"img" : "icon-edit",
"label" : "",
"title" : _("Edit the selected mailbox"),
"class" : "btn btn-mini"},
{"name" : "removembox",
"url" : reverse(webmail.views.delfolder),
"img" : "icon-remove",
"label" : "",
"title" : _("Remove the selected mailbox"),
"class" : "btn btn-mini"}
]
+10 -10
View File
@@ -214,11 +214,12 @@ def mark(request, name):
@login_required
@needs_mailbox()
def empty(request, name):
if name == parameters.get_user(request.user, "TRASH_FOLDER"):
get_imapconnector(request).empty(name)
if name != parameters.get_user(request.user, "TRASH_FOLDER"):
raise WebmailError(_("Invalid request"))
get_imapconnector(request).empty(name)
content = "<div class='alert alert-info'>%s</div>" % _("Empty mailbox")
return ajax_simple_response(dict(
status="ok", listing=content
status="ok", listing=content, mailbox=name
))
@login_required
@@ -620,13 +621,12 @@ def newindex(request):
response["refreshrate"] = \
int(parameters.get_user(request.user, "REFRESH_INTERVAL"))
response["quota"] = ImapListing.computequota(imapc)
if response["quota"] < 50:
response["quotalevel"] = "success"
elif response["quotalevel"] < 80:
response["quotalevel"] = "warning"
else:
response["quotalevel"] = "danger"
return _render(request, "webmail/index2.html", response)
response["ro_mboxes"] = ["INBOX", "Junk",
parameters.get_user(request.user, "SENT_FOLDER"),
parameters.get_user(request.user, "TRASH_FOLDER"),
parameters.get_user(request.user, "DRAFTS_FOLDER")]
return _render(request, "webmail/index.html", response)
if action in ["reply", "forward"]:
action = "compose"
+4 -1
View File
@@ -35,6 +35,9 @@ def join(items, sep=','):
res += "%s : '%s'" % (k, v)
return res
@register.simple_tag
def tolist(values):
return "[%s]" % ",".join(map(lambda v: '"%s"' % v, values))
@register.simple_tag
def display_messages(msgs):
@@ -134,7 +137,7 @@ def alert(msg, typ):
@register.simple_tag
def render_link(linkdef, mdclass=None):
t = Template("""<a href="{{ link.url }}" name="{{ link.name }}"
t = Template("""<a href="{{ link.url }}" name="{{ link.name }}" title="{{ link.title }}"
{% if link.modal %}data-toggle="ajaxmodal{% if link.autowidth %}-autowidth{% endif %}"{% endif %}
{% if link.modalcb %}modalcb="{{ link.modalcb }}"{% endif %}
class="{{ mdclass }}{% if link.class %} {{ link.class }}{% endif %}"