forms: add dynamic source support to items field (#53763)
This commit is contained in:
parent
f278716206
commit
40e934a92c
|
@ -5,7 +5,7 @@ import json
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from webtest import Hidden
|
||||
from webtest import Checkbox, Hidden
|
||||
|
||||
from wcs import fields
|
||||
from wcs.blocks import BlockDef
|
||||
|
@ -591,6 +591,89 @@ def test_field_live_select(pub, http_requests):
|
|||
assert len(live_resp.json['result']['3']['items']) == 1
|
||||
|
||||
|
||||
def test_field_live_items_checkboxes(pub, http_requests):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'Foo'
|
||||
formdef.fields = [
|
||||
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
||||
fields.ItemsField(
|
||||
type='items',
|
||||
id='3',
|
||||
label='Foo',
|
||||
data_source={
|
||||
'type': 'json',
|
||||
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
||||
},
|
||||
),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = get_app(pub)
|
||||
resp = app.get('/foo/')
|
||||
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
||||
assert resp.html.find('div', {'data-field-id': '3'}).find('ul')
|
||||
assert not resp.html.find('div', {'data-field-id': '3'}).find('ul li')
|
||||
resp.form['f2'] = 'plop'
|
||||
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
||||
assert len(live_resp.json['result']['3']['items']) == 1
|
||||
# simulate js, add relevant checkboxes
|
||||
for option in live_resp.json['result']['3']['items']:
|
||||
checkbox_name = '%s$element%s' % (
|
||||
resp.html.find('div', {'data-field-id': '3'}).attrs['data-widget-name'],
|
||||
option['id'],
|
||||
)
|
||||
resp.form.fields[checkbox_name] = Checkbox(
|
||||
form=resp.form, name=checkbox_name, tag='input', value='yes', pos=10
|
||||
)
|
||||
resp.form.field_order.append((checkbox_name, resp.form.fields[checkbox_name]))
|
||||
resp.form.fields[checkbox_name].checked = True
|
||||
resp = resp.form.submit('submit') # -> validation
|
||||
assert resp.pyquery('.CheckboxesWidget li label').text() == 'b'
|
||||
resp = resp.form.submit('submit') # -> submitted
|
||||
assert formdef.data_class().select()[0].data['3'] == ['a']
|
||||
assert formdef.data_class().select()[0].data['3_display'] == 'b'
|
||||
|
||||
|
||||
def test_field_live_items_select_multiple(pub, http_requests):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'Foo'
|
||||
formdef.fields = [
|
||||
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'),
|
||||
fields.ItemsField(
|
||||
type='items',
|
||||
display_mode='autocomplete',
|
||||
id='3',
|
||||
label='Foo',
|
||||
data_source={
|
||||
'type': 'json',
|
||||
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}',
|
||||
},
|
||||
),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = get_app(pub)
|
||||
resp = app.get('/foo/')
|
||||
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true'
|
||||
assert resp.html.find('div', {'data-field-id': '3'}).find('select')
|
||||
assert not resp.html.find('div', {'data-field-id': '3'}).find('select option')
|
||||
resp.form['f2'] = 'plop'
|
||||
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields())
|
||||
assert len(live_resp.json['result']['3']['items']) == 1
|
||||
# simulate js, add relevant options
|
||||
resp.form['f3[]'].options = [(x['id'], False, x['text']) for x in live_resp.json['result']['3']['items']]
|
||||
resp.form['f3[]'].select_multiple(['a'])
|
||||
resp = resp.form.submit('submit') # -> validation
|
||||
assert resp.pyquery('select option[selected]').text() == 'b'
|
||||
resp = resp.form.submit('submit') # -> submitted
|
||||
assert formdef.data_class().select()[0].data['3'] == ['a']
|
||||
assert formdef.data_class().select()[0].data['3_display'] == 'b'
|
||||
|
||||
|
||||
def test_field_live_template_content(pub, http_requests):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
|
|
|
@ -2068,6 +2068,15 @@ class ItemFieldMixin:
|
|||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_extended_options(self):
|
||||
if self.data_source:
|
||||
return data_sources.get_structured_items(
|
||||
self.data_source, mode='lazy', include_disabled=self.display_disabled_items
|
||||
)
|
||||
if self.items:
|
||||
return [{'id': x, 'text': x} for x in self.items]
|
||||
return []
|
||||
|
||||
|
||||
class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin):
|
||||
key = 'item'
|
||||
|
@ -2128,15 +2137,6 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin):
|
|||
return data_sources.get_id_by_option_text(self.data_source, text_value)
|
||||
return text_value
|
||||
|
||||
def get_extended_options(self):
|
||||
if self.data_source:
|
||||
return data_sources.get_structured_items(
|
||||
self.data_source, mode='lazy', include_disabled=self.display_disabled_items
|
||||
)
|
||||
if self.items:
|
||||
return [{'id': x, 'text': x} for x in self.items]
|
||||
return []
|
||||
|
||||
def get_display_mode(self, data_source=None):
|
||||
if not data_source:
|
||||
data_source = data_sources.get_object(self.data_source)
|
||||
|
|
|
@ -967,7 +967,7 @@ class FormDef(StorableObject):
|
|||
if varname not in live_condition_fields:
|
||||
live_condition_fields[varname] = []
|
||||
live_condition_fields[varname].append(field)
|
||||
if field.key == 'item' and field.data_source:
|
||||
if field.key in ('item', 'items') and field.data_source:
|
||||
data_source = data_sources.get_object(field.data_source)
|
||||
if data_source.type not in ('json', 'geojson') and not data_source.type.startswith(
|
||||
'carddef:'
|
||||
|
|
|
@ -785,7 +785,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
break
|
||||
|
||||
for field in displayed_fields:
|
||||
if field.key == 'item' and field.data_source:
|
||||
if field.key in ('item', 'items') and field.data_source:
|
||||
data_source = data_sources.get_object(field.data_source)
|
||||
if data_source.type not in ('json', 'geojson') and not data_source.type.startswith(
|
||||
'carddef:'
|
||||
|
@ -793,7 +793,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
continue
|
||||
varnames = data_source.get_referenced_varnames(field.formdef)
|
||||
if (not modified_field_varnames or modified_field_varnames.intersection(varnames)) and (
|
||||
field.display_mode == 'autocomplete' and data_source.can_jsonp()
|
||||
field.display_mode == 'autocomplete' and data_source.can_jsonp() and field.type != 'items'
|
||||
):
|
||||
# computed earlier, in perform_more_widget_changes, when the field
|
||||
# was added to the form
|
||||
|
|
|
@ -514,6 +514,35 @@ $(function() {
|
|||
$label.appendTo($content);
|
||||
}
|
||||
$hint.appendTo($content);
|
||||
} else if (value.items && $widget.is('.CheckboxesWidget')) {
|
||||
var widget_name = $widget.data('widget-name');
|
||||
var $ul = $widget.find('ul');
|
||||
var current_value = $ul.find('input[type=checkbox]'
|
||||
).filter(function() {return this.checked}
|
||||
).map(function() {return this.name;}
|
||||
).toArray();
|
||||
var base_for_name = $ul.data('base-for-name');
|
||||
var input_name = $widget.data('widget-name');
|
||||
$ul.empty();
|
||||
for (var i=0; i<value.items.length; i++) {
|
||||
var $li = $('<li>');
|
||||
var $label = $('<label>', {'for': base_for_name + i});
|
||||
var $input = $('<input>', {
|
||||
type: 'checkbox', 'id': base_for_name + i,
|
||||
value: 'yes', name: widget_name + '$element' + value.items[i].id});
|
||||
if (current_value.indexOf(widget_name + '$element' + value.items[i].id) != -1) {
|
||||
$input.attr('checked', 'checked');
|
||||
}
|
||||
if (value.items[i].disabled) {
|
||||
$input.prop('disabled', true);
|
||||
$li.addClass('disabled');
|
||||
}
|
||||
var $span = $('<span>', {text: value.items[i].text});
|
||||
$input.appendTo($label);
|
||||
$span.appendTo($label);
|
||||
$label.appendTo($li);
|
||||
$li.appendTo($ul);
|
||||
}
|
||||
} else if (value.items) {
|
||||
// replace <select> contents
|
||||
var $select = $widget.find('select');
|
||||
|
@ -527,7 +556,8 @@ $(function() {
|
|||
}
|
||||
for (var i=0; i<value.items.length; i++) {
|
||||
var $option = $('<option></option>', {value: value.items[i].id, text: value.items[i].text});
|
||||
if (value.items[i].id == current_value) {
|
||||
if ((Array.isArray(current_value) && current_value.indexOf(value.items[i].id.toString()) != -1) ||
|
||||
value.items[i].id == current_value) {
|
||||
$option.attr('selected', 'selected');
|
||||
value.items[i].selected = true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "qommon/forms/widget.html" %}
|
||||
|
||||
{% block widget-control %}
|
||||
<ul {% if widget.inline %}class="inline"{% endif %}>
|
||||
<ul {% if widget.inline %}class="inline"{% endif %} data-base-for-name="{{ widget.get_name_for_id }}_op_">
|
||||
{% for option in widget.get_options %}
|
||||
<li {% if option.disabled %}class="disabled"{% endif %}><label for="{{ widget.get_name_for_id }}_op_{{ forloop.counter0 }}"><input
|
||||
id="{{ widget.get_name_for_id }}_op_{{ forloop.counter0 }}"
|
||||
|
|
Loading…
Reference in New Issue