0001-forms-add-dynamic-source-support-to-items-field-5376.patch
tests/form_pages/test_live.py | ||
---|---|---|
5 | 5 |
from unittest import mock |
6 | 6 | |
7 | 7 |
import pytest |
8 |
from webtest import Hidden |
|
8 |
from webtest import Checkbox, Hidden
|
|
9 | 9 | |
10 | 10 |
from wcs import fields |
11 | 11 |
from wcs.blocks import BlockDef |
... | ... | |
591 | 591 |
assert len(live_resp.json['result']['3']['items']) == 1 |
592 | 592 | |
593 | 593 | |
594 |
def test_field_live_items_checkboxes(pub, http_requests): |
|
595 |
FormDef.wipe() |
|
596 |
formdef = FormDef() |
|
597 |
formdef.name = 'Foo' |
|
598 |
formdef.fields = [ |
|
599 |
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'), |
|
600 |
fields.ItemsField( |
|
601 |
type='items', |
|
602 |
id='3', |
|
603 |
label='Foo', |
|
604 |
data_source={ |
|
605 |
'type': 'json', |
|
606 |
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}', |
|
607 |
}, |
|
608 |
), |
|
609 |
] |
|
610 |
formdef.store() |
|
611 |
formdef.data_class().wipe() |
|
612 | ||
613 |
app = get_app(pub) |
|
614 |
resp = app.get('/foo/') |
|
615 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true' |
|
616 |
assert resp.html.find('div', {'data-field-id': '3'}).find('ul') |
|
617 |
assert not resp.html.find('div', {'data-field-id': '3'}).find('ul li') |
|
618 |
resp.form['f2'] = 'plop' |
|
619 |
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields()) |
|
620 |
assert len(live_resp.json['result']['3']['items']) == 1 |
|
621 |
# simulate js, add relevant checkboxes |
|
622 |
for option in live_resp.json['result']['3']['items']: |
|
623 |
checkbox_name = '%s$element%s' % ( |
|
624 |
resp.html.find('div', {'data-field-id': '3'}).attrs['data-widget-name'], |
|
625 |
option['id'], |
|
626 |
) |
|
627 |
resp.form.fields[checkbox_name] = Checkbox( |
|
628 |
form=resp.form, name=checkbox_name, tag='input', value='yes', pos=10 |
|
629 |
) |
|
630 |
resp.form.field_order.append((checkbox_name, resp.form.fields[checkbox_name])) |
|
631 |
resp.form.fields[checkbox_name].checked = True |
|
632 |
resp = resp.form.submit('submit') # -> validation |
|
633 |
assert resp.pyquery('.CheckboxesWidget li label').text() == 'b' |
|
634 |
resp = resp.form.submit('submit') # -> submitted |
|
635 |
assert formdef.data_class().select()[0].data['3'] == ['a'] |
|
636 |
assert formdef.data_class().select()[0].data['3_display'] == 'b' |
|
637 | ||
638 | ||
639 |
def test_field_live_items_select_multiple(pub, http_requests): |
|
640 |
FormDef.wipe() |
|
641 |
formdef = FormDef() |
|
642 |
formdef.name = 'Foo' |
|
643 |
formdef.fields = [ |
|
644 |
fields.StringField(type='string', id='2', label='Bar2', size='40', required=True, varname='bar2'), |
|
645 |
fields.ItemsField( |
|
646 |
type='items', |
|
647 |
display_mode='autocomplete', |
|
648 |
id='3', |
|
649 |
label='Foo', |
|
650 |
data_source={ |
|
651 |
'type': 'json', |
|
652 |
'value': '{% if form_var_bar2 %}http://remote.example.net/json-list?plop={{form_var_bar2}}{% endif %}', |
|
653 |
}, |
|
654 |
), |
|
655 |
] |
|
656 |
formdef.store() |
|
657 |
formdef.data_class().wipe() |
|
658 | ||
659 |
app = get_app(pub) |
|
660 |
resp = app.get('/foo/') |
|
661 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs['data-live-source'] == 'true' |
|
662 |
assert resp.html.find('div', {'data-field-id': '3'}).find('select') |
|
663 |
assert not resp.html.find('div', {'data-field-id': '3'}).find('select option') |
|
664 |
resp.form['f2'] = 'plop' |
|
665 |
live_resp = app.post('/foo/live?modified_field_id=2', params=resp.form.submit_fields()) |
|
666 |
assert len(live_resp.json['result']['3']['items']) == 1 |
|
667 |
# simulate js, add relevant options |
|
668 |
resp.form['f3[]'].options = [(x['id'], False, x['text']) for x in live_resp.json['result']['3']['items']] |
|
669 |
resp.form['f3[]'].select_multiple(['a']) |
|
670 |
resp = resp.form.submit('submit') # -> validation |
|
671 |
assert resp.pyquery('select option[selected]').text() == 'b' |
|
672 |
resp = resp.form.submit('submit') # -> submitted |
|
673 |
assert formdef.data_class().select()[0].data['3'] == ['a'] |
|
674 |
assert formdef.data_class().select()[0].data['3_display'] == 'b' |
|
675 | ||
676 | ||
594 | 677 |
def test_field_live_template_content(pub, http_requests): |
595 | 678 |
FormDef.wipe() |
596 | 679 |
formdef = FormDef() |
wcs/fields.py | ||
---|---|---|
2066 | 2066 |
except KeyError: |
2067 | 2067 |
return None |
2068 | 2068 | |
2069 |
def get_extended_options(self): |
|
2070 |
if self.data_source: |
|
2071 |
return data_sources.get_structured_items( |
|
2072 |
self.data_source, mode='lazy', include_disabled=self.display_disabled_items |
|
2073 |
) |
|
2074 |
if self.items: |
|
2075 |
return [{'id': x, 'text': x} for x in self.items] |
|
2076 |
return [] |
|
2077 | ||
2069 | 2078 | |
2070 | 2079 |
class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin): |
2071 | 2080 |
key = 'item' |
... | ... | |
2126 | 2135 |
return data_sources.get_id_by_option_text(self.data_source, text_value) |
2127 | 2136 |
return text_value |
2128 | 2137 | |
2129 |
def get_extended_options(self): |
|
2130 |
if self.data_source: |
|
2131 |
return data_sources.get_structured_items( |
|
2132 |
self.data_source, mode='lazy', include_disabled=self.display_disabled_items |
|
2133 |
) |
|
2134 |
if self.items: |
|
2135 |
return [{'id': x, 'text': x} for x in self.items] |
|
2136 |
return [] |
|
2137 | ||
2138 | 2138 |
def get_display_mode(self, data_source=None): |
2139 | 2139 |
if not data_source: |
2140 | 2140 |
data_source = data_sources.get_object(self.data_source) |
wcs/formdef.py | ||
---|---|---|
967 | 967 |
if varname not in live_condition_fields: |
968 | 968 |
live_condition_fields[varname] = [] |
969 | 969 |
live_condition_fields[varname].append(field) |
970 |
if field.key == 'item' and field.data_source:
|
|
970 |
if field.key in ('item', 'items') and field.data_source:
|
|
971 | 971 |
data_source = data_sources.get_object(field.data_source) |
972 | 972 |
if data_source.type not in ('json', 'geojson') and not data_source.type.startswith( |
973 | 973 |
'carddef:' |
wcs/forms/common.py | ||
---|---|---|
785 | 785 |
break |
786 | 786 | |
787 | 787 |
for field in displayed_fields: |
788 |
if field.key == 'item' and field.data_source:
|
|
788 |
if field.key in ('item', 'items') and field.data_source:
|
|
789 | 789 |
data_source = data_sources.get_object(field.data_source) |
790 | 790 |
if data_source.type not in ('json', 'geojson') and not data_source.type.startswith( |
791 | 791 |
'carddef:' |
... | ... | |
793 | 793 |
continue |
794 | 794 |
varnames = data_source.get_referenced_varnames(field.formdef) |
795 | 795 |
if (not modified_field_varnames or modified_field_varnames.intersection(varnames)) and ( |
796 |
field.display_mode == 'autocomplete' and data_source.can_jsonp() |
|
796 |
field.display_mode == 'autocomplete' and data_source.can_jsonp() and field.type != 'items'
|
|
797 | 797 |
): |
798 | 798 |
# computed earlier, in perform_more_widget_changes, when the field |
799 | 799 |
# was added to the form |
wcs/qommon/static/js/qommon.forms.js | ||
---|---|---|
514 | 514 |
$label.appendTo($content); |
515 | 515 |
} |
516 | 516 |
$hint.appendTo($content); |
517 |
} else if (value.items && $widget.is('.CheckboxesWidget')) { |
|
518 |
var widget_name = $widget.data('widget-name'); |
|
519 |
var $ul = $widget.find('ul'); |
|
520 |
var current_value = $ul.find('input[type=checkbox]' |
|
521 |
).filter(function() {return this.checked} |
|
522 |
).map(function() {return this.name;} |
|
523 |
).toArray(); |
|
524 |
var base_for_name = $ul.data('base-for-name'); |
|
525 |
var input_name = $widget.data('widget-name'); |
|
526 |
$ul.empty(); |
|
527 |
for (var i=0; i<value.items.length; i++) { |
|
528 |
var $li = $('<li>'); |
|
529 |
var $label = $('<label>', {'for': base_for_name + i}); |
|
530 |
var $input = $('<input>', { |
|
531 |
type: 'checkbox', 'id': base_for_name + i, |
|
532 |
value: 'yes', name: widget_name + '$element' + value.items[i].id}); |
|
533 |
if (current_value.indexOf(widget_name + '$element' + value.items[i].id) != -1) { |
|
534 |
$input.attr('checked', 'checked'); |
|
535 |
} |
|
536 |
if (value.items[i].disabled) { |
|
537 |
$input.prop('disabled', true); |
|
538 |
$li.addClass('disabled'); |
|
539 |
} |
|
540 |
var $span = $('<span>', {text: value.items[i].text}); |
|
541 |
$input.appendTo($label); |
|
542 |
$span.appendTo($label); |
|
543 |
$label.appendTo($li); |
|
544 |
$li.appendTo($ul); |
|
545 |
} |
|
517 | 546 |
} else if (value.items) { |
518 | 547 |
// replace <select> contents |
519 | 548 |
var $select = $widget.find('select'); |
... | ... | |
527 | 556 |
} |
528 | 557 |
for (var i=0; i<value.items.length; i++) { |
529 | 558 |
var $option = $('<option></option>', {value: value.items[i].id, text: value.items[i].text}); |
530 |
if (value.items[i].id == current_value) { |
|
559 |
if ((Array.isArray(current_value) && current_value.indexOf(value.items[i].id.toString()) != -1) || |
|
560 |
value.items[i].id == current_value) { |
|
531 | 561 |
$option.attr('selected', 'selected'); |
532 | 562 |
value.items[i].selected = true; |
533 | 563 |
} |
wcs/qommon/templates/qommon/forms/widgets/checkboxes.html | ||
---|---|---|
1 | 1 |
{% extends "qommon/forms/widget.html" %} |
2 | 2 | |
3 | 3 |
{% block widget-control %} |
4 |
<ul {% if widget.inline %}class="inline"{% endif %}> |
|
4 |
<ul {% if widget.inline %}class="inline"{% endif %} data-base-for-name="{{ widget.get_name_for_id }}_op_">
|
|
5 | 5 |
{% for option in widget.get_options %} |
6 | 6 |
<li {% if option.disabled %}class="disabled"{% endif %}><label for="{{ widget.get_name_for_id }}_op_{{ forloop.counter0 }}"><input |
7 | 7 |
id="{{ widget.get_name_for_id }}_op_{{ forloop.counter0 }}" |
8 |
- |