0004-add-live-field-conditions-436.patch
tests/test_admin_pages.py | ||
---|---|---|
984 | 984 | |
985 | 985 |
# check it's in the preview |
986 | 986 |
resp = app.get('/backoffice/forms/1/') |
987 |
assert '<h3>baz</h3>' in resp.body |
|
987 |
assert '<h3 data-field-id="1">baz</h3>' in resp.body
|
|
988 | 988 | |
989 | 989 |
def test_form_delete_field(pub): |
990 | 990 |
create_role() |
tests/test_backoffice_pages.py | ||
---|---|---|
4120 | 4120 |
app = login(get_app(pub)) |
4121 | 4121 | |
4122 | 4122 |
resp = app.get('/backoffice/submission/test/') |
4123 |
assert '<p class="comment-field ">XbarY</p>' in resp.body |
|
4123 |
assert '<p data-field-id="7" class="comment-field ">XbarY</p>' in resp.body
|
|
4124 | 4124 | |
4125 | 4125 |
# check with publisher variable in named webservice call |
4126 | 4126 |
if not pub.site_options.has_section('variables'): |
... | ... | |
4135 | 4135 |
wscall.store() |
4136 | 4136 | |
4137 | 4137 |
resp = app.get('/backoffice/submission/test/') |
4138 |
assert '<p class="comment-field ">XbarY</p>' in resp.body |
|
4138 |
assert '<p data-field-id="7" class="comment-field ">XbarY</p>' in resp.body
|
|
4139 | 4139 | |
4140 | 4140 |
# django-templated URL |
4141 | 4141 |
wscall.request = {'url': '{{ example_url }}json'} |
4142 | 4142 |
wscall.store() |
4143 | 4143 |
resp = app.get('/backoffice/submission/test/') |
4144 |
assert '<p class="comment-field ">XbarY</p>' in resp.body |
|
4144 |
assert '<p data-field-id="7" class="comment-field ">XbarY</p>' in resp.body
|
|
4145 | 4145 | |
4146 | 4146 |
# webservice call in django template |
4147 | 4147 |
formdef.fields = [ |
... | ... | |
4150 | 4150 |
formdef.store() |
4151 | 4151 |
formdef.data_class().wipe() |
4152 | 4152 |
resp = app.get('/backoffice/submission/test/') |
4153 |
assert '<p class="comment-field ">dja-bar-ngo</p>' in resp.body |
|
4153 |
assert '<p data-field-id="7" class="comment-field ">dja-bar-ngo</p>' in resp.body
|
|
4154 | 4154 | |
4155 | 4155 |
def test_backoffice_session_var(pub): |
4156 | 4156 |
open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w').write('''[options] |
... | ... | |
4174 | 4174 |
resp = app.get('/backoffice/submission/test/?session_var_foo=bar') |
4175 | 4175 |
assert resp.location.endswith('/backoffice/submission/test/') |
4176 | 4176 |
resp = resp.follow() |
4177 |
assert '<p class="comment-field ">XbarY</p>' in resp.body |
|
4177 |
assert '<p data-field-id="7" class="comment-field ">XbarY</p>' in resp.body
|
|
4178 | 4178 | |
4179 | 4179 |
# django template |
4180 | 4180 |
formdef.fields = [ |
... | ... | |
4185 | 4185 |
resp = app.get('/backoffice/submission/test/?session_var_foo=jang') |
4186 | 4186 |
assert resp.location.endswith('/backoffice/submission/test/') |
4187 | 4187 |
resp = resp.follow() |
4188 |
assert '<p class="comment-field ">django</p>' in resp.body |
|
4188 |
assert '<p data-field-id="7" class="comment-field ">django</p>' in resp.body
|
|
4189 | 4189 | |
4190 | 4190 |
def test_backoffice_display_message(pub): |
4191 | 4191 |
user = create_user(pub) |
tests/test_fields.py | ||
---|---|---|
133 | 133 |
field = fields.TitleField(label='Foobar') |
134 | 134 |
form = Form(use_tokens=False) |
135 | 135 |
field.add_to_form(form) |
136 |
assert '<h3>Foobar</h3>' in str(form.render()) |
|
136 |
assert '<h3 data-field-id="None">Foobar</h3>' in str(form.render())
|
|
137 | 137 | |
138 | 138 |
field = fields.TitleField(label='Foobar', extra_css_class='test') |
139 | 139 |
form = Form(use_tokens=False) |
140 | 140 |
field.add_to_form(form) |
141 |
assert '<h3 class="test">Foobar</h3>' in str(form.render()) |
|
141 |
assert '<h3 data-field-id="None" class="test">Foobar</h3>' in str(form.render())
|
|
142 | 142 | |
143 | 143 |
def test_subtitle(): |
144 | 144 |
field = fields.SubtitleField(label='Foobar') |
145 | 145 |
form = Form(use_tokens=False) |
146 | 146 |
field.add_to_form(form) |
147 |
assert '<h4>Foobar</h4>' in str(form.render()) |
|
147 |
assert '<h4 data-field-id="None">Foobar</h4>' in str(form.render())
|
|
148 | 148 | |
149 | 149 |
field = fields.SubtitleField(label='Foobar', extra_css_class='test') |
150 | 150 |
form = Form(use_tokens=False) |
151 | 151 |
field.add_to_form(form) |
152 |
assert '<h4 class="test">Foobar</h4>' in str(form.render()) |
|
152 |
assert '<h4 data-field-id="None" class="test">Foobar</h4>' in str(form.render())
|
|
153 | 153 | |
154 | 154 |
def test_comment(): |
155 | 155 |
field = fields.CommentField(label='Foobar') |
156 | 156 |
form = Form(use_tokens=False) |
157 | 157 |
field.add_to_form(form) |
158 |
assert '<p class="comment-field ">Foobar</p>' in str(form.render()) |
|
158 |
assert '<p data-field-id="None" class="comment-field ">Foobar</p>' in str(form.render())
|
|
159 | 159 | |
160 | 160 |
field = fields.CommentField(label='Foo\n\nBar\n\nBaz') |
161 | 161 |
form = Form(use_tokens=False) |
162 | 162 |
field.add_to_form(form) |
163 | 163 |
assert '<p>Foo</p>\n<p>Bar</p>\n<p>Baz</p>' in str(form.render()) |
164 |
assert '<div class="comment-field "' in str(form.render()) |
|
164 |
assert '<div data-field-id="None" class="comment-field "' in str(form.render())
|
|
165 | 165 | |
166 | 166 |
# test for variable substitution |
167 | 167 |
pub.substitutions.feed(MockSubstitutionVariables()) |
168 | 168 |
field = fields.CommentField(label='{{ bar }}') |
169 | 169 |
form = Form(use_tokens=False) |
170 | 170 |
field.add_to_form(form) |
171 |
assert '<p class="comment-field ">Foobar</p>' in str(form.render()) |
|
171 |
assert '<p data-field-id="None" class="comment-field ">Foobar</p>' in str(form.render())
|
|
172 | 172 | |
173 | 173 |
field = fields.CommentField(label='[bar]') |
174 | 174 |
form = Form(use_tokens=False) |
175 | 175 |
field.add_to_form(form) |
176 |
assert '<p class="comment-field ">Foobar</p>' in str(form.render()) |
|
176 |
assert '<p data-field-id="None" class="comment-field ">Foobar</p>' in str(form.render())
|
|
177 | 177 | |
178 | 178 |
# test for proper escaping of substitution variables |
179 | 179 |
field = fields.CommentField(label='{{ foo }}') |
180 | 180 |
form = Form(use_tokens=False) |
181 | 181 |
field.add_to_form(form) |
182 |
assert '<p class="comment-field ">1 < 3</p>' in str(form.render()) |
|
182 |
assert '<p data-field-id="None" class="comment-field ">1 < 3</p>' in str(form.render())
|
|
183 | 183 | |
184 | 184 |
field = fields.CommentField(label='[foo]') |
185 | 185 |
form = Form(use_tokens=False) |
186 | 186 |
field.add_to_form(form) |
187 |
assert '<p class="comment-field ">1 < 3</p>' in str(form.render()) |
|
187 |
assert '<p data-field-id="None" class="comment-field ">1 < 3</p>' in str(form.render())
|
|
188 | 188 | |
189 | 189 |
# test for html content |
190 | 190 |
field = fields.CommentField(label='<p>Foobar</p>') |
191 | 191 |
form = Form(use_tokens=False) |
192 | 192 |
field.add_to_form(form) |
193 | 193 |
assert '<p>Foobar</p>' in str(form.render()) |
194 |
assert '<div class="comment-field "' in str(form.render()) |
|
194 |
assert '<div data-field-id="None" class="comment-field "' in str(form.render())
|
|
195 | 195 |
assert field.unhtmled_label == 'Foobar' |
196 | 196 | |
197 | 197 |
field = fields.CommentField(label='<p>Foobaré</p>') |
tests/test_form_pages.py | ||
---|---|---|
1084 | 1084 |
formdef.data_class().wipe() |
1085 | 1085 | |
1086 | 1086 |
resp = get_app(pub).get('/test/') |
1087 |
assert not '<h3>1st page/h3>' in resp.body |
|
1088 |
assert '<h4>subtitle of 1st page</h4>' in resp.body |
|
1087 |
assert not '<h3 data-field-id="0">1st page/h3>' in resp.body
|
|
1088 |
assert '<h4 data-field-id="5">subtitle of 1st page</h4>' in resp.body
|
|
1089 | 1089 |
resp.form['f1'] = 'foo' |
1090 | 1090 |
resp = resp.form.submit('submit') |
1091 |
assert '<h3>title of second page</h3>' in resp.body |
|
1091 |
assert '<h3 data-field-id="6">title of second page</h3>' in resp.body
|
|
1092 | 1092 |
resp = resp.form.submit('submit') # -> validation page |
1093 | 1093 |
assert '<h3>1st page</h3>' in resp.body |
1094 |
assert '<h4>subtitle of 1st page</h4>' in resp.body |
|
1095 |
assert '<h3>title of second page</h3>' in resp.body |
|
1094 |
assert '<h4 data-field-id="5">subtitle of 1st page</h4>' in resp.body
|
|
1095 |
assert '<h3 data-field-id="6">title of second page</h3>' in resp.body
|
|
1096 | 1096 |
resp.form['f3'] = 'foo' |
1097 | 1097 |
resp = resp.form.submit('submit').follow() # -> submit |
1098 | 1098 |
assert '<h3>1st page</h3>' in resp.body |
... | ... | |
5030 | 5030 |
resp = resp.follow() |
5031 | 5031 |
assert '<span class="label">Bar</span>' in resp.body |
5032 | 5032 |
assert '<span class="label">Foo</span>' not in resp.body |
5033 | ||
5034 |
def test_field_live_condition(pub): |
|
5035 |
FormDef.wipe() |
|
5036 |
formdef = FormDef() |
|
5037 |
formdef.name = 'Foo' |
|
5038 |
formdef.fields = [ |
|
5039 |
fields.StringField(type='string', id='1', label='Bar', size='40', |
|
5040 |
required=True, varname='bar'), |
|
5041 |
fields.StringField(type='string', id='2', label='Foo', size='40', |
|
5042 |
required=True, varname='foo', |
|
5043 |
condition={'type': 'django', 'value': 'form_var_bar == "bye"'}), |
|
5044 |
] |
|
5045 |
formdef.store() |
|
5046 | ||
5047 |
app = get_app(pub) |
|
5048 |
resp = app.get('/foo/') |
|
5049 |
assert 'f1' in resp.form.fields |
|
5050 |
assert 'f2' in resp.form.fields |
|
5051 |
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true' |
|
5052 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none' |
|
5053 |
resp.form['f1'] = 'hello' |
|
5054 |
live_resp = app.post('/foo/live', params=resp.form.submit_fields()) |
|
5055 |
assert live_resp.json['result']['1']['visible'] |
|
5056 |
assert not live_resp.json['result']['2']['visible'] |
|
5057 |
resp.form['f1'] = 'bye' |
|
5058 |
live_resp = app.post('/foo/live', params=resp.form.submit_fields()) |
|
5059 |
assert live_resp.json['result']['1']['visible'] |
|
5060 |
assert live_resp.json['result']['2']['visible'] |
|
5061 |
resp.form['f1'] = 'hello' |
|
5062 |
resp = resp.form.submit('submit') |
|
5063 |
assert 'Check values then click submit.' in resp.body |
|
5064 |
assert 'name="f1"' in resp.body |
|
5065 |
assert 'name="f2"' not in resp.body |
|
5066 |
resp = resp.form.submit('submit') |
|
5067 |
resp = resp.follow() |
|
5068 |
assert '<span class="label">Bar</span>' in resp.body |
|
5069 |
assert '<span class="label">Foo</span>' not in resp.body |
|
5070 | ||
5071 |
resp = get_app(pub).get('/foo/') |
|
5072 |
assert 'f1' in resp.form.fields |
|
5073 |
assert 'f2' in resp.form.fields |
|
5074 |
resp.form['f1'] = 'bye' |
|
5075 |
resp = resp.form.submit('submit') |
|
5076 |
assert 'There were errors' in resp.body |
|
5077 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') is None |
|
5078 |
resp.form['f2'] = 'bye' |
|
5079 |
resp = resp.form.submit('submit') |
|
5080 |
assert 'Check values then click submit.' in resp.body |
|
5081 |
assert 'name="f1"' in resp.body |
|
5082 |
assert 'name="f2"' in resp.body |
|
5083 |
resp = resp.form.submit('submit') |
|
5084 |
resp = resp.follow() |
|
5085 |
assert '<span class="label">Bar</span>' in resp.body |
|
5086 |
assert '<span class="label">Foo</span>' in resp.body |
|
5087 | ||
5088 |
def test_field_live_condition_multipages(pub): |
|
5089 |
FormDef.wipe() |
|
5090 |
formdef = FormDef() |
|
5091 |
formdef.name = 'Foo' |
|
5092 |
formdef.fields = [ |
|
5093 |
fields.PageField(id='0', label='2nd page', type='page'), |
|
5094 |
fields.StringField(type='string', id='1', label='Bar', size='40', |
|
5095 |
required=True, varname='bar'), |
|
5096 |
fields.StringField(type='string', id='2', label='Foo', size='40', |
|
5097 |
required=True, varname='foo', |
|
5098 |
condition={'type': 'django', 'value': 'form_var_bar == "bye"'}), |
|
5099 |
fields.PageField(id='3', label='1st page', type='page'), |
|
5100 |
fields.StringField(type='string', id='4', label='Baz', size='40', |
|
5101 |
required=True, varname='baz'), |
|
5102 |
] |
|
5103 |
formdef.store() |
|
5104 | ||
5105 |
app = get_app(pub) |
|
5106 |
resp = app.get('/foo/') |
|
5107 |
assert 'f1' in resp.form.fields |
|
5108 |
assert 'f2' in resp.form.fields |
|
5109 |
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true' |
|
5110 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none' |
|
5111 |
resp.form['f1'] = 'hello' |
|
5112 |
live_resp = app.post('/foo/live', params=resp.form.submit_fields()) |
|
5113 |
assert live_resp.json['result']['1']['visible'] |
|
5114 |
assert not live_resp.json['result']['2']['visible'] |
|
5115 |
resp.form['f1'] = 'bye' |
|
5116 |
live_resp = app.post('/foo/live', params=resp.form.submit_fields()) |
|
5117 |
assert live_resp.json['result']['1']['visible'] |
|
5118 |
assert live_resp.json['result']['2']['visible'] |
|
5119 |
resp.form['f1'] = 'bye' |
|
5120 |
resp.form['f2'] = 'bye' |
|
5121 |
resp = resp.form.submit('submit') |
|
5122 |
resp = resp.form.submit('previous') |
|
5123 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') is None |
|
5124 |
live_resp = app.post('/foo/live', params=resp.form.submit_fields()) |
|
5125 |
assert live_resp.json['result']['1']['visible'] |
|
5126 |
assert live_resp.json['result']['2']['visible'] |
|
5127 |
resp = resp.form.submit('submit') |
|
5128 |
resp.form['f4'] = 'plop' |
|
5129 |
resp = resp.form.submit('submit') |
|
5130 |
assert 'Check values then click submit.' in resp.body |
|
5131 |
assert 'name="f1"' in resp.body |
|
5132 |
assert 'name="f2"' in resp.body |
|
5133 |
assert 'name="f4"' in resp.body |
|
5134 |
resp = resp.form.submit('submit') |
wcs/backoffice/submission.py | ||
---|---|---|
76 | 76 | |
77 | 77 |
class FormFillPage(PublicFormFillPage): |
78 | 78 |
_q_exports = ['', 'tempfile', 'autosave', 'code', |
79 |
('remove', 'remove_draft')] |
|
79 |
('remove', 'remove_draft'), 'live']
|
|
80 | 80 | |
81 | 81 |
filling_templates = ['wcs/formdata_filling.html'] |
82 | 82 |
validation_templates = ['wcs/formdata_validation.html'] |
wcs/fields.py | ||
---|---|---|
381 | 381 |
except RuntimeError: |
382 | 382 |
return True |
383 | 383 | |
384 |
def get_condition_varnames(self): |
|
385 |
return re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)', self.condition['value']) |
|
386 | ||
387 |
def has_live_conditions(self, formdef): |
|
388 |
varnames = self.get_condition_varnames() |
|
389 |
if not varnames: |
|
390 |
return False |
|
391 |
field_position = formdef.fields.index(self) |
|
392 |
# rewind to field page |
|
393 |
for field_position in range(field_position, -1, -1): |
|
394 |
if formdef.fields[field_position].type == 'page': |
|
395 |
break |
|
396 |
else: |
|
397 |
field_position = -1 # form with no page |
|
398 |
# start from there |
|
399 |
for field in formdef.fields[field_position+1:]: |
|
400 |
if field.type == 'page': |
|
401 |
# stop at next page |
|
402 |
break |
|
403 |
if field.varname in varnames: |
|
404 |
return True |
|
405 |
return False |
|
406 | ||
384 | 407 | |
385 | 408 |
class WidgetField(Field): |
386 | 409 |
hint = None |
... | ... | |
413 | 436 |
widget.extra_css_class = self.extra_css_class |
414 | 437 |
if self.varname: |
415 | 438 |
widget.div_id = 'var_%s' % self.varname |
439 |
return widget |
|
416 | 440 | |
417 | 441 |
def perform_more_widget_changes(self, form, kwargs, edit = True): |
418 | 442 |
pass |
... | ... | |
519 | 543 |
description = N_('Title') |
520 | 544 | |
521 | 545 |
def add_to_form(self, form, value = None): |
546 |
extra_attributes = ' data-field-id="%s"' % self.id |
|
522 | 547 |
if self.extra_css_class: |
523 |
extra_css_class = ' class="%s"' % self.extra_css_class |
|
524 |
else: |
|
525 |
extra_css_class = '' |
|
526 |
form.widgets.append(HtmlWidget( |
|
527 |
htmltext('<h3%s>%s</h3>' % (extra_css_class, self.label)))) |
|
548 |
extra_attributes += ' class="%s"' % self.extra_css_class |
|
549 |
widget = HtmlWidget(htmltext('<h3%s>%s</h3>' % (extra_attributes, self.label))) |
|
550 |
form.widgets.append(widget) |
|
551 |
return widget |
|
528 | 552 |
add_to_view_form = add_to_form |
529 | 553 | |
530 | 554 |
def fill_admin_form(self, form): |
... | ... | |
547 | 571 |
description = N_('Subtitle') |
548 | 572 | |
549 | 573 |
def add_to_form(self, form, value = None): |
574 |
extra_attributes = ' data-field-id="%s"' % self.id |
|
550 | 575 |
if self.extra_css_class: |
551 |
extra_css_class = ' class="%s"' % self.extra_css_class |
|
552 |
else: |
|
553 |
extra_css_class = '' |
|
554 |
form.widgets.append(HtmlWidget( |
|
555 |
htmltext('<h4%s>%s</h4>' % (extra_css_class, self.label)))) |
|
576 |
extra_attributes += ' class="%s"' % self.extra_css_class |
|
577 |
widget = HtmlWidget(htmltext('<h4%s>%s</h4>' % (extra_attributes, self.label))) |
|
578 |
form.widgets.append(widget) |
|
579 |
return widget |
|
556 | 580 |
add_to_view_form = add_to_form |
557 | 581 | |
558 | 582 |
register_field_class(SubtitleField) |
... | ... | |
563 | 587 |
description = N_('Comment') |
564 | 588 | |
565 | 589 |
def add_to_form(self, form, value = None): |
566 |
class_attribute = 'class="comment-field %s"' % (self.extra_css_class or '') |
|
590 |
tag_attributes = 'data-field-id="%s" class="comment-field %s"' % ( |
|
591 |
self.id, self.extra_css_class or '') |
|
567 | 592 | |
568 | 593 |
if '\n\n' in self.label: |
569 | 594 |
label = '<p>' + re.sub('\n\n+', '</p>\n<p>', self.label) + '</p>' |
... | ... | |
579 | 604 |
enclosing_tag = 'div' |
580 | 605 |
break |
581 | 606 | |
582 |
form.widgets.append(HtmlWidget( |
|
583 |
htmltext('<%s %s>%s</%s>' % (enclosing_tag, class_attribute, |
|
584 |
label, enclosing_tag)))) |
|
607 |
widget = HtmlWidget(htmltext('<%s %s>%s</%s>' % ( |
|
608 |
enclosing_tag, tag_attributes, label, enclosing_tag))) |
|
609 |
form.widgets.append(widget) |
|
610 |
return widget |
|
585 | 611 | |
586 | 612 |
def add_to_view_form(self, *args): |
587 | 613 |
pass |
... | ... | |
1050 | 1076 |
def add_to_form(self, form, value=None): |
1051 | 1077 |
if value and type(value) is not str: |
1052 | 1078 |
value = self.convert_value_to_str(value) |
1053 |
WidgetField.add_to_form(self, form, value=value) |
|
1079 |
return WidgetField.add_to_form(self, form, value=value)
|
|
1054 | 1080 | |
1055 | 1081 |
def add_to_view_form(self, form, value = None): |
1056 | 1082 |
value = localstrftime(value) |
... | ... | |
1531 | 1557 |
# create variables with values currently being evaluated, not yet |
1532 | 1558 |
# available in the formdata. |
1533 | 1559 |
from formdata import get_dict_with_varnames |
1534 |
live_data = get_dict_with_varnames(formdef.fields, dict_vars) |
|
1535 |
form_live_data = dict(('form_' + x, y) for x, y in live_data.items()) |
|
1560 |
live_data = {} |
|
1561 |
form_live_data = {} |
|
1562 |
if dict_vars is not None: |
|
1563 |
live_data = get_dict_with_varnames(formdef.fields, dict_vars) |
|
1564 |
form_live_data = dict(('form_' + x, y) for x, y in live_data.items()) |
|
1536 | 1565 | |
1537 | 1566 |
# 1) feed the form_var_* variables in the global substitution system, |
1538 | 1567 |
# they will shadow formdata context variables with their new "live" |
wcs/formdef.py | ||
---|---|---|
532 | 532 |
continue |
533 | 533 |
if not on_page: |
534 | 534 |
continue |
535 |
if not field.is_visible(form_data, self): |
|
536 |
continue |
|
535 |
visible = field.is_visible(form_data, self) |
|
536 |
if not visible: |
|
537 |
if not field.has_live_conditions(self): |
|
538 |
# no live conditions so field can be skipped |
|
539 |
continue |
|
537 | 540 |
if type(displayed_fields) is list: |
538 | 541 |
displayed_fields.append(field) |
539 | 542 |
value = None |
540 | 543 |
if form_data: |
541 | 544 |
value = form_data.get(field.id) |
542 |
field.add_to_form(form, value) |
|
545 |
widget = field.add_to_form(form, value) |
|
546 |
widget.is_hidden = not(visible) |
|
547 |
widget.field = field |
|
543 | 548 | |
544 | 549 |
def get_page(self, page_no): |
545 | 550 |
return [x for x in self.fields if x.type == 'page'][page_no] |
wcs/forms/root.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
import copy |
18 | 18 |
import json |
19 |
import re |
|
19 | 20 |
import time |
20 | 21 |
from StringIO import StringIO |
21 | 22 |
import sys |
... | ... | |
171 | 172 | |
172 | 173 |
class FormPage(Directory, FormTemplateMixin): |
173 | 174 |
_q_exports = ['', 'tempfile', 'schema', 'tryauth', |
174 |
'auth', 'qrcode', 'autosave', 'code', 'removedraft'] |
|
175 |
'auth', 'qrcode', 'autosave', 'code', 'removedraft', 'live']
|
|
175 | 176 | |
176 | 177 |
filling_templates = ['wcs/front/formdata_filling.html', 'wcs/formdata_filling.html'] |
177 | 178 |
validation_templates = ['wcs/front/formdata_validation.html', 'wcs/formdata_validation.html'] |
... | ... | |
378 | 379 |
if not one: |
379 | 380 |
req.form = {} |
380 | 381 | |
382 |
live_condition_fields = {} |
|
381 | 383 |
for field in displayed_fields: |
382 | 384 |
if field.prefill: |
383 | 385 |
# always set additional attributes as they will be used for |
384 | 386 |
# "live prefill", regardless of existing data. |
385 | 387 |
form.get_widget('f%s' % field.id).prefill_attributes = field.get_prefill_attributes() |
388 |
if field.condition: |
|
389 |
field.varnames = field.get_condition_varnames() |
|
390 |
for varname in field.varnames: |
|
391 |
if not varname in live_condition_fields: |
|
392 |
live_condition_fields[varname] = [] |
|
393 |
live_condition_fields[varname].append(field) |
|
394 | ||
395 |
for field in displayed_fields: |
|
396 |
if field.varname not in live_condition_fields: |
|
397 |
continue |
|
398 |
form.get_widget('f%s' % field.id).live_condition_source = True |
|
386 | 399 | |
387 | 400 |
self.html_top(self.formdef.name) |
388 | 401 | |
389 | 402 |
form.add_hidden('step', '0') |
390 | 403 |
form.add_hidden('page', self.pages.index(page)) |
404 |
if page: |
|
405 |
form.add_hidden('page_id', page.id) |
|
391 | 406 | |
392 | 407 |
form.add_submit('cancel', _('Cancel'), css_class = 'cancel') |
393 | 408 |
if self.formdef.enable_tracking_codes and not self.edit_mode: |
... | ... | |
696 | 711 | |
697 | 712 |
self.feed_current_data(magictoken) |
698 | 713 | |
699 |
form = self.create_form(page=page) |
|
714 |
submitted_fields = [] |
|
715 |
form = self.create_form(page=page, displayed_fields=submitted_fields) |
|
700 | 716 |
form.add_submit('previous') |
701 | 717 |
if self.formdef.enable_tracking_codes: |
702 | 718 |
form.add_submit('removedraft') |
... | ... | |
708 | 724 |
if self.formdef.enable_tracking_codes and form.get_submit() == 'removedraft': |
709 | 725 |
return self.removedraft() |
710 | 726 | |
727 |
form_data = session.get_by_magictoken(magictoken, {}) |
|
728 |
data = self.formdef.get_data(form) |
|
729 |
form_data.update(data) |
|
730 | ||
711 | 731 |
if self.formdef.enable_tracking_codes and form.get_submit() == 'savedraft': |
712 |
form_data = session.get_by_magictoken(magictoken, {}) |
|
713 |
data = self.formdef.get_data(form) |
|
714 |
form_data.update(data) |
|
715 | 732 |
filled = self.save_draft(form_data, page_no) |
716 | 733 |
return redirect(filled.get_url().rstrip('/')) |
717 | 734 | |
735 |
for field in submitted_fields: |
|
736 |
if not field.is_visible(form_data, self.formdef): |
|
737 |
del form._names['f%s' % field.id] |
|
738 | ||
718 | 739 |
page_error_messages = [] |
719 | 740 |
if form.get_submit() == 'submit' and page: |
720 | 741 |
post_conditions = page.post_conditions or [] |
... | ... | |
988 | 1009 |
pass |
989 | 1010 |
return None |
990 | 1011 | |
1012 |
def live(self): |
|
1013 |
get_request().ignore_session = True |
|
1014 |
# live evaluation of fields |
|
1015 |
get_response().set_content_type('application/json') |
|
1016 |
def result_error(reason): |
|
1017 |
return json.dumps({'result': 'error', 'reason': reason}) |
|
1018 | ||
1019 |
session = get_session() |
|
1020 |
if not session: |
|
1021 |
return result_error('missing session') |
|
1022 | ||
1023 |
formdata = self.get_transient_formdata() |
|
1024 |
get_publisher().substitutions.feed(formdata) |
|
1025 | ||
1026 |
page_id = get_request().form.get('page_id') |
|
1027 |
if page_id: |
|
1028 |
for field in self.formdef.fields: |
|
1029 |
if str(field.id) == page_id: |
|
1030 |
page = field |
|
1031 |
break |
|
1032 |
else: |
|
1033 |
page = None |
|
1034 | ||
1035 |
displayed_fields = [] |
|
1036 |
form = self.create_form(page=page, displayed_fields=displayed_fields) |
|
1037 |
formdata.data.update(self.formdef.get_data(form)) |
|
1038 | ||
1039 |
result = {} |
|
1040 |
for field in displayed_fields: |
|
1041 |
result[field.id] = {'visible': field.is_visible(formdata.data, self.formdef)} |
|
1042 | ||
1043 |
return json.dumps({'result': result}) |
|
1044 | ||
991 | 1045 |
def submitted(self, form, existing_formdata = None): |
992 | 1046 |
if existing_formdata: # modifying |
993 | 1047 |
filled = existing_formdata |
wcs/qommon/form.py | ||
---|---|---|
417 | 417 |
return self.render_content() |
418 | 418 | |
419 | 419 |
def render_content(self): |
420 |
if self.title: |
|
421 |
return htmltext(self.title) |
|
422 |
return htmltext(self.string) |
|
420 |
content = self.title or self.string or '' |
|
421 |
if getattr(self, 'is_hidden', False): |
|
422 |
content = htmltext(str(content).replace('>', ' style="display: none">', 1)) |
|
423 |
return htmltext(content) |
|
423 | 424 | |
424 | 425 |
def has_error(self, request): |
425 | 426 |
return False |
wcs/qommon/static/js/qommon.forms.js | ||
---|---|---|
67 | 67 |
} |
68 | 68 |
return true; |
69 | 69 |
}); |
70 |
var live_evaluation = null; |
|
71 |
$('form div[data-live-source] input, form div[data-live-source] select').on('change keyup paste', function() { |
|
72 |
var new_data = $(this).parents('form').serialize(); |
|
73 |
if (live_evaluation) { |
|
74 |
live_evaluation.abort(); |
|
75 |
} |
|
76 |
live_evaluation = $.ajax({ |
|
77 |
type: 'POST', |
|
78 |
url: window.location.pathname + 'live', |
|
79 |
dataType: 'json', |
|
80 |
data: new_data, |
|
81 |
headers: {'accept': 'application/json'}, |
|
82 |
success: function(json) { |
|
83 |
$.each(json.result, function(key, value) { |
|
84 |
var $widget = $('[data-field-id="' + key + '"]'); |
|
85 |
if (value.visible) { |
|
86 |
$widget.show(); |
|
87 |
} else { |
|
88 |
$widget.hide(); |
|
89 |
} |
|
90 |
}); |
|
91 |
} |
|
92 |
}); |
|
93 |
}); |
|
70 | 94 |
}); |
wcs/qommon/templates/qommon/forms/widget.html | ||
---|---|---|
4 | 4 |
{% if widget.get_error %}widget-with-error{% endif %} |
5 | 5 |
{% if widget.is_required %}widget-required{% else %}widget-optional{% endif %} |
6 | 6 |
{% if widget.is_prefilled %}widget-prefilled{% endif %}" |
7 |
{% if widget.is_hidden %}style="display: none"{% endif %} |
|
8 |
{% if widget.field %}data-field-id="{{ widget.field.id }}"{% endif %} |
|
7 | 9 |
{% if widget.div_id %}id="{{widget.div_id}}" data-valuecontainerid="form_{{widget.name}}"{% endif %} |
8 | 10 |
{% for attr in widget.prefill_attributes %} |
9 | 11 |
data-{{attr}}="{{widget.prefill_attributes|get:attr}}" |
... | ... | |
13 | 15 |
{% endif %} |
14 | 16 |
{% if "data-dynamic-display-value" in widget.attrs %} |
15 | 17 |
data-dynamic-display-value="{{widget.attrs|get:"data-dynamic-display-value"}}" |
16 |
{% endif %}> |
|
18 |
{% endif %} |
|
19 |
{% if widget.live_condition_source %}data-live-source="true"{% endif %} |
|
20 |
> |
|
17 | 21 |
{% block widget-title %} |
18 | 22 |
{{widget.rendered_title}} |
19 | 23 |
{% endblock %} |
20 |
- |