From 6a5ffde764fad2ab7f98087d03c5633d2b67851c Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Mon, 24 Nov 2014 18:01:56 +0100 Subject: [PATCH] Top checkbox to select/unselect all extensions. fix #628 --- modoboa/core/static/core/js/settings.js | 25 ++ modoboa/core/tables.py | 15 -- modoboa/core/templates/core/extensions.html | 24 +- modoboa/core/views/admin.py | 20 +- modoboa/lib/tables.py | 256 -------------------- 5 files changed, 61 insertions(+), 279 deletions(-) delete mode 100644 modoboa/core/tables.py delete mode 100644 modoboa/lib/tables.py diff --git a/modoboa/core/static/core/js/settings.js b/modoboa/core/static/core/js/settings.js index 30b0faf4c..ae1b65c95 100644 --- a/modoboa/core/static/core/js/settings.js +++ b/modoboa/core/static/core/js/settings.js @@ -19,6 +19,9 @@ Settings.prototype = { TwocolsNav.prototype.initialize.call(this, this.options); this.navobj.register_callback( "logs", $.proxy(this.logs_callback, this)); + this.navobj.register_callback( + "extensions", $.proxy(this.extensions_callback, this)); + $(document).on("click", "#toggle_extensions_sel", this.toggle_extensions_sel); }, /** @@ -31,6 +34,28 @@ Settings.prototype = { $('#' + this.options.divid).html(data.content); } this.update_listing(data); + }, + + /** + * Navigation callback: extensions. + */ + extensions_callback: function(data) { + if (data.content) { + $('#' + this.options.divid).html(data.content); + } + this.update_listing(data); + if ($("tbody input[type=checkbox]:checked").length) { + $("#toggle_extensions_sel").prop("checked", true); + } + }, + + /** + * Select or unselect all extensions in on click. + */ + toggle_extensions_sel: function(evt) { + var status = $(this).prop("checked"); + + $("tbody input[type=checkbox]").prop("checked", status); } }; diff --git a/modoboa/core/tables.py b/modoboa/core/tables.py deleted file mode 100644 index 78a730983..000000000 --- a/modoboa/core/tables.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.utils.translation import ugettext_lazy -from modoboa.lib import tables - - -class ExtensionsTable(tables.Table): - idkey = "id" - styles = "table-hover" - selection = tables.SelectionColumn("selection", width="4%", header=False) - label = tables.Column("label", label=ugettext_lazy("Name"), width="15%") - version = tables.Column( - "version", label=ugettext_lazy("Version"), width="6%" - ) - descr = tables.Column("description", label=ugettext_lazy("Description")) - - cols_order = ["selection", "label", "version", "descr"] diff --git a/modoboa/core/templates/core/extensions.html b/modoboa/core/templates/core/extensions.html index acccfbd56..cc51b3ecb 100644 --- a/modoboa/core/templates/core/extensions.html +++ b/modoboa/core/templates/core/extensions.html @@ -1,6 +1,26 @@ {% load i18n %}{% load url from future %}

{% trans "Extensions" %} {% trans "Choose the extension(s) to use" %}


-
{% csrf_token %} - {{ extensions|safe }} + + {% csrf_token %} + + + + + + + + + + + {% for extension in extensions %} + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Version" %}{% trans "Description" %}
{{ extension.label }}{{ extension.version }}{{ extension.description }}
{% trans 'Save' %} diff --git a/modoboa/core/views/admin.py b/modoboa/core/views/admin.py index 911544e8b..6da5a04d2 100644 --- a/modoboa/core/views/admin.py +++ b/modoboa/core/views/admin.py @@ -1,17 +1,23 @@ +""" +Views available to super administrators only. +""" + from django.shortcuts import render from django.template.loader import render_to_string from django.utils.translation import ugettext as _ + from django.contrib.auth.decorators import ( login_required, user_passes_test ) + + +from modoboa.core.models import Extension, Log +from modoboa.core.utils import new_version_available from modoboa.lib import events, parameters +from modoboa.lib.listing import get_sort_order, get_listing_page from modoboa.lib.webutils import ( _render_to_string, render_to_json_response ) -from modoboa.lib.listing import get_sort_order, get_listing_page -from modoboa.core.models import Extension, Log -from modoboa.core.utils import new_version_available -from modoboa.core.tables import ExtensionsTable @login_required @@ -51,6 +57,7 @@ def saveparameters(request): @login_required @user_passes_test(lambda u: u.is_superuser) def viewextensions(request, tplname='core/extensions.html'): + """List available extensions.""" from modoboa.core.extensions import exts_pool exts = exts_pool.list_all() @@ -65,15 +72,16 @@ def viewextensions(request, tplname='core/extensions.html'): dbext.save() ext["selection"] = False - tbl = ExtensionsTable(request, exts) return render_to_json_response({ - "content": _render_to_string(request, tplname, {"extensions": tbl}) + "callback": "extensions", + "content": _render_to_string(request, tplname, {"extensions": exts}) }) @login_required @user_passes_test(lambda u: u.is_superuser) def saveextensions(request): + """Enable of disable extension(s).""" actived_exts = Extension.objects.filter(enabled=True) found = [] for k in request.POST.keys(): diff --git a/modoboa/lib/tables.py b/modoboa/lib/tables.py deleted file mode 100644 index 356ada43d..000000000 --- a/modoboa/lib/tables.py +++ /dev/null @@ -1,256 +0,0 @@ -# coding: utf-8 -""" -:mod:`tables` --- simple tabular renderer ------------------------------------------ - -This module offers a simple (I hope so) interface to render tabular -data. For a given Table class, it generates the corresponding HTML -output (using standard tags like and co.). - -""" -import inspect - -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _ -from django.template import Template, RequestContext, Context - -from .templatetags.lib_tags import render_link - - -class Column(object): - """Simple column representation - """ - def __init__(self, name, **kwargs): - self.name = name - self.sortable = True - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - def __unicode__(self): - try: - label = getattr(self, "label") - except AttributeError: - return u'' - return label - - def transform(self, row, col, table): - if "class" in row.keys(): - col["cssclass"] += col["cssclass"] != "" \ - and ", %s" % row["class"] or row["class"] - try: - col["value"] = table.parse(self.name, row[self.name]) - except AttributeError: - col["value"] = row[self.name] - try: - limit = getattr(self, "limit") - if limit: - # The value is not necessarily a string, so... - col["value"] = unicode(col["value"], "utf-8") if isinstance(col["value"], str) else unicode(col["value"]) - if len(col["value"]) > limit: - col["value"] = col["value"][0:limit] + "..." - except AttributeError: - pass - try: - col["safe"] = getattr(self, "safe") - except AttributeError: - pass - - -class SelectionColumn(Column): - """Specific column: selection - - A 'selection' column contains only checkboxes (one per row). It is - usefull to select rows for grouped actions (modify, delete, etc.) - """ - def __unicode__(self): - if self.header: - return "" - return "" - - def render(self, value, selection): - return "" \ - % {'id': self.name, 'value': value, - "checked": "checked=''" if selection else ""} - - def transform(self, row, col, table): - selection = row[self.name] if self.name in row else False - col["value"] = self.render(row[table.idkey], selection) - col["safe"] = True - - -class ImgColumn(Column): - """Specific column: image - - This kind of column only contains images tags (). - """ - def __str__(self): - self.sortable = False - try: - return getattr(self, "header") - except AttributeError: - return "" - - def render(self, value): - if getattr(self, "bootstrap", False) and value.startswith("icon"): - return "" % value - if type(value) in [list, tuple]: - return "".join(["" % i for i in value]) - return "" % value - - def transform(self, row, col, table): - key = "img_%s" % self.name - if key in row.keys(): - col["value"] = self.render(row[key]) - else: - try: - col["value"] = self.render(self.defvalue) - except Exception: - pass - col["safe"] = True - - -class DivColumn(Column): - def __str__(self): - return "" - - def render(self): - return "
 
