0001-fields-make-it-possible-to-include-disabled-items-in.patch
tests/test_datasource.py | ||
---|---|---|
58 | 58 |
def test_python_datasource(): |
59 | 59 |
plain_list = [('1', 'foo'), ('2', 'bar')] |
60 | 60 |
datasource = {'type': 'formula', 'value': repr(plain_list)} |
61 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
61 |
assert data_sources.get_items(datasource) == [ |
|
62 |
('1', 'foo', '1', {'id': '1', 'text': 'foo'}), |
|
63 |
('2', 'bar', '2', {'id': '2', 'text': 'bar'})] |
|
62 | 64 |
assert data_sources.get_structured_items(datasource) == [ |
63 | 65 |
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}] |
64 | 66 | |
... | ... | |
73 | 75 |
# three-item tuples |
74 | 76 |
plain_list = [('1', 'foo', 'a'), ('2', 'bar', 'b')] |
75 | 77 |
datasource = {'type': 'formula', 'value': repr(plain_list)} |
76 |
assert data_sources.get_items(datasource) == [('1', 'foo', 'a'), ('2', 'bar', 'b')] |
|
78 |
assert data_sources.get_items(datasource) == [ |
|
79 |
('1', 'foo', 'a', {'id': '1', 'key': 'a', 'text': 'foo'}), |
|
80 |
('2', 'bar', 'b', {'id': '2', 'key': 'b', 'text': 'bar'})] |
|
77 | 81 | |
78 | 82 |
# single-item tuples |
79 | 83 |
plain_list = [('foo', ), ('bar', )] |
80 | 84 |
datasource = {'type': 'formula', 'value': repr(plain_list)} |
81 |
assert data_sources.get_items(datasource) == [('foo', 'foo', 'foo'), ('bar', 'bar', 'bar')] |
|
85 |
assert data_sources.get_items(datasource) == [ |
|
86 |
('foo', 'foo', 'foo', {'id': 'foo', 'text': 'foo'}), |
|
87 |
('bar', 'bar', 'bar', {'id': 'bar', 'text': 'bar'})] |
|
82 | 88 | |
83 | 89 |
# list of strings |
84 | 90 |
plain_list = ['foo', 'bar'] |
85 | 91 |
datasource = {'type': 'formula', 'value': repr(plain_list)} |
86 |
assert data_sources.get_items(datasource) == [('foo', 'foo', 'foo'), ('bar', 'bar', 'bar')] |
|
92 |
assert data_sources.get_items(datasource) == [ |
|
93 |
('foo', 'foo', 'foo', {'id': 'foo', 'text': 'foo'}), |
|
94 |
('bar', 'bar', 'bar', {'id': 'bar', 'text': 'bar'})] |
|
87 | 95 | |
88 | 96 |
def test_json_datasource(): |
89 | 97 |
datasource = {'type': 'json', 'value': ''} |
... | ... | |
122 | 130 |
json_file = open(json_file_path, 'w') |
123 | 131 |
json.dump({'data': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]}, json_file) |
124 | 132 |
json_file.close() |
125 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
133 |
assert data_sources.get_items(datasource) == [ |
|
134 |
('1', 'foo', '1', {'id': '1', 'text': 'foo'}), |
|
135 |
('2', 'bar', '2', {'id': '2', 'text': 'bar'})] |
|
126 | 136 |
assert data_sources.get_structured_items(datasource) == [ |
127 | 137 |
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}] |
128 | 138 | |
... | ... | |
131 | 141 |
json.dump({'data': [{'id': '1', 'text': 'foo', 'more': 'xxx'}, |
132 | 142 |
{'id': '2', 'text': 'bar', 'more': 'yyy'}]}, json_file) |
133 | 143 |
json_file.close() |
134 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
144 |
assert data_sources.get_items(datasource) == [ |
|
145 |
('1', 'foo', '1', {'id': '1', 'text': 'foo', 'more': 'xxx'}), |
|
146 |
('2', 'bar', '2', {'id': '2', 'text': 'bar', 'more': 'yyy'})] |
|
135 | 147 |
assert data_sources.get_structured_items(datasource) == [ |
136 | 148 |
{'id': '1', 'text': 'foo', 'more': 'xxx'}, |
137 | 149 |
{'id': '2', 'text': 'bar', 'more': 'yyy'}] |
... | ... | |
142 | 154 |
return {'json_url': 'file://%s' % json_file_path} |
143 | 155 |
pub.substitutions.feed(JsonUrlPath()) |
144 | 156 |
datasource = {'type': 'json', 'value': '[json_url]'} |
145 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
157 |
assert data_sources.get_items(datasource) == [ |
|
158 |
('1', 'foo', '1', {'id': '1', 'text': 'foo', 'more': 'xxx'}), |
|
159 |
('2', 'bar', '2', {'id': '2', 'text': 'bar', 'more': 'yyy'})] |
|
146 | 160 | |
147 | 161 |
# a json file with integer as 'id' |
148 | 162 |
json_file = open(json_file_path, 'w') |
149 | 163 |
json.dump({'data': [{'id': 1, 'text': 'foo'}, {'id': 2, 'text': 'bar'}]}, json_file) |
150 | 164 |
json_file.close() |
151 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
165 |
assert data_sources.get_items(datasource) == [ |
|
166 |
('1', 'foo', '1', {'id': 1, 'text': 'foo'}), |
|
167 |
('2', 'bar', '2', {'id': 2, 'text': 'bar'})] |
|
152 | 168 |
assert data_sources.get_structured_items(datasource) == [ |
153 | 169 |
{'id': 1, 'text': 'foo'}, {'id': 2, 'text': 'bar'}] |
154 | 170 | |
... | ... | |
156 | 172 |
json_file = open(json_file_path, 'w') |
157 | 173 |
json.dump({'data': [{'id': '1', 'text': ''}, {'id': '2'}]}, json_file) |
158 | 174 |
json_file.close() |
159 |
assert data_sources.get_items(datasource) == [('1', '', '1'), ('2', '2', '2')] |
|
175 |
assert data_sources.get_items(datasource) == [ |
|
176 |
('1', '', '1', {'id': '1', 'text': ''}), |
|
177 |
('2', '2', '2', {'id': '2', 'text': '2'})] |
|
160 | 178 |
assert data_sources.get_structured_items(datasource) == [ |
161 | 179 |
{'id': '1', 'text': ''}, |
162 | 180 |
{'id': '2', 'text': '2'}] |
... | ... | |
193 | 211 |
register_data_source_function(xxx) |
194 | 212 | |
195 | 213 |
datasource = {'type': 'formula', 'value': 'xxx()'} |
196 |
assert data_sources.get_items(datasource) == [('1', 'foo', '1'), ('2', 'bar', '2')] |
|
214 |
assert data_sources.get_items(datasource) == [ |
|
215 |
('1', 'foo', '1', {'id': '1', 'text': 'foo'}), |
|
216 |
('2', 'bar', '2', {'id': '2', 'text': 'bar'})] |
|
197 | 217 |
assert data_sources.get_structured_items(datasource) == [ |
198 | 218 |
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}] |
199 | 219 | |
... | ... | |
243 | 263 |
data_source2 = NamedDataSource.select()[0] |
244 | 264 |
assert data_source2.data_source == data_source.data_source |
245 | 265 |
assert data_sources.get_items({'type': 'foobar'}) == [ |
246 |
('uné',) * 3,
|
|
247 |
('deux',) * 3,
|
|
266 |
('uné', 'uné', 'uné', {'id': 'uné', 'text': 'uné'}),
|
|
267 |
('deux', 'deux', 'deux', {'id': 'deux', 'text': 'deux'}),
|
|
248 | 268 |
] |
249 | 269 | |
250 | 270 |
NamedDataSource.wipe() |
... | ... | |
258 | 278 |
urllib2.urlopen.return_value.read.return_value = \ |
259 | 279 |
'{"data": [{"id": 0, "text": "zéro"}, {"id": 1, "text": "uné"}, {"id": 2, "text": "deux"}]}' |
260 | 280 |
assert data_sources.get_items({'type': 'foobar'}) == [ |
261 |
('0', 'zéro', '0'), |
|
262 |
('1', 'uné', '1'), |
|
263 |
('2', 'deux', '2'), |
|
281 |
('0', 'zéro', '0', {"id": 0, "text": "zéro"}),
|
|
282 |
('1', 'uné', '1', {"id": 1, "text": "uné"}),
|
|
283 |
('2', 'deux', '2', {"id": 2, "text": "deux"}),
|
|
264 | 284 |
] |
tests/test_form_pages.py | ||
---|---|---|
3261 | 3261 |
assert 'readonly' in resp.form['f0'].attrs |
3262 | 3262 |
assert not 'Check values then click submit.' in resp.body |
3263 | 3263 |
assert resp.form['f0'].value == 'foo@localhost' |
3264 | ||
3265 |
def test_item_field_with_disabled_items(pub): |
|
3266 |
user = create_user(pub) |
|
3267 |
formdef = create_formdef() |
|
3268 |
formdef.data_class().wipe() |
|
3269 |
ds = {'type': 'json', 'value': 'http://remote.example.net/json'} |
|
3270 |
formdef.fields = [fields.ItemField(id='0', label='string', data_source=ds)] |
|
3271 |
formdef.store() |
|
3272 | ||
3273 |
with mock.patch('urllib2.urlopen') as urlopen: |
|
3274 |
data = {'data': [{'id': '1', 'text': 'hello'}, {'id': '2', 'text': 'world'}]} |
|
3275 |
urlopen.side_effect = lambda *args: StringIO.StringIO(json.dumps(data)) |
|
3276 |
resp = get_app(pub).get('/test/') |
|
3277 |
resp.form['f0'] = '1' |
|
3278 |
resp.form['f0'] = '2' |
|
3279 |
resp = resp.form.submit('submit') # -> validation page |
|
3280 |
resp = resp.form.submit('submit') # -> submit |
|
3281 |
assert formdef.data_class().select()[0].data['0'] == '2' |
|
3282 |
assert formdef.data_class().select()[0].data['0_display'] == 'world' |
|
3283 | ||
3284 |
formdef.data_class().wipe() |
|
3285 | ||
3286 |
with mock.patch('urllib2.urlopen') as urlopen: |
|
3287 |
data = {'data': [{'id': '1', 'text': 'hello', 'disabled': True}, {'id': '2', 'text': 'world'}]} |
|
3288 |
urlopen.side_effect = lambda *args: StringIO.StringIO(json.dumps(data)) |
|
3289 |
resp = get_app(pub).get('/test/') |
|
3290 |
assert '<option disabled="disabled" value="1">hello</option>' in resp.body |
|
3291 |
resp.form['f0'] = '1' |
|
3292 |
resp.form['f0'] = '2' |
|
3293 |
resp = resp.form.submit('submit') # -> validation page |
|
3294 |
resp = resp.form.submit('submit') # -> submit |
|
3295 |
assert formdef.data_class().select()[0].data['0'] == '2' |
|
3296 |
assert formdef.data_class().select()[0].data['0_display'] == 'world' |
|
3297 | ||
3298 |
resp = get_app(pub).get('/test/') |
|
3299 |
assert '<option disabled="disabled" value="1">hello</option>' in resp.body |
|
3300 |
resp.form['f0'] = '1' |
|
3301 |
resp = resp.form.submit('submit') # -> validation page |
|
3302 |
assert 'There were errors processing the form' in resp.body |
|
3303 | ||
3304 |
formdef.data_class().wipe() |
|
3305 |
formdef.fields = [fields.ItemField(id='0', label='string', data_source=ds, show_as_radio=True)] |
|
3306 |
formdef.store() |
|
3307 | ||
3308 |
with mock.patch('urllib2.urlopen') as urlopen: |
|
3309 |
data = {'data': [{'id': '1', 'text': 'hello'}, {'id': '2', 'text': 'world'}]} |
|
3310 |
urlopen.side_effect = lambda *args: StringIO.StringIO(json.dumps(data)) |
|
3311 |
resp = get_app(pub).get('/test/') |
|
3312 |
resp.form['f0'] = '1' |
|
3313 |
resp.form['f0'] = '2' |
|
3314 |
resp = resp.form.submit('submit') # -> validation page |
|
3315 |
resp = resp.form.submit('submit') # -> submit |
|
3316 |
assert formdef.data_class().select()[0].data['0'] == '2' |
|
3317 |
assert formdef.data_class().select()[0].data['0_display'] == 'world' |
|
3318 | ||
3319 |
formdef.data_class().wipe() |
|
3320 | ||
3321 |
with mock.patch('urllib2.urlopen') as urlopen: |
|
3322 |
data = {'data': [{'id': '1', 'text': 'hello', 'disabled': True}, {'id': '2', 'text': 'world'}]} |
|
3323 |
urlopen.side_effect = lambda *args: StringIO.StringIO(json.dumps(data)) |
|
3324 |
resp = get_app(pub).get('/test/') |
|
3325 |
assert '<input disabled="disabled" type="radio" name="f0" value="1" />' in resp.body |
|
3326 |
resp.form['f0'] = '1' |
|
3327 |
resp.form['f0'] = '2' |
|
3328 |
resp = resp.form.submit('submit') # -> validation page |
|
3329 |
resp = resp.form.submit('submit') # -> submit |
|
3330 |
assert formdef.data_class().select()[0].data['0'] == '2' |
|
3331 |
assert formdef.data_class().select()[0].data['0_display'] == 'world' |
|
3332 | ||
3333 |
resp = get_app(pub).get('/test/') |
|
3334 |
assert '<input disabled="disabled" type="radio" name="f0" value="1" />' in resp.body |
|
3335 |
resp.form['f0'] = '1' |
|
3336 |
resp = resp.form.submit('submit') # -> validation page |
|
3337 |
assert 'There were errors processing the form' in resp.body |
wcs/data_sources.py | ||
---|---|---|
84 | 84 |
return r.getvalue() |
85 | 85 | |
86 | 86 | |
87 |
def get_items(data_source): |
|
87 |
def get_items(data_source, include_disabled=False):
|
|
88 | 88 |
structured_items = get_structured_items(data_source) |
89 | 89 |
tupled_items = [] |
90 | 90 |
for item in structured_items: |
91 |
tupled_items.append((str(item['id']), str(item['text']), str(item.get('key', item['id'])))) |
|
91 |
if item.get('disabled') and not include_disabled: |
|
92 |
continue |
|
93 |
tupled_items.append((str(item['id']), |
|
94 |
str(item['text']), |
|
95 |
str(item.get('key', item['id'])), |
|
96 |
item)) |
|
92 | 97 |
return tupled_items |
93 | 98 | |
94 | 99 |
wcs/fields.py | ||
---|---|---|
1056 | 1056 | |
1057 | 1057 |
def get_options(self): |
1058 | 1058 |
if self.data_source: |
1059 |
return data_sources.get_items(self.data_source)
|
|
1059 |
return [x[:3] for x in data_sources.get_items(self.data_source)]
|
|
1060 | 1060 |
if self.items: |
1061 | 1061 |
return self.items[:] |
1062 | 1062 |
return [] |
... | ... | |
1066 | 1066 |
if real_data_source and real_data_source.get('type') == 'jsonp': |
1067 | 1067 |
kwargs['url'] = real_data_source.get('value') |
1068 | 1068 |
self.widget_class = JsonpSingleSelectWidget |
1069 |
elif self.items: |
|
1070 |
kwargs['options'] = self.items[:] |
|
1071 |
elif self.data_source: |
|
1072 |
items = data_sources.get_items(self.data_source, include_disabled=True) |
|
1073 |
kwargs['options'] = [x[:3] for x in items if not x[-1].get('disabled')] |
|
1074 |
kwargs['options_with_disabled'] = items[:] |
|
1069 | 1075 |
else: |
1070 | 1076 |
kwargs['options'] = self.get_options() |
1071 | 1077 |
if not kwargs.get('options'): |
... | ... | |
1239 | 1245 |
if self.data_source: |
1240 | 1246 |
if self._cached_data_source: |
1241 | 1247 |
return self._cached_data_source |
1242 |
self._cached_data_source = data_sources.get_items(self.data_source)
|
|
1248 |
self._cached_data_source = [x[:3] for x in data_sources.get_items(self.data_source)]
|
|
1243 | 1249 |
return self._cached_data_source[:] |
1244 | 1250 |
elif self.items: |
1245 | 1251 |
return self.items[:] |
wcs/qommon/form.py | ||
---|---|---|
200 | 200 |
SubmitWidget.render_content = submit_render_content |
201 | 201 | |
202 | 202 | |
203 |
def radiobuttons_render_content(self): |
|
204 |
tags = [] |
|
205 |
for object, description, key in self.options: |
|
206 |
if self.is_selected(object): |
|
207 |
checked = 'checked' |
|
208 |
else: |
|
209 |
checked = None |
|
210 |
r = htmltag("input", xml_end=True, |
|
211 |
type="radio", |
|
212 |
name=self.name, |
|
213 |
value=key, |
|
214 |
checked=checked, |
|
215 |
**self.attrs) |
|
216 |
tags.append(htmltext('<label>') + r + htmlescape(description) + htmltext('</label>')) |
|
217 |
return htmlescape(self.delim).join(tags) |
|
218 |
RadiobuttonsWidget.render_content = radiobuttons_render_content |
|
203 |
class RadiobuttonsWidget(quixote.form.RadiobuttonsWidget): |
|
204 |
def __init__(self, name, value=None, **kwargs): |
|
205 |
self.options_with_disabled = kwargs.pop('options_with_disabled', None) |
|
206 |
super(RadiobuttonsWidget, self).__init__(name, value=value, **kwargs) |
|
219 | 207 | |
208 |
def render_content(self): |
|
209 |
include_disabled = False |
|
210 |
options = self.options[:] |
|
211 |
if self.options_with_disabled: |
|
212 |
options = self.options_with_disabled |
|
213 |
include_disabled = True |
|
214 | ||
215 |
tags = [] |
|
216 |
for option in options: |
|
217 |
object, description, key = option[:3] |
|
218 |
html_attrs = self.attrs.copy() |
|
219 |
if self.is_selected(object): |
|
220 |
html_attrs['checked'] = 'checked' |
|
221 |
if self.options_with_disabled and option[-1].get('disabled'): |
|
222 |
html_attrs['disabled'] = 'disabled' |
|
223 |
r = htmltag("input", xml_end=True, |
|
224 |
type="radio", |
|
225 |
name=self.name, |
|
226 |
value=key, |
|
227 |
**html_attrs) |
|
228 |
tags.append(htmltext('<label>') + r + htmlescape(description) + htmltext('</label>')) |
|
229 |
return htmlescape(self.delim).join(tags) |
|
220 | 230 | |
221 | 231 |
def checkbox_render_content(self): |
222 | 232 |
attrs = {'id': 'form_' + self.name} |
... | ... | |
1523 | 1533 | |
1524 | 1534 | |
1525 | 1535 |
class SingleSelectHintWidget(SingleSelectWidget): |
1536 |
def __init__(self, name, value=None, **kwargs): |
|
1537 |
self.options_with_disabled = kwargs.pop('options_with_disabled', None) |
|
1538 |
super(SingleSelectHintWidget, self).__init__(name, value=value, **kwargs) |
|
1526 | 1539 | |
1527 | 1540 |
def separate_hint(self): |
1528 | 1541 |
return (self.hint and len(self.hint) > 80) |
... | ... | |
1533 | 1546 |
attrs.update(self.attrs) |
1534 | 1547 |
tags = [htmltag('select', name=self.name, **attrs)] |
1535 | 1548 |
options = self.options[:] |
1549 |
include_disabled = False |
|
1550 |
if self.options_with_disabled: |
|
1551 |
options = self.options_with_disabled |
|
1552 |
include_disabled = True |
|
1536 | 1553 |
if not self.separate_hint() and self.hint: |
1537 | 1554 |
r = htmltag('option', value='', selected=None) |
1538 | 1555 |
tags.append(r + htmlescape(self.hint) + htmltext('</option>')) |
... | ... | |
1540 | 1557 |
# hint has been put as first element, skip the default empty |
1541 | 1558 |
# value. |
1542 | 1559 |
options = self.options[1:] |
1543 |
for object, description, key in options: |
|
1560 |
for option in options: |
|
1561 |
object, description, key = option[:3] |
|
1562 |
html_attrs = {} |
|
1563 |
html_attrs['value'] = key |
|
1544 | 1564 |
if self.is_selected(object): |
1545 |
selected = 'selected'
|
|
1546 |
else:
|
|
1547 |
selected = None
|
|
1565 |
html_attrs['selected'] = 'selected'
|
|
1566 |
if self.options_with_disabled and option[-1].get('disabled'):
|
|
1567 |
html_attrs['disabled'] = 'disabled'
|
|
1548 | 1568 |
if description is None: |
1549 | 1569 |
description = '' |
1550 |
r = htmltag('option', value=key, selected=selected)
|
|
1570 |
r = htmltag('option', **html_attrs)
|
|
1551 | 1571 |
tags.append(r + htmlescape(description) + htmltext('</option>')) |
1552 | 1572 |
tags.append(htmltext('</select>')) |
1553 | 1573 |
return htmltext('\n').join(tags) |
1554 |
- |