From 3fe149adb05239ae511675fa37b1fb9f4606ed50 Mon Sep 17 00:00:00 2001 From: tonio Date: Fri, 30 Oct 2009 11:28:40 +0100 Subject: [PATCH] Bugfix on permissions verification (on domain admin was able to access any domain :p) Added help tips when filling forms (domain, mailbox, etc.) French translation update. Tips class added to mootools-more.js is not the official version (1.2.4.2). There are some bugs with this version so I've decided to integrate modifications coming from here : https://mootools.lighthouseapp.com/projects/24057/tickets/167-tips-class-issues-in-more-1242 --- admin/forms.py | 18 +- admin/models.py | 25 ++- admin/views.py | 33 ++- extensions/amavis_quarantine/main.py | 3 +- .../amavis_quarantine/templates/index.html | 16 +- .../amavis_quarantine/templates/listing.html | 7 +- locale/fr/LC_MESSAGES/django.po | 163 ++++++++++---- locale/fr/LC_MESSAGES/djangojs.po | 10 +- static/js/domains.js | 1 - static/js/form.js | 8 + static/js/mootools-more.js | 207 +++++++++++++++++- static/stylesheets/basic.css | 5 + static/stylesheets/box.css | 26 ++- templates/admin/addpermission.html | 2 +- templates/admin/editalias.html | 2 +- templates/admin/editdomain.html | 2 +- templates/admin/editmailbox.html | 4 +- templates/admin/genericform.html | 2 + templates/admin/layout_simple.html | 18 -- templates/admin/newalias.html | 2 +- templates/admin/newmailbox.html | 2 +- templates/layout_simple.html | 3 + 22 files changed, 451 insertions(+), 108 deletions(-) delete mode 100644 templates/admin/layout_simple.html diff --git a/admin/forms.py b/admin/forms.py index 446bfab63..4028ddf2f 100644 --- a/admin/forms.py +++ b/admin/forms.py @@ -14,10 +14,13 @@ class DomainForm(forms.ModelForm): class MailboxForm(forms.ModelForm): quota = forms.IntegerField(label=_("Quota"), required=False) - password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput) - password2 = forms.CharField(label=_("Confirmation"), widget=forms.PasswordInput) + password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput, + help_text=_("Password used to log in")) + password2 = forms.CharField(label=_("Confirmation"), widget=forms.PasswordInput, + help_text=_("Password confirmation")) enabled = forms.BooleanField(label=gender("Enabled", "f"), required=False, - initial=True) + initial=True, + help_text=_("Check to activate this mailbox")) class Meta: model = Mailbox @@ -50,8 +53,11 @@ class AliasForm(forms.ModelForm): class PermissionForm(forms.Form): domain = forms.ModelChoiceField(queryset=Domain.objects.all(), label=_("Domain"), - required=True) - user = forms.ChoiceField(label=_("User"), required=True) + required=True, + help_text=_("Select a domain in the list")) + user = forms.ChoiceField(label=_("User"), required=True, + help_text=_("Select a user in the list")) role = forms.ChoiceField(label=_("Role"), required=True, choices=(("SuperAdmins", _("Super administrator")), - ("DomainAdmins", _("Domain administrator")))) + ("DomainAdmins", _("Domain administrator"))), + help_text=_("Select the role you want this user to have")) diff --git a/admin/models.py b/admin/models.py index c384c3c1c..6c4c6fe04 100644 --- a/admin/models.py +++ b/admin/models.py @@ -6,9 +6,11 @@ from mailng.lib import exec_pipe, exec_as_vuser import os class Domain(models.Model): - name = models.CharField(_('name'), max_length=100) - quota = models.IntegerField() - enabled = models.BooleanField(_('enabled')) + name = models.CharField(_('name'), max_length=100, + help_text=_("The domain name")) + quota = models.IntegerField(help_text=_("Default quota in MB applied to mailboxes")) + enabled = models.BooleanField(_('enabled'), + help_text=_("Check to activate this domain")) class Meta: permissions = ( @@ -33,11 +35,13 @@ class Domain(models.Model): return self.name class Mailbox(models.Model): - name = models.CharField(_('name'), max_length=100) - address = models.CharField(_('address'), max_length=100) + name = models.CharField(_('name'), max_length=100, + help_text=_("First name and last name of mailbox owner")) + address = models.CharField(_('address'), max_length=100, + help_text=_("Mailbox address (without the @domain.tld part)")) full_address = models.CharField(max_length=150) password = models.CharField(_('password'), max_length=100) - quota = models.IntegerField() + quota = models.IntegerField(help_text=_("Mailbox quota in MB (default to domain quota if blank)")) uid = models.IntegerField() gid = models.IntegerField() path = models.CharField(max_length=200) @@ -99,10 +103,13 @@ class Mailbox(models.Model): self.domain.name, self.address)) class Alias(models.Model): - address = models.CharField(_('address'), max_length=100) + address = models.CharField(_('address'), max_length=100, + help_text=_("The alias address (without the domain part)")) full_address = models.CharField(max_length=150) - mbox = models.ForeignKey(Mailbox, verbose_name=_('mailbox')) - enabled = models.BooleanField(_('enabled')) + mbox = models.ForeignKey(Mailbox, verbose_name=_('mailbox'), + help_text=_("The mailbox this alias points to")) + enabled = models.BooleanField(_('enabled'), + help_text=_("Check to activate this alias")) class Meta: permissions = ( diff --git a/admin/views.py b/admin/views.py index efcbd14e9..cbeae3cf2 100644 --- a/admin/views.py +++ b/admin/views.py @@ -4,6 +4,7 @@ from django.template import RequestContext from django.http import HttpResponse, HttpResponseRedirect from django.utils import simplejson from django.utils.translation import ugettext as _ +from django.utils.http import urlquote from django.core import serializers from django.core.urlresolvers import reverse from django.contrib.auth.decorators \ @@ -23,6 +24,21 @@ def is_superuser(user): return False return True +def good_domain(f): + def dec(request, dom_id, **kwargs): + if request.user.is_superuser: + return f(request, dom_id, **kwargs) + mb = Mailbox.objects.get(user=request.user.id) + domid = isinstance(dom_id, str) and "%d" % dom_id or dom_id + if domid == mb.domain.id: + return f(request, domid, **kwargs) + + from django.conf import settings + path = urlquote(request.get_full_path()) + login_url = settings.LOGIN_URL + return HttpResponseRedirect("%s?next=%s" % (login_url, path)) + return dec + @login_required def domains(request): if not request.user.has_perm("admin.view_domains"): @@ -41,10 +57,8 @@ def domains(request): }) @login_required -@permission_required("admin.add_mailbox") +@permission_required("admin.add_domain") def newdomain(request): - if not is_superuser(request.user): - return mailboxes(request, dom_id) if request.method == "POST": form = DomainForm(request.POST) error = None @@ -71,10 +85,8 @@ def newdomain(request): }) @login_required -@permission_required("admin.change_mailbox") +@permission_required("admin.change_domain") def editdomain(request, dom_id): - if not is_superuser(request.user): - return mailboxes(request, dom_id) domain = Domain.objects.get(pk=dom_id) if request.method == "POST": form = DomainForm(request.POST, instance=domain) @@ -110,6 +122,7 @@ def deldomain(request, dom_id): return HttpResponseRedirect('/mailng/admin/') @login_required +@good_domain @permission_required("admin.view_mailboxes") def mailboxes(request, dom_id=None): domain = Domain.objects.get(pk=dom_id) @@ -119,6 +132,7 @@ def mailboxes(request, dom_id=None): }) @login_required +@good_domain @permission_required("admin.view_mailboxes") def mailboxes_raw(request, dom_id=None): mailboxes = Mailbox.objects.filter(domain=dom_id) @@ -127,6 +141,7 @@ def mailboxes_raw(request, dom_id=None): }) @login_required +@good_domain @permission_required("admin.add_mailbox") def newmailbox(request, dom_id=None): domain = Domain.objects.get(pk=dom_id) @@ -183,6 +198,7 @@ def newmailbox(request, dom_id=None): }) @login_required +@good_domain @permission_required("admin.change_mailbox") def editmailbox(request, dom_id, mbox_id=None): mb = Mailbox.objects.get(pk=mbox_id) @@ -231,6 +247,7 @@ def editmailbox(request, dom_id, mbox_id=None): }) @login_required +@good_domain @permission_required("admin.delete_mailbox") def delmailbox(request, dom_id, mbox_id=None): mb = Mailbox.objects.get(pk=mbox_id) @@ -246,6 +263,7 @@ def delmailbox(request, dom_id, mbox_id=None): # args=[dom_id])) @login_required +@good_domain @permission_required("admin.view_aliases") def aliases(request, dom_id=None, mbox_id=None): domain = Domain.objects.get(pk=dom_id) @@ -261,6 +279,7 @@ def aliases(request, dom_id=None, mbox_id=None): }) @login_required +@good_domain @permission_required("admin.add_alias") def newalias(request, dom_id, mbox_id): mbox = Mailbox.objects.get(pk=mbox_id) @@ -289,6 +308,7 @@ def newalias(request, dom_id, mbox_id): }) @login_required +@good_domain @permission_required("admin.change_alias") def editalias(request, dom_id, alias_id): alias = Alias.objects.get(pk=alias_id) @@ -318,6 +338,7 @@ def editalias(request, dom_id, alias_id): }) @login_required +@good_domain @permission_required("admin.delete_alias") def delalias(request, dom_id, alias_id): alias = Alias.objects.get(pk=alias_id) diff --git a/extensions/amavis_quarantine/main.py b/extensions/amavis_quarantine/main.py index 3797f5529..d5d66a931 100644 --- a/extensions/amavis_quarantine/main.py +++ b/extensions/amavis_quarantine/main.py @@ -83,13 +83,12 @@ def render_listing(request, cursor): "subject" : row[2], "content" : row[3], "mailid" : row[4], "time" : datetime.fromtimestamp(row[5]), "type" : row[6]}) - paginator = Paginator(emails, 10) try: pagenum = int(request.GET.get('page', '1')) except ValueError: pagenum = 1 - page = paginator.page(pagenum) + page = paginator.page(pagenum) return render_to_string("amavis_quarantine/listing.html", { "count" : len(rows), "emails" : page, "current_page" : pagenum, diff --git a/extensions/amavis_quarantine/templates/index.html b/extensions/amavis_quarantine/templates/index.html index 0424e96fc..d50041d40 100644 --- a/extensions/amavis_quarantine/templates/index.html +++ b/extensions/amavis_quarantine/templates/index.html @@ -106,13 +106,15 @@ window.addEvent("domready", function() { mysubmit(event, "release"); }); - $("selectall").addEvent("click", function(event) { - if ($("selectall").checked) { - toggleSelection(true); - } else { - toggleSelection(false); - } - }); + if ($("selectall")) { + $("selectall").addEvent("click", function(event) { + if ($("selectall").checked) { + toggleSelection(true); + } else { + toggleSelection(false); + } + }); + } {% url extensions.amavis_quarantine.main.search as s_url %} $("searchfield").addEvent("change", function(event) { diff --git a/extensions/amavis_quarantine/templates/listing.html b/extensions/amavis_quarantine/templates/listing.html index 0b105b2ae..9ce78ec9c 100644 --- a/extensions/amavis_quarantine/templates/listing.html +++ b/extensions/amavis_quarantine/templates/listing.html @@ -1,5 +1,8 @@ {% load i18n %} +{% if not count %} +
{% trans "No messages in quarantine" %}
+{% else %}
Messages {{ emails.start_index }} à {{ emails.end_index }} sur {{ count }} @@ -43,4 +46,6 @@ {{ m.time }} {% endfor %} - \ No newline at end of file + + +{% endif %} diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 72ffca6d1..864e8c9ee 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-10-29 14:54+0100\n" +"POT-Creation-Date: 2009-10-30 11:19+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Antoine Nguyen \n" "Language-Team: LANGUAGE \n" @@ -25,93 +25,154 @@ msgstr "" msgid "Password" msgstr "Mot de passe" -#: admin/forms.py:18 main/forms.py:21 +#: admin/forms.py:18 +msgid "Password used to log in" +msgstr "Mot de passe utilisé pour se connecter" + +#: admin/forms.py:19 main/forms.py:21 msgid "Confirmation" msgstr "" -#: admin/forms.py:33 main/forms.py:36 +#: admin/forms.py:20 +msgid "Password confirmation" +msgstr "Confirmation du mot de passe" + +#: admin/forms.py:23 +msgid "Check to activate this mailbox" +msgstr "Cocher pour activer cette boite aux lettres" + +#: admin/forms.py:36 main/forms.py:36 msgid "Passwords mismatch" msgstr "Les mots de passe diffèrent" -#: admin/forms.py:52 templates/admin/domain_header.html:7 +#: admin/forms.py:55 templates/admin/domain_header.html:7 #: templates/admin/editdomain.html:7 templates/admin/permissions.html:42 msgid "Domain" msgstr "Domaine" -#: admin/forms.py:54 +#: admin/forms.py:57 +msgid "Select a domain in the list" +msgstr "Sélectionner un domaine dans la liste" + +#: admin/forms.py:58 msgid "User" msgstr "Utilisateur" -#: admin/forms.py:55 +#: admin/forms.py:59 +msgid "Select a user in the list" +msgstr "Sélectionner un utilisateur dans la liste" + +#: admin/forms.py:60 msgid "Role" msgstr "Rôle" -#: admin/forms.py:56 +#: admin/forms.py:61 msgid "Super administrator" msgstr "Super administrateur" -#: admin/forms.py:57 +#: admin/forms.py:62 msgid "Domain administrator" msgstr "Admin. de domaine" -#: admin/models.py:9 admin/models.py:36 +#: admin/forms.py:63 +msgid "Select the role you want this user to have" +msgstr "Sélectionner le rôle souhaité pour cet utilisateur" + +#: admin/models.py:9 admin/models.py:38 msgid "name" msgstr "Nom" -#: admin/models.py:11 admin/models.py:105 main/models.py:9 +#: admin/models.py:10 +msgid "The domain name" +msgstr "Le nom du domaine" + +#: admin/models.py:11 +msgid "Default quota in MB applied to mailboxes" +msgstr "Quota par défaut en Mo appliqué aux boites aux lettres" + +#: admin/models.py:12 admin/models.py:111 main/models.py:9 msgid "enabled" msgstr "Activé" -#: admin/models.py:37 admin/models.py:102 +#: admin/models.py:13 +msgid "Check to activate this domain" +msgstr "Cocher pour activer ce domaine" + +#: admin/models.py:39 +msgid "First name and last name of mailbox owner" +msgstr "Prénom et nom du propriétaire de la boite aux lettres" + +#: admin/models.py:40 admin/models.py:106 msgid "address" msgstr "Adresse" -#: admin/models.py:39 +#: admin/models.py:41 +msgid "Mailbox address (without the @domain.tld part)" +msgstr "Adresse de la boite aux lettres (sans la partie @domain.tld)" + +#: admin/models.py:43 msgid "password" msgstr "Mot de passe" -#: admin/models.py:104 +#: admin/models.py:44 +msgid "Mailbox quota in MB (default to domain quota if blank)" +msgstr "" +"Quota en Mo de la boite aux lettres (par défaut celui du domaine si vide)" + +#: admin/models.py:107 +msgid "The alias address (without the domain part)" +msgstr "L'adresse de l'alias (sans la partie domaine)" + +#: admin/models.py:109 msgid "mailbox" msgstr "Boite aux lettres" -#: admin/views.py:22 +#: admin/models.py:110 +msgid "The mailbox this alias points to" +msgstr "La boite aux lettres sur laquelle pointe cet alias" + +#: admin/models.py:112 +msgid "Check to activate this alias" +msgstr "Cocher pour activer cet alias" + +#: admin/views.py:23 msgid "Permission denied." msgstr "Permission refusée." -#: admin/views.py:53 admin/views.py:85 +#: admin/views.py:67 admin/views.py:97 msgid "Domain with this name already defined" msgstr "Un domaine avec ce nom existe déjà" -#: admin/views.py:62 +#: admin/views.py:76 msgid "Failed to initialise domain, check permissions" msgstr "Impossible d'initialiser le domaine, vérifier les permissions" -#: admin/views.py:88 +#: admin/views.py:100 msgid "Failed to rename domain, check permissions" msgstr "Impossible de renommer le domaine, vérifier les permissions" -#: admin/views.py:139 admin/views.py:197 +#: admin/views.py:154 admin/views.py:213 msgid "Mailbox with this address already exists" msgstr "Une boite aux lettres pour cette adresse existe déjà" -#: admin/views.py:170 +#: admin/views.py:185 msgid "Mailbox created." msgstr "Boite aux lettres créé." -#: admin/views.py:174 +#: admin/views.py:189 msgid "Failed to initialise mailbox, check permissions" msgstr "" "Impossible d'initialiser la boite aux lettres, vérifier les permissions" -#: admin/views.py:200 +#: admin/views.py:216 msgid "Failed to rename mailbox, check permissions" msgstr "Impossible de renommer la boite aux lettres, vérifier les permissions." -#: admin/views.py:273 admin/views.py:302 +#: admin/views.py:292 admin/views.py:322 msgid "Alias with this address already exists" msgstr "Un alias avec cette adresse existe déjà" -#: admin/views.py:374 +#: admin/views.py:395 msgid "admin is intouchable!!" msgstr "admin est intouchable!!" @@ -140,16 +201,16 @@ msgid "Properties" msgstr "Propriétés" #: extensions/amavis_quarantine/main.py:49 -#: extensions/amavis_quarantine/templates/index.html:151 +#: extensions/amavis_quarantine/templates/index.html:153 msgid "Quarantine" msgstr "Quarantaine" -#: extensions/amavis_quarantine/main.py:226 +#: extensions/amavis_quarantine/main.py:227 #, python-format msgid "%(count)d message%(plural)s deleted successfully" msgstr "%(count)d message%(plural)s supprimé correctement" -#: extensions/amavis_quarantine/main.py:264 +#: extensions/amavis_quarantine/main.py:267 #, fuzzy, python-format msgid "%(count)d message%(plural)s released successfully" msgstr "%(count)d messages relâché correctement" @@ -162,50 +223,53 @@ msgstr "Supprimer cette sélection?" msgid "Release this selection?" msgstr "Relâcher cette sélection?" -#: extensions/amavis_quarantine/templates/index.html:134 -#: extensions/amavis_quarantine/templates/index.html:156 +#: extensions/amavis_quarantine/templates/index.html:136 +#: extensions/amavis_quarantine/templates/index.html:158 msgid "Search..." msgstr "Chercher..." -#: extensions/amavis_quarantine/templates/index.html:158 -#, fuzzy +#: extensions/amavis_quarantine/templates/index.html:160 msgid "From address" msgstr "Emetteur" -#: extensions/amavis_quarantine/templates/index.html:159 -#: extensions/amavis_quarantine/templates/listing.html:32 +#: extensions/amavis_quarantine/templates/index.html:161 +#: extensions/amavis_quarantine/templates/listing.html:35 msgid "Subject" -msgstr "sujet" +msgstr "Sujet" -#: extensions/amavis_quarantine/templates/index.html:160 +#: extensions/amavis_quarantine/templates/index.html:162 msgid "Both" msgstr "Tous" -#: extensions/amavis_quarantine/templates/listing.html:10 +#: extensions/amavis_quarantine/templates/listing.html:4 +msgid "No messages in quarantine" +msgstr "Aucun message dans la quarantaine" + +#: extensions/amavis_quarantine/templates/listing.html:13 msgid "First" msgstr "Première" -#: extensions/amavis_quarantine/templates/listing.html:13 +#: extensions/amavis_quarantine/templates/listing.html:16 msgid "Previous" msgstr "Précédente" -#: extensions/amavis_quarantine/templates/listing.html:18 +#: extensions/amavis_quarantine/templates/listing.html:21 msgid "Next" msgstr "Suivante" -#: extensions/amavis_quarantine/templates/listing.html:21 +#: extensions/amavis_quarantine/templates/listing.html:24 msgid "Last" msgstr "Dernière" -#: extensions/amavis_quarantine/templates/listing.html:30 +#: extensions/amavis_quarantine/templates/listing.html:33 msgid "Type" msgstr "" -#: extensions/amavis_quarantine/templates/listing.html:31 +#: extensions/amavis_quarantine/templates/listing.html:34 msgid "From" msgstr "De" -#: extensions/amavis_quarantine/templates/listing.html:33 +#: extensions/amavis_quarantine/templates/listing.html:36 msgid "Date" msgstr "" @@ -271,6 +335,22 @@ msgstr "" msgid "Auto-reply message" msgstr "Message de réponse automatique" +#: extensions/stats/main.py:39 +msgid "Statistics" +msgstr "Statistiques" + +#: extensions/stats/main.py:66 extensions/stats/main.py:95 +msgid "No Domain defined" +msgstr "Aucun domaine défini." + +#: extensions/stats/templates/index.html:62 +msgid "Graph type" +msgstr "" + +#: extensions/stats/templates/index.html:63 +msgid "Domain name" +msgstr "Nom du domaine" + #: main/forms.py:17 msgid "Old password" msgstr "Ancien mot de passe" @@ -459,7 +539,6 @@ msgid "Permissions" msgstr "" #: templates/main/confirm.html:26 -#, fuzzy msgid "Do not delete mailbox directory" msgstr "Ne pas supprimer le répertoire de la boite aux lettres" diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index bf41cfd6b..5b98fe149 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-04-17 11:30+0200\n" +"POT-Creation-Date: 2009-10-30 11:11+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -20,14 +20,18 @@ msgstr "" msgid "Delete this domain?" msgstr "Supprimer ce domaine?" -#: static/js/domains.js:21 +#: static/js/domains.js:22 msgid "Delete this mailbox?" msgstr "Supprimer cette boite aux lettres?" -#: static/js/domains.js:27 +#: static/js/domains.js:36 msgid "Delete this alias?" msgstr "Supprimer cet alias?" +#: static/js/form.js:55 +msgid "Help" +msgstr "Aide" + #: static/js/settings.js:9 msgid "Remove this permission?" msgstr "Supprimer cette permission?" diff --git a/static/js/domains.js b/static/js/domains.js index 8e7927d93..c78c4790d 100644 --- a/static/js/domains.js +++ b/static/js/domains.js @@ -55,7 +55,6 @@ window.addEvent('domready', function() { }); $('body').addEvent('submit', function(event) { - alert("newodm submit"); target = event.target; if (target.get('tag') == 'form') { name = target.get('name'); diff --git a/static/js/form.js b/static/js/form.js index 43891ff9b..4392d63ed 100644 --- a/static/js/form.js +++ b/static/js/form.js @@ -50,4 +50,12 @@ window.addEvent("domready", function() { if ($("chpwdform")) $("chpwdform").addEvent("submit", chpassword_submit); + + $$("input[type!=submit]", "select").each(function(elt) { + elt.store("tip:title", gettext("Help")); + if ($(elt.name + "_helptext")) { + elt.store("tip:text", $(elt.name + "_helptext").get("html")); + } + }); + var tip = new Tips($$("input[type!=submit]", "select")); }); diff --git a/static/js/mootools-more.js b/static/js/mootools-more.js index a6e81d7ed..2337e8bba 100644 --- a/static/js/mootools-more.js +++ b/static/js/mootools-more.js @@ -23,8 +23,8 @@ provides: [MooTools.More] */ MooTools.More = { - 'version': '1.2.4.2dev', - 'build': '%build%' + 'version': '1.2.4.2', + 'build': 'bd5a93c0913cce25917c48cbdacde568e15e02ef' }; /* @@ -53,7 +53,8 @@ Fx.Slide = new Class({ Extends: Fx, options: { - mode: 'vertical' + mode: 'vertical', + hideOverflow: true }, initialize: function(element, options){ @@ -64,9 +65,10 @@ Fx.Slide = new Class({ this.element = this.subject = document.id(element); this.parent(options); var wrapper = this.element.retrieve('wrapper'); + var styles = this.element.getStyles('margin', 'position', 'overflow'); + if (this.options.hideOverflow) styles = $extend(styles, {overflow: 'hidden'}); this.wrapper = wrapper || new Element('div', { - styles: $extend(this.element.getStyles('margin', 'position'), {overflow: 'hidden'}) - /*styles: this.element.getStyles('margin', 'position', 'overflow', 'hidden')*/ + styles: styles }).wraps(this.element); this.element.store('wrapper', this.wrapper).setStyle('margin', 0); this.now = []; @@ -178,3 +180,198 @@ Element.implement({ } }); + + +/* +--- + +script: Tips.js + +description: Class for creating nice tips that follow the mouse cursor when hovering an element. + +license: MIT-style license + +authors: +- Valerio Proietti +- Christoph Pojer + +requires: +- core:1.2.4/Options +- core:1.2.4/Events +- core:1.2.4/Element.Event +- core:1.2.4/Element.Style +- core:1.2.4/Element.Dimensions +- /MooTools.More + +provides: [Tips] + +... +*/ + +(function(){ + +var read = function(option, element){ + return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : ''; +}; + +this.Tips = new Class({ + + Implements: [Events, Options], + + options: { + /* + onAttach: $empty(element), + onDetach: $empty(element), + */ + onShow: function(){ + this.tip.setStyle('display', 'block'); + }, + onHide: function(){ + this.tip.setStyle('display', 'none'); + }, + title: 'title', + text: function(element){ + return element.get('rel') || element.get('href'); + }, + showDelay: 100, + hideDelay: 100, + className: 'tip-wrap', + offset: {x: 16, y: 16}, + fixed: false + }, + + initialize: function(){ + var params = Array.link(arguments, {options: Object.type, elements: $defined}); + this.setOptions(params.options); + document.id(this); + + if (params.elements) this.attach(params.elements); + }, + + toElement: function(){ + if (this.tip) return this.tip; + + this.container = new Element('div', {'class': 'tip'}); + return this.tip = new Element('div', { + 'class': this.options.className, + styles: { + position: 'absolute', + top: 0, + left: 0, + visibility: 'hidden', + display: 'none' + } + }).adopt( + new Element('div', {'class': 'tip-top'}), + this.container, + new Element('div', {'class': 'tip-bottom'}) + ).inject(document.body); + }, + + attach: function(elements){ + $$(elements).each(function(element){ + var title = read(this.options.title, element), + text = read(this.options.text, element); + + element.erase('title').store('tip:native', title).retrieve('tip:title', title); + element.retrieve('tip:text', text); + this.fireEvent('attach', [element]); + + var events = ['enter', 'leave']; + if (!this.options.fixed) events.push('move'); + + events.each(function(value){ + var event = element.retrieve('tip:' + value); + if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element); + element.store('tip:' + value, event).addEvent('mouse' + value, event); + }, this); + + element.addEvent('mouseout', this.hide.bind(this, element)); // firefox doesn't handle mouseleave correct + + }, this); + + return this; + }, + + detach: function(elements){ + $$(elements).each(function(element){ + ['enter', 'leave', 'move'].each(function(value){ + element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); + }); + + this.fireEvent('detach', [element]); + + if (this.options.title == 'title'){ // This is necessary to check if we can revert the title + var original = element.retrieve('tip:native'); + if (original) element.set('title', original); + } + }, this); + + return this; + }, + + elementEnter: function(event, element){ + this.container.empty(); + + ['title', 'text'].each(function(value){ + var content = element.retrieve('tip:' + value); + if (content) this.fill(new Element('div', {'class': 'tip-' + value}).inject(this.container), content); + }, this); + + $clear(this.timer); + this.timer = this.show.delay(this.options.showDelay, this, [element, event]); + }, + + elementLeave: function(event, element){ + this.tip.setStyle('visibility', 'hidden'); + $clear(this.timer); + this.timer = this.hide.delay(this.options.hideDelay, this, element); + this.fireForParent(event, element); + }, + + fireForParent: function(event, element){ + var element = $(element); + if (!element) return; + parentNode = element.getParent(); + if (parentNode == document.body) return; + if (parentNode.retrieve('tip:enter')) parentNode.fireEvent('mouseenter', event); + else this.fireForParent(event, parentNode); + }, + + elementMove: function(event, element) { + this.position(event); + }, + + position: function(event){ + if (this.tip.getStyle('display') != 'block') return; + var size = window.getSize(), scroll = window.getScroll(), + tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, + props = {x: 'left', y: 'top'}, + obj = {}; + + for (var z in props){ + obj[props[z]] = event.page[z] + this.options.offset[z]; + if ((obj[props[z]] + tip[z] - scroll[z]) > size[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + } + + this.tip.setStyles(obj); + this.tip.setStyle('visibility', 'visible'); + }, + + fill: function(element, contents){ + if(typeof contents == 'string') element.set('html', contents); + else element.adopt(contents); + }, + + show: function(element, event) { + this.fireEvent('show', [this.tip, element]); + this.position((this.options.fixed) ? {page: element.getPosition()} : event); + }, + + hide: function(element){ + this.fireEvent('hide', [this.tip, element]); + } + +}); + +})(); \ No newline at end of file diff --git a/static/stylesheets/basic.css b/static/stylesheets/basic.css index 96f36dacd..6529c8112 100644 --- a/static/stylesheets/basic.css +++ b/static/stylesheets/basic.css @@ -337,3 +337,8 @@ body { float: left; font-style: italic; } + +#notifybox { + margin: 20px; + font-weight: bold; +} diff --git a/static/stylesheets/box.css b/static/stylesheets/box.css index 039aac015..3ed1924b8 100644 --- a/static/stylesheets/box.css +++ b/static/stylesheets/box.css @@ -101,4 +101,28 @@ input:hover { #dlg-buttons input { width: 90px; -} \ No newline at end of file +} + +/* Mootools tooltips */ +.tip { + color: #fff; + width: 139px; + z-index: 13000; + border: 1px solid #cccccc; +} + +.tip-title { + font-weight: bold; + font-size: 11px; + margin: 0; + color: #9FD4FF; + padding: 8px 8px 4px; + background: #eee; +} + +.tip-text { + font-size: 11px; + padding: 4px 8px 8px; + background: #eee; + color: black; +} diff --git a/templates/admin/addpermission.html b/templates/admin/addpermission.html index e6eef8392..dfbbee887 100644 --- a/templates/admin/addpermission.html +++ b/templates/admin/addpermission.html @@ -1,4 +1,4 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% load i18n %} {% block html_head %} diff --git a/templates/admin/editalias.html b/templates/admin/editalias.html index acef7838a..5993301b5 100644 --- a/templates/admin/editalias.html +++ b/templates/admin/editalias.html @@ -1,4 +1,4 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% block html_head %} {% endblock %} diff --git a/templates/admin/editdomain.html b/templates/admin/editdomain.html index cc887f38e..c7e71c2cf 100644 --- a/templates/admin/editdomain.html +++ b/templates/admin/editdomain.html @@ -1,4 +1,4 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% block html_head %} {% endblock %} diff --git a/templates/admin/editmailbox.html b/templates/admin/editmailbox.html index 96cd75237..7233ebe1d 100644 --- a/templates/admin/editmailbox.html +++ b/templates/admin/editmailbox.html @@ -1,10 +1,10 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% load i18n %} {% block html_head %} {% endblock %} {% block content %} -

