forms: autosave existing drafts (#4858)

This commit is contained in:
Frédéric Péters 2014-12-26 13:12:48 +01:00
parent 64c16c1a5a
commit 0f17fa2172
3 changed files with 91 additions and 2 deletions

View File

@ -167,7 +167,7 @@ class FormData(StorableObject):
def migrate(self):
changed = False
if self.status and not self.status.startswith('wf-'):
if self.status and not self.status.startswith('wf-') and self.status != 'draft':
self.status = 'wf-%s' % self.status
changed = True
if self.evolution:

View File

@ -120,7 +120,7 @@ class TokensDirectory(Directory):
class FormPage(Directory):
_q_exports = ['', 'listing', 'tempfile', 'tokens', 'schema', 'tryauth',
'auth', 'qrcode']
'auth', 'qrcode', 'autosave']
steps = [N_("Filling"), N_("Validating"), N_("Receipt")]
@ -223,6 +223,14 @@ class FormPage(Directory):
self.feed_current_data(magictoken)
form = self.formdef.create_form(page_no, displayed_fields)
# include a data-has-draft attribute on the <form> element when a draft
# already exists for the form; this will activate the autosave.
magictoken = get_request().form.get('magictoken')
if magictoken:
form_data = session.get_by_magictoken(magictoken, {})
if form_data.get('draft_formdata_id'):
form.attrs['data-has-draft'] = 'yes'
get_response().add_javascript(['jquery.js', 'qommon.forms.js'])
if page_no == 0 and not get_request().form.has_key('magictoken'):
magictoken = randbytes(8)
@ -440,6 +448,11 @@ class FormPage(Directory):
if next_page.is_visible(form_data, self.formdef):
break
# if there's a draft, update it with current data
draft_id = session.get_by_magictoken(magictoken, {}).get('draft_formdata_id')
if draft_id:
self.autosave_draft(draft_id, page_no, form_data)
if page_no == self.page_number:
# last page has been submitted
req = get_request()
@ -543,6 +556,64 @@ class FormPage(Directory):
if form_data.get('draft_formdata_id'):
self.formdef.data_class().remove_object(form_data.get('draft_formdata_id'))
def autosave_draft(self, draft_id, page_no, form_data):
try:
formdata = self.formdef.data_class().get(draft_id)
except KeyError:
return
if not formdata.status == 'draft':
return
formdata.page_no = page_no
formdata.data = form_data
formdata.receipt_time = time.localtime()
session = get_session()
if session and session.user and not str(session.user).startswith('anonymous-'):
formdata.user_id = session.user
formdata.store()
def autosave(self):
get_response().set_content_type('application/json')
def result_error(reason):
return json.dumps({'result': 'error', 'reason': reason})
try:
page_no = int(get_request().form.get('page'))
except TypeError:
return result_error('missing page_no')
magictoken = get_request().form.get('magictoken')
if not magictoken:
return result_error('missing magictoken')
session = get_session()
if not session:
return result_error('missing session')
draft_id = session.get_by_magictoken(magictoken, {}).get('draft_formdata_id')
if not draft_id:
return result_error('missing draft id')
try:
formdata = self.formdef.data_class().get(draft_id)
except KeyError:
return result_error('missing formdata')
if not formdata.is_draft():
return result_error('formdata has already been saved')
formdata.page_no = page_no
form = self.formdef.create_form(page_no)
formdata.data.update(self.formdef.get_data(form))
formdata.receipt_time = time.localtime()
session = get_session()
if session and session.user and not str(session.user).startswith('anonymous-'):
formdata.user_id = session.user
formdata.store()
return json.dumps({'result': 'success'})
def save_draft(self, data, page_no):
filled = self.formdef.data_class()()
filled.data = data

View File

@ -3,4 +3,22 @@ $(function() {
$('fieldset.form-plus legend').on('click', function() {
$(this).parent().toggleClass('closed');
});
if ($('form[data-has-draft]').length == 1) {
var last_auto_save = $('form[data-has-draft]').serialize();
var timeout_id = window.setInterval(function() {
var new_auto_save = $('form[data-has-draft]').serialize();
if (last_auto_save == new_auto_save) return;
$.ajax({
type: 'POST',
url: window.location.pathname + 'autosave',
data: new_auto_save,
success: function(json) {
if (json.result == 'success') {
last_auto_save = new_auto_save;
}
last_auto_save = new_auto_save;
}
});
}, 5000);
}
});