author | Sylvain Thénault <sylvain.thenault@logilab.fr> |
Wed, 16 Sep 2009 17:27:04 +0200 | |
branch | 3.5 |
changeset 3263 | 5129918c671b |
parent 3244 | 1fc804b2c5ba |
child 3264 | 5d1f3f6c042d |
permissions | -rw-r--r-- |
1147 | 1 |
"""form renderers, responsible to layout a form to html |
2 |
||
3 |
:organization: Logilab |
|
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1967
diff
changeset
|
4 |
:copyright: 2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
1147 | 5 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1967
diff
changeset
|
6 |
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
1147 | 7 |
""" |
8 |
__docformat__ = "restructuredtext en" |
|
9 |
||
10 |
from logilab.common import dictattr |
|
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
11 |
from logilab.mtconverter import xml_escape |
1147 | 12 |
|
13 |
from simplejson import dumps |
|
14 |
||
15 |
from cubicweb.common import tags |
|
2656
a93ae0f6c0ad
R [base classes] only AppObject remaning, no more AppRsetObject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2586
diff
changeset
|
16 |
from cubicweb.appobject import AppObject |
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
17 |
from cubicweb.selectors import entity_implements, yes |
1147 | 18 |
from cubicweb.web import eid_param |
19 |
from cubicweb.web import formwidgets as fwdgs |
|
20 |
from cubicweb.web.widgets import checkbox |
|
1601
171afa270086
hidden input fields : compute displayability using the associated visible field
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1576
diff
changeset
|
21 |
from cubicweb.web.formfields import HiddenInitialValueField |
1147 | 22 |
|
1319 | 23 |
|
2656
a93ae0f6c0ad
R [base classes] only AppObject remaning, no more AppRsetObject
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2586
diff
changeset
|
24 |
class FormRenderer(AppObject): |
1147 | 25 |
"""basic renderer displaying fields in a two columns table label | value |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
26 |
|
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
27 |
+--------------+--------------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
28 |
| field1 label | field1 input | |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
29 |
+--------------+--------------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
30 |
| field1 label | field2 input | |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
31 |
+--------------+--------------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
32 |
+---------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
33 |
| buttons | |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
34 |
+---------+ |
1147 | 35 |
""" |
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
36 |
__registry__ = 'formrenderers' |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
37 |
id = 'default' |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
38 |
|
1434
42e57dbbc585
new display_relations_form option on EntityFormRender
sylvain.thenault@logilab.fr
parents:
1412
diff
changeset
|
39 |
_options = ('display_fields', 'display_label', 'display_help', |
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
40 |
'display_progress_div', 'table_class', 'button_bar_class', |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
41 |
# add entity since it may be given to select the renderer |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
42 |
'entity') |
1362
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
43 |
display_fields = None # None -> all fields |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
44 |
display_label = True |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
45 |
display_help = True |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
46 |
display_progress_div = True |
1710
8c717cc0b353
refactor error handling: get validation error information from a form attribute instead of req.data to avoid pb when multiple forms are displayed
sylvain.thenault@logilab.fr
parents:
1691
diff
changeset
|
47 |
table_class = u'attributeForm' |
1147 | 48 |
button_bar_class = u'formButtonBar' |
1436 | 49 |
|
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
50 |
def __init__(self, req=None, rset=None, row=None, col=None, **kwargs): |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
51 |
super(FormRenderer, self).__init__(req, rset, row, col) |
1362
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
52 |
if self._set_options(kwargs): |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
53 |
raise ValueError('unconsumed arguments %s' % kwargs) |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
54 |
|
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
55 |
def _set_options(self, kwargs): |
1434
42e57dbbc585
new display_relations_form option on EntityFormRender
sylvain.thenault@logilab.fr
parents:
1412
diff
changeset
|
56 |
for key in self._options: |
1362
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
57 |
try: |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
58 |
setattr(self, key, kwargs.pop(key)) |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
59 |
except KeyError: |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
60 |
continue |
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
61 |
return kwargs |
1436 | 62 |
|
1147 | 63 |
# renderer interface ###################################################### |
1436 | 64 |
|
1147 | 65 |
def render(self, form, values): |
1362
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
66 |
self._set_options(values) |
1147 | 67 |
form.add_media() |
68 |
data = [] |
|
69 |
w = data.append |
|
70 |
w(self.open_form(form, values)) |
|
1362
decb7507fa91
nicer renderer options handling: can be passed to __init__ or to render
sylvain.thenault@logilab.fr
parents:
1340
diff
changeset
|
71 |
if self.display_progress_div: |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
72 |
w(u'<div id="progress">%s</div>' % self.req._('validating...')) |
1147 | 73 |
w(u'<fieldset>') |
74 |
w(tags.input(type=u'hidden', name=u'__form_id', |
|
75 |
value=values.get('formvid', form.id))) |
|
76 |
if form.redirect_path: |
|
77 |
w(tags.input(type='hidden', name='__redirectpath', value=form.redirect_path)) |
|
78 |
self.render_fields(w, form, values) |
|
79 |
self.render_buttons(w, form) |
|
80 |
w(u'</fieldset>') |
|
81 |
w(u'</form>') |
|
82 |
errormsg = self.error_message(form) |
|
83 |
if errormsg: |
|
1436 | 84 |
data.insert(0, errormsg) |
1147 | 85 |
return '\n'.join(data) |
86 |
||
87 |
def render_label(self, form, field): |
|
2521
782360fa6cc0
take care to None labels
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2520
diff
changeset
|
88 |
if field.label is None: |
782360fa6cc0
take care to None labels
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2520
diff
changeset
|
89 |
return u'' |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
90 |
label = self.req._(field.label) |
1147 | 91 |
attrs = {'for': form.context[field]['id']} |
92 |
if field.required: |
|
93 |
attrs['class'] = 'required' |
|
94 |
return tags.label(label, **attrs) |
|
95 |
||
96 |
def render_help(self, form, field): |
|
1946
d60ddfc4bb09
don't use tab
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1863
diff
changeset
|
97 |
help = [] |
1147 | 98 |
descr = field.help |
2093
e3aaf61f8c66
field's help may now be a callable taking the form as argument
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2006
diff
changeset
|
99 |
if callable(descr): |
e3aaf61f8c66
field's help may now be a callable taking the form as argument
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2006
diff
changeset
|
100 |
descr = descr(form) |
1147 | 101 |
if descr: |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
102 |
help.append('<div class="helper">%s</div>' % self.req._(descr)) |
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
103 |
example = field.example_format(self.req) |
1147 | 104 |
if example: |
1863
9a02979a2c00
do not use <br> in widgets
Katia Saurfelt <katia.saurfelt@logilab.fr>
parents:
1757
diff
changeset
|
105 |
help.append('<div class="helper">(%s: %s)</div>' |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
106 |
% (self.req._('sample format'), example)) |
2996
866a2c135c33
B #345282 xhtml requires to use   instead of
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2656
diff
changeset
|
107 |
return u' '.join(help) |
1147 | 108 |
|
109 |
# specific methods (mostly to ease overriding) ############################# |
|
110 |
||
111 |
def error_message(self, form): |
|
112 |
"""return formatted error message |
|
113 |
||
114 |
This method should be called once inlined field errors has been consumed |
|
115 |
""" |
|
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
116 |
req = self.req |
1710
8c717cc0b353
refactor error handling: get validation error information from a form attribute instead of req.data to avoid pb when multiple forms are displayed
sylvain.thenault@logilab.fr
parents:
1691
diff
changeset
|
117 |
errex = form.form_valerror |
1147 | 118 |
# get extra errors |
119 |
if errex is not None: |
|
120 |
errormsg = req._('please correct the following errors:') |
|
1710
8c717cc0b353
refactor error handling: get validation error information from a form attribute instead of req.data to avoid pb when multiple forms are displayed
sylvain.thenault@logilab.fr
parents:
1691
diff
changeset
|
121 |
displayed = form.form_displayed_errors |
1147 | 122 |
errors = sorted((field, err) for field, err in errex.errors.items() |
123 |
if not field in displayed) |
|
124 |
if errors: |
|
125 |
if len(errors) > 1: |
|
1436 | 126 |
templstr = '<li>%s</li>\n' |
1147 | 127 |
else: |
2996
866a2c135c33
B #345282 xhtml requires to use   instead of
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2656
diff
changeset
|
128 |
templstr = ' %s\n' |
1147 | 129 |
for field, err in errors: |
130 |
if field is None: |
|
131 |
errormsg += templstr % err |
|
132 |
else: |
|
133 |
errormsg += templstr % '%s: %s' % (req._(field), err) |
|
134 |
if len(errors) > 1: |
|
135 |
errormsg = '<ul>%s</ul>' % errormsg |
|
136 |
return u'<div class="errorMessage">%s</div>' % errormsg |
|
137 |
return u'' |
|
1436 | 138 |
|
1147 | 139 |
def open_form(self, form, values): |
140 |
if form.form_needs_multipart: |
|
141 |
enctype = 'multipart/form-data' |
|
142 |
else: |
|
143 |
enctype = 'application/x-www-form-urlencoded' |
|
144 |
if form.action is None: |
|
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
145 |
action = self.req.build_url('edit') |
1147 | 146 |
else: |
147 |
action = form.action |
|
1274
b730932a79b7
we don't want dom id systematically
sylvain.thenault@logilab.fr
parents:
1181
diff
changeset
|
148 |
tag = ('<form action="%s" method="post" enctype="%s"' % ( |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
149 |
xml_escape(action or '#'), enctype)) |
1274
b730932a79b7
we don't want dom id systematically
sylvain.thenault@logilab.fr
parents:
1181
diff
changeset
|
150 |
if form.domid: |
b730932a79b7
we don't want dom id systematically
sylvain.thenault@logilab.fr
parents:
1181
diff
changeset
|
151 |
tag += ' id="%s"' % form.domid |
1147 | 152 |
if form.onsubmit: |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
153 |
tag += ' onsubmit="%s"' % xml_escape(form.onsubmit % dictattr(form)) |
1147 | 154 |
if form.cssstyle: |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
155 |
tag += ' style="%s"' % xml_escape(form.cssstyle) |
1147 | 156 |
if form.cssclass: |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
157 |
tag += ' class="%s"' % xml_escape(form.cssclass) |
1147 | 158 |
if form.cwtarget: |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
159 |
tag += ' cubicweb:target="%s"' % xml_escape(form.cwtarget) |
1147 | 160 |
return tag + '>' |
1436 | 161 |
|
1147 | 162 |
def display_field(self, form, field): |
1601
171afa270086
hidden input fields : compute displayability using the associated visible field
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1576
diff
changeset
|
163 |
if isinstance(field, HiddenInitialValueField): |
171afa270086
hidden input fields : compute displayability using the associated visible field
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1576
diff
changeset
|
164 |
field = field.visible_field |
1147 | 165 |
return (self.display_fields is None |
1628 | 166 |
or field.name in form.internal_fields |
1576
3bfcf1e4eb26
display_fields should search for name+role
sylvain.thenault@logilab.fr
parents:
1436
diff
changeset
|
167 |
or (field.name, field.role) in self.display_fields |
3bfcf1e4eb26
display_fields should search for name+role
sylvain.thenault@logilab.fr
parents:
1436
diff
changeset
|
168 |
or (field.name, field.role) in form.internal_fields) |
1436 | 169 |
|
1147 | 170 |
def render_fields(self, w, form, values): |
171 |
form.form_build_context(values) |
|
172 |
fields = self._render_hidden_fields(w, form) |
|
173 |
if fields: |
|
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
174 |
self._render_fields(fields, w, form) |
1147 | 175 |
self.render_child_forms(w, form, values) |
1436 | 176 |
|
1147 | 177 |
def render_child_forms(self, w, form, values): |
1436 | 178 |
# render |
1147 | 179 |
for childform in getattr(form, 'forms', []): |
180 |
self.render_fields(w, childform, values) |
|
181 |
||
182 |
def _render_hidden_fields(self, w, form): |
|
183 |
fields = form.fields[:] |
|
184 |
for field in form.fields: |
|
185 |
if not self.display_field(form, field): |
|
186 |
fields.remove(field) |
|
187 |
elif not field.is_visible(): |
|
188 |
w(field.render(form, self)) |
|
189 |
fields.remove(field) |
|
190 |
return fields |
|
1436 | 191 |
|
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
192 |
def _render_fields(self, fields, w, form): |
2520
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
193 |
byfieldset = {} |
1147 | 194 |
for field in fields: |
2520
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
195 |
byfieldset.setdefault(field.fieldset, []).append(field) |
2574
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
196 |
if form.fieldsets_in_order: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
197 |
fieldsets = form.fieldsets_in_order |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
198 |
else: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
199 |
fieldsets = byfieldset.keys() |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
200 |
for fieldset in fieldsets: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
201 |
try: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
202 |
fields = byfieldset.pop(fieldset) |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
203 |
except KeyError: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
204 |
self.warning('no such fieldset: %s (%s)', fieldset, form) |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
205 |
continue |
2520
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
206 |
w(u'<fieldset class="%s">' % (fieldset or u'default')) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
207 |
if fieldset: |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
208 |
w(u'<legend>%s</legend>' % self.req._(fieldset)) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
209 |
w(u'<table class="%s">' % self.table_class) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
210 |
for field in fields: |
2561
c6f0634e2d77
[F xhml] use a class to avoid duplicated ids when editing several entities at once
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2550
diff
changeset
|
211 |
w(u'<tr class="%s_%s_row">' % (field.name, field.role)) |
2520
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
212 |
if self.display_label: |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
213 |
w(u'<th class="labelCol">%s</th>' % self.render_label(form, field)) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
214 |
error = form.form_field_error(field) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
215 |
if error: |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
216 |
w(u'<td class="error">') |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
217 |
w(error) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
218 |
else: |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
219 |
w(u'<td>') |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
220 |
w(field.render(form, self)) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
221 |
if self.display_help: |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
222 |
w(self.render_help(form, field)) |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
223 |
w(u'</td></tr>') |
8c5cf48ae9ea
new fieldset attribute on field, use to group fields by the default form renderer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
224 |
w(u'</table></fieldset>') |
2574
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
225 |
if byfieldset: |
37154aa90947
[form renderer] consider form.fieldsets_in_order if specified. Warn about unexistant or unused fieldsets.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2561
diff
changeset
|
226 |
self.warning('unused fieldsets: %s', ', '.join(byfieldset)) |
1147 | 227 |
|
228 |
def render_buttons(self, w, form): |
|
2148
2b2b9626a98f
do not write -invalid- empty table row when form has no buttons
Florent <florent@secondweb.fr>
parents:
2093
diff
changeset
|
229 |
if not form.form_buttons: |
2b2b9626a98f
do not write -invalid- empty table row when form has no buttons
Florent <florent@secondweb.fr>
parents:
2093
diff
changeset
|
230 |
return |
1147 | 231 |
w(u'<table class="%s">\n<tr>\n' % self.button_bar_class) |
1304 | 232 |
for button in form.form_buttons: |
233 |
w(u'<td>%s</td>\n' % button.render(form)) |
|
1147 | 234 |
w(u'</tr></table>') |
235 |
||
236 |
||
2005
e8032965f37a
turn every form class into appobject. They should not be instantiated manually anymore.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1995
diff
changeset
|
237 |
class BaseFormRenderer(FormRenderer): |
2198
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
238 |
"""use form_renderer_id = 'base' if you want base FormRenderer layout even |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
239 |
when selected for an entity |
2005
e8032965f37a
turn every form class into appobject. They should not be instantiated manually anymore.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1995
diff
changeset
|
240 |
""" |
e8032965f37a
turn every form class into appobject. They should not be instantiated manually anymore.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1995
diff
changeset
|
241 |
id = 'base' |
e8032965f37a
turn every form class into appobject. They should not be instantiated manually anymore.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1995
diff
changeset
|
242 |
|
e8032965f37a
turn every form class into appobject. They should not be instantiated manually anymore.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1995
diff
changeset
|
243 |
|
2198
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
244 |
class EntityBaseFormRenderer(BaseFormRenderer): |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
245 |
"""use form_renderer_id = 'base' if you want base FormRenderer layout even |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
246 |
when selected for an entity |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
247 |
""" |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
248 |
__select__ = entity_implements('Any') |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
249 |
|
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
250 |
def display_field(self, form, field): |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
251 |
if not super(EntityBaseFormRenderer, self).display_field(form, field): |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
252 |
if isinstance(field, HiddenInitialValueField): |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
253 |
field = field.visible_field |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
254 |
ismeta = form.edited_entity.e_schema.is_metadata(field.name) |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
255 |
return ismeta is not None and ( |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
256 |
ismeta[0] in self.display_fields or |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
257 |
(ismeta[0], 'subject') in self.display_fields) |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
258 |
return True |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
259 |
|
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
260 |
|
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
261 |
class HTableFormRenderer(FormRenderer): |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
262 |
"""display fields horizontally in a table |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
263 |
|
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
264 |
+--------------+--------------+---------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
265 |
| field1 label | field2 label | | |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
266 |
+--------------+--------------+---------+ |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
267 |
| field1 input | field2 input | buttons |
1436 | 268 |
+--------------+--------------+---------+ |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
269 |
""" |
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
270 |
id = 'htable' |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
271 |
|
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
272 |
display_help = False |
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
273 |
def _render_fields(self, fields, w, form): |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
274 |
w(u'<table border="0">') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
275 |
w(u'<tr>') |
1436 | 276 |
for field in fields: |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
277 |
if self.display_label: |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
278 |
w(u'<th class="labelCol">%s</th>' % self.render_label(form, field)) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
279 |
if self.display_help: |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
280 |
w(self.render_help(form, field)) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
281 |
# empty slot for buttons |
2996
866a2c135c33
B #345282 xhtml requires to use   instead of
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2656
diff
changeset
|
282 |
w(u'<th class="labelCol"> </th>') |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
283 |
w(u'</tr>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
284 |
w(u'<tr>') |
1436 | 285 |
for field in fields: |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
286 |
error = form.form_field_error(field) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
287 |
if error: |
1757 | 288 |
w(u'<td class="error">') |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
289 |
w(error) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
290 |
else: |
1757 | 291 |
w(u'<td>') |
1401
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
292 |
w(field.render(form, self)) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
293 |
w(u'</td>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
294 |
w(u'<td>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
295 |
for button in form.form_buttons: |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
296 |
w(button.render(form)) |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
297 |
w(u'</td>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
298 |
w(u'</tr>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
299 |
w(u'</table>') |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
300 |
|
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
301 |
def render_buttons(self, w, form): |
56764b1b4887
new renderer displaying field in an horizontable table
sylvain.thenault@logilab.fr
parents:
1362
diff
changeset
|
302 |
pass |
1436 | 303 |
|
304 |
||
1147 | 305 |
class EntityCompositeFormRenderer(FormRenderer): |
306 |
"""specific renderer for multiple entities edition form (muledit)""" |
|
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
307 |
id = 'composite' |
1436 | 308 |
|
2575
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
309 |
_main_display_fields = None |
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
310 |
|
1147 | 311 |
def render_fields(self, w, form, values): |
312 |
if not form.is_subform: |
|
313 |
w(u'<table class="listing">') |
|
2586
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
314 |
subfields = [field for field in form.forms[0].fields |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
315 |
if self.display_field(form, field) |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
316 |
and field.is_visible()] |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
317 |
if subfields: |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
318 |
# main form, display table headers |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
319 |
w(u'<tr class="header">') |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
320 |
w(u'<th align="left">%s</th>' % |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
321 |
tags.input(type='checkbox', |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
322 |
title=self.req._('toggle check boxes'), |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
323 |
onclick="setCheckboxesState('eid', this.checked)")) |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
324 |
for field in subfields: |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
325 |
w(u'<th>%s</th>' % self.req._(field.label)) |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
326 |
w(u'</tr>') |
1147 | 327 |
super(EntityCompositeFormRenderer, self).render_fields(w, form, values) |
328 |
if not form.is_subform: |
|
329 |
w(u'</table>') |
|
2575
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
330 |
if self._main_display_fields: |
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
331 |
super(EntityCompositeFormRenderer, self)._render_fields( |
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
332 |
self._main_display_fields, w, form) |
1436 | 333 |
|
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
334 |
def _render_fields(self, fields, w, form): |
1147 | 335 |
if form.is_subform: |
336 |
entity = form.edited_entity |
|
1710
8c717cc0b353
refactor error handling: get validation error information from a form attribute instead of req.data to avoid pb when multiple forms are displayed
sylvain.thenault@logilab.fr
parents:
1691
diff
changeset
|
337 |
values = form.form_previous_values |
1147 | 338 |
qeid = eid_param('eid', entity.eid) |
2577 | 339 |
cbsetstate = "setCheckboxesState2('eid', %s, 'checked')" % \ |
340 |
xml_escape(dumps(entity.eid)) |
|
1147 | 341 |
w(u'<tr class="%s">' % (entity.row % 2 and u'even' or u'odd')) |
342 |
# XXX turn this into a widget used on the eid field |
|
2577 | 343 |
w(u'<td>%s</td>' % checkbox('eid', entity.eid, |
344 |
checked=qeid in values)) |
|
1147 | 345 |
for field in fields: |
346 |
error = form.form_field_error(field) |
|
347 |
if error: |
|
348 |
w(u'<td class="error">') |
|
349 |
w(error) |
|
350 |
else: |
|
351 |
w(u'<td>') |
|
2577 | 352 |
if isinstance(field.widget, (fwdgs.Select, fwdgs.CheckBox, |
353 |
fwdgs.Radio)): |
|
1147 | 354 |
field.widget.attrs['onchange'] = cbsetstate |
355 |
elif isinstance(field.widget, fwdgs.Input): |
|
356 |
field.widget.attrs['onkeypress'] = cbsetstate |
|
2577 | 357 |
# XXX else |
1147 | 358 |
w(u'<div>%s</div>' % field.render(form, self)) |
2586
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
359 |
w(u'</td>\n') |
879912fe94e1
[xhtml form renderer] fix html structure, move header where we are sure to display it when necesary (_render_fields not displayed if main form has no visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2577
diff
changeset
|
360 |
w(u'</tr>') |
1147 | 361 |
else: |
2575
e033939d5664
[form renderer] fix composite form renderer in case the main form has some visible fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2574
diff
changeset
|
362 |
self._main_display_fields = fields |
1436 | 363 |
|
364 |
||
2198
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
365 |
class EntityFormRenderer(EntityBaseFormRenderer): |
1147 | 366 |
"""specific renderer for entity edition form (edition)""" |
2198
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
367 |
id = 'default' |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
368 |
# needs some additional points in some case (XXX explain cases) |
ac45d4dbaf76
close #344264, pb with composite fields / renderer.display_fields
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2148
diff
changeset
|
369 |
__select__ = EntityBaseFormRenderer.__select__ & yes() |
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
370 |
|
1434
42e57dbbc585
new display_relations_form option on EntityFormRender
sylvain.thenault@logilab.fr
parents:
1412
diff
changeset
|
371 |
_options = FormRenderer._options + ('display_relations_form',) |
42e57dbbc585
new display_relations_form option on EntityFormRender
sylvain.thenault@logilab.fr
parents:
1412
diff
changeset
|
372 |
display_relations_form = True |
1436 | 373 |
|
1181
620ec8e6ae19
cleanup, various fix to get something working
sylvain.thenault@logilab.fr
parents:
1147
diff
changeset
|
374 |
def render(self, form, values): |
620ec8e6ae19
cleanup, various fix to get something working
sylvain.thenault@logilab.fr
parents:
1147
diff
changeset
|
375 |
rendered = super(EntityFormRenderer, self).render(form, values) |
620ec8e6ae19
cleanup, various fix to get something working
sylvain.thenault@logilab.fr
parents:
1147
diff
changeset
|
376 |
return rendered + u'</div>' # close extra div introducted by open_form |
1436 | 377 |
|
1147 | 378 |
def open_form(self, form, values): |
379 |
attrs_fs_label = ('<div class="iformTitle"><span>%s</span></div>' |
|
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
380 |
% self.req._('main informations')) |
1147 | 381 |
attrs_fs_label += '<div class="formBody">' |
1181
620ec8e6ae19
cleanup, various fix to get something working
sylvain.thenault@logilab.fr
parents:
1147
diff
changeset
|
382 |
return attrs_fs_label + super(EntityFormRenderer, self).open_form(form, values) |
1147 | 383 |
|
384 |
def render_fields(self, w, form, values): |
|
385 |
super(EntityFormRenderer, self).render_fields(w, form, values) |
|
386 |
self.inline_entities_form(w, form) |
|
1436 | 387 |
if form.edited_entity.has_eid() and self.display_relations_form: |
1147 | 388 |
self.relations_form(w, form) |
389 |
||
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
390 |
def _render_fields(self, fields, w, form): |
1147 | 391 |
if not form.edited_entity.has_eid() or form.edited_entity.has_perm('update'): |
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
392 |
super(EntityFormRenderer, self)._render_fields(fields, w, form) |
1436 | 393 |
|
1147 | 394 |
def render_buttons(self, w, form): |
1304 | 395 |
if len(form.form_buttons) == 3: |
1147 | 396 |
w("""<table width="100%%"> |
397 |
<tbody> |
|
398 |
<tr><td align="center"> |
|
399 |
%s |
|
400 |
</td><td style="align: right; width: 50%%;"> |
|
401 |
%s |
|
402 |
%s |
|
403 |
</td></tr> |
|
404 |
</tbody> |
|
1304 | 405 |
</table>""" % tuple(button.render(form) for button in form.form_buttons)) |
1147 | 406 |
else: |
407 |
super(EntityFormRenderer, self).render_buttons(w, form) |
|
1436 | 408 |
|
1147 | 409 |
def relations_form(self, w, form): |
3244
1fc804b2c5ba
since unrelated_rql now consider security, we may consider returning relation having local role in some cases
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2996
diff
changeset
|
410 |
srels_by_cat = form.srelations_by_category('generic', 'add', strict=True) |
1147 | 411 |
if not srels_by_cat: |
412 |
return u'' |
|
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
413 |
req = self.req |
1147 | 414 |
_ = req._ |
3263
5129918c671b
i18n update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3244
diff
changeset
|
415 |
__ = _ |
5129918c671b
i18n update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3244
diff
changeset
|
416 |
label = u'%s :' % __('This %s' % form.edited_entity.e_schema).capitalize() |
1147 | 417 |
eid = form.edited_entity.eid |
418 |
w(u'<fieldset class="subentity">') |
|
419 |
w(u'<legend class="iformTitle">%s</legend>' % label) |
|
420 |
w(u'<table id="relatedEntities">') |
|
421 |
for rschema, target, related in form.relations_table(): |
|
422 |
# already linked entities |
|
423 |
if related: |
|
424 |
w(u'<tr><th class="labelCol">%s</th>' % rschema.display_name(req, target)) |
|
425 |
w(u'<td>') |
|
426 |
w(u'<ul>') |
|
427 |
for viewparams in related: |
|
428 |
w(u'<li class="invisible">%s<div id="span%s" class="%s">%s</div></li>' |
|
429 |
% (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) |
|
430 |
if not form.force_display and form.maxrelitems < len(related): |
|
1436 | 431 |
link = (u'<span class="invisible">' |
1147 | 432 |
'[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]' |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
433 |
'</span>' % self.req._('view all')) |
1147 | 434 |
w(u'<li class="invisible">%s</li>' % link) |
435 |
w(u'</ul>') |
|
436 |
w(u'</td>') |
|
437 |
w(u'</tr>') |
|
438 |
pendings = list(form.restore_pending_inserts()) |
|
439 |
if not pendings: |
|
2996
866a2c135c33
B #345282 xhtml requires to use   instead of
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2656
diff
changeset
|
440 |
w(u'<tr><th> </th><td> </td></tr>') |
1147 | 441 |
else: |
442 |
for row in pendings: |
|
443 |
# soon to be linked to entities |
|
444 |
w(u'<tr id="tr%s">' % row[1]) |
|
445 |
w(u'<th>%s</th>' % row[3]) |
|
446 |
w(u'<td>') |
|
447 |
w(u'<a class="handle" title="%s" href="%s">[x]</a>' % |
|
448 |
(_('cancel this insert'), row[2])) |
|
449 |
w(u'<a id="a%s" class="editionPending" href="%s">%s</a>' |
|
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
450 |
% (row[1], row[4], xml_escape(row[5]))) |
1147 | 451 |
w(u'</td>') |
452 |
w(u'</tr>') |
|
453 |
w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid) |
|
454 |
w(u'<th class="labelCol">') |
|
455 |
w(u'<span>%s</span>' % _('add relation')) |
|
1305
395ef7f2b95b
cleanup, remove some unnecessary (sometime buggy) stuff
sylvain.thenault@logilab.fr
parents:
1304
diff
changeset
|
456 |
w(u'<select id="relationSelector_%s" tabindex="%s" ' |
395ef7f2b95b
cleanup, remove some unnecessary (sometime buggy) stuff
sylvain.thenault@logilab.fr
parents:
1304
diff
changeset
|
457 |
'onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">' |
2312
af4d8f75c5db
use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2247
diff
changeset
|
458 |
% (eid, req.next_tabindex(), xml_escape(dumps(eid)))) |
1147 | 459 |
w(u'<option value="">%s</option>' % _('select a relation')) |
460 |
for i18nrtype, rschema, target in srels_by_cat: |
|
461 |
# more entities to link to |
|
462 |
w(u'<option value="%s_%s">%s</option>' % (rschema, target, i18nrtype)) |
|
463 |
w(u'</select>') |
|
464 |
w(u'</th>') |
|
465 |
w(u'<td id="unrelatedDivs_%s"></td>' % eid) |
|
466 |
w(u'</tr>') |
|
467 |
w(u'</table>') |
|
468 |
w(u'</fieldset>') |
|
1436 | 469 |
|
1147 | 470 |
def inline_entities_form(self, w, form): |
471 |
"""create a form to edit entity's inlined relations""" |
|
1967
28eed65ce1e6
don't crash if inlined_relation is not defined on the form
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1964
diff
changeset
|
472 |
if not hasattr(form, 'inlined_relations'): |
28eed65ce1e6
don't crash if inlined_relation is not defined on the form
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1964
diff
changeset
|
473 |
return |
1291
22b4d300d18d
inlineview is no more a 'category', needs specific handling
sylvain.thenault@logilab.fr
parents:
1274
diff
changeset
|
474 |
for rschema, targettypes, role in form.inlined_relations(): |
1147 | 475 |
# show inline forms only if there's one possible target type |
476 |
# for rschema |
|
477 |
if len(targettypes) != 1: |
|
478 |
self.warning('entity related by the %s relation should have ' |
|
479 |
'inlined form but there is multiple target types, ' |
|
480 |
'dunno what to do', rschema) |
|
481 |
continue |
|
482 |
targettype = targettypes[0].type |
|
483 |
if form.should_inline_relation_form(rschema, targettype, role): |
|
2103
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
484 |
self.inline_relation_form(w, form, rschema, targettype, role) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
485 |
|
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
486 |
def inline_relation_form(self, w, form, rschema, targettype, role): |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
487 |
entity = form.edited_entity |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
488 |
__ = self.req.__ |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
489 |
w(u'<div id="inline%sslot">' % rschema) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
490 |
existant = entity.has_eid() and entity.related(rschema) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
491 |
if existant: |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
492 |
# display inline-edition view for all existing related entities |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
493 |
w(form.view('inline-edition', existant, rtype=rschema, role=role, |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
494 |
ptype=entity.e_schema, peid=entity.eid)) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
495 |
if role == 'subject': |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
496 |
card = rschema.rproperty(entity.e_schema, targettype, 'cardinality')[0] |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
497 |
else: |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
498 |
card = rschema.rproperty(targettype, entity.e_schema, 'cardinality')[1] |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
499 |
# there is no related entity and we need at least one: we need to |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
500 |
# display one explicit inline-creation view |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
501 |
if form.should_display_inline_creation_form(rschema, existant, card): |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
502 |
w(form.view('inline-creation', None, etype=targettype, |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
503 |
peid=entity.eid, ptype=entity.e_schema, |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
504 |
rtype=rschema, role=role)) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
505 |
# we can create more than one related entity, we thus display a link |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
506 |
# to add new related entities |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
507 |
if form.should_display_add_new_relation_link(rschema, existant, card): |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
508 |
divid = "addNew%s%s%s:%s" % (targettype, rschema, role, entity.eid) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
509 |
w(u'<div class="inlinedform" id="%s" cubicweb:limit="true">' |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
510 |
% divid) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
511 |
js = "addInlineCreationForm('%s', '%s', '%s', '%s')" % ( |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
512 |
entity.eid, targettype, rschema, role) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
513 |
if card in '1?': |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
514 |
js = "toggleVisibility('%s'); %s" % (divid, js) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
515 |
w(u'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>' |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
516 |
% (rschema, entity.eid, js, __('add a %s' % targettype))) |
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
517 |
w(u'</div>') |
2996
866a2c135c33
B #345282 xhtml requires to use   instead of
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
2656
diff
changeset
|
518 |
w(u'<div class="trame_grise"> </div>') |
2103
41840b1a2a1a
make inline relation forms individually renderable
Florent <florent@secondweb.fr>
parents:
2006
diff
changeset
|
519 |
w(u'</div>') |
1147 | 520 |
|
1436 | 521 |
|
1147 | 522 |
class EntityInlinedFormRenderer(EntityFormRenderer): |
523 |
"""specific renderer for entity inlined edition form |
|
524 |
(inline-[creation|edition]) |
|
525 |
""" |
|
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
526 |
id = 'inline' |
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
527 |
|
1147 | 528 |
def render(self, form, values): |
529 |
form.add_media() |
|
530 |
data = [] |
|
531 |
w = data.append |
|
532 |
try: |
|
533 |
w(u'<div id="div-%(divid)s" onclick="%(divonclick)s">' % values) |
|
534 |
except KeyError: |
|
535 |
w(u'<div id="div-%(divid)s">' % values) |
|
536 |
else: |
|
537 |
w(u'<div id="notice-%s" class="notice">%s</div>' % ( |
|
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
538 |
values['divid'], self.req._('click on the box to cancel the deletion'))) |
1147 | 539 |
w(u'<div class="iformBody">') |
2006
78d5b57d4964
we can now use self.req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2005
diff
changeset
|
540 |
values['removemsg'] = self.req.__('remove this %s' % form.edited_entity.e_schema) |
1147 | 541 |
w(u'<div class="iformTitle"><span>%(title)s</span> ' |
2247
9dbbe6a4c9b0
use a counter of displayed inlined forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2198
diff
changeset
|
542 |
'#<span class="icounter">%(counter)s</span> ' |
1147 | 543 |
'[<a href="javascript: %(removejs)s;noop();">%(removemsg)s</a>]</div>' |
544 |
% values) |
|
1964
b60719223965
need to cleanup values if we don't want them to be interpreted by fields (title is a common field name for instance)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1946
diff
changeset
|
545 |
# cleanup values |
b60719223965
need to cleanup values if we don't want them to be interpreted by fields (title is a common field name for instance)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1946
diff
changeset
|
546 |
for key in ('title', 'removejs', 'removemsg'): |
b60719223965
need to cleanup values if we don't want them to be interpreted by fields (title is a common field name for instance)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1946
diff
changeset
|
547 |
values.pop(key) |
1147 | 548 |
self.render_fields(w, form, values) |
1293 | 549 |
w(u'</div></div>') |
1147 | 550 |
return '\n'.join(data) |
1436 | 551 |
|
1147 | 552 |
def render_fields(self, w, form, values): |
553 |
form.form_build_context(values) |
|
554 |
w(u'<fieldset id="fs-%(divid)s">' % values) |
|
555 |
fields = self._render_hidden_fields(w, form) |
|
556 |
w(u'</fieldset>') |
|
557 |
w(u'<fieldset class="subentity">') |
|
558 |
if fields: |
|
1403
425892e14e67
_render_fields don't need values argument
sylvain.thenault@logilab.fr
parents:
1401
diff
changeset
|
559 |
self._render_fields(fields, w, form) |
1147 | 560 |
self.render_child_forms(w, form, values) |
561 |
self.inline_entities_form(w, form) |
|
562 |
w(u'</fieldset>') |
|
1436 | 563 |