diff --git a/modoboa/lib/form_utils.py b/modoboa/lib/form_utils.py index f21a9a21d..2d8469dc5 100644 --- a/modoboa/lib/form_utils.py +++ b/modoboa/lib/form_utils.py @@ -24,26 +24,17 @@ class WizardStep(object): """A wizard step.""" - def __init__(self, cls, title, formtpl=None, new_args=None): - """Constructor. - - """ - self._cls = cls - self._title = title + def __init__(self, uid, formclass, title, formtpl=None, new_args=None): + """Constructor.""" + self.uid = uid + self._cls = formclass + 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): - """Return step title""" - if self.index is None: - return self._title - return "%d. %s" % (self.index + 1, self._title) - @property def prev(self): return self._prev @@ -60,7 +51,12 @@ class WizardStep(object): def next(self, step): self._next = step + def check_access(self, wizard): + """Check if this step should be displayed or not.""" + return True + def create_form(self, data=None): + """Instantiate a new form.""" args = [] if self._new_args is not None: args += self._new_args @@ -100,44 +96,69 @@ class WizardForm(object): @property def first_step(self): - """Return the first step. - """ + """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) + def add_step(self, step): + """Add a new step to the wizard.""" 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: step.create_form(data) - def validate_step(self): + def _get_step_id(self): + """Retrieve the step identifier from the request.""" stepid = self.request.POST.get("stepid", None) if stepid is None: raise BadRequest(_("Invalid request")) stepid = int(stepid.replace("step", "")) - if stepid < 0 or stepid > len(self.steps): + if stepid < 0: raise BadRequest(_("Invalid request")) + return min(stepid, len(self.steps)) + + def previous_step(self): + """Go back to the previous step.""" + stepid = self._get_step_id() + stepid -= 2 + self.create_forms(self.request.POST) + for step in self.steps: + step.form.is_valid() + while stepid >= 0: + if self.steps[stepid].check_access(self): + break + stepid -= 1 + return render_to_json_response({ + "title": self.steps[stepid].title, "id": self.steps[stepid].uid, + "stepid": stepid + }) + + def next_step(self): + """Go to the next step if previous forms are valid.""" + stepid = self._get_step_id() self.create_forms(self.request.POST) statuses = [] for cpt in xrange(0, stepid): - statuses.append(self.steps[cpt].form.is_valid()) + if self.steps[cpt].check_access(self): + statuses.append(self.steps[cpt].form.is_valid()) if False in statuses: return render_to_json_response({ - 'stepid': stepid, 'form_errors': self.errors + "stepid": stepid, "id": self.steps[stepid - 1].uid, + "form_errors": self.errors }, status=400) + while stepid < len(self.steps): + if self.steps[stepid].check_access(self): + break + stepid += 1 if stepid == len(self.steps): return self.done() - return render_to_json_response( - {'title': self.steps[stepid].title, 'stepid': stepid} - ) + return render_to_json_response({ + "title": self.steps[stepid].title, "id": self.steps[stepid].uid, + "stepid": stepid + }) def extra_context(self, context): """Provide additional information to template's context. @@ -145,10 +166,11 @@ class WizardForm(object): pass def process(self): - """Process the request. - """ + """Process the request.""" if self.request.method == "POST": - return self.validate_step() + if self.request.POST.get("target", "next") == "next": + return self.next_step() + return self.previous_step() self.create_forms() context = {"wizard": self} self.extra_context(context) diff --git a/modoboa/static/js/creation_wizard.js b/modoboa/static/js/creation_wizard.js index ebf073599..20a1a8ab9 100644 --- a/modoboa/static/js/creation_wizard.js +++ b/modoboa/static/js/creation_wizard.js @@ -34,9 +34,9 @@ $(".modal-header").find("small").html(title); }, - post: function(last) { + post: function(last, target) { var $form = (this.options.formid) ? $('#' + this.options.formid) : $('form'); - var data = $form.serialize() + "&stepid=" + this.get_current_step_id(); + var data = $form.serialize() + "&stepid=" + this.get_current_step_id() + "&target=" + target; $.ajax({ type: 'POST', url: $form.attr("action"), data: data, global: false @@ -44,11 +44,11 @@ if (!last) { $('input:text:visible:first').focus(); this.set_current_title(resp.title); - if (this.options.transition_callbacks[resp.stepid] !== undefined) { - this.options.transition_callbacks[resp.stepid](); + if (this.options.transition_callbacks[resp.id] !== undefined) { + this.options.transition_callbacks[resp.id](); } $(".carousel-inner").css("overflow", "hidden"); - this.$element.carousel('next'); + this.$element.carousel(resp.stepid); } else { $("#modalbox").modal('hide'); if (this.options.success_callback !== undefined) { @@ -86,20 +86,23 @@ var step_id = this.get_current_step_id(); this.titles[step_id] = this.get_current_title(); this.$element.on('slid.bs.carousel', this.update_buttons); - this.post(false); + this.post(false, "next"); }, + /** + * Go back to the previous step. + */ prev: function(evt) { + var stepid = this.get_current_step_id(); + evt.preventDefault(); this.$element.on('slid.bs.carousel', this.update_buttons); - $(".carousel-inner").css("overflow", "hidden"); - this.$element.carousel('prev'); - this.set_current_title(this.titles[this.get_current_step_id()]); + this.post(false, "prev", stepid); }, submit: function(evt) { evt.preventDefault(); - this.post(true); + this.post(true, "next"); } };