Mailbox {{ mbox.name }}

+

{% trans "Mailbox" %} {{ mbox.name }}

{% if error %}
{{ error }}
{% endif %} {% url admin.views.editmailbox mbox.domain_id mbox.id as box_url %} diff --git a/templates/admin/genericform.html b/templates/admin/genericform.html index 728f1c91a..5f993d07c 100644 --- a/templates/admin/genericform.html +++ b/templates/admin/genericform.html @@ -1,5 +1,7 @@ {% for field in form %}
+ {% if field.help_text %} + {% endif %} {{ field.label_tag }} {{ field }} {% ifequal noerrors False %}{{ field.errors }}{% endifequal %}
{% endfor %} diff --git a/templates/admin/layout_simple.html b/templates/admin/layout_simple.html deleted file mode 100644 index 47431d742..000000000 --- a/templates/admin/layout_simple.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - {%block html_head %}{% endblock %} - - - -
- {%block content %}{% endblock %} -
- - diff --git a/templates/admin/newalias.html b/templates/admin/newalias.html index 5cd4b8460..7062ec0e1 100644 --- a/templates/admin/newalias.html +++ b/templates/admin/newalias.html @@ -1,4 +1,4 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% load i18n %} {% block html_head %} diff --git a/templates/admin/newmailbox.html b/templates/admin/newmailbox.html index e0af22d60..b640b9bf6 100644 --- a/templates/admin/newmailbox.html +++ b/templates/admin/newmailbox.html @@ -1,4 +1,4 @@ -{% extends "admin/layout_simple.html" %} +{% extends "layout_simple.html" %} {% load i18n %} {% block html_head %} diff --git a/templates/layout_simple.html b/templates/layout_simple.html index 47431d742..e9614c4e2 100644 --- a/templates/layout_simple.html +++ b/templates/layout_simple.html @@ -6,7 +6,10 @@ + + {% url django.views.i18n.javascript_catalog as catalog_url %} + {%block html_head %}{% endblock %}