form: extend widget list to compute list of children and new options (#.....)
gitea-wip/wcs/pipeline/head Build started... Details
gitea/wcs/pipeline/head Build started... Details

This commit is contained in:
Frédéric Péters 2020-06-01 22:19:14 +02:00
parent e3c1d71d64
commit 8cb4429eca
5 changed files with 74 additions and 24 deletions

View File

@ -2730,6 +2730,7 @@ def test_workflows_edit_dispatch_action(pub):
resp = resp.click('Function/Role Linking')
assert resp.form['rules$element0$value'].value == 'FOOBAR'
resp = resp.form.submit('rules$add_element') # add one
resp.form['rules$element1$value'].value = 'BARFOO'
resp.form['rules$element1$role_id'].value = str(role.id)
resp = resp.form.submit('submit')
@ -2818,6 +2819,7 @@ def test_workflows_edit_email_action(pub):
assert "Attachments (Python expressions)" not in resp.text
assert resp.form['attachments$element0$choice'].value == 'form_var_upload_raw'
assert len(resp.form['attachments$element0$choice'].options) == 5
resp = resp.form.submit('attachments$add_element') # add one
resp.form['attachments$element1$choice'] = 'form_var_upload2_raw'
resp = resp.form.submit('submit')
assert resp.location
@ -2825,6 +2827,7 @@ def test_workflows_edit_email_action(pub):
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw']
resp = app.get(item_url)
resp = resp.form.submit('attachments$add_element') # add one
resp.form['attachments$element2$choice'] = 'form_fbo3_3x'
resp = resp.form.submit('submit')
assert resp.location
@ -2832,6 +2835,7 @@ def test_workflows_edit_email_action(pub):
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3_3x']
resp = app.get(item_url)
resp = resp.form.submit('attachments$add_element') # add one
resp.form['attachments$element3$choice'] = '__other'
resp.form['attachments$element3$other'] = '{"content":"foo", "filename":"bar.txt"}'
resp = resp.form.submit('submit')
@ -3548,6 +3552,7 @@ def test_workflows_global_actions_edit(pub):
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id,
index=0)
assert resp.form['roles$element0'].value == '_receiver'
resp = resp.form.submit('roles$add_element')
resp.form['roles$element1'].value = '_submitter'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).global_actions[0].triggers[0].roles == [
@ -4027,7 +4032,7 @@ def test_users_edit_with_managing_idp(pub):
assert '>Manage Roles<' in resp.text
resp = resp.click(href='edit')
assert not 'email' in resp.form.fields
assert 'roles$added_elements' in resp.form.fields
assert 'roles$add_element' in resp.form.fields
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
@ -4035,7 +4040,7 @@ def test_users_edit_with_managing_idp(pub):
assert '>Edit<' in resp.text
resp = resp.click(href='edit')
assert 'email' in resp.form.fields
assert not 'roles$added_elements' in resp.form.fields
assert 'roles$add_element' not in resp.form.fields
pub.cfg['sp'] = {'idp-manage-roles': True, 'idp-manage-user-attributes': True}
pub.write_cfg()

View File

@ -3304,10 +3304,12 @@ def test_form_table_rows_add_row(pub):
formdef.data_class().wipe()
resp = get_app(pub).get('/test/')
assert resp.form['f0$added_elements'].value == '5'
assert len(resp.pyquery.find('input[name^="f0$element"]')) == 10
resp = resp.form.submit('f0$add_element')
assert resp.form['f0$added_elements'].value == '6'
assert 'There were errors processing the form' not in resp
assert len(resp.pyquery.find('input[name^="f0$element"]')) == 12
resp = resp.form.submit('f0$add_element')
assert len(resp.pyquery.find('input[name^="f0$element"]')) == 14
resp = resp.form.submit('submit')
assert 'There were errors processing the form' in resp

View File

@ -1436,15 +1436,50 @@ class WidgetList(quixote.form.widget.WidgetList):
def __init__(self, name, value=None,
element_type=StringWidget,
element_kwargs={},
add_element_label="Add row", **kwargs):
add_element_label="Add row",
max_items=None,
**kwargs):
if add_element_label == 'Add row':
add_element_label = _('Add row')
super(WidgetList, self).__init__(name, value=value,
element_type=element_type,
element_kwargs=element_kwargs,
add_element_label=add_element_label, **kwargs)
CompositeWidget.__init__(self, name, value=value, **kwargs)
self.element_type = element_type
self.element_kwargs = element_kwargs
self.element_names = []
# Add element widgets for initial value
if value is not None:
for element_value in value:
self.add_element(value=element_value)
if not self.element_names:
# Add at least an element widget
self.add_element()
if not kwargs.get('readonly'):
# add element widgets to match submitted list
prefix = '%s$element' % self.name
if get_request().form:
known_prefixes = {x.split('$', 2)[1] for x in get_request().form.keys() if x.startswith(prefix)}
for i in range(len(known_prefixes) - len(self.element_names)):
self.add_element()
current_len = len(self.element_names)
if (not max_items) or current_len < max_items:
# Add submit to add more element widgets
self.add(SubmitWidget, 'add_element', value=add_element_label,
render_br=False, extra_css_class='list-add')
if self.get('add_element'):
self.add_element()
current_len = len(self.element_names)
if max_items and current_len >= max_items:
self.widgets.remove(self.get_widget('add_element'))
del self._names['add_element']
def add_element(self, value=None):
name = "element%d" % len(self.element_names)
self.add(self.element_type, name, value=value, **self.element_kwargs)
self.element_names.append(name)
def add_media(self):
get_response().add_javascript(['jquery.js', 'widget_list.js'])
@ -1453,19 +1488,32 @@ class WidgetList(quixote.form.widget.WidgetList):
for widget in self.get_widgets():
widget.transfer_form_value(request)
def set_value(self, value):
for i in range(len(value) - len(self.element_names)):
self.add_element()
for element_name, subvalue in zip(self.element_names, value):
self.get_widget(element_name).set_value(subvalue)
def render(self):
return render(self)
def render_content(self):
r = TemplateIO(html=True)
add_element_widget = self.get_widget('add_element')
add_element_widget.render_br = False
add_element_widget.extra_css_class = 'list-add'
clear_errors = False
if self.value is None and self.required:
# if there's no value and it's marked required, there won't be
# values in subwidgets either, clear them instead of filling the
# screen with "required field" messages.
clear_errors = True
for widget in self.get_widgets():
if widget is add_element_widget:
continue
if clear_errors:
widget.clear_error()
r += widget.render()
r += add_element_widget.render()
if add_element_widget:
r += add_element_widget.render()
return r.getvalue()
@ -1762,22 +1810,23 @@ class WidgetListAsTable(WidgetList):
def render_content(self):
r = TemplateIO(html=True)
add_element_widget = self.get_widget('add_element')
add_element_widget.render_br = False
add_element_widget.extra_css_class = 'list-add'
if add_element_widget:
add_element_widget.render_br = False
add_element_widget.extra_css_class = 'list-add'
for widget in self.get_widgets():
if widget is add_element_widget:
continue
if not hasattr(widget, 'render_content_as_tr'):
r += widget.render()
r += htmltext('<table>')
r += self.get_widgets()[1].render_as_thead()
r += self.get_widgets()[0].render_as_thead()
for widget in self.get_widgets():
if widget is add_element_widget:
continue
if hasattr(widget, 'render_content_as_tr'):
r += widget.render_content_as_tr()
r += htmltext('</table>')
if not self.readonly:
if add_element_widget and not self.readonly:
r += add_element_widget.render()
return r.getvalue()
@ -1804,7 +1853,6 @@ class TableListRowsWidget(WidgetListAsTable):
name = "element%d" % len(self.element_names)
self.add(self.table_row_class, name, value=value, **self.widget_kwargs)
self.element_names.append(name)
self.get_widget('added_elements').value = len(self.element_names)
def __init__(self, name, value=None, columns=None, min_rows=5, **kwargs):
self.table_row_class = self.create_row_class(columns)