" - - def transform(self, row, col, table): - col["value"] = self.render() - col["safe"] = True - - -class ActionColumn(Column): - def render(self, fct, user, rowid): - return fct(user, rowid) - - def transform(self, row, col, table): - col["value"] = self.render(self.defvalue, table.request.user, row[table.idkey]) - col["safe"] = True - - -class LinkColumn(Column): - def render(self, rowid, value): - linkdef = dict(label=value, modal=self.modal) - if type(self.urlpattern) is dict: - t, value = rowid.split(":") - linkdef.update(url=reverse(self.urlpattern[t], args=[value]), - modalcb=self.modalcb[t]) - else: - linkdef.update(url=reverse(self.urlpattern, args=[rowid]), - modalcb=self.modalcb) - return render_link(linkdef) - - def transform(self, row, col, table): - col["value"] = self.render(row[table.idkey], row[self.name]) - col["safe"] = True - - -class Table(object): - tableid = "" - - def __init__(self, request, rows=None): - self.columns = [] - self.request = request - if rows is None: - rows = {} - try: - order = getattr(self, "cols_order") - except AttributeError: - for m in inspect.getmembers(self): - if isinstance(m[1], Column): - try: - if getattr(m[1], "first"): - self.columns = [m[1]] + self.columns - except AttributeError: - self.columns += [m[1]] - else: - for colname in order: - try: - col = getattr(self, colname) - except AttributeError: - continue - if not isinstance(col, Column): - continue - self.columns += [col] - - if rows != {}: - self.populate(rows) - - def populate(self, rows): - self.rows = [] - trcpt = 0 - for row in rows: - nrow = {"id": row[self.idkey], "cols": [], "trcpt": trcpt} - for name in ["style", "options"]: - if name in row: - nrow[name] = row[name] - - for c in self.columns: - newcol = {"name": c.name} - for key in ["width", "align", "cssclass"]: - try: - newcol[key] = getattr(c, key) - except AttributeError: - newcol[key] = "" - c.transform(row, newcol, self) - nrow["cols"] += [newcol] - self.rows += [nrow] - trcpt += 1 - - def _rows_from_model(self, objects, include_type_in_id=False): - rows = [] - for obj in objects: - nrow = {} - try: - idkey = getattr(self, "idkey") - nrow[idkey] = getattr(obj, idkey) - if include_type_in_id: - nrow[idkey] = "%s:%s" % (obj.__class__.__name__, nrow[idkey]) - except AttributeError: - pass - for c in self.columns: - try: - nrow[c.name] = getattr(obj, c.name) - except AttributeError: - pass - for meth in ["options", "class"]: - try: - nrow[meth] = getattr(self, "row_%s" % meth)(self.request, obj) - except AttributeError: - pass - rows += [nrow] - return rows - - def parse(self, header, value): - try: - return getattr(self, "parse_%s" % header)(value) - except AttributeError: - return value - - def __unicode__(self): - return self.render() - - def render(self, withheader=True): - if len(self.rows): - try: - styles = self.styles - except AttributeError: - styles = "table-striped table-bordered" - - t = Template(""" -
- {% if withheader %}{% include "common/table_head.html" %}{% endif %} - {% include "common/table_body.html" %} -
-""") - return t.render(RequestContext(self.request, { - "table": self, "tableid": self.tableid, "styles": styles, - "withheader": withheader - })) - - t = Template(""" -
%s
-""" % _("No entries to display")) - return t.render(Context())