mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: Global user interface improvment
* The quarantine manager is done * The webmail is not yet completed * Cleanup * More...
This commit is contained in:
+1
-1
@@ -246,11 +246,11 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
role = self.cleaned_data["role"]
|
||||
else:
|
||||
role = "SimpleUsers"
|
||||
account.groups.clear()
|
||||
if role == "SuperAdmins":
|
||||
account.is_superuser = True
|
||||
else:
|
||||
account.is_superuser = False
|
||||
account.groups.clear()
|
||||
account.groups.add(Group.objects.get(name=role))
|
||||
account.save()
|
||||
return account
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ class User(DUser):
|
||||
@property
|
||||
def group(self):
|
||||
if self.is_superuser:
|
||||
return "SuperAdmin"
|
||||
return "SuperAdmins"
|
||||
try:
|
||||
return self.groups.all()[0].name
|
||||
except IndexError:
|
||||
|
||||
@@ -76,14 +76,15 @@ class SQLconnector(MBconnector):
|
||||
return emails
|
||||
|
||||
class SQLlisting(EmailListing):
|
||||
tpl = "amavis_quarantine/index.html"
|
||||
tpl = "amavis_quarantine/index2.html"
|
||||
tbltype = Qtable
|
||||
deflocation = "listing/"
|
||||
defcallback = "updatelisting"
|
||||
reset_wm_url = True
|
||||
table_styles = "table-condensed"
|
||||
|
||||
def __init__(self, user, msgs, filter, **kwargs):
|
||||
if user.belongs_to_group('SimpleUsers'):
|
||||
if user.group == 'SimpleUsers':
|
||||
Qtable.cols_order = ['type', 'rstatus', 'from_', 'subject', 'time']
|
||||
else:
|
||||
Qtable.cols_order = ['type', 'rstatus', 'to', 'from_', 'subject', 'time']
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
#menubar {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#listing {
|
||||
position: fixed;
|
||||
padding: 0 15px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#mailcontent {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
thead tr {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
tr.table-tr-selected {
|
||||
background: #ffffcc;
|
||||
}
|
||||
td.unseen {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -1,136 +1,180 @@
|
||||
function updatehash(evt) {
|
||||
evt.stop();
|
||||
var url = $defined(this.get("href")) ? this.get("href") : "";
|
||||
current_anchor.parse_string(url, true).setparams(navparams);
|
||||
current_anchor.update();
|
||||
}
|
||||
var Quarantine = function(options) {
|
||||
this.initialize(options);
|
||||
};
|
||||
|
||||
function appendhash(evt) {
|
||||
evt.stop();
|
||||
location.hash += evt.target.get("href");
|
||||
}
|
||||
Quarantine.prototype = {
|
||||
constructor: Quarantine,
|
||||
|
||||
function updateparams(evt) {
|
||||
evt.stop();
|
||||
current_anchor.updateparams(evt.target.get("href"));
|
||||
current_anchor.update();
|
||||
}
|
||||
defaults: {
|
||||
deflocation: "listing",
|
||||
defcallback: "listing_cb"
|
||||
},
|
||||
|
||||
function actioncallback(resp) {
|
||||
$("listing").set("html", "");
|
||||
$("menubar").set("html", "");
|
||||
$("navbar").set("html", "");
|
||||
if (resp.status == "ok") {
|
||||
infobox.info(resp.respmsg);
|
||||
current_anchor.parse_string(resp.url, true).setparams(navparams);
|
||||
current_anchor.update(1);
|
||||
} else {
|
||||
infobox.error(resp.respmsg);
|
||||
}
|
||||
}
|
||||
initialize: function(options) {
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.navobj = new History(this.options);
|
||||
|
||||
function actionclick(evt) {
|
||||
new Request.JSON.mdb({
|
||||
url: evt.target.get("href"),
|
||||
onSuccess: actioncallback
|
||||
}).get();
|
||||
}
|
||||
this.register_navcallbacks();
|
||||
this.listen();
|
||||
},
|
||||
|
||||
function deleteclick(evt) {
|
||||
evt.stop();
|
||||
if (!confirm(gettext("Delete this message?"))) {
|
||||
return false;
|
||||
update_page: function(data) {
|
||||
if (data.menu != undefined) {
|
||||
$("#menubar").html(data.menu);
|
||||
$("#searchfield").searchbar({navobj: this.navobj});
|
||||
}
|
||||
if (data.navbar) {
|
||||
$("#bottom-bar-in").html(data.navbar);
|
||||
}
|
||||
if (data.listing != undefined) {
|
||||
$("#listing").html(data.listing);
|
||||
$("#listing").css({
|
||||
top: $("#menubar").outerHeight() + 60 + "px",
|
||||
bottom: $("#bottom-bar").outerHeight() + "px",
|
||||
overflow: "auto"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
listen: function() {
|
||||
$(document).on("dblclick", "tbody>tr", $.proxy(this.viewmail_loader, this));
|
||||
$(document).on("click", "a[name=selectmsgs]", $.proxy(this.selectmsgs, this));
|
||||
$(document).on("click", "a[name=release-multi]",
|
||||
$.proxy(this.release_selection, this));
|
||||
$(document).on("click", "a[name=delete-multi]",
|
||||
$.proxy(this.delete_selection, this));
|
||||
$(document).on("click", "#bottom-bar a", $.proxy(this.load_page, this));
|
||||
|
||||
$(document).on("click", "a[name=release]", $.proxy(this.release, this));
|
||||
$(document).on("click", "a[name=delete]", $.proxy(this.delete, this));
|
||||
$(document).on("click", "a[name=viewmode]", $.proxy(this.update_params, this));
|
||||
},
|
||||
|
||||
load_page: function(e) {
|
||||
e.preventDefault();
|
||||
var $link = $(e.target).parent();
|
||||
|
||||
this.navobj.deleteParam("rcpt");
|
||||
this.navobj.from_string($link.attr("href")).update();
|
||||
},
|
||||
|
||||
viewmail_loader: function(e) {
|
||||
e.preventDefault();
|
||||
var $tr = $(e.target).parent();
|
||||
var $to = $tr.find("td[name=to]");
|
||||
|
||||
this.navobj.baseurl($tr.attr("id"));
|
||||
if ($to.length) {
|
||||
this.navobj.setparam("rcpt", $to.html().trim());
|
||||
}
|
||||
this.navobj.update();
|
||||
},
|
||||
|
||||
selectmsgs: function(e) {
|
||||
e.preventDefault();
|
||||
var type = $(e.target).attr("href");
|
||||
|
||||
if (type == "") {
|
||||
$("#emails").htmltable("clear_selection");
|
||||
return;
|
||||
}
|
||||
$("td[name=type]").each(function() {
|
||||
var $this = $(this);
|
||||
if ($this.html().trim() == type) {
|
||||
$("#emails").htmltable("select_row", $this.parent());
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_send_selection: function(e, name, message) {
|
||||
var $link = $(e.target);
|
||||
|
||||
e.preventDefault();
|
||||
if (!this.htmltable.current_selection().length ||
|
||||
!confirm(message)) {
|
||||
return;
|
||||
}
|
||||
var selection = [];
|
||||
|
||||
this.htmltable.current_selection().each(function() {
|
||||
var $tr = $(this);
|
||||
var $to = $tr.find("td[name=to]");
|
||||
|
||||
if ($to.length) {
|
||||
selection.push($to.html().trim() + " " + $tr.attr("id"));
|
||||
} else {
|
||||
selection.push($tr.attr("id"));
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: $link.attr("href"),
|
||||
data: "action=" + name + "&selection=" + selection.join(","),
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: $.proxy(this.action_cb, this)
|
||||
});
|
||||
},
|
||||
|
||||
release_selection: function(e) {
|
||||
this._send_selection(e, "release", gettext("Release this selection?"));
|
||||
},
|
||||
|
||||
delete_selection: function(e) {
|
||||
this._send_selection(e, "delete", gettext("Delete this selection?"));
|
||||
},
|
||||
|
||||
_send_action: function(e, message) {
|
||||
var $link = $(e.target);
|
||||
|
||||
e.preventDefault();
|
||||
if (!confirm(message)) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: $link.attr("href"),
|
||||
dataType: 'json',
|
||||
success: $.proxy(this.action_cb, this)
|
||||
});
|
||||
},
|
||||
|
||||
release: function(e) {
|
||||
this._send_action(e, gettext("Release this message?"));
|
||||
},
|
||||
|
||||
delete: function(e) {
|
||||
this._send_action(e, gettext("Delete this message?"));
|
||||
},
|
||||
|
||||
update_params: function(e) {
|
||||
var $link = $(e.target);
|
||||
e.preventDefault();
|
||||
this.navobj.updateparams($link.attr("href")).update();
|
||||
},
|
||||
|
||||
register_navcallbacks: function() {
|
||||
this.navobj.register_callback("_listing",
|
||||
$.proxy(this.listing_cb, this));
|
||||
this.navobj.register_callback("viewmail",
|
||||
$.proxy(this.viewmail_cb, this));
|
||||
},
|
||||
|
||||
listing_cb: function(data) {
|
||||
this.update_page(data);
|
||||
$("#emails").htmltable();
|
||||
this.htmltable = $("#emails").data("htmltable");
|
||||
},
|
||||
|
||||
viewmail_cb: function(data) {
|
||||
this.update_page(data);
|
||||
$("#listing").css("overflow", "hidden");
|
||||
},
|
||||
|
||||
action_cb: function(data) {
|
||||
if (data.status == "ok") {
|
||||
this.navobj.parse_string(data.url, true).update(true);
|
||||
$("body").notify("success", data.respmsg, 2000);
|
||||
} else {
|
||||
$("body").notify("error", data.respmsg);
|
||||
}
|
||||
}
|
||||
actionclick(evt);
|
||||
}
|
||||
|
||||
function releaseclick(evt) {
|
||||
evt.stop();
|
||||
if (!confirm(gettext("Release this message?"))) {
|
||||
return false;
|
||||
}
|
||||
actionclick(evt);
|
||||
}
|
||||
|
||||
function viewmail_cs(evt) {
|
||||
evt.stop();
|
||||
var to = this.getFirst("td[name=to]");
|
||||
|
||||
current_anchor.baseurl(this.get("id"));
|
||||
if ($defined(to)) {
|
||||
current_anchor.setparam("rcpt", to.get("html").trim());
|
||||
}
|
||||
current_anchor.update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback of the 'listing' action (the main screen)
|
||||
*/
|
||||
function listing_cb(resp) {
|
||||
updatelisting(resp);
|
||||
|
||||
var tbl = new HtmlTable($("emails"), {
|
||||
useKeyboard: false,
|
||||
selectable: true
|
||||
});
|
||||
|
||||
if ($("toggleselect")) {
|
||||
$("toggleselect").addEvent("click", function(evt) {
|
||||
if ($$("tr[class*=table-tr-selected]").length) {
|
||||
tbl.selectNone();
|
||||
} else {
|
||||
tbl.selectAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
$$("a[name=selectmsgs]").addEvent("click", function(evt) {
|
||||
evt.stop();
|
||||
var type = evt.target.get("href");
|
||||
|
||||
if (!$chk(type)) {
|
||||
$$("tr[class*=table-tr-selected]").each(function(item) {
|
||||
item.removeClass("table-tr-selected");
|
||||
});
|
||||
if ($("toggleselect").checked) {
|
||||
$("toggleselect").checked = false;
|
||||
tbl.selectNone();
|
||||
}
|
||||
return;
|
||||
}
|
||||
$$("td[name=type]").each(function(item) {
|
||||
if (item.get("html").trim() == type) {
|
||||
item.getParent().addClass("table-tr-selected");
|
||||
}
|
||||
});
|
||||
});
|
||||
$$("a[name=release]").addEvent("click", function(event) {
|
||||
if (!checkTableSelection(gettext("Release this selection?"))) {
|
||||
event.stop();
|
||||
return;
|
||||
}
|
||||
mysubmit(event, "release");
|
||||
});
|
||||
$$("a[name=delete]").addEvent("click", function(event) {
|
||||
if (!checkTableSelection(gettext("Delete this selection?"))) {
|
||||
event.stop();
|
||||
return;
|
||||
}
|
||||
mysubmit(event, "delete");
|
||||
});
|
||||
searchbox_init();
|
||||
init_sortable_columns();
|
||||
update_sortable_column();
|
||||
$$("tbody>tr").addEvent("dblclick", viewmail_cs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback of the 'viewmail' action
|
||||
*/
|
||||
function viewmail_cb(resp) {
|
||||
updatelisting(resp);
|
||||
$$("a[name=back]").addEvent("click", updatehash);
|
||||
$$("a[name=delete]").addEvent("click", deleteclick);
|
||||
$$("a[name=release]").addEvent("click", releaseclick);
|
||||
$$("a[name=viewmode]").addEvent("click", updateparams);
|
||||
setDivHeight("mailcontent", 5, 0);
|
||||
}
|
||||
};
|
||||
@@ -1,42 +1,22 @@
|
||||
{% extends "common/email_listing.html" %}
|
||||
{% load i18n %}
|
||||
{% extends "fixed.html" %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}amavis_quarantine/css/quarantine.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.htmltable.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/searchbar.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}amavis_quarantine/js/quarantine.js"></script>
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
mysubmit = function(event, name) {
|
||||
event.stop();
|
||||
var selection = new Array();
|
||||
$$("tr[class*=table-tr-selected]").each(function(item) {
|
||||
var content = "";
|
||||
var to = item.getFirst("td[name=to]");
|
||||
|
||||
if ($defined(to)) {
|
||||
content = to.get("html").trim() + " ";
|
||||
}
|
||||
selection.push(content + item.get("id"));
|
||||
$(document).ready(function() {
|
||||
var qm = new Quarantine({
|
||||
deflocation: "{{ deflocation }}",
|
||||
defcallback: "{{ defcallback }}"
|
||||
});
|
||||
new Element("input", {
|
||||
"type" : "hidden", "name" : "selection", "value" : selection
|
||||
}).inject($("listingform"), "top");
|
||||
new Element('input', {
|
||||
'type' : 'hidden', 'name' : "action", style: "display:none", 'value' : name
|
||||
}).inject($("listingform"), "top");
|
||||
{% url modoboa.extensions.amavis_quarantine.views.process as actionurl %}
|
||||
$("listingform").set("action", "{{ actionurl }}");
|
||||
$("listingform").set("send", {
|
||||
onSuccess : function(res) {
|
||||
response = JSON.decode(res);
|
||||
actioncallback(response);
|
||||
}
|
||||
});
|
||||
$("listingform").send();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
current_anchor.register_callback("_listing", listing_cb);
|
||||
current_anchor.register_callback("viewmail", viewmail_cb);
|
||||
{% block fixed_content %}
|
||||
<div id="menubar"></div>
|
||||
<div id="listing"></div>
|
||||
{% endblock %}
|
||||
{% block footer %}
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Quarantine" %}{% endblock %}
|
||||
|
||||
@@ -1,43 +1,11 @@
|
||||
{% extends "layout_simple.html" %}
|
||||
{% extends "common/generic_modal.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<style type="text/css">
|
||||
table {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 20px;
|
||||
}
|
||||
|
||||
table th {
|
||||
background: #CEDBEC;
|
||||
text-align: left;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
table td {
|
||||
border-bottom: 1px solid #C8D6E8;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
td.odd {
|
||||
background: #F7F9Fb;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: smaller;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<table border="0">
|
||||
<tr><th colspan="2">{% trans "Message headers" %}</th></tr>
|
||||
{% block modalbody %}
|
||||
<table class="table table-condensed table-striped">
|
||||
{% for k, v in headers %}
|
||||
<tr>
|
||||
<td class="odd">{{ k }}</td><td>{{ v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -24,46 +24,44 @@ def viewm_menu(selection, backurl, mail_id, rcpt, perms):
|
||||
|
||||
entries = [
|
||||
{"name" : "back",
|
||||
"url" : backurl,
|
||||
"img" : static_url("pics/back.png"),
|
||||
"img" : "icon-arrow-left",
|
||||
"url" : "javascript:history.go(-1);",
|
||||
"label" : _("Back to list")},
|
||||
{"name" : "headers",
|
||||
"url" : reverse(amavis_quarantine.views.viewheaders, args=[mail_id]),
|
||||
"img" : static_url("pics/add.png"),
|
||||
"label" : _("View full headers"),
|
||||
"class" : "boxed",
|
||||
"rel" : "{handler:'iframe',size:{x:600,y:500}}"},
|
||||
"modal" : True,
|
||||
"autowidth" : True},
|
||||
{"name" : "release",
|
||||
"img" : "icon-ok",
|
||||
"url" : reverse(amavis_quarantine.views.release, args=[mail_id]) \
|
||||
+ "?rcpt=%s" % rcpt,
|
||||
"img" : static_url("pics/release.png"),
|
||||
"label" : _("Release")},
|
||||
{"name" : "delete",
|
||||
"img" : "icon-remove",
|
||||
"url" : reverse(amavis_quarantine.views.delete, args=[mail_id]) \
|
||||
+ "?rcpt=%s" % rcpt,
|
||||
"img" : static_url("pics/remove.png"),
|
||||
"label" : _("Delete")},
|
||||
{"name" : "options",
|
||||
"label" : _("Options"),
|
||||
"img" : static_url("pics/settings.png"),
|
||||
"class" : "menubardropdown",
|
||||
"img" : "icon-cog",
|
||||
"menu" : options_menu}
|
||||
]
|
||||
|
||||
return render_to_string('common/menu.html',
|
||||
return render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
|
||||
@register.simple_tag
|
||||
def quar_menu(selection, user):
|
||||
entries = [
|
||||
{"name" : "release",
|
||||
"url" : "",
|
||||
"img" : static_url("pics/release.png"),
|
||||
{"name" : "release-multi",
|
||||
"url" : reverse(amavis_quarantine.views.process),
|
||||
"img" : "icon-ok",
|
||||
"label" : _("Release")},
|
||||
{"name" : "delete",
|
||||
"url" : "",
|
||||
"img" : static_url("pics/remove.png"),
|
||||
{"name" : "delete-multi",
|
||||
"img" : "icon-remove",
|
||||
"url" : reverse(amavis_quarantine.views.process),
|
||||
"label" : _("Delete")},
|
||||
{"name" : "select",
|
||||
"url" : "",
|
||||
@@ -87,9 +85,7 @@ def quar_menu(selection, user):
|
||||
}
|
||||
]
|
||||
|
||||
menu = render_to_string('common/menu.html',
|
||||
{"selection" : selection, "entries" : entries})
|
||||
if not user.belongs_to_group('SimpleUsers'):
|
||||
if user.group != 'SimpleUsers':
|
||||
extraopts = [{"name" : "to", "label" : _("To")}]
|
||||
else:
|
||||
extraopts = []
|
||||
@@ -97,4 +93,7 @@ def quar_menu(selection, user):
|
||||
"MEDIA_URL" : settings.MEDIA_URL,
|
||||
"extraopts" : extraopts
|
||||
})
|
||||
return menu + searchbar
|
||||
|
||||
return render_to_string('common/buttons_list.html', dict(
|
||||
selection=selection, entries=entries, extracontent=searchbar
|
||||
))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# coding: utf-8
|
||||
import email
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.template import Template, Context
|
||||
@@ -29,14 +28,14 @@ def __get_current_url(request):
|
||||
return res
|
||||
|
||||
def empty_quarantine(request):
|
||||
content = "<div class='info'>%s</div>" % _("Empty quarantine")
|
||||
content = "<div class='alert alert-info'>%s</div>" % _("Empty quarantine")
|
||||
ctx = getctx("ok", level=2, listing=content, navbar="",
|
||||
menu=quar_menu("", request.user))
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
|
||||
@login_required
|
||||
def _listing(request):
|
||||
filter = None
|
||||
flt = None
|
||||
rcptfilter = None
|
||||
msgs = None
|
||||
|
||||
@@ -60,11 +59,11 @@ def _listing(request):
|
||||
continue
|
||||
else:
|
||||
raise Exception("unsupported search criteria %s" % c)
|
||||
filter = nfilter if filter is None else filter | nfilter
|
||||
flt = nfilter if flt is None else flt | nfilter
|
||||
|
||||
q = ~Q(rs='D')
|
||||
if not request.user.is_superuser:
|
||||
if not request.user.belongs_to_group('SimpleUsers'):
|
||||
if request.user.group != 'SimpleUsers':
|
||||
doms = request.user.get_domains()
|
||||
if not len(doms):
|
||||
return empty_quarantine(request)
|
||||
@@ -73,7 +72,7 @@ def _listing(request):
|
||||
else:
|
||||
q &= Q(rid__email=request.user.email)
|
||||
|
||||
if not request.user.belongs_to_group('SimpleUsers') \
|
||||
if request.user.group != 'SimpleUsers' \
|
||||
and rcptfilter is not None:
|
||||
q &= Q(rid__email__contains=rcptfilter)
|
||||
msgs = Msgrcpt.objects.filter(q).values("mail_id")
|
||||
@@ -86,7 +85,7 @@ def _listing(request):
|
||||
del request.session["page"]
|
||||
pageid = 1
|
||||
|
||||
lst = SQLlisting(request.user, msgs, filter, baseurl="listing/",
|
||||
lst = SQLlisting(request.user, msgs, flt,
|
||||
navparams=request.session["navparams"],
|
||||
elems_per_page=int(parameters.get_user(request.user,
|
||||
"MESSAGES_PER_PAGE")))
|
||||
@@ -95,14 +94,16 @@ def _listing(request):
|
||||
return empty_quarantine(request)
|
||||
|
||||
content = lst.fetch(request, page.id_start, page.id_stop)
|
||||
navbar = lst.render_navbar(page)
|
||||
navbar = lst.render_navbar(page, "listing/")
|
||||
ctx = getctx("ok", listing=content, navbar=navbar,
|
||||
menu=quar_menu("", request.user))
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
return SQLlisting(request.user, None, None, empty=True).render(request)
|
||||
return _render(request, "amavis_quarantine/index.html", dict(
|
||||
deflocation="listing/", defcallback="listing_cb", selection="quarantine"
|
||||
))
|
||||
|
||||
@login_required
|
||||
def getmailcontent(request, mail_id):
|
||||
@@ -123,7 +124,7 @@ def getmailcontent(request, mail_id):
|
||||
|
||||
@login_required
|
||||
def viewmail(request, mail_id):
|
||||
if not request.user.belongs_to_group('SimpleUsers'):
|
||||
if request.user.group != 'SimpleUsers':
|
||||
rcpt = request.GET["rcpt"]
|
||||
else:
|
||||
mb = Mailbox.objects.get(user=request.user)
|
||||
@@ -137,7 +138,7 @@ def viewmail(request, mail_id):
|
||||
args += ["%s=%s" % (kw, request.GET[kw])]
|
||||
|
||||
content = Template("""
|
||||
<iframe width="100%" frameBorder="0" src="{{ url }}" id="mailcontent"></iframe>
|
||||
<iframe src="{{ url }}" id="mailcontent"></iframe>
|
||||
""").render(Context({"url" : reverse(getmailcontent, args=[mail_id]) \
|
||||
+ "?%s" % "&".join(args)}))
|
||||
menu = viewm_menu("", __get_current_url(request), mail_id, rcpt,
|
||||
@@ -152,6 +153,7 @@ def viewheaders(request, mail_id):
|
||||
content += qm.mail_text
|
||||
msg = email.message_from_string(content)
|
||||
return _render(request, 'amavis_quarantine/viewheader.html', {
|
||||
"title" : _("Message headers"),
|
||||
"headers" : msg.items()
|
||||
})
|
||||
|
||||
@@ -166,7 +168,7 @@ def check_mail_id(request, mail_id):
|
||||
@login_required
|
||||
def delete(request, mail_id):
|
||||
mail_id = check_mail_id(request, mail_id)
|
||||
if request.user.belongs_to_group('SimpleUsers'):
|
||||
if request.user.group == 'SimpleUsers':
|
||||
mb = Mailbox.objects.get(user=request.user)
|
||||
msgrcpts = Msgrcpt.objects.filter(mail__in=mail_id, rid__email=mb.full_address)
|
||||
msgrcpts.update(rs='D')
|
||||
@@ -186,7 +188,7 @@ def delete(request, mail_id):
|
||||
@login_required
|
||||
def release(request, mail_id):
|
||||
mail_id = check_mail_id(request, mail_id)
|
||||
if request.user.belongs_to_group('SimpleUsers'):
|
||||
if request.user.group == 'SimpleUsers':
|
||||
mb = Mailbox.objects.get(user=request.user)
|
||||
msgrcpts = Msgrcpt.objects.filter(mail__in=mail_id, rid__email=mb.full_address)
|
||||
else:
|
||||
|
||||
@@ -367,13 +367,13 @@ class IMAPconnector(object):
|
||||
if len(topmailbox):
|
||||
md_mailboxes = []
|
||||
else:
|
||||
md_mailboxes = [{"name" : "INBOX", "class" : "inbox"},
|
||||
md_mailboxes = [{"name" : "INBOX", "class" : "icon-home"},
|
||||
{"name" : parameters.get_user(user, "DRAFTS_FOLDER"),
|
||||
"class" : "drafts"},
|
||||
"class" : "icon-file"},
|
||||
{"name" : 'Junk'},
|
||||
{"name" : parameters.get_user(user, "SENT_FOLDER")},
|
||||
{"name" : parameters.get_user(user, "TRASH_FOLDER"),
|
||||
"class" : "trash"}]
|
||||
"class" : "icon-trash"}]
|
||||
md_mailboxes += self._listfolders(topmailbox, md_mailboxes)
|
||||
if unseen_messages:
|
||||
for fd in md_mailboxes:
|
||||
@@ -476,7 +476,10 @@ class IMAPconnector(object):
|
||||
return
|
||||
|
||||
data = self._cmd("GETQUOTAROOT", self._encodefolder(mailbox))
|
||||
print data
|
||||
if data is None:
|
||||
self.quota_limit = self.quota_actual = None
|
||||
return
|
||||
|
||||
quotadef = data[1][0]
|
||||
m = re.match("[^\s]+ \(STORAGE (\d+) (\d+)\)", quotadef)
|
||||
if not m:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{% load i18n %}
|
||||
{% load i18n libextras %}
|
||||
<form method="POST" action="{{ posturl }}" id="composemail">
|
||||
<div id="compose-container">
|
||||
<div id="mailheader">
|
||||
{% include "common/genericform.html" %}
|
||||
{% render_form form %}
|
||||
<div id="attachments" name="{% url modoboa.extensions.webmail.views.attachments %}">
|
||||
<div>
|
||||
<img src="{{ MEDIA_URL }}pics/attachment.png" />
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
{% load i18n %}
|
||||
{% load webextras %}
|
||||
{% if titlebar %}
|
||||
<div class="boxtitle">
|
||||
<a href="{% url modoboa.extensions.webmail.views.newfolder %}" class="boxed"
|
||||
rel="{handler: 'iframe', size: {x: 350, y: 400}, closeBtn: true}">
|
||||
<img src="{{MEDIA_URL}}pics/add.png"
|
||||
alt="{% trans 'Add a new folder' %}"/>
|
||||
</a>
|
||||
<label class="aligned">{% trans "Folders" %}</label>
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<ul>
|
||||
<ul class="nav nav-list">
|
||||
{% if titlebar %}
|
||||
<li class="nav-header">
|
||||
<a href="{% url modoboa.extensions.webmail.views.newfolder %}">
|
||||
<i class="icon-plus"></i>
|
||||
{% trans "Folders" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% print_folders folders selected withunseen withmenu %}
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{% extends "common/mailheaders.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extraheaders %}
|
||||
{% if attachments %}
|
||||
<tr>
|
||||
|
||||
@@ -50,7 +50,7 @@ def viewmail_menu(selection, folder, user, mail_id=None):
|
||||
}
|
||||
]
|
||||
|
||||
return render_to_string('common/menu.html',
|
||||
return render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"user" : user})
|
||||
|
||||
@@ -66,7 +66,7 @@ def compose_menu(selection, backurl, user):
|
||||
"img" : static_url("pics/send-receive.png"),
|
||||
"label" : _("Send")},
|
||||
]
|
||||
return render_to_string('common/menu.html',
|
||||
return render_to_string('common/buttons_list.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"user" : user})
|
||||
|
||||
@@ -74,13 +74,13 @@ def compose_menu(selection, backurl, user):
|
||||
def listmailbox_menu(selection, folder, user):
|
||||
entries = [
|
||||
{"name" : "compose",
|
||||
"url" : "compose",
|
||||
"img" : static_url("pics/edit.png"),
|
||||
"label" : _("New message")},
|
||||
"url" : "compose",
|
||||
"label" : _("New message"),
|
||||
"class" : "btn"},
|
||||
{"name" : "mark",
|
||||
"img" : static_url("pics/domains.png"),
|
||||
|
||||
"label" : _("Mark messages"),
|
||||
"class" : "menubardropdown",
|
||||
"class" : "btn",
|
||||
"menu" : [
|
||||
{"name" : "mark-read",
|
||||
"label" : _("As read"),
|
||||
@@ -93,8 +93,7 @@ def listmailbox_menu(selection, folder, user):
|
||||
{"name" : "actions",
|
||||
"img" : static_url("pics/settings.png"),
|
||||
"label" : _("Actions"),
|
||||
"class" : "menubardropdown",
|
||||
"width" : "150",
|
||||
"class" : "btn",
|
||||
"menu" : [
|
||||
{"name" : "fdaction",
|
||||
"label" : _("Compress folder"),
|
||||
@@ -110,24 +109,25 @@ def listmailbox_menu(selection, folder, user):
|
||||
"img" : static_url("pics/clear.png"),
|
||||
"url" : reverse(webmail.views.empty, args=[folder])}
|
||||
]
|
||||
menu = render_to_string("common/menu.html",
|
||||
menu = render_to_string("common/buttons_list.html",
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"user" : user})
|
||||
searchbar = render_to_string("common/email_searchbar.html", {
|
||||
"MEDIA_URL" : settings.MEDIA_URL
|
||||
})
|
||||
return menu + searchbar
|
||||
"user" : user, "css" : "nav"})
|
||||
# searchbar = render_to_string("common/email_searchbar.html", {
|
||||
# "MEDIA_URL" : settings.MEDIA_URL
|
||||
# })
|
||||
# return menu + searchbar
|
||||
return menu
|
||||
|
||||
@register.simple_tag
|
||||
def print_folders(folders, selected=None, withunseen=False, withmenu=False):
|
||||
result = ""
|
||||
|
||||
for fd in folders:
|
||||
cssclass = fd["class"] if fd.has_key("class") else "folder"
|
||||
cssclass = ""
|
||||
name = fd["path"] if fd.has_key("sub") else fd["name"]
|
||||
label = fd["name"]
|
||||
if selected == name:
|
||||
cssclass += " selected"
|
||||
cssclass = "active"
|
||||
result += "<li name='%s' class='droppable %s'>\n" % (name, cssclass)
|
||||
if fd.has_key("sub"):
|
||||
if selected is not None and selected != name and selected.count(name):
|
||||
@@ -136,17 +136,21 @@ def print_folders(folders, selected=None, withunseen=False, withmenu=False):
|
||||
else:
|
||||
ul_state = "hidden"
|
||||
div_state = "collapsed"
|
||||
result += "<div class='clickbox %s'> </div>" % div_state
|
||||
if withmenu:
|
||||
result += "<img src='%spics/go-down.png' class='footer' />" \
|
||||
% settings.MEDIA_URL
|
||||
result += "<div class='clickbox %s'></div>" % div_state
|
||||
# if withmenu:
|
||||
# result += "<img src='%spics/go-down.png' class='footer' />" \
|
||||
# % settings.MEDIA_URL
|
||||
|
||||
cssclass = "block"
|
||||
if withunseen and fd.has_key("unseen"):
|
||||
label += " (%d)" % fd["unseen"]
|
||||
cssclass += " unseen"
|
||||
result += "<a href='%s' class='%s' name='loadfolder'>%s</a>\n" \
|
||||
% (fd.has_key("path") and fd["path"] or fd["name"], cssclass, label)
|
||||
iclass = fd["class"] if fd.has_key("class") else "icon-folder-close"
|
||||
result += """<a href='%s' class='%s' name='loadfolder'>
|
||||
<i class="%s"></i>
|
||||
%s
|
||||
</a>
|
||||
""" % (fd.has_key("path") and fd["path"] or fd["name"], cssclass, iclass, label)
|
||||
if fd.has_key("sub") and len(fd["sub"]):
|
||||
result += "<ul name='%s' class='%s'>" % (fd["path"], ul_state) \
|
||||
+ print_folders(fd["sub"], selected, withunseen, withmenu) + "</ul>\n"
|
||||
|
||||
@@ -526,7 +526,7 @@ def viewmail(request):
|
||||
url = reverse(getmailcontent) + "?mbox=%s&mailid=%s&links=%d" % \
|
||||
(request.session["mbox"], mailid, links)
|
||||
content = Template("""
|
||||
<iframe width="100%" frameBorder="0" src="{{ url }}" id="mailcontent"></iframe>
|
||||
<iframe src="{{ url }}" id="mailcontent"></iframe>
|
||||
""").render(Context({"url" : url}))
|
||||
|
||||
return dict(listing=content, menuargs=dict(mail_id=mailid))
|
||||
@@ -571,7 +571,7 @@ def newindex(request):
|
||||
else:
|
||||
if request.is_ajax():
|
||||
raise WebmailError(_("Bad request"))
|
||||
response = dict(deflocation="?action=listmailbox",
|
||||
response = dict(selection="webmail", deflocation="?action=listmailbox",
|
||||
defcallback="wm_updatelisting")
|
||||
|
||||
curmbox = request.session.get("mbox", "INBOX")
|
||||
@@ -582,7 +582,7 @@ def newindex(request):
|
||||
int(parameters.get_user(request.user, "REFRESH_INTERVAL")) * 1000
|
||||
response["mboxes"] = render_mboxes_list(request, imapc)
|
||||
response["quota"] = ImapListing.computequota(imapc)
|
||||
return _render(request, "webmail/index.html", response)
|
||||
return _render(request, "webmail/index2.html", response)
|
||||
|
||||
if action in ["reply", "forward"]:
|
||||
action = "compose"
|
||||
|
||||
+22
-15
@@ -26,7 +26,7 @@ class Page(object):
|
||||
def __init__(self, pageid, id_start, id_stop, items,
|
||||
items_per_page, has_previous, has_next,
|
||||
baseurl=None):
|
||||
self.pageid = pageid
|
||||
self.number = pageid
|
||||
self.id_start = id_start
|
||||
self.id_stop = id_stop
|
||||
self.items = items
|
||||
@@ -35,15 +35,15 @@ class Page(object):
|
||||
self.has_next = has_next
|
||||
self.baseurl = baseurl
|
||||
|
||||
def previous_page(self):
|
||||
def previous_page_number(self):
|
||||
if not self.has_previous:
|
||||
return False
|
||||
return self.pageid - 1
|
||||
return self.number - 1
|
||||
|
||||
def next_page(self):
|
||||
def next_page_number(self):
|
||||
if not self.has_next:
|
||||
return False
|
||||
return self.pageid + 1
|
||||
return self.number + 1
|
||||
|
||||
def last_page(self):
|
||||
lid = self.items / self.items_per_page
|
||||
@@ -57,7 +57,9 @@ class Paginator(object):
|
||||
def __init__(self, total, elems_per_page):
|
||||
self.total = total
|
||||
self.elems_per_page = elems_per_page
|
||||
self.baseurl = None
|
||||
self.num_pages = total / elems_per_page
|
||||
if total % elems_per_page:
|
||||
self.num_pages += 1
|
||||
|
||||
def _indexes(self, page):
|
||||
id_start = self.elems_per_page * page + 1
|
||||
@@ -80,11 +82,12 @@ class Paginator(object):
|
||||
return None
|
||||
p = Page(page, id_start, id_stop, self.total,
|
||||
self.elems_per_page, has_previous, has_next)
|
||||
if self.baseurl:
|
||||
p.baseurl = self.baseurl
|
||||
p.paginator = self
|
||||
return p
|
||||
|
||||
class EmailListing(object):
|
||||
table_styles = "table-striped table-condensed"
|
||||
|
||||
def __init__(self, baseurl=None, folder=None, elems_per_page=40,
|
||||
navparams={}, **kwargs):
|
||||
self.folder = folder
|
||||
@@ -102,15 +105,14 @@ class EmailListing(object):
|
||||
self.paginator = Paginator(self.mbc.messages_count(folder=self.folder,
|
||||
order=order),
|
||||
elems_per_page)
|
||||
if baseurl:
|
||||
self.paginator.baseurl = baseurl
|
||||
self.baseurl = baseurl
|
||||
|
||||
@staticmethod
|
||||
def render_navbar(page):
|
||||
def render_navbar(page, baseurl=None):
|
||||
if page is None:
|
||||
return ""
|
||||
context = {"page" : page, "MEDIA_URL" : settings.MEDIA_URL}
|
||||
return render_to_string("common/navbar.html", context)
|
||||
context = {"page" : page, "MEDIA_URL" : settings.MEDIA_URL, "baseurl" : baseurl}
|
||||
return render_to_string("common/pagination_bar.html", context)
|
||||
|
||||
def fetch(self, request, id_start, id_stop):
|
||||
table = self.tbltype(request,
|
||||
@@ -121,7 +123,12 @@ class EmailListing(object):
|
||||
<form method="POST" id="listingform">
|
||||
{{ table }}
|
||||
</form>""")
|
||||
return tpl.render(Context({"table" : table.render()}))
|
||||
return tpl.render(
|
||||
Context(
|
||||
{"table" : table.render(styles=self.table_styles,
|
||||
withheader=False)}
|
||||
)
|
||||
)
|
||||
|
||||
# def render(self, request, pageid=1, **kwargs):
|
||||
# listing = ""
|
||||
@@ -153,7 +160,7 @@ class EmailListing(object):
|
||||
listing = _("This folder contains no message")
|
||||
else:
|
||||
listing = self.fetch(request, page.id_start, page.id_stop)
|
||||
return dict(listing=listing, navbar=self.render_navbar(page))
|
||||
return dict(listing=listing, navbar=self.render_navbar(page, self.baseurl))
|
||||
|
||||
def parse_search_parameters(request):
|
||||
if request.GET.has_key("pattern"):
|
||||
|
||||
+5
-4
@@ -188,16 +188,17 @@ class Table(object):
|
||||
def __str__(self):
|
||||
return self.render()
|
||||
|
||||
def render(self):
|
||||
def render(self, styles="table-striped table-bordered", withheader=True):
|
||||
if len(self.rows):
|
||||
t = Template("""
|
||||
<table id="{{ tableid }}" class="table table-striped table-bordered">
|
||||
{% include "common/table_head.html" %}
|
||||
<table id="{{ tableid }}" class="table {{ styles }}">
|
||||
{% if withheader %}{% include "common/table_head.html" %}{% endif %}
|
||||
{% include "common/table_body.html" %}
|
||||
</table>
|
||||
""")
|
||||
return t.render(RequestContext(self.request, {
|
||||
"table" : self, "tableid" : self.tableid
|
||||
"table" : self, "tableid" : self.tableid, "styles" : styles,
|
||||
"withheader" : withheader
|
||||
}))
|
||||
t = Template("""
|
||||
<div class="info">%s</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
from django.conf import settings
|
||||
from django import template
|
||||
from django.contrib import messages
|
||||
from django.template import Template, Context
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
@@ -116,3 +117,15 @@ def alert(msg, typ):
|
||||
<a class="close" data-dismiss="alert">×</a>
|
||||
%s
|
||||
</div>""" % (typ, msg)
|
||||
|
||||
@register.simple_tag
|
||||
def render_link(linkdef, mdclass=None):
|
||||
t = Template("""<a href="{{ link.url }}" name="{{ link.name }}"
|
||||
{% 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 %}"
|
||||
{% if link.confirm %} onclick="return confirm('{{ link.confirm }}')"{% endif %}>
|
||||
{% if link.img %}<i class="{{ link.img }}"></i>{% endif %}
|
||||
{{ link.label }}
|
||||
</a>""")
|
||||
return t.render(Context(dict(link=linkdef, mdclass=mdclass)))
|
||||
|
||||
@@ -2,6 +2,14 @@ body {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
#fixed_content {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#bottom-bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
@@ -46,6 +54,19 @@ body {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dropdown-menu .radio {
|
||||
padding: 3px 33px;
|
||||
}
|
||||
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu label:hover {
|
||||
background-color: #0088CC;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.spaced select,
|
||||
.spaced input[type="text"] {
|
||||
margin-bottom: 8px;
|
||||
@@ -62,3 +83,7 @@ body {
|
||||
.buttons_list .active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tr-selected {
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
@@ -233,21 +233,6 @@ function searchbox_init() {
|
||||
}
|
||||
};
|
||||
|
||||
// The following code prevents a bug under IE7 because fullpath is
|
||||
// returned instead of a relative one. (even if mootools uses
|
||||
// getAttribute("href", 2), this is not working for AJAX requests)
|
||||
gethref = function(obj) {
|
||||
var url = obj.get("href");
|
||||
var re = new RegExp("^(https?):");
|
||||
var scheme = re.exec(url);
|
||||
|
||||
if (scheme != null) {
|
||||
var baseurl = scheme[0] + "://" + location.host + location.pathname;
|
||||
return url.replace(baseurl, "");
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
/*function saveparams(id, message) {
|
||||
$("#update").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -12,20 +12,20 @@ function navbarcallback(event) {
|
||||
}
|
||||
|
||||
function updatelisting(resp) {
|
||||
if ($defined(resp.url)) {
|
||||
current_anchor.baseurl(resp.url).update();
|
||||
if (resp.url != undefined) {
|
||||
history.baseurl(resp.url).update();
|
||||
return;
|
||||
}
|
||||
if ($defined(resp.menu)) {
|
||||
/*if (resp.menu != undefined) {
|
||||
$("menubar").set("html", resp.menu);
|
||||
parse_menubar("menubar");
|
||||
}*/
|
||||
if (resp.listing != undefined) {
|
||||
$("#listing").html(resp.listing);
|
||||
}
|
||||
if ($defined(resp.listing)) {
|
||||
$("listing").set("html", resp.listing);
|
||||
}
|
||||
if ($defined(resp.navbar)) {
|
||||
/*if ($defined(resp.navbar)) {
|
||||
$("navbar").set("html", resp.navbar);
|
||||
$$("#navbar a").addEvent("click", navbarcallback);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
+35
-15
@@ -1,16 +1,5 @@
|
||||
var History = function(options) {
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.callbacks = {};
|
||||
this.params = {};
|
||||
this.base = '';
|
||||
this.serialized = null;
|
||||
this.updatenext = true;
|
||||
this.reset_loading_infos();
|
||||
if (this.options.defcallback) {
|
||||
this.register_callback("default", this.options.defcallback);
|
||||
this.check_id =
|
||||
setInterval($.proxy(this.check, this), this.options.checkinterval);
|
||||
}
|
||||
this.initialize(options);
|
||||
};
|
||||
|
||||
History.prototype = {
|
||||
@@ -24,6 +13,34 @@ History.prototype = {
|
||||
defcallback: null
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.callbacks = {};
|
||||
this.base = '';
|
||||
this.serialized = null;
|
||||
this.updatenext = true;
|
||||
this.load_params();
|
||||
this.reset_loading_infos();
|
||||
if (this.options.defcallback) {
|
||||
this.register_callback("default", this.options.defcallback);
|
||||
this.check_id =
|
||||
setInterval($.proxy(this.check, this), this.options.checkinterval);
|
||||
}
|
||||
},
|
||||
|
||||
load_params: function() {
|
||||
var rawqs = window.location.hash.substr(1);
|
||||
|
||||
if (rawqs.indexOf('?')) {
|
||||
this.params = {};
|
||||
return;
|
||||
}
|
||||
var tmp = rawqs.split('?');
|
||||
|
||||
rawqs = (tmp.length == 1) ? tmp[0] : tmp[1];
|
||||
this.params = parse_qs(rawqs.split('&'));
|
||||
},
|
||||
|
||||
paramslength: function() {
|
||||
return Object.keys(this.params).length;
|
||||
},
|
||||
@@ -34,7 +51,7 @@ History.prototype = {
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.base = null;
|
||||
this.base = "";
|
||||
this.params = {};
|
||||
return this;
|
||||
},
|
||||
@@ -100,7 +117,9 @@ History.prototype = {
|
||||
},
|
||||
|
||||
deleteParam: function(str) {
|
||||
this.params.erase(str);
|
||||
if (this.params[str] != undefined) {
|
||||
delete this.params[str];
|
||||
}
|
||||
},
|
||||
|
||||
updateparams: function(str) {
|
||||
@@ -111,6 +130,7 @@ History.prototype = {
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
this.setparamfromstring(elems[i]);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
setparamfromstring: function(str) {
|
||||
@@ -124,7 +144,7 @@ History.prototype = {
|
||||
},
|
||||
|
||||
setparams: function(params) {
|
||||
this.params.extend(params);
|
||||
this.params = $.extend({}, this.params, params);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
(function($) {
|
||||
var HtmlTable = function(element, options) {
|
||||
this.initialize(element, options);
|
||||
};
|
||||
|
||||
HtmlTable.prototype = {
|
||||
constructor: HtmlTable,
|
||||
|
||||
initialize: function(element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.htmltable.defaults, options);
|
||||
this.shift_pressed = false;
|
||||
this.last_selection = null;
|
||||
this.prev_dir = null;
|
||||
this.listen();
|
||||
|
||||
this.$element.css({
|
||||
"-moz-user-select": "-moz-none",
|
||||
"-khtml-user-select": "none",
|
||||
"-webkit-user-select": "none",
|
||||
"-ms-user-select": "none",
|
||||
"user-select": "none"
|
||||
});
|
||||
this.$element.attr("unselectable", "on");
|
||||
},
|
||||
|
||||
listen: function() {
|
||||
$(document).on("click", "tbody>tr",
|
||||
$.proxy(this.toggle_select, this));
|
||||
$(document).on("keydown", "body", $.proxy(this.keydown, this));
|
||||
$(document).on("keyup", "body", $.proxy(this.keyup, this));
|
||||
},
|
||||
|
||||
_toggle_select: function($tr) {
|
||||
this.last_selection = $tr;
|
||||
if ($tr.hasClass(this.options.tr_selected_class)) {
|
||||
$tr.removeClass(this.options.tr_selected_class);
|
||||
} else {
|
||||
$tr.addClass(this.options.tr_selected_class);
|
||||
}
|
||||
},
|
||||
|
||||
toggle_select: function(e) {
|
||||
e.preventDefault();
|
||||
var $tr = $(e.target).parent();
|
||||
|
||||
if (this.shift_pressed && this.last_selection) {
|
||||
var itfunc = ($tr.index() >= this.last_selection.index())
|
||||
? "next" : "prev";
|
||||
var $curtr = null;
|
||||
|
||||
if (this.prev_dir && itfunc != this.prev_dir) {
|
||||
$curtr = this.last_selection;
|
||||
} else {
|
||||
$curtr = this.last_selection[itfunc]("tr");
|
||||
}
|
||||
for (; $curtr.length; $curtr = $curtr[itfunc]("tr")) {
|
||||
this._toggle_select($curtr);
|
||||
if ($tr.attr("id") == $curtr.attr("id")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.prev_dir = itfunc;
|
||||
return;
|
||||
}
|
||||
this._toggle_select($tr);
|
||||
},
|
||||
|
||||
current_selection: function() {
|
||||
return $("tr[class*=" + this.options.tr_selected_class + "]");
|
||||
},
|
||||
|
||||
/*
|
||||
* Cancel the current selection
|
||||
*/
|
||||
clear_selection: function() {
|
||||
this.current_selection().removeClass(this.options.tr_selected_class);
|
||||
},
|
||||
|
||||
/*
|
||||
* Manually select a table row
|
||||
*/
|
||||
select_row: function($row) {
|
||||
$row.addClass(this.options.tr_selected_class);
|
||||
},
|
||||
|
||||
keydown: function(e) {
|
||||
switch (e.which) {
|
||||
case 16:
|
||||
e.preventDefault();
|
||||
this.shift_pressed = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
keyup: function(e) {
|
||||
switch (e.which) {
|
||||
case 16:
|
||||
e.preventDefault();
|
||||
this.shift_pressed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.htmltable = function(method) {
|
||||
var args = arguments;
|
||||
|
||||
return this.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('htmltable'),
|
||||
options = typeof method === "object" && method;
|
||||
|
||||
if (!data) {
|
||||
$this.data('htmltable', new HtmlTable(this, options));
|
||||
data = $this.data('htmltable');
|
||||
}
|
||||
if (typeof method === "string") {
|
||||
data[method].apply(data, Array.prototype.slice.call(args, 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.htmltable.defaults = {
|
||||
tr_selected_class: 'tr-selected'
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,68 @@
|
||||
(function($) {
|
||||
var SearchBar = function(element, options) {
|
||||
this.initialize(element, options);
|
||||
};
|
||||
|
||||
SearchBar.prototype = {
|
||||
constructor: SearchBar,
|
||||
|
||||
initialize: function(element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.searchbar.defaults, options);
|
||||
|
||||
this.$element.change($.proxy(this.pattern_change, this));
|
||||
this.$element.click(function(e) {
|
||||
$(this).select();
|
||||
});
|
||||
this.$element.blur(function(e) {
|
||||
var $this = $(this);
|
||||
if ($this.attr("value") == "") {
|
||||
$this.attr("value", gettext("Search..."));
|
||||
}
|
||||
});
|
||||
if (this.options.navobj.params.pattern != undefined) {
|
||||
this.$element.attr("value", this.options.navobj.params.pattern);
|
||||
}
|
||||
if (this.options.navobj.params.criteria != undefined) {
|
||||
$("#crit_" + this.options.navobj.params.criteria).attr("checked", "checked");
|
||||
}
|
||||
},
|
||||
|
||||
pattern_change: function(e) {
|
||||
var $input = $(e.target);
|
||||
var criteria = $("input[name=scriteria]:checked").attr("value");
|
||||
var pattern = $input.attr("value");
|
||||
|
||||
if (pattern != "") {
|
||||
this.options.navobj.setparams({
|
||||
pattern: pattern,
|
||||
criteria: criteria
|
||||
});
|
||||
} else {
|
||||
this.options.navobj.deleteParam("pattern");
|
||||
this.options.navobj.deleteParam("criteria");
|
||||
this.options.navobj.deleteParam("page");
|
||||
}
|
||||
this.options.navobj.update();
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.searchbar = function(method) {
|
||||
return this.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('searchbar'),
|
||||
options = typeof method === "object" && method;
|
||||
|
||||
if (!data) {
|
||||
$this.data('searchbar', new SearchBar(this, options));
|
||||
}
|
||||
if (typeof method === "string") {
|
||||
data[method]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.searchbar.defaults = {
|
||||
navobj: null
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -123,6 +123,42 @@ function simple_ajax_form_post(e, options) {
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* The following code prevents a bug under IE7 because fullpath is
|
||||
* returned instead of a relative one. (even if mootools uses
|
||||
* getAttribute("href", 2), this is not working for AJAX requests)
|
||||
*/
|
||||
function gethref(obj) {
|
||||
var url = $(obj).attr("href");
|
||||
var re = new RegExp("^(https?):");
|
||||
var scheme = re.exec(url);
|
||||
|
||||
if (scheme != null) {
|
||||
var baseurl = scheme[0] + "://" + location.host + location.pathname;
|
||||
return url.replace(baseurl, "");
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
/*
|
||||
* Extract the current URL parameters into a dictionnary.
|
||||
*
|
||||
* Ref:
|
||||
* http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
|
||||
*/
|
||||
function parse_qs(raw) {
|
||||
if (raw == "") return {};
|
||||
var res = {};
|
||||
|
||||
for (var i = 0; i < raw.length; i++) {
|
||||
var p = raw[i].split('=');
|
||||
|
||||
if (p.length != 2) continue;
|
||||
res[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple wrapper around Request.JSON. We just ensure that
|
||||
* redirections are correctly catched. (on session timeout for
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{% load libextras %}
|
||||
<div class="btn-toolbar">{% for entry in entries %}
|
||||
<div class="btn-group">{% if entry.menu %}
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown">{{ entry.label }}<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">{% for sentry in entry.menu %}
|
||||
<li>{% render_link sentry %}</li>
|
||||
{% endfor %}</ul>
|
||||
{% else %}{% render_link entry "btn" %}{% endif %}
|
||||
</div>
|
||||
{% endfor %}{{ extracontent }}</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{% load i18n %}
|
||||
<div id="searchbox">
|
||||
<img src="{{ MEDIA_URL }}pics/search.png" id="searchopts" />
|
||||
<input type="text" name="searchfield" id="searchfield" value="{% trans "Search..." %}" />
|
||||
<div id="searchparams">
|
||||
<input type="radio" id="crit_from_addr" name="scriteria" value="from_addr" checked>{% trans "From address" %}<br/>
|
||||
<input type="radio" id="crit_subject" name="scriteria" value="subject">{% trans "Subject" %}<br/>
|
||||
<div id="searchbox" class="btn-group">
|
||||
<a href="#" class="btn dropdown-toggle" data-toggle="dropdown"><i class="icon-search" id="searchopts"></i></a>
|
||||
<ul class="dropdown-menu" id="searchparams">
|
||||
<li><label class="radio"><input type="radio" id="crit_from_addr" name="scriteria" value="from_addr" checked>{% trans "From address" %}</label></li>
|
||||
<li><label class="radio"><input type="radio" id="crit_subject" name="scriteria" value="subject">{% trans "Subject" %}</label></li>
|
||||
{% for opt in extraopts %}
|
||||
<input type="radio" id="crit_{{ opt.name }}" name="scriteria" value="{{ opt.name }}">{{ opt.label }}</br>
|
||||
<li><label class="radio"><input type="radio" id="crit_{{ opt.name }}" name="scriteria" value="{{ opt.name }}">{{ opt.label }}</label></li>
|
||||
{% endfor %}
|
||||
<input type="radio" id="crit_both" name="scriteria" value="both">{% trans "Both" %}<br/>
|
||||
</div>
|
||||
<li><label class="radio"><input type="radio" id="crit_both" name="scriteria" value="both">{% trans "Both" %}</label></li>
|
||||
</ul>
|
||||
<input type="text" class="pull-right no-margin" name="searchfield" id="searchfield" value="{% trans "Search..." %}" />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{% load i18n %}
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal">x</a>
|
||||
<h3>{{ title }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% block modalbody %}{% endblock %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{% if action_label %}<a href="#" class="btn btn-primary {{ action_classes }}">{{ action_label }}</a>{% endif %}
|
||||
<a class="btn" data-dismiss="modal">{% trans "Close" %}</a>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
<table id="emailheaders">
|
||||
<table id="emailheaders" class="table table-striped table-bordered table-condensed">
|
||||
{% for hdr in headers %}
|
||||
<tr><th width="130px">{% trans hdr.name %}</th><td>{{ hdr.value }}</td></tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% load i18n libextras %}
|
||||
{% for entry in entries %}
|
||||
{% if entry.separator %}
|
||||
<li class="divider"> </li>
|
||||
@@ -12,33 +12,13 @@
|
||||
<ul class="dropdown-menu"
|
||||
{% if entry.width %}style="width: {{ entry.width }}px"{% endif %}>
|
||||
{% for sentry in entry.menu %}
|
||||
<li>
|
||||
<a href="{{ sentry.url }}" name="{{ sentry.name }}"
|
||||
{% if sentry.modal %}data-toggle="ajaxmodal{% if sentry.autowidth %}-autowidth{% endif %}"{% endif %}
|
||||
{% if sentry.modalcb %}modalcb="{{ entry.modalcb }}"{% endif %}
|
||||
{% if sentry.class %}class={{ sentry.class }}{% endif %}
|
||||
{% if sentry.rel %}rel={{ sentry.rel }}{% endif %}
|
||||
{% if sentry.confirm %} onclick="return confirm('{{ sentry.confirm }}')"{% endif %}>
|
||||
{% if sentry.img %}<i class="{{ sentry.img }}"></i>{% endif %}
|
||||
{{ sentry.label }}
|
||||
</a>
|
||||
</li>
|
||||
<li>{% render_link sentry %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li {% if selection == entry.name %}class="active"{% endif %}>
|
||||
{% if not entry.disabled %}
|
||||
<a href="{{ entry.url }}" name="{{ entry.name }}"
|
||||
{% if entry.modal %}data-toggle="ajaxmodal{% if entry.autowidth %}-autowidth{% endif %}"{% endif %}
|
||||
{% if entry.modalcb %}modalcb="{{ entry.modalcb }}"{% endif %}
|
||||
{% if entry.class %}class={{ entry.class }}{% endif %}
|
||||
{% if entry.rel %}rel={{ entry.rel }}{% endif %}
|
||||
{% if entry.confirm %} onclick="return confirm('{{ entry.confirm }}')"{% endif %}>
|
||||
{% endif %}
|
||||
{% if entry.img %}<i class="{{ entry.img }}"></i>{% endif %}
|
||||
{{ entry.label }}
|
||||
{% if not entry.disabled %}</a>{% endif %}
|
||||
{% render_link entry %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<div id="pagination_bar" class="simplepagination pull-right padded5">
|
||||
<ul>
|
||||
<li class="{% if not page.has_previous %}disabled{% endif %}">
|
||||
<a href="?page=1"><i class="icon-white icon-fast-backward"></i></a>
|
||||
<a href="{{ baseurl }}?page=1"><i class="icon-white icon-fast-backward"></i></a>
|
||||
</li>
|
||||
<li class="{% if not page.has_previous %}disabled{% endif %}">
|
||||
<a href="?page={{ page.previous_page_number }}">
|
||||
<a href="{{ baseurl }}?page={{ page.previous_page_number }}">
|
||||
<i class="icon-step-backward icon-white"></i></a>
|
||||
</li>
|
||||
<li class="disabled">
|
||||
{{ page.number }}/{{ page.paginator.num_pages }}
|
||||
</li>
|
||||
<li class="{% if not page.has_next %}disabled{% endif %}">
|
||||
<a href="?page={{ page.next_page_number }}">
|
||||
<a href="{{ baseurl }}?page={{ page.next_page_number }}">
|
||||
<i class="icon-step-forward icon-white"></i></a>
|
||||
</li>
|
||||
<li class="{% if not page.has_next %}disabled{% endif %}">
|
||||
<a href="?page={{ page.next_page_number }}">
|
||||
<a href="{{ baseurl }}?page={{ page.paginator.num_pages }}">
|
||||
<i class="icon-fast-forward icon-white"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<tbody>
|
||||
{% for row in table.rows %}
|
||||
<tr id="{{ row.id }}" class="{% cycle 'odd' 'even' %} {{ row.style }}" name="{{ row.trcpt }}"
|
||||
rel="{{ row.options }}">
|
||||
<tr id="{{ row.id }}" class="{{ row.style }}" name="{{ row.trcpt }}">
|
||||
{% for cell in row.cols %}
|
||||
<td name="{{ cell.name }}" width="{{ cell.width }}" align="{{ cell.align }}" class="{{ cell.cssclass }}">
|
||||
{% if cell.safe %}{{ cell.value|safe }}{% else %}{{ cell.value }}{% endif %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head profile="http://www.w3.org/2005/10/profile">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/box.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
@@ -22,24 +22,7 @@
|
||||
border: 0px transparent none;
|
||||
margin: 0;
|
||||
}
|
||||
table#emailheaders {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#emailheaders td,
|
||||
#emailheaders th {
|
||||
height: 22px;
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
#emailheaders td {
|
||||
font-size: 1em;
|
||||
}
|
||||
#emailheaders th {
|
||||
background: #F7F9Fb;
|
||||
}
|
||||
|
||||
#emailheaders a, #emailheaders a:visited {
|
||||
color: blue;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{% extends "nlayout.html" %}
|
||||
{% block content %}
|
||||
<div id="fixed_content">{% block fixed_content %}{% endblock %}</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% extends "nlayout.html" %}
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
{% block rowcontent %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
+45
-56
@@ -1,66 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
{% load i18n admin_extras uprefs_extras libextras %}
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head profile="http://www.w3.org/2005/10/profile">
|
||||
<meta charset="utf-8" />
|
||||
<title>Modoboa - {% block pagetitle %}{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/datepicker.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/custom.css" />
|
||||
<script src="{{ MEDIA_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap-datepicker.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/utils.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/common.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/confirmation.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/notify.js" type="text/javascript"></script>
|
||||
{% url django.views.i18n.javascript_catalog as catalog_url %}
|
||||
<script type="text/javascript" src="{{ catalog_url }}"></script>
|
||||
<script type="text/javascript">
|
||||
set_media_url("{{ MEDIA_URL }}");
|
||||
</script>
|
||||
{% block html_head %}{% endblock %}
|
||||
</head>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Modoboa - {% block pagetitle %}{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/datepicker.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/custom.css" />
|
||||
<script src="{{ MEDIA_URL }}js/jquery.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/bootstrap-datepicker.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/utils.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/common.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/confirmation.js" type="text/javascript"></script>
|
||||
<script src="{{ MEDIA_URL }}js/notify.js" type="text/javascript"></script>
|
||||
{% url django.views.i18n.javascript_catalog as catalog_url %}
|
||||
<script type="text/javascript" src="{{ catalog_url }}"></script>
|
||||
<script type="text/javascript">
|
||||
set_media_url("{{ MEDIA_URL }}");
|
||||
</script>
|
||||
{% block html_head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<div class="nav-collapse">
|
||||
<ul class="nav">
|
||||
{% loadextmenu user %}
|
||||
{% if selection %}{% admin_menu selection user %}{% else %}{% admin_menu "" user %}{% endif %}
|
||||
{% load_optionalmenu user %}
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
{% user_menu user %}
|
||||
</ul>
|
||||
<body>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<div class="nav-collapse">
|
||||
<ul class="nav">{% if selection %}
|
||||
{% loadextmenu selection user %}{% admin_menu selection user %}
|
||||
{% else %}{% loadextmenu "" user %}{% admin_menu "" user %}{% endif %}
|
||||
{% load_optionalmenu user %}
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
{% user_menu user %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
</div>
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="bottom-bar">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<div class="nav-collapse">
|
||||
{% block footer %}{% endblock %}
|
||||
<div id="bottom-bar">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<div id="bottom-bar-in" class="nav-collapse">
|
||||
{% block footer %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "nlayout.html" %}
|
||||
{% extends "fluid.html" %}
|
||||
{% load libextras %}
|
||||
{% block content %}
|
||||
{% block rowcontent %}
|
||||
<div class="span2">{% block leftcol %}{% endblock %}</div>
|
||||
<div class="span10">
|
||||
{% if messages %}{% display_messages messages %}{% endif %}
|
||||
|
||||
@@ -65,10 +65,10 @@ def user_menu(user):
|
||||
{"entries" : entries, "user" : user})
|
||||
|
||||
@register.simple_tag
|
||||
def loadextmenu(user):
|
||||
def loadextmenu(selection, user):
|
||||
menu = events.raiseQueryEvent("UserMenuDisplay", "top_menu", user)
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries" : menu, "user" : user})
|
||||
{"selection" : selection, "entries" : menu, "user" : user})
|
||||
|
||||
@register.simple_tag
|
||||
def extra_head_content():
|
||||
|
||||
Reference in New Issue
Block a user