View File

@ -48,11 +48,6 @@ function prepare_widget_list_elements() {
/* trigger advanced widget setup */
$(document).trigger('wcs:new-widgets-on-page');
/* increase hidden $added_elements value */
var hidden = $($(this).parents('div').parents('div')[0]).prevAll(
'input[type=hidden]')[0];
$(hidden).attr('value', parseInt($(hidden).attr('value'))+1);
return false;
}
);

View File

@ -254,13 +254,13 @@ class CreateFormdataWorkflowStatusItem(WorkflowStatusItem):
formdef_slug = form.get('%sformdef_slug' % prefix)
formdef = self._resolve_formdef_slug(formdef_slug)
if 'mappings' in parameters and formdef:
form.add(MappingsWidget, '%smappings' % prefix,
widget = form.add(MappingsWidget, '%smappings' % prefix,
title=_(self.mappings_label),
to_formdef=formdef,
value=self.mappings)
if form.is_submitted():
# do not validate form if formdef is changed and there is no mappings
if formdef_slug != self.formdef_slug and '%smappings$added_elements' % prefix not in get_request().form:
if formdef_slug != self.formdef_slug and not widget.parse():
form.get_widget('%smappings' % prefix).set_error(_('Please define new mappings'))
if 'varname' in parameters:
form.add(VarnameWidget, '%svarname' % prefix,