In Murano App configuration wizard move Back/Next w/o losing any data

- solution uses HTML5 sessionStorage to store form data:
    When 'Back' is clicked on N step of wizard, its data is stored in the
    sessionStorage.
    When we return to N step from N-1 step, all its visible fields
    will be overwritten with the value from the sessionStorage

Closes-Bug:#1629904

Change-Id: Ie419be395d3ebddb5a82ce5248ef758117fb49a5
This commit is contained in:
Kate Pimenova 2016-09-23 14:30:28 +02:00
parent cef39fc96d
commit 34525c0a56
2 changed files with 77 additions and 9 deletions

View File

@ -17,6 +17,7 @@ import copy
import functools import functools
import json import json
import re import re
import uuid
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth
@ -432,6 +433,10 @@ class Wizard(generic_views.PageTitleMixin, views.ModalFormMixin, LazyWizard):
app = mc.packages.get(app_id) app = mc.packages.get(app_id)
self.storage.extra_data['app'] = app self.storage.extra_data['app'] = app
wizard_id = self.request.REQUEST.get('wizard_id')
if wizard_id is None:
wizard_id = uuid.uuid4()
environment_id = self.kwargs.get('environment_id') environment_id = self.kwargs.get('environment_id')
environment_id = utils.ensure_python_obj(environment_id) environment_id = utils.ensure_python_obj(environment_id)
if environment_id is not None: if environment_id is not None:
@ -450,6 +455,7 @@ class Wizard(generic_views.PageTitleMixin, views.ModalFormMixin, LazyWizard):
'do_redirect': self.get_wizard_flag('do_redirect'), 'do_redirect': self.get_wizard_flag('do_redirect'),
'drop_wm_form': self.get_wizard_flag('drop_wm_form'), 'drop_wm_form': self.get_wizard_flag('drop_wm_form'),
'prefix': self.prefix, 'prefix': self.prefix,
'wizard_id': wizard_id,
'field_descriptions': field_descr, 'field_descriptions': field_descr,
'extended_descriptions': extended_descr, 'extended_descriptions': extended_descr,
}) })

View File

@ -66,13 +66,46 @@
<script type="text/javascript"> <script type="text/javascript">
{# TODO(efedorova): extract to a separate file #} {# TODO(efedorova): extract to a separate file #}
$(function() { $(function() {
"use strict";
{# Make element ids unique per-wizard to avoid interference #} {# Make element ids unique per-wizard to avoid interference #}
{# upon pressing 'Back' button while creating one application #} {# upon pressing 'Back' button while creating one application #}
{# from another #} {# from another #}
var btn_id = '#{{ prefix }}_btn', val_id = '#{{ prefix }}_val'; var btn_id = '#{{ prefix }}_btn',
val_id = '#{{ prefix }}_val',
current_step = {{ wizard.steps.index }},
form_data = {},
wizard_id = '{{ wizard_id }}',
session_data = sessionStorage.getItem(wizard_id + current_step),
form = $('#form_' + '{{ prefix }}'.split("_")[1]),
fields = '.form-group input, .form-group select, .form-group textarea';
if (current_step > 0) {
// Update form with saved data
if (session_data) {
setFormData(JSON.parse(session_data));
}
// Collect loaded form data
form_data = rearrangeKeys(getFormData());
}
$(btn_id).click(function() { $(btn_id).click(function() {
var current_data = JSON.stringify(rearrangeKeys(getFormData()));
// Check if there any changes in the form
if (current_data != JSON.stringify(form_data)) {
// Save current data into session storage
sessionStorage.setItem(wizard_id + current_step, current_data);
}
$(val_id).val('{{ wizard.steps.prev }}') $(val_id).val('{{ wizard.steps.prev }}')
}); });
$('input[type="submit"]').click(function() {
clearSession(current_step);
return true;
});
$('a.close').click(function() {
var step = 1;
for (; step < {{ wizard.steps.count }}; step++) {
clearSession(step);
}
return true;
});
$('#modal_wrapper').on('new_modal', function(evt, modal) { $('#modal_wrapper').on('new_modal', function(evt, modal) {
var $modal = $(modal); var $modal = $(modal);
$modal.find('.form-group input, select').each(function(index, elem) { $modal.find('.form-group input, select').each(function(index, elem) {
@ -99,20 +132,49 @@
} }
}).filter(':first').trigger('focus'); }).filter(':first').trigger('focus');
}); });
// show full name on text overflow // show full name on text overflow
$('.modal-dialog h3').each(function () { $('.modal-dialog h3').each(function () {
$(this).bind('mouseenter', function () { $(this).bind('mouseenter', function () {
var $this = $(this); var $this = $(this);
if (this.offsetWidth < this.scrollWidth && !$this.attr('title')) { if (this.offsetWidth < this.scrollWidth && !$this.attr('title')) {
$this.attr('title', $this.text()); $this.attr('title', $this.text());
} }
});
}); });
});
function getFormData() {
var inputs = {};
form.find(fields).each(function() {
inputs[this.id] = [$(this).val(), $(this).is(':checked')];
});
return inputs;
}
function setFormData(data) {
form.find(fields).each(function() {
var field = $(this);
if (field.is('select')) {
field.find('option:selected').removeAttr('selected');
}
if (data[this.id][1]) {
field.prop('checked', true);
}
field.val(data[this.id][0]);
});
}
function clearSession(step) {
sessionStorage.removeItem(wizard_id + step);
}
function rearrangeKeys(obj) {
return Object.keys(obj).sort().reduce(function assemble(acc, key) {
acc[key] = obj[key];
return acc;
}, {});
}
}); });
</script> </script>
{{ wizard.form.media }} {{ wizard.form.media }}
<input type="hidden" name="wizard_id" value="{{ wizard_id }}"/>
<input type="hidden" name="wizard_goto_step" id="{{ prefix }}_val"/> <input type="hidden" name="wizard_goto_step" id="{{ prefix }}_val"/>
<input type="hidden" name="do_redirect" value="{{ do_redirect }}"/> <input type="hidden" name="do_redirect" value="{{ do_redirect }}"/>
<input type="hidden" name="drop_wm_form" value="{{ drop_wm_form }}"/> <input type="hidden" name="drop_wm_form" value="{{ drop_wm_form }}"/>