mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
A piece of refactoring.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
from .domain import DomainFormGeneral, DomainFormOptions, DomainForm
|
||||
from .domain import (
|
||||
DomainFormGeneral, DomainFormOptions, DomainForm, DomainWizard
|
||||
)
|
||||
from .account import (
|
||||
AccountFormGeneral, AccountFormMail, AccountPermissionsForm,
|
||||
AccountForm
|
||||
AccountForm, AccountWizard
|
||||
)
|
||||
from .alias import AliasForm
|
||||
from .forward import ForwardForm
|
||||
@@ -13,5 +15,5 @@ __all__ = [
|
||||
'AccountFormGeneral', 'AccountFormMail', 'AccountPermissionsForm',
|
||||
'AccountForm', 'AliasForm', 'ImportDataForm', 'ImportIdentitiesForm',
|
||||
'ExportDataForm', 'ExportDomainsForm', 'ExportIdentitiesForm',
|
||||
'ForwardForm'
|
||||
'ForwardForm', 'DomainWizard', 'AccountWizard'
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@ from modoboa.lib.exceptions import PermDeniedException, Conflict, NotFound
|
||||
from modoboa.lib.permissions import get_account_roles
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.lib.formutils import (
|
||||
DomainNameField, DynamicForm, TabForms, YesNoField
|
||||
DomainNameField, DynamicForm, TabForms, WizardForm
|
||||
)
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.models import (
|
||||
@@ -370,3 +370,25 @@ class AccountForm(TabForms):
|
||||
return
|
||||
for f in self.forms[2:]:
|
||||
f["instance"].save()
|
||||
|
||||
|
||||
class AccountWizard(WizardForm):
|
||||
"""Account creation wizard.
|
||||
"""
|
||||
def __init__(self, request):
|
||||
super(AccountWizard, self).__init__(request)
|
||||
self.add_step(
|
||||
AccountFormGeneral, _("General"), new_args=[request.user]
|
||||
)
|
||||
self.add_step(
|
||||
AccountFormMail, _("Mail"), formtpl="admin/mailform.html"
|
||||
)
|
||||
|
||||
def done(self):
|
||||
from modoboa.lib.webutils import render_to_json_response
|
||||
|
||||
account = self.first_step.form.save()
|
||||
account.post_create(self.request.user)
|
||||
mailform = self.steps[1].form
|
||||
mailform.save(self.request.user, account)
|
||||
return render_to_json_response(_("Account created"))
|
||||
|
||||
@@ -2,10 +2,11 @@ from django import forms
|
||||
from django.http import QueryDict
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.exceptions import Conflict
|
||||
from modoboa.lib.exceptions import ModoboaException, Conflict
|
||||
from modoboa.lib.formutils import (
|
||||
DomainNameField, YesNoField, DynamicForm, TabForms
|
||||
DomainNameField, YesNoField, WizardForm, DynamicForm, TabForms
|
||||
)
|
||||
from modoboa.lib.webutils import render_to_json_response
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.models import (
|
||||
Domain, DomainAlias, Mailbox, Alias, Quota
|
||||
@@ -269,3 +270,31 @@ class DomainForm(TabForms):
|
||||
self.forms[0]['instance'].save(user, domalias_post_create=True)
|
||||
for f in self.forms[1:]:
|
||||
f["instance"].save(user)
|
||||
|
||||
|
||||
class DomainWizard(WizardForm):
|
||||
"""Domain creation wizard.
|
||||
"""
|
||||
def __init__(self, request):
|
||||
super(DomainWizard, self).__init__(request)
|
||||
self.add_step(
|
||||
DomainFormGeneral, _("General"),
|
||||
formtpl="admin/domain_general_form.html"
|
||||
)
|
||||
self.add_step(
|
||||
DomainFormOptions, _("Options"),
|
||||
formtpl="admin/domain_options_form.html",
|
||||
new_args=[self.request.user]
|
||||
)
|
||||
|
||||
def done(self):
|
||||
genform = self.first_step.form
|
||||
domain = genform.save(self.request.user)
|
||||
domain.post_create(self.request.user)
|
||||
try:
|
||||
self.steps[1].form.save(self.request.user, domain)
|
||||
except ModoboaException:
|
||||
from django.db import transaction
|
||||
transaction.rollback()
|
||||
raise
|
||||
return render_to_json_response(_("Domain created"))
|
||||
|
||||
@@ -12,15 +12,14 @@ from modoboa.lib import parameters, events
|
||||
from modoboa.lib.webutils import (
|
||||
_render_to_string, render_to_json_response
|
||||
)
|
||||
from modoboa.lib.formutils import CreationWizard
|
||||
from modoboa.lib.exceptions import (
|
||||
ModoboaException, PermDeniedException, BadRequest
|
||||
PermDeniedException
|
||||
)
|
||||
from modoboa.lib.templatetags.lib_tags import pagination_bar
|
||||
from modoboa.extensions.admin.lib import get_sort_order, get_listing_page
|
||||
from modoboa.extensions.admin.models import Domain, Mailbox
|
||||
from modoboa.extensions.admin.forms import (
|
||||
DomainForm, DomainFormGeneral, DomainFormOptions
|
||||
DomainForm
|
||||
)
|
||||
from modoboa.extensions.admin.lib import get_domains
|
||||
|
||||
@@ -91,50 +90,19 @@ def domains_list(request):
|
||||
@transaction.commit_on_success
|
||||
@reversion.create_revision()
|
||||
def newdomain(request, tplname="common/wizard_forms.html"):
|
||||
from modoboa.extensions.admin.forms import DomainWizard
|
||||
|
||||
events.raiseEvent("CanCreate", request.user, "domains")
|
||||
|
||||
cwizard = CreationWizard()
|
||||
cwizard.add_step(DomainFormGeneral, _("General"),
|
||||
[dict(classes="btn-inverse next", label=_("Next"))],
|
||||
formtpl="admin/domain_general_form.html")
|
||||
cwizard.add_step(
|
||||
DomainFormOptions, _("Options"),
|
||||
[dict(classes="btn-primary submit", label=_("Create")),
|
||||
dict(classes="btn-inverse prev", label=_("Previous"))],
|
||||
formtpl="admin/domain_options_form.html",
|
||||
new_args=[request.user]
|
||||
)
|
||||
|
||||
wizard = DomainWizard(request)
|
||||
if request.method == "POST":
|
||||
retcode, data = cwizard.validate_step(request)
|
||||
if retcode == -1:
|
||||
raise BadRequest(data)
|
||||
if retcode == 1:
|
||||
return render_to_json_response(
|
||||
{'title': cwizard.get_title(data + 1), 'stepid': data}
|
||||
)
|
||||
if retcode == 2:
|
||||
genform = cwizard.steps[0]["form"]
|
||||
domain = genform.save(request.user)
|
||||
domain.post_create(request.user)
|
||||
try:
|
||||
cwizard.steps[1]["form"].save(request.user, domain)
|
||||
except ModoboaException as e:
|
||||
transaction.rollback()
|
||||
raise
|
||||
return render_to_json_response(_("Domain created"))
|
||||
return render_to_json_response({
|
||||
'stepid': data, 'form_errors': cwizard.errors
|
||||
}, status=400)
|
||||
|
||||
return wizard.validate_step()
|
||||
ctx = {"title": _("New domain"),
|
||||
"action_label": _("Create"),
|
||||
"action_classes": "submit",
|
||||
"action": reverse(newdomain),
|
||||
"formid": "domform"}
|
||||
cwizard.create_forms()
|
||||
ctx.update(steps=cwizard.steps)
|
||||
ctx.update(subtitle="1. %s" % cwizard.steps[0]['title'])
|
||||
wizard.create_forms()
|
||||
ctx.update(wizard=wizard)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from modoboa.lib.exceptions import (
|
||||
from modoboa.lib.webutils import (
|
||||
_render_to_string, render_to_json_response
|
||||
)
|
||||
from modoboa.lib.formutils import CreationWizard
|
||||
from modoboa.lib.formutils import WizardForm
|
||||
from modoboa.lib.templatetags.lib_tags import pagination_bar
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.models import Mailbox, Domain
|
||||
@@ -125,43 +125,17 @@ def newaccount(request, tplname='common/wizard_forms.html'):
|
||||
doesn't work very well with nested functions. Need to wait for
|
||||
django 1.6 and atomicity.
|
||||
"""
|
||||
cwizard = CreationWizard()
|
||||
cwizard.add_step(AccountFormGeneral, _("General"),
|
||||
[dict(classes="btn-inverse next", label=_("Next"))],
|
||||
new_args=[request.user])
|
||||
cwizard.add_step(AccountFormMail, _("Mail"),
|
||||
[dict(classes="btn-primary submit", label=_("Create")),
|
||||
dict(classes="btn-inverse prev", label=_("Previous"))],
|
||||
formtpl="admin/mailform.html")
|
||||
|
||||
from modoboa.extensions.admin.forms import AccountWizard
|
||||
wizard = AccountWizard(request)
|
||||
if request.method == "POST":
|
||||
retcode, data = cwizard.validate_step(request)
|
||||
if retcode == -1:
|
||||
raise BadRequest(data)
|
||||
if retcode == 1:
|
||||
return render_to_json_response(
|
||||
{'title': cwizard.get_title(data + 1), 'stepid': data}
|
||||
)
|
||||
if retcode == 2:
|
||||
genform = cwizard.steps[0]["form"]
|
||||
account = genform.save()
|
||||
account.post_create(request.user)
|
||||
mailform = cwizard.steps[1]["form"]
|
||||
mailform.save(request.user, account)
|
||||
return render_to_json_response(_("Account created"))
|
||||
return render_to_json_response({
|
||||
'stepid': data, 'form_errors': cwizard.errors
|
||||
}, status=400)
|
||||
|
||||
return wizard.validate_step()
|
||||
ctx = {
|
||||
'title': _("New account"),
|
||||
'action': reverse(newaccount),
|
||||
'formid': 'newaccount_form',
|
||||
'submit_label': _("Create")
|
||||
'formid': 'newaccount_form'
|
||||
}
|
||||
cwizard.create_forms()
|
||||
ctx.update(steps=cwizard.steps)
|
||||
ctx.update(subtitle="1. %s" % cwizard.steps[0]['title'])
|
||||
wizard.create_forms()
|
||||
ctx.update(wizard=wizard)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"""
|
||||
Radicale extension forms.
|
||||
"""
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
from modoboa.lib.webutils import render_to_json_response
|
||||
from modoboa.lib.formutils import WizardForm
|
||||
from modoboa.extensions.radicale.models import UserCalendar
|
||||
|
||||
|
||||
class UserCalendarForm(forms.ModelForm):
|
||||
"""
|
||||
User calendar form.
|
||||
"""
|
||||
class Meta:
|
||||
model = UserCalendar
|
||||
fields = ('name', )
|
||||
|
||||
|
||||
class RightsForm(forms.Form):
|
||||
username = forms.CharField(required=False)
|
||||
|
||||
|
||||
class UserCalendarWizard(WizardForm):
|
||||
"""
|
||||
"""
|
||||
def __init__(self, request):
|
||||
super(UserCalendarWizard, self).__init__(request)
|
||||
self.add_step(UserCalendarForm, _("General"))
|
||||
self.add_step(RightsForm, _("Rights"))
|
||||
|
||||
def done(self, request):
|
||||
calendar = self.first_step.form.save(commit=False)
|
||||
calendar.mailbox = request.user.mailbox_set.all()[0]
|
||||
calendar.save()
|
||||
return render_to_json_response(_("Calendar created"))
|
||||
@@ -1,3 +1,66 @@
|
||||
from django.db import models
|
||||
"""
|
||||
Radicale extension models.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Create your models here.
|
||||
import abc
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Calendar(models.Model):
|
||||
"""Abstract calendar definition.
|
||||
"""
|
||||
name = models.CharField(max_length=200)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def url(self):
|
||||
"""Return the calendar URL"""
|
||||
|
||||
|
||||
class UserCalendar(Calendar):
|
||||
"""User calendar.
|
||||
|
||||
We associate the calendar to a mailbox because we need to access
|
||||
the related domain.
|
||||
|
||||
"""
|
||||
mailbox = models.ForeignKey("admin.Mailbox")
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""Return the calendar URL.
|
||||
|
||||
<domain>/user/<localpart>/<name>
|
||||
"""
|
||||
return "%s/user/%s/%s" % (
|
||||
self.mailbox.domain.name, self.mailbox.address, self.name
|
||||
)
|
||||
|
||||
|
||||
class SharedCalendar(Calendar):
|
||||
"""Shared calendar.
|
||||
|
||||
A shared calendar is associated to a domain and is readable and
|
||||
writable by all domain members.
|
||||
|
||||
"""
|
||||
domain = models.ForeignKey("admin.Domain")
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""Return the calendar URL.
|
||||
|
||||
<domain>/shared/<name>
|
||||
"""
|
||||
return "%s/shared/%s" % (
|
||||
self.mailbox.domain.name, self.name
|
||||
)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
var Radicale = function() {
|
||||
|
||||
};
|
||||
|
||||
Radicale.prototype = {
|
||||
constructor: Radicale,
|
||||
|
||||
initialize: function() {
|
||||
|
||||
},
|
||||
|
||||
add_calendar_cb: function() {
|
||||
$("#wizard").cwizard({
|
||||
formid: "newcal_form"
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
{% extends "twocols.html" %}{% load i18n radicale_tags %}
|
||||
{% block html_head %}
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/creation_wizard.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}radicale/js/radicale.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
radicale = new Radicale();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block leftcol %}<div class="well sidebar-nav">
|
||||
<ul class="nav nav-list">
|
||||
<li class="nav-header">{% trans "Filter" %}</li>
|
||||
<li>{% include "admin/searchform.html" %}</li>
|
||||
<li id="taglist"></li>
|
||||
<li class="nav-header">{% trans "Actions" %}</li>
|
||||
{% radicale_left_menu user %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,4 @@
|
||||
{% extends "common/generic_modal_form.html" %}{% load crispy_forms_tags %}
|
||||
{% block formbody %}
|
||||
{{ form|crispy }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Custom template tags.
|
||||
"""
|
||||
from django import template
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def radicale_left_menu(user):
|
||||
"""Menu located inside the left column.
|
||||
|
||||
:param ``User`` user: current user
|
||||
:rtype: string
|
||||
:return: the menu rendered as HTML code
|
||||
"""
|
||||
entries = [
|
||||
{"name": "newcalendar",
|
||||
"label": _("Add calendar"),
|
||||
"img": "icon-plus",
|
||||
"modal": True,
|
||||
"modalcb": "radicale.add_calendar_cb",
|
||||
"url": reverse("new_calendar")},
|
||||
]
|
||||
return render_to_string('common/menulist.html', {
|
||||
"entries": entries,
|
||||
"user": user
|
||||
})
|
||||
@@ -1,6 +1,8 @@
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url, patterns
|
||||
|
||||
urlpatterns = patterns(
|
||||
'modoboa.extensions.radicale.views',
|
||||
(r'^$', 'index'),
|
||||
(r'^calendars/$', 'calendars'),
|
||||
url(r'^calendar/$', 'new_calendar', name='new_calendar'),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# Create your views here.
|
||||
"""
|
||||
Radicale extension views.
|
||||
"""
|
||||
from django.shortcuts import render
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import (
|
||||
login_required
|
||||
)
|
||||
from django.utils.translation import ugettext as _
|
||||
from modoboa.extensions.radicale.forms import UserCalendarWizard
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
pass
|
||||
return HttpResponseRedirect(reverse(calendars))
|
||||
|
||||
|
||||
@login_required
|
||||
def calendars(request, tplname="radicale/calendars.html"):
|
||||
return render(request, tplname, {
|
||||
"selection": "radicale"
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def new_calendar(request, tplname="common/wizard_forms.html"):
|
||||
wizard = UserCalendarWizard(request)
|
||||
if request.method == "POST":
|
||||
return wizard.validate_step()
|
||||
wizard.create_forms()
|
||||
return render(request, tplname, {
|
||||
"title": _("New calendar"),
|
||||
"action": reverse(new_calendar),
|
||||
"formid": "newcal_form",
|
||||
"wizard": wizard
|
||||
})
|
||||
|
||||
+101
-29
@@ -1,5 +1,6 @@
|
||||
# coding: utf-8
|
||||
import re
|
||||
import abc
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.forms import ChoiceField
|
||||
from django.forms.widgets import RadioSelect, RadioInput
|
||||
@@ -8,59 +9,130 @@ from django.core.exceptions import ValidationError
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.html import conditional_escape
|
||||
from modoboa.lib.exceptions import BadRequest
|
||||
from modoboa.lib.webutils import render_to_json_response
|
||||
|
||||
|
||||
class CreationWizard(object):
|
||||
def __init__(self, done_cb=None):
|
||||
class WizardStep(object):
|
||||
"""A wizard step.
|
||||
"""
|
||||
def __init__(self, cls, title, formtpl=None, new_args=None):
|
||||
"""Constructor.
|
||||
|
||||
"""
|
||||
self._cls = cls
|
||||
self._title = title
|
||||
self.formtpl = formtpl
|
||||
self._new_args = new_args
|
||||
self._prev = None
|
||||
self._next = None
|
||||
self.index = None
|
||||
self.form = None
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
if self.index is None:
|
||||
return self._title
|
||||
return "%d. %s" % (self.index + 1, self._title)
|
||||
|
||||
@property
|
||||
def prev(self):
|
||||
return self._prev
|
||||
|
||||
@prev.setter
|
||||
def prev(self, step):
|
||||
self._prev = step
|
||||
|
||||
@property
|
||||
def next(self):
|
||||
return self._next
|
||||
|
||||
@next.setter
|
||||
def next(self, step):
|
||||
self._next = step
|
||||
|
||||
def create_form(self, data=None):
|
||||
args = []
|
||||
if self._new_args is not None:
|
||||
args += self._new_args
|
||||
if data:
|
||||
args.append(data)
|
||||
self.form = self._cls(*args)
|
||||
|
||||
|
||||
class WizardForm(object):
|
||||
"""Custom wizard.
|
||||
"""
|
||||
def __init__(self, request, submit_button_label=None):
|
||||
self.request = request
|
||||
self.steps = []
|
||||
self.done_cb = done_cb
|
||||
self._submit_button_label = submit_button_label
|
||||
|
||||
@property
|
||||
def submit_button_label(self):
|
||||
if self._submit_button_label is None:
|
||||
self._submit_button_label = _("Submit")
|
||||
return self._submit_button_label
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
result = {}
|
||||
for step in self.steps:
|
||||
for name, value in step['form'].errors.items():
|
||||
for name, value in step.form.errors.items():
|
||||
if name == '__all__':
|
||||
continue
|
||||
result[name] = value
|
||||
return result
|
||||
|
||||
def add_step(self, cls, title, buttons, formtpl=None, new_args=None):
|
||||
self.steps += [dict(cls=cls, title=title, buttons=buttons,
|
||||
formtpl=formtpl, new_args=new_args)]
|
||||
@property
|
||||
def first_step(self):
|
||||
"""Return the first step.
|
||||
"""
|
||||
return self.steps[0] if self.steps else None
|
||||
|
||||
def add_step(self, cls, title, formtpl=None, new_args=None):
|
||||
"""Add a new step to the wizard.
|
||||
"""
|
||||
step = WizardStep(cls, title, formtpl, new_args)
|
||||
if self.steps:
|
||||
step.prev = self.steps[-1]
|
||||
self.steps[-1].next = step
|
||||
self.steps += [step]
|
||||
step.index = len(self.steps) - 1
|
||||
|
||||
def create_forms(self, data=None):
|
||||
for step in self.steps:
|
||||
args = []
|
||||
if 'new_args' in step and step["new_args"]:
|
||||
args += step["new_args"]
|
||||
if data:
|
||||
args.append(data)
|
||||
step["form"] = step["cls"](*args)
|
||||
step.create_form(data)
|
||||
|
||||
def validate_step(self, request):
|
||||
stepid = request.POST.get("stepid", None)
|
||||
def validate_step(self):
|
||||
stepid = self.request.POST.get("stepid", None)
|
||||
if stepid is None:
|
||||
return -1, _("Invalid request")
|
||||
|
||||
stepid = stepid.replace("step", "")
|
||||
stepid = int(stepid)
|
||||
raise BadRequest(_("Invalid request"))
|
||||
stepid = int(stepid.replace("step", ""))
|
||||
if stepid < 0 or stepid > len(self.steps):
|
||||
return -1, _("Invalid request")
|
||||
self.create_forms(request.POST)
|
||||
raise BadRequest(_("Invalid request"))
|
||||
self.create_forms(self.request.POST)
|
||||
statuses = []
|
||||
for cpt in xrange(0, stepid):
|
||||
statuses.append(self.steps[cpt]["form"].is_valid())
|
||||
statuses.append(self.steps[cpt].form.is_valid())
|
||||
if False in statuses:
|
||||
return 0, stepid
|
||||
return render_to_json_response({
|
||||
'stepid': stepid, 'form_errors': self.errors
|
||||
}, status=400)
|
||||
if stepid == len(self.steps):
|
||||
if self.done_cb is not None:
|
||||
self.done_cb(self.steps)
|
||||
return 2, None
|
||||
return 1, stepid
|
||||
return self.done()
|
||||
return render_to_json_response(
|
||||
{'title': self.steps[stepid].title, 'stepid': stepid}
|
||||
)
|
||||
|
||||
def get_title(self, stepid):
|
||||
return "%d. %s" % (stepid, self.steps[stepid - 1]["title"])
|
||||
@abc.abstractmethod
|
||||
def done(self):
|
||||
"""Method to exexute when all steps are validated.
|
||||
|
||||
Must be implemented by all sub classes.
|
||||
|
||||
:rtype: HttpResponse
|
||||
"""
|
||||
|
||||
|
||||
class DynamicForm(object):
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{% load i18n lib_tags %}
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal">x</a>
|
||||
<h3>{{ title }} / <small>{{ subtitle }}</small></h3>
|
||||
<h3>{{ title }} / <small>{{ wizard.first_step.title }}</small></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" action="{{ action }}" enctype="{{ enctype }}"
|
||||
method="POST" id="{{ formid }}" name="{{ formid }}">{% csrf_token %}
|
||||
<div id="wizard" class="carousel">
|
||||
<div class="carousel-inner">{% for step in steps %}
|
||||
<div id="step{{ forloop.counter }}"
|
||||
<div class="carousel-inner">{% for step in wizard.steps %}
|
||||
<div id="step{{ forloop.counter }}"
|
||||
class="item{% if forloop.first %} active{% endif %}">
|
||||
{% if step.formtpl %}{% render_form step.form step.formtpl %}{% else %}{% render_form step.form %}{% endif %}
|
||||
</div>{% endfor %}
|
||||
@@ -18,12 +18,11 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="buttons_list">
|
||||
{% for step in steps %}
|
||||
{% for step in wizard.steps %}
|
||||
<div id="step{{ forloop.counter }}_buttons"
|
||||
class="bset{% if forloop.first %} active{% endif %}">
|
||||
{% for button in step.buttons %}
|
||||
<a href="#" class="btn {{ button.classes }}">{{ button.label }}</a>
|
||||
{% endfor %}
|
||||
{% if step.prev %}<a href="#" class="btn btn-inverse prev">{% trans "Previous" %}</a>{% endif %}
|
||||
{% if step.next %}<a href="#" class="btn btn-inverse next">{% trans "Next" %}</a>{% else %}<a href="#" class="btn btn-primary submit">{{ wizard.submit_button_label }}</a>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<a class="btn" data-dismiss="modal">{% trans "Close" %}</a>
|
||||
|
||||
Reference in New Issue
Block a user