forms: allow clicking back to any previous page (#11249) #1115
|
@ -1282,7 +1282,7 @@ def test_form_multi_page_page_name_as_title(pub):
|
|||
next_page = next_page.forms[0].submit('submit')
|
||||
assert_current_page(next_page, 'Validating')
|
||||
assert 'Check values then click submit.' in next_page.text
|
||||
assert next_page.text.count('1st page') == 2 # in steps and in main body
|
||||
assert next_page.text.count('1st page') == 3 # in steps (twice) and in main body
|
||||
|
||||
# add a comment that will not be displayed and should therefore not be
|
||||
# considered.
|
||||
|
@ -1305,7 +1305,48 @@ def test_form_multi_page_page_name_as_title(pub):
|
|||
next_page = next_page.forms[0].submit('submit')
|
||||
assert_current_page(next_page, 'Validating')
|
||||
assert 'Check values then click submit.' in next_page.text
|
||||
assert next_page.text.count('1st page') == 2 # in steps and in main body
|
||||
assert next_page.text.count('1st page') == 3 # in steps (twice) and in main body
|
||||
|
||||
|
||||
def test_form_multi_page_go_back(pub):
|
||||
formdef = create_formdef()
|
||||
formdef.fields = [
|
||||
fields.PageField(id='0', label='1st page'),
|
||||
fields.StringField(id='1', label='string'),
|
||||
fields.PageField(id='2', label='2nd page'),
|
||||
fields.PageField(id='3', label='3rd page'),
|
||||
fields.StringField(id='4', label='string 2'),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
resp.forms[0]['f1'] = 'foo'
|
||||
resp = resp.forms[0].submit('submit') # -> 2nd page
|
||||
assert_current_page(resp, '2nd page')
|
||||
resp = resp.forms[0].submit('submit') # -> 3rd page
|
||||
assert_current_page(resp, '3rd page')
|
||||
resp.forms[0]['f4'] = 'foo'
|
||||
resp = resp.forms[0].submit('submit') # -> validation page
|
||||
assert_current_page(resp, 'Validating')
|
||||
|
||||
# go back to second page (javascript would set this)
|
||||
resp.forms[0]['previous-page-id'] = '2'
|
||||
resp = resp.forms[0].submit('previous')
|
||||
assert_current_page(resp, '2nd page')
|
||||
resp = resp.forms[0].submit('submit') # -> 3rd page
|
||||
|
||||
# go back to first page (javascript would set this)
|
||||
resp.forms[0]['previous-page-id'] = '0'
|
||||
resp = resp.forms[0].submit('previous')
|
||||
assert_current_page(resp, '1st page')
|
||||
resp = resp.forms[0].submit('submit') # -> 2nd page
|
||||
resp = resp.forms[0].submit('submit') # -> 3rd page
|
||||
|
||||
# go back to invalid page (javascript would not set this)
|
||||
resp.forms[0]['previous-page-id'] = '10'
|
||||
resp = resp.forms[0].submit('previous')
|
||||
assert_current_page(resp, '1st page') # fallback to first page
|
||||
|
||||
|
||||
def test_form_submit_with_user(pub, emails):
|
||||
|
|
|
@ -422,6 +422,7 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
'current_page_index': current_position,
|
||||
'current_page_no': current_position, # legacy, for themes
|
||||
'page_labels': page_labels,
|
||||
'pages': self.pages,
|
||||
}
|
||||
|
||||
def step(self):
|
||||
|
@ -1013,6 +1014,7 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
# if there's a form with a single page (at all, not as the result of conditions),
|
||||
# and no confirmation page, add native quixote CSRF protection.
|
||||
form.add(FormTokenWidget, form.TOKEN_NAME)
|
||||
form.add_hidden('previous-page-id', '')
|
||||
form.attrs['data-live-url'] = self.formdef.get_url(language=get_publisher().current_language) + 'live'
|
||||
form.attrs['data-live-validation-url'] = (
|
||||
self.formdef.get_url(language=get_publisher().current_language) + 'live-validation'
|
||||
|
@ -1027,7 +1029,9 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
return form
|
||||
|
||||
def create_view_form(self, *args, **kwargs):
|
||||
return self.formdef.create_view_form(*args, **kwargs)
|
||||
form = self.formdef.create_view_form(*args, **kwargs)
|
||||
form.add_hidden('previous-page-id', '')
|
||||
return form
|
||||
|
||||
def check_authentication_context(self):
|
||||
if not self.formdef.required_authentication_contexts:
|
||||
|
@ -1595,8 +1599,14 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
|
||||
def previous_page(self, page_no, magictoken):
|
||||
try:
|
||||
new_page_no = page_no - 1
|
||||
previous_page = self.pages[new_page_no]
|
||||
previous_page_id = get_request().form.get('previous-page-id')
|
||||
if previous_page_id:
|
||||
new_page_no, previous_page = [
|
||||
x for x in enumerate(self.pages[:page_no]) if x[1].id == previous_page_id
|
||||
][0]
|
||||
else:
|
||||
new_page_no = page_no - 1
|
||||
previous_page = self.pages[new_page_no]
|
||||
except IndexError:
|
||||
new_page_no = 0
|
||||
previous_page = self.pages[0]
|
||||
|
|
|
@ -1083,3 +1083,20 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||
initLiveValidation(blockWidgets)
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
const previous_page_id_input = document.querySelector('[name="previous-page-id"]')
|
||||
if (!previous_page_id_input) return
|
||||
fpeters
commented
Pour la navigation au clavier, s'il y a enter ou un espace on remplit l' Pour la navigation au clavier, s'il y a enter ou un espace on remplit l'`<input type=hidden>` et on "click" sur le bouton précédent.
|
||||
document.querySelectorAll('.wcs-step[data-page-id]').forEach((step, idx) => {
|
||||
step.addEventListener('keydown', function(e) {
|
||||
if (e.key !== "Enter" && e.key !== " ") return
|
||||
e.preventDefault()
|
||||
fpeters
commented
Même chose sur un clic. Même chose sur un clic.
|
||||
previous_page_id_input.value = step.dataset.pageId
|
||||
document.querySelector('button[name="previous"]').dispatchEvent(new MouseEvent('click'))
|
||||
})
|
||||
step.addEventListener('click', function() {
|
||||
previous_page_id_input.value = step.dataset.pageId
|
||||
document.querySelector('button[name="previous"]').dispatchEvent(new MouseEvent('click'))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
{% if forloop.last %}last{% endif %}
|
||||
{% if forloop.counter == current_page_no %}current{% endif %}
|
||||
{% if forloop.counter < current_page_no %}step-before{% endif %}
|
||||
{% if forloop.counter > current_page_no %}step-after{% endif %}" >
|
||||
{% if forloop.counter > current_page_no %}step-after{% endif %}"
|
||||
{% if forloop.counter < current_page_no %}
|
||||
aria-label="{% blocktrans with page_label=page_label %}Go back to step: {{ page_label }}{% endblocktrans %}"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
fpeters
commented
Avec le js plus haut, ces attributs assurent normalement tout le nécessaire pour l'accessibilité au clavier. Avec le js plus haut, ces attributs assurent normalement tout le nécessaire pour l'accessibilité au clavier.
|
||||
data-page-id="{% with page=pages|get:forloop.counter0 %}{{ page.id }}{% endwith %}"
|
||||
{% endif %}
|
||||
>
|
||||
<abbr
|
||||
aria-label="{% blocktrans with page_no=forloop.counter page_count=page_labels|length %}Step {{ page_no }} of {{ page_count }}:{% endblocktrans %}"
|
||||
title="{% blocktrans with page_no=forloop.counter page_count=page_labels|length %}Step {{ page_no }} of {{ page_count }}{% endblocktrans %}"
|
||||
|
|
Loading…
Reference in New Issue
S'il n'y a pas l'
<input type=hidden>
on ne fait rien, ça permettrait d'ajouter un feature flag pour désactiver ça, mais pour le moment ça me va de faire ça sans feature flag.