diff --git a/modoboa/extensions/admin/static/admin/js/admin.js b/modoboa/extensions/admin/static/admin/js/admin.js index 9c596b78d..5200fc4c6 100644 --- a/modoboa/extensions/admin/static/admin/js/admin.js +++ b/modoboa/extensions/admin/static/admin/js/admin.js @@ -24,11 +24,25 @@ Admin.prototype = { }, list_cb: function(data) { - $("#listing").html(data.table); + $("#objects_table tbody").html(function(pos, oldhtml) { + return oldhtml + data.rows; + }); this.update_listing(data); $("a.filter").click($.proxy(this.filter_by_tag, this)); }, + /** + * A new page has been received, inject it. + * + * @param {Object} data - page content + * @param {string} direction - + */ + add_new_page: function(data, direction) { + $("#objects_table tbody").html(function(pos, oldhtml) { + return oldhtml + data.rows; + }); + }, + /** * Children must override this method. */ @@ -95,6 +109,14 @@ Domains.prototype = { this.register_tag_handler("dom", this.generic_tag_handler); }, + end_of_list_reached: function(element) { + $("#objects_table").after( + $("
{0}
".format( + gettext("No more domain to show") + )) + ); + }, + list_cb: function(data) { Admin.prototype.list_cb.call(this, data); var deloptions = (data.handle_mailboxes) @@ -237,6 +259,14 @@ Identities.prototype = { this.navobj.baseurl($link.attr("href")).update(); }, + end_of_list_reached: function(element) { + $("#objects_table").after( + $("
{0}
".format( + gettext("No more identity to show") + )) + ); + }, + list_cb: function(data) { Admin.prototype.list_cb.call(this, data); var deloptions = {}; diff --git a/modoboa/extensions/admin/templates/admin/domains.html b/modoboa/extensions/admin/templates/admin/domains.html index d32690232..a22be905c 100644 --- a/modoboa/extensions/admin/templates/admin/domains.html +++ b/modoboa/extensions/admin/templates/admin/domains.html @@ -4,9 +4,18 @@ {{ block.super }} {% extra_static_content "domains" user %} {% endblock %} {% block actions %}{% domains_menu "domains" user %}{% endblock %} + +{% block table_header %} +{% trans "Name" %} +{% trans "Alias(es)" %} +{% trans "Tags" %} +{% trans "Actions" %} +{% endblock %} diff --git a/modoboa/extensions/admin/templates/admin/domains_table.html b/modoboa/extensions/admin/templates/admin/domains_table.html index c2e5ec105..572750c87 100644 --- a/modoboa/extensions/admin/templates/admin/domains_table.html +++ b/modoboa/extensions/admin/templates/admin/domains_table.html @@ -1,21 +1,9 @@ {% load i18n admin_tags lib_tags %} - - - - - - - - - - - {% for domain in domains %} - - - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Alias(es)" %}{% trans "Tags" %}{% trans "Actions" %}
{% domain_modify_link domain %}{% domain_aliases domain %} {% render_tags domain.tags %}{% domain_actions user domain %}
+{% for domain in domains %} + + {% domain_modify_link domain %} + {% domain_aliases domain %} + {% render_tags domain.tags %} + {% domain_actions user domain %} + +{% endfor %} diff --git a/modoboa/extensions/admin/templates/admin/identities.html b/modoboa/extensions/admin/templates/admin/identities.html index 8655ce8ef..ca1e434b1 100644 --- a/modoboa/extensions/admin/templates/admin/identities.html +++ b/modoboa/extensions/admin/templates/admin/identities.html @@ -6,10 +6,18 @@ {% extra_static_content "identities" user %} {% endblock %} {% block actions %}{% identities_menu user "identities" %}{% endblock %} + +{% block table_header %} +{% trans "Name" %} +{% trans "Fullname/Recipient" %} +{% trans "Tags" %} +{% trans "Actions" %} +{% endblock %} diff --git a/modoboa/extensions/admin/templates/admin/identities_table.html b/modoboa/extensions/admin/templates/admin/identities_table.html index 31d9693bb..a0e110c68 100644 --- a/modoboa/extensions/admin/templates/admin/identities_table.html +++ b/modoboa/extensions/admin/templates/admin/identities_table.html @@ -1,21 +1,9 @@ {% load i18n admin_tags lib_tags %} - - - - - - - - - - - {% for ident in identities %} - - - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Fullname/Recipient" %}{% trans "Tags" %}{% trans "Actions" %}
{% identity_modify_link ident %}{{ ident.name_or_rcpt }}{% render_tags ident.tags %}{% identity_actions user ident %}
+{% for ident in identities %} + + {% identity_modify_link ident %} + {{ ident.name_or_rcpt }} + {% render_tags ident.tags %} + {% identity_actions user ident %} + +{% endfor %} diff --git a/modoboa/extensions/admin/templates/admin/listing.html b/modoboa/extensions/admin/templates/admin/listing.html index 7fda5c330..eb48aef94 100644 --- a/modoboa/extensions/admin/templates/admin/listing.html +++ b/modoboa/extensions/admin/templates/admin/listing.html @@ -5,6 +5,7 @@ + @@ -21,10 +22,19 @@ var admin;
{% include "admin/searchform.html" %}
-
- -
+
+ + +
+ + + + {% block table_header %}{% endblock %} + + + + +
-
{% endblock %} {% block footerright %}{% endblock %} diff --git a/modoboa/extensions/admin/templatetags/admin_tags.py b/modoboa/extensions/admin/templatetags/admin_tags.py index 284705fd1..eaba5c93a 100644 --- a/modoboa/extensions/admin/templatetags/admin_tags.py +++ b/modoboa/extensions/admin/templatetags/admin_tags.py @@ -105,7 +105,7 @@ def identities_menu(user, selection=None): {"name": "import", "label": _("Import"), "img": "fa fa-folder-open", - "url": reverse("admin:domain_import"), + "url": reverse("admin:identity_import"), "modal": True, "modalcb": "admin.importform_cb"}, {"name": "export", diff --git a/modoboa/extensions/admin/views/domain.py b/modoboa/extensions/admin/views/domain.py index 289d705cf..bbcdfbff0 100644 --- a/modoboa/extensions/admin/views/domain.py +++ b/modoboa/extensions/admin/views/domain.py @@ -1,4 +1,7 @@ -import reversion +""" +Domain related views. +""" + from django.http import HttpResponseRedirect from django.utils.translation import ugettext as _, ungettext from django.core.urlresolvers import reverse @@ -8,6 +11,9 @@ from django.views.decorators.csrf import ensure_csrf_cookie from django.contrib.auth.decorators import ( login_required, permission_required, user_passes_test ) + +import reversion + from modoboa.lib import parameters, events from modoboa.lib.webutils import ( _render_to_string, render_to_json_response @@ -31,7 +37,8 @@ def index(request): @login_required @user_passes_test( - lambda u: u.has_perm("admin.view_domains") or u.has_perm("admin.view_mailboxes") + lambda u: u.has_perm("admin.view_domains") + or u.has_perm("admin.view_mailboxes") ) def _domains(request): sort_order, sort_dir = get_sort_order(request.GET, "name") @@ -41,9 +48,7 @@ def _domains(request): + events.raiseQueryEvent('ExtraDomainFilters') ) request.session['domains_filters'] = filters - domainlist = get_domains( - request.user, **filters - ) + domainlist = get_domains(request.user, **filters) if sort_order == 'name': domainlist = sorted( domainlist, @@ -52,18 +57,22 @@ def _domains(request): else: domainlist = sorted(domainlist, key=lambda d: d.tags[0], reverse=sort_dir == '-') - page = get_listing_page(domainlist, request.GET.get("page", 1)) - return render_to_json_response({ - "table": _render_to_string(request, 'admin/domains_table.html', { - 'domains': page.object_list, - 'tableid': 'domains' - }), - "page": page.number, - "paginbar": pagination_bar(page), - "handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES", - raise_error=False), + context = { + "handle_mailboxes": parameters.get_admin( + "HANDLE_MAILBOXES", raise_error=False), "auto_account_removal": parameters.get_admin("AUTO_ACCOUNT_REMOVAL") - }) + } + page = get_listing_page(domainlist, request.GET.get("page", 1)) + if page is None: + context["length"] = 0 + else: + context["rows"] = _render_to_string( + request, 'admin/domains_table.html', { + 'domains': page.object_list, + } + ) + context["page"] = page.number + return render_to_json_response(context) @login_required diff --git a/modoboa/extensions/admin/views/identity.py b/modoboa/extensions/admin/views/identity.py index ebd096178..ef4498aee 100644 --- a/modoboa/extensions/admin/views/identity.py +++ b/modoboa/extensions/admin/views/identity.py @@ -1,4 +1,6 @@ -import reversion +""" +Identity related views. +""" from django.shortcuts import render from django.db import transaction from django.utils.translation import ugettext as _, ungettext @@ -6,6 +8,9 @@ from django.contrib.auth.decorators import ( login_required, permission_required, user_passes_test ) from django.views.decorators.csrf import ensure_csrf_cookie + +import reversion + from modoboa.lib import parameters, events from modoboa.lib.exceptions import ( PermDeniedException, BadRequest @@ -42,17 +47,21 @@ def _identities(request): else: objects = sorted(idents_list, key=lambda o: o.tags[0], reverse=sort_dir == '-') + context = { + "handle_mailboxes": parameters.get_admin( + "HANDLE_MAILBOXES", raise_error=False) + } page = get_listing_page(objects, request.GET.get("page", 1)) - return render_to_json_response({ - "table": _render_to_string(request, "admin/identities_table.html", { - "identities": page.object_list, - "tableid": "objects_table" - }), - "handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES", - raise_error=False), - "page": page.number, - "paginbar": pagination_bar(page) - }) + if page is None: + context["length"] = 0 + else: + context["rows"] = _render_to_string( + request, "admin/identities_table.html", { + "identities": page.object_list + } + ) + context["page"] = page.number + return render_to_json_response(context) @login_required diff --git a/modoboa/lib/listing.py b/modoboa/lib/listing.py index f8abb12dc..61a4f18f6 100644 --- a/modoboa/lib/listing.py +++ b/modoboa/lib/listing.py @@ -38,5 +38,5 @@ def get_listing_page(objects, pagenum): try: page = paginator.page(int(pagenum)) except (EmptyPage, PageNotAnInteger, ValueError): - page = paginator.page(paginator.num_pages) + page = None return page diff --git a/modoboa/static/js/jquery.infinitescroll.js b/modoboa/static/js/jquery.infinitescroll.js index 80f0fc43a..c531bf97e 100644 --- a/modoboa/static/js/jquery.infinitescroll.js +++ b/modoboa/static/js/jquery.infinitescroll.js @@ -99,7 +99,7 @@ * @param {string} direction - direction of the scroll (up or down) */ load_page: function(direction) { - var args = this.$options.get_args(); + var args = (this.$options.get_args) ? this.$options.get_args() : {}; var $this = this; this.executing = true; diff --git a/modoboa/static/js/jquery.sortable.js b/modoboa/static/js/jquery.sortable.js index 3699b11d7..1690ea203 100644 --- a/modoboa/static/js/jquery.sortable.js +++ b/modoboa/static/js/jquery.sortable.js @@ -1,4 +1,11 @@ (function($) { + /** + * Return an instance of Sortable. + * + * @constructor + * @param {Object} element - + * @param {Object} options - instance options + */ var Sortable = function(element, options) { this.initialize(element, options); }; @@ -32,8 +39,15 @@ } }, + /** + * Mark a column as the one used to sort content. + * + * @this Sortable + * @param {string} dir - optional sort direction (up or down) + * @return {string} - new sort direction + */ select: function(dir) { - $("i.sort-selection").remove(); + $("span.sort-selection").remove(); if (dir !== undefined) { this.$element.removeClass("sort-header-" + ((dir == "asc") ? "desc" : "asc")); this.$element.addClass("sort-header-" + dir); diff --git a/modoboa/static/js/listing.js b/modoboa/static/js/listing.js index d1019d1f4..a8317eba9 100644 --- a/modoboa/static/js/listing.js +++ b/modoboa/static/js/listing.js @@ -1,3 +1,9 @@ +/** + * Return an instance of Listing. + * + * @constructor + * @param {Object} options - instance options + */ var Listing = function(options) { this.initialize(options); }; @@ -10,7 +16,8 @@ Listing.prototype = { pbar_container: '#bottom-bar-right', pbar_id: '#pagination_bar', sortable_selector: '.sortable', - with_searchform: true + with_searchform: true, + load_page_url: null }, initialize: function(options) { @@ -69,17 +76,24 @@ Listing.prototype = { this.navobj.updateparams($link.attr("href")).update(); }, + /** + * Update the listing with the received data. + * + * @this Listing + * @param {Object} data - new content + */ update_listing: function(data) { - if (data.paginbar) { - $(this.options.pbar_container).html(data.paginbar); - $(this.options.presp_container).html(data.paginbar); - $(this.options.pbar_id).find(".disabled a").click(function(e) { - e.preventDefault(); - }); - } - if (data.page && data.page != this.navobj.getparam("page")) { - this.navobj.setparam("page", data.page).update(false, true); - } + $(window).infinite_scroll({ + url: this.options.load_page_url, + calculate_bottom: function($element) { + var $last_row = $("#objects_table").find("tr").last(); + + return $last_row.offset().top - $element.height(); + }, + process_results: this.add_new_page, + end_of_list_reached: this.end_of_list_reached + }); + var $sortables = $(this.options.sortable_selector); if ($sortables.length) { $(this.options.sortable_selector).sortable({ @@ -89,6 +103,11 @@ Listing.prototype = { } }, + /** + * Set current sort order. + * + * @this Listing + */ set_sort_order: function() { var sort_order = this.navobj.getparam("sort_order"); var sort_dir; @@ -105,6 +124,11 @@ Listing.prototype = { $("th[data-sort_order=" + sort_order + "]").sortable('select', sort_dir); }, + /** + * Change current sort order. + * + * @this Listing + */ change_sort_order: function(sort_order, dir) { if (dir == "desc") { sort_order = "-" + sort_order;