author | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> |
Thu, 19 Feb 2009 21:35:27 +0100 | |
branch | tls-sprint |
changeset 863 | 4fde01fc39ca |
parent 849 | 8591d896db7e |
child 864 | e0947007542a |
permissions | -rw-r--r-- |
0 | 1 |
"""abstract form classes for CubicWeb web client |
2 |
||
3 |
:organization: Logilab |
|
751 | 4 |
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
0 | 5 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 |
""" |
|
7 |
__docformat__ = "restructuredtext en" |
|
8 |
||
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
9 |
from warnings import warn |
0 | 10 |
from simplejson import dumps |
11 |
||
844 | 12 |
from logilab.common.compat import any |
0 | 13 |
from logilab.mtconverter import html_escape |
14 |
||
15 |
from cubicweb import typed_eid |
|
692
800592b8d39b
replace deprecated cubicweb.common.selectors by its new module path (cubicweb.selectors)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
431
diff
changeset
|
16 |
from cubicweb.selectors import match_form_params |
751 | 17 |
from cubicweb.view import NOINDEX, NOFOLLOW, View, EntityView, AnyRsetView |
0 | 18 |
from cubicweb.common.registerers import accepts_registerer |
19 |
from cubicweb.web import stdmsgs |
|
20 |
from cubicweb.web.httpcache import NoHTTPCacheManager |
|
21 |
from cubicweb.web.controller import redirect_params |
|
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
22 |
from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
23 |
|
0 | 24 |
|
25 |
||
26 |
def relation_id(eid, rtype, target, reid): |
|
27 |
if target == 'subject': |
|
28 |
return u'%s:%s:%s' % (eid, rtype, reid) |
|
29 |
return u'%s:%s:%s' % (reid, rtype, eid) |
|
844 | 30 |
|
31 |
def toggable_relation_link(eid, nodeid, label='x'): |
|
32 |
js = u"javascript: togglePendingDelete('%s', %s);" % (nodeid, html_escape(dumps(eid))) |
|
33 |
return u'[<a class="handle" href="%s" id="handle%s">%s</a>]' % (js, nodeid, label) |
|
0 | 34 |
|
35 |
||
36 |
class FormMixIn(object): |
|
37 |
"""abstract form mix-in""" |
|
38 |
category = 'form' |
|
39 |
controller = 'edit' |
|
40 |
domid = 'entityForm' |
|
41 |
||
42 |
http_cache_manager = NoHTTPCacheManager |
|
43 |
add_to_breadcrumbs = False |
|
44 |
skip_relations = set() |
|
45 |
||
46 |
def __init__(self, req, rset): |
|
47 |
super(FormMixIn, self).__init__(req, rset) |
|
48 |
self.maxrelitems = self.req.property_value('navigation.related-limit') |
|
49 |
self.maxcomboitems = self.req.property_value('navigation.combobox-limit') |
|
50 |
self.force_display = not not req.form.get('__force_display') |
|
51 |
# get validation session data which may have been previously set. |
|
52 |
# deleting validation errors here breaks form reloading (errors are |
|
53 |
# no more available), they have to be deleted by application's publish |
|
54 |
# method on successful commit |
|
55 |
formurl = req.url() |
|
56 |
forminfo = req.get_session_data(formurl) |
|
57 |
if forminfo: |
|
58 |
req.data['formvalues'] = forminfo['values'] |
|
59 |
req.data['formerrors'] = errex = forminfo['errors'] |
|
60 |
req.data['displayederrors'] = set() |
|
61 |
# if some validation error occured on entity creation, we have to |
|
62 |
# get the original variable name from its attributed eid |
|
63 |
foreid = errex.entity |
|
64 |
for var, eid in forminfo['eidmap'].items(): |
|
65 |
if foreid == eid: |
|
66 |
errex.eid = var |
|
67 |
break |
|
68 |
else: |
|
69 |
errex.eid = foreid |
|
70 |
||
71 |
def html_headers(self): |
|
72 |
"""return a list of html headers (eg something to be inserted between |
|
73 |
<head> and </head> of the returned page |
|
74 |
||
75 |
by default forms are neither indexed nor followed |
|
76 |
""" |
|
77 |
return [NOINDEX, NOFOLLOW] |
|
78 |
||
79 |
def linkable(self): |
|
80 |
"""override since forms are usually linked by an action, |
|
81 |
so we don't want them to be listed by appli.possible_views |
|
82 |
""" |
|
83 |
return False |
|
84 |
||
85 |
@property |
|
86 |
def limit(self): |
|
87 |
if self.force_display: |
|
88 |
return None |
|
89 |
return self.maxrelitems + 1 |
|
90 |
||
91 |
def need_multipart(self, entity, categories=('primary', 'secondary')): |
|
92 |
"""return a boolean indicating if form's enctype should be multipart |
|
93 |
""" |
|
94 |
for rschema, _, x in entity.relations_by_category(categories): |
|
95 |
if entity.get_widget(rschema, x).need_multipart: |
|
96 |
return True |
|
97 |
# let's find if any of our inlined entities needs multipart |
|
98 |
for rschema, targettypes, x in entity.relations_by_category('inlineview'): |
|
99 |
assert len(targettypes) == 1, \ |
|
100 |
"I'm not able to deal with several targets and inlineview" |
|
101 |
ttype = targettypes[0] |
|
102 |
inlined_entity = self.vreg.etype_class(ttype)(self.req, None, None) |
|
103 |
for irschema, _, x in inlined_entity.relations_by_category(categories): |
|
104 |
if inlined_entity.get_widget(irschema, x).need_multipart: |
|
105 |
return True |
|
106 |
return False |
|
107 |
||
108 |
def error_message(self): |
|
109 |
"""return formatted error message |
|
110 |
||
111 |
This method should be called once inlined field errors has been consumed |
|
112 |
""" |
|
113 |
errex = self.req.data.get('formerrors') |
|
114 |
# get extra errors |
|
115 |
if errex is not None: |
|
116 |
errormsg = self.req._('please correct the following errors:') |
|
117 |
displayed = self.req.data['displayederrors'] |
|
118 |
errors = sorted((field, err) for field, err in errex.errors.items() |
|
119 |
if not field in displayed) |
|
120 |
if errors: |
|
121 |
if len(errors) > 1: |
|
122 |
templstr = '<li>%s</li>\n' |
|
123 |
else: |
|
124 |
templstr = ' %s\n' |
|
125 |
for field, err in errors: |
|
126 |
if field is None: |
|
127 |
errormsg += templstr % err |
|
128 |
else: |
|
129 |
errormsg += templstr % '%s: %s' % (self.req._(field), err) |
|
130 |
if len(errors) > 1: |
|
131 |
errormsg = '<ul>%s</ul>' % errormsg |
|
132 |
return u'<div class="errorMessage">%s</div>' % errormsg |
|
133 |
return u'' |
|
134 |
||
135 |
def restore_pending_inserts(self, entity, cell=False): |
|
136 |
"""used to restore edition page as it was before clicking on |
|
137 |
'search for <some entity type>' |
|
138 |
|
|
139 |
""" |
|
140 |
eid = entity.eid |
|
141 |
cell = cell and "div_insert_" or "tr" |
|
142 |
pending_inserts = set(self.req.get_pending_inserts(eid)) |
|
143 |
for pendingid in pending_inserts: |
|
144 |
eidfrom, rtype, eidto = pendingid.split(':') |
|
145 |
if typed_eid(eidfrom) == entity.eid: # subject |
|
146 |
label = display_name(self.req, rtype, 'subject') |
|
147 |
reid = eidto |
|
148 |
else: |
|
149 |
label = display_name(self.req, rtype, 'object') |
|
150 |
reid = eidfrom |
|
151 |
jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \ |
|
152 |
% (pendingid, cell, eid) |
|
153 |
rset = self.req.eid_rset(reid) |
|
154 |
eview = self.view('text', rset, row=0) |
|
155 |
# XXX find a clean way to handle baskets |
|
156 |
if rset.description[0][0] == 'Basket': |
|
157 |
eview = '%s (%s)' % (eview, display_name(self.req, 'Basket')) |
|
158 |
yield rtype, pendingid, jscall, label, reid, eview |
|
159 |
||
160 |
||
161 |
def force_display_link(self): |
|
162 |
return (u'<span class="invisible">' |
|
163 |
u'[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]' |
|
164 |
u'</span>' % self.req._('view all')) |
|
165 |
||
166 |
def relations_table(self, entity): |
|
167 |
"""yiels 3-tuples (rtype, target, related_list) |
|
168 |
where <related_list> itself a list of : |
|
169 |
- node_id (will be the entity element's DOM id) |
|
170 |
- appropriate javascript's togglePendingDelete() function call |
|
171 |
- status 'pendingdelete' or '' |
|
172 |
- oneline view of related entity |
|
173 |
""" |
|
174 |
eid = entity.eid |
|
175 |
pending_deletes = self.req.get_pending_deletes(eid) |
|
176 |
# XXX (adim) : quick fix to get Folder relations |
|
177 |
for label, rschema, target in entity.srelations_by_category(('generic', 'metadata'), 'add'): |
|
178 |
if rschema in self.skip_relations: |
|
179 |
continue |
|
180 |
relatedrset = entity.related(rschema, target, limit=self.limit) |
|
181 |
toggable_rel_link = self.toggable_relation_link_func(rschema) |
|
182 |
related = [] |
|
183 |
for row in xrange(relatedrset.rowcount): |
|
184 |
nodeid = relation_id(eid, rschema, target, relatedrset[row][0]) |
|
185 |
if nodeid in pending_deletes: |
|
186 |
status = u'pendingDelete' |
|
187 |
label = '+' |
|
188 |
else: |
|
189 |
status = u'' |
|
190 |
label = 'x' |
|
191 |
dellink = toggable_rel_link(eid, nodeid, label) |
|
192 |
eview = self.view('oneline', relatedrset, row=row) |
|
193 |
related.append((nodeid, dellink, status, eview)) |
|
194 |
yield (rschema, target, related) |
|
195 |
||
196 |
def toggable_relation_link_func(self, rschema): |
|
197 |
if not rschema.has_perm(self.req, 'delete'): |
|
198 |
return lambda x, y, z: u'' |
|
199 |
return toggable_relation_link |
|
200 |
||
201 |
||
202 |
def redirect_url(self, entity=None): |
|
203 |
"""return a url to use as next direction if there are some information |
|
204 |
specified in current form params, else return the result the reset_url |
|
205 |
method which should be defined in concrete classes |
|
206 |
""" |
|
207 |
rparams = redirect_params(self.req.form) |
|
208 |
if rparams: |
|
209 |
return self.build_url('view', **rparams) |
|
210 |
return self.reset_url(entity) |
|
211 |
||
212 |
def reset_url(self, entity): |
|
213 |
raise NotImplementedError('implement me in concrete classes') |
|
214 |
||
215 |
BUTTON_STR = u'<input class="validateButton" type="submit" name="%s" value="%s" tabindex="%s"/>' |
|
216 |
ACTION_SUBMIT_STR = u'<input class="validateButton" type="button" onclick="postForm(\'%s\', \'%s\', \'%s\')" value="%s" tabindex="%s"/>' |
|
217 |
||
218 |
def button_ok(self, label=None, tabindex=None): |
|
219 |
label = self.req._(label or stdmsgs.BUTTON_OK).capitalize() |
|
220 |
return self.BUTTON_STR % ('defaultsubmit', label, tabindex or 2) |
|
221 |
||
222 |
def button_apply(self, label=None, tabindex=None): |
|
223 |
label = self.req._(label or stdmsgs.BUTTON_APPLY).capitalize() |
|
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
224 |
return self.ACTION_SUBMIT_STR % ('__action_apply', label, self.domid, |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
225 |
label, tabindex or 3) |
0 | 226 |
|
227 |
def button_delete(self, label=None, tabindex=None): |
|
228 |
label = self.req._(label or stdmsgs.BUTTON_DELETE).capitalize() |
|
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
229 |
return self.ACTION_SUBMIT_STR % ('__action_delete', label, self.domid, |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
230 |
label, tabindex or 3) |
0 | 231 |
|
232 |
def button_cancel(self, label=None, tabindex=None): |
|
233 |
label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() |
|
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
234 |
return self.ACTION_SUBMIT_STR % ('__action_cancel', label, self.domid, |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
235 |
label, tabindex or 4) |
0 | 236 |
|
237 |
def button_reset(self, label=None, tabindex=None): |
|
238 |
label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() |
|
239 |
return u'<input class="validateButton" type="reset" value="%s" tabindex="%s"/>' % ( |
|
240 |
label, tabindex or 4) |
|
844 | 241 |
|
242 |
||
243 |
############################################################################### |
|
244 |
||
245 |
from cubicweb.common import tags |
|
246 |
||
247 |
# widgets ############ |
|
248 |
||
249 |
class FieldWidget(object): |
|
250 |
def __init__(self, attrs=None): |
|
251 |
self.attrs = attrs or {} |
|
252 |
||
253 |
def render(self, form, field): |
|
254 |
raise NotImplementedError |
|
255 |
||
256 |
class Input(FieldWidget): |
|
257 |
type = None |
|
258 |
||
259 |
def render(self, form, field): |
|
260 |
name, value, attrs = self._render_attrs(form, field) |
|
261 |
if attrs is None: |
|
262 |
return tags.input(name=name, value=value) |
|
263 |
return tags.input(name=name, value=value, type=self.type, **attrs) |
|
264 |
||
265 |
def _render_attrs(self, form, field): |
|
266 |
name = form.context[field]['name'] # qualified name |
|
267 |
value = form.context[field]['value'] |
|
268 |
#fattrs = field.widget_attributes(self) |
|
269 |
attrs = self.attrs.copy() |
|
270 |
#attrs.update(fattrs) |
|
271 |
# XXX id |
|
272 |
return name, value, attrs |
|
273 |
||
274 |
class TextInput(Input): |
|
275 |
type = 'text' |
|
276 |
||
277 |
class PasswordInput(Input): |
|
278 |
type = 'password' |
|
279 |
||
280 |
class FileInput(Input): |
|
281 |
type = 'file' |
|
282 |
||
283 |
class HiddenInput(Input): |
|
284 |
type = 'hidden' |
|
285 |
||
286 |
class Button(Input): |
|
287 |
type = 'button' |
|
288 |
||
289 |
class TextArea(FieldWidget): |
|
290 |
def render(self, form, field): |
|
291 |
name, value, attrs = self._render_attrs(form, field) |
|
292 |
if attrs is None: |
|
293 |
return tags.textarea(value, name=name) |
|
294 |
return tags.textarea(value, name=name, **attrs) |
|
295 |
||
296 |
class Select: |
|
297 |
def render(self, form, field): |
|
298 |
name, value, attrs = self._render_attrs(form, field) |
|
299 |
if self.vocabulary: |
|
300 |
# static vocabulary defined in form definition |
|
301 |
vocab = self.vocabulary |
|
302 |
else: |
|
303 |
vocab = form.get_vocabulary(field) |
|
304 |
options = [] |
|
305 |
for label, value in vocab: |
|
306 |
options.append(tags.option(label, value=value)) |
|
307 |
if attrs is None: |
|
308 |
return tags.select(name=name, options=options) |
|
309 |
return tags.select(name=name, options=options, **attrs) |
|
310 |
||
311 |
class CheckBox: pass |
|
312 |
||
313 |
class Radio: pass |
|
314 |
||
315 |
class DateTimePicker: pass |
|
316 |
||
317 |
||
318 |
# fields ############ |
|
319 |
||
320 |
class Field(object): |
|
321 |
"""field class is introduced to control what's displayed in edition form |
|
322 |
""" |
|
323 |
widget = TextInput |
|
324 |
needs_multipart = False |
|
325 |
creation_rank = 0 |
|
326 |
||
327 |
def __init__(self, name=None, id=None, label=None, |
|
328 |
widget=None, required=False, initial=None, help=None, |
|
329 |
eidparam=True): |
|
330 |
self.required = required |
|
331 |
if widget is not None: |
|
332 |
self.widget = widget |
|
333 |
if isinstance(self.widget, type): |
|
334 |
self.widget = self.widget() |
|
335 |
self.name = name |
|
336 |
self.label = label or name |
|
337 |
self.id = id or name |
|
338 |
self.initial = initial |
|
339 |
self.help = help |
|
340 |
self.eidparam = eidparam |
|
341 |
# global fields ordering in forms |
|
342 |
Field.creation_rank += 1 |
|
343 |
||
344 |
def set_name(self, name): |
|
345 |
self.name = name |
|
346 |
if not self.id: |
|
347 |
self.id = name |
|
348 |
if not self.label: |
|
349 |
self.label = name |
|
350 |
||
351 |
def format_value(self, req, value): |
|
352 |
return unicode(value) |
|
353 |
||
354 |
def render(self, form): |
|
355 |
return self.widget.render(form, self) |
|
356 |
||
357 |
||
358 |
class StringField(Field): |
|
359 |
def __init__(self, max_length=None, **kwargs): |
|
360 |
super(StringField, self).__init__(**kwargs) |
|
361 |
self.max_length = max_length |
|
0 | 362 |
|
844 | 363 |
class TextField(Field): |
364 |
widget = TextArea |
|
365 |
def __init__(self, row=None, col=None, **kwargs): |
|
366 |
super(TextField, self).__init__(**kwargs) |
|
367 |
self.row = row |
|
368 |
self.col = col |
|
369 |
||
370 |
class RichTextField(Field): |
|
371 |
pass |
|
372 |
||
373 |
class IntField(Field): |
|
374 |
def __init__(self, min=None, max=None, **kwargs): |
|
375 |
super(IntField, self).__init__(**kwargs) |
|
376 |
self.min = min |
|
377 |
self.max = max |
|
378 |
||
379 |
class FloatField(IntField): |
|
380 |
||
381 |
def format_value(self, req, value): |
|
382 |
if value is not None: |
|
383 |
return ustrftime(value, req.property_value('ui.float-format')) |
|
384 |
return u'' |
|
385 |
||
386 |
class DateField(IntField): |
|
387 |
||
388 |
def format_value(self, req, value): |
|
389 |
return value and ustrftime(value, req.property_value('ui.date-format')) or u'' |
|
390 |
||
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
391 |
class HiddenInitialValueField(Field): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
392 |
def __init__(self, visible_field, name): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
393 |
super(HiddenInitialValueField, self).__init__(name=name, |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
394 |
widget=HiddenInput) |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
395 |
self.visible_field = visible_field |
844 | 396 |
|
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
397 |
class RelationField(Field): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
398 |
def __init__(self, role='subject', **kwargs): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
399 |
super(RelationField, self).__init__(**kwargs) |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
400 |
self.role = role |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
401 |
|
844 | 402 |
# forms ############ |
403 |
class metafieldsform(type): |
|
404 |
def __new__(mcs, name, bases, classdict): |
|
405 |
allfields = [] |
|
406 |
for base in bases: |
|
407 |
if hasattr(base, '_fields_'): |
|
408 |
allfields += base._fields_ |
|
409 |
clsfields = (item for item in classdict.items() |
|
410 |
if isinstance(item[1], Field)) |
|
411 |
for name, field in sorted(clsfields, key=lambda x: x[1].creation_rank): |
|
412 |
if not field.name: |
|
413 |
field.set_name(name) |
|
414 |
allfields.append(field) |
|
415 |
classdict['_fields_'] = allfields |
|
416 |
return super(metafieldsform, mcs).__new__(mcs, name, bases, classdict) |
|
417 |
||
418 |
||
419 |
class FieldsForm(object): |
|
420 |
__metaclass__ = metafieldsform |
|
421 |
||
422 |
def __init__(self, req, id=None, title=None, action='edit', |
|
423 |
redirect_path=None): |
|
424 |
self.req = req |
|
425 |
self.id = id or 'form' |
|
426 |
self.title = title |
|
427 |
self.action = action |
|
428 |
self.redirect_path = None |
|
429 |
self.fields = list(self.__class__._fields_) |
|
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
430 |
self.fields.append(TextField(name='__errorurl', widget=HiddenInput, |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
431 |
initial=req.url())) |
844 | 432 |
self.context = {} |
433 |
||
434 |
@property |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
435 |
def form_needs_multipart(self): |
844 | 436 |
return any(field.needs_multipart for field in self.fields) |
0 | 437 |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
438 |
def form_render(self, **values): |
844 | 439 |
renderer = values.pop('renderer', FormRenderer()) |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
440 |
self.form_build_context(values) |
844 | 441 |
return renderer.render(self) |
442 |
||
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
443 |
def form_build_context(self, values): |
844 | 444 |
self.context = context = {} |
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
445 |
# on validation error, we get a dictionnary of previously submitted values |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
446 |
previous_values = self.req.data.get('formvalues') |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
447 |
if previous_values: |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
448 |
values.update(previous_values) |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
449 |
for field in self.fields: |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
450 |
context[field] = {'value': self.form_field_value(field, values), |
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
451 |
'name': self.form_field_name(field), |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
452 |
'id': self.form_field_id(field), |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
453 |
} |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
454 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
455 |
def form_field_value(self, field, values): |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
456 |
"""looks for field's value in |
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
457 |
1. kw args given to render_form (including previously submitted form |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
458 |
values if any) |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
459 |
2. req.form |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
460 |
3. field's initial value |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
461 |
""" |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
462 |
if field.name in values: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
463 |
value = values[field.name] |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
464 |
elif field.name in self.req.form: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
465 |
value = self.req.form[field.name] |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
466 |
else: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
467 |
value = field.initial |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
468 |
return field.format_value(self.req, value) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
469 |
|
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
470 |
def form_field_name(self, field): |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
471 |
return field.name |
844 | 472 |
|
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
473 |
def form_field_id(self, field): |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
474 |
return field.id |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
475 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
476 |
def form_field_vocabulary(self, field): |
844 | 477 |
raise NotImplementedError |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
478 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
479 |
BUTTON_STR = u'<input class="validateButton" type="submit" name="%s" value="%s" tabindex="%s"/>' |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
480 |
ACTION_SUBMIT_STR = u'<input class="validateButton" type="button" onclick="postForm(\'%s\', \'%s\', \'%s\')" value="%s" tabindex="%s"/>' |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
481 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
482 |
def button_ok(self, label=None, tabindex=None): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
483 |
label = self.req._(label or stdmsgs.BUTTON_OK).capitalize() |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
484 |
return self.BUTTON_STR % ('defaultsubmit', label, tabindex or 2) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
485 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
486 |
def button_apply(self, label=None, tabindex=None): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
487 |
label = self.req._(label or stdmsgs.BUTTON_APPLY).capitalize() |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
488 |
return self.ACTION_SUBMIT_STR % ('__action_apply', label, self.id, label, tabindex or 3) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
489 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
490 |
def button_delete(self, label=None, tabindex=None): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
491 |
label = self.req._(label or stdmsgs.BUTTON_DELETE).capitalize() |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
492 |
return self.ACTION_SUBMIT_STR % ('__action_delete', label, self.id, label, tabindex or 3) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
493 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
494 |
def button_cancel(self, label=None, tabindex=None): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
495 |
label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
496 |
return self.ACTION_SUBMIT_STR % ('__action_cancel', label, self.id, label, tabindex or 4) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
497 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
498 |
def button_reset(self, label=None, tabindex=None): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
499 |
label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
500 |
return u'<input class="validateButton" type="reset" value="%s" tabindex="%s"/>' % ( |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
501 |
label, tabindex or 4) |
844 | 502 |
|
503 |
||
504 |
class EntityFieldsForm(FieldsForm): |
|
505 |
def __init__(self, *args, **kwargs): |
|
506 |
kwargs.setdefault('id', 'entityForm') |
|
507 |
super(EntityFieldsForm, self).__init__(*args, **kwargs) |
|
508 |
self.fields.append(TextField(name='__type', widget=HiddenInput)) |
|
509 |
self.fields.append(TextField(name='eid', widget=HiddenInput)) |
|
510 |
||
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
511 |
def form_render(self, entity, **values): |
844 | 512 |
self.entity = entity |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
513 |
eschema = self.entity.e_schema |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
514 |
for field in self.fields[:]: |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
515 |
fieldname = field.name |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
516 |
if fieldname != 'eid' and ( |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
517 |
(eschema.has_subject_relation(fieldname) or |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
518 |
eschema.has_object_relation(fieldname))): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
519 |
self.fields.append(self.build_hidden_field(field)) |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
520 |
return super(EntityFieldsForm, self).form_render(**values) |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
521 |
|
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
522 |
def build_hidden_field(self, field): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
523 |
"""returns the hidden field which will indicate the value |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
524 |
before the modification |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
525 |
""" |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
526 |
# Only RelationField has a `role` attribute, others are used |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
527 |
# to describe attribute fields => role is 'subject' |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
528 |
role = getattr(field, 'role', 'subject') |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
529 |
if role == 'subject': |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
530 |
name = 'edits-%s' % field.name |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
531 |
else: |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
532 |
name = 'edito-%s' % field.name |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
533 |
return HiddenInitialValueField(field, name=name) |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
534 |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
535 |
def form_field_value(self, field, values): |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
536 |
"""look for field's value with the following rules: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
537 |
1. handle special __type and eid fields |
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
538 |
2. looks in kw args given to render_form (including previously submitted |
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
539 |
form values if any) |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
540 |
3. looks in req.form |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
541 |
4. if entity has an eid: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
542 |
1. looks for an associated attribute / method |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
543 |
2. use field's initial value |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
544 |
else: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
545 |
1. looks for a default_<fieldname> attribute / method on the form |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
546 |
2. use field's initial value |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
547 |
|
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
548 |
values found in step 4 may be a callable which'll then be called. |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
549 |
""" |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
550 |
fieldname = field.name |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
551 |
if fieldname.startswith('edits-') or fieldname.startswith('edito-'): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
552 |
value = self.form_field_value(field.visible_field, values) |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
553 |
if value is None or not self.entity.has_eid(): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
554 |
value = INTERNAL_FIELD_VALUE |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
555 |
elif fieldname == '__type': |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
556 |
value = self.entity.id |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
557 |
elif fieldname == 'eid': |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
558 |
value = self.entity.eid |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
559 |
elif fieldname in values: |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
560 |
value = values[fieldname] |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
561 |
elif fieldname in self.req.form: |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
562 |
value = self.req.form[fieldname] |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
563 |
else: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
564 |
if self.entity.has_eid(): |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
565 |
# use value found on the entity or field's initial value if it's |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
566 |
# not an attribute of the entity (XXX may conflicts and get |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
567 |
# undesired value) |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
568 |
value = getattr(self.entity, fieldname, field.initial) |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
569 |
else: |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
570 |
defaultattr = 'default_%s' % fieldname |
848
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
571 |
if hasattr(self.entity, defaultattr): |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
572 |
# XXX bw compat, default_<field name> on the entity |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
573 |
warn('found %s on %s, should be set on a specific form' |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
574 |
% (defaultattr, self.entity.id), DeprecationWarning) |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
575 |
value = getattr(self.entity, defaultattr) |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
576 |
elif hasattr(self, defaultattr): |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
577 |
# search for default_<field name> on the form instance |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
578 |
value = getattr(self, defaultattr) |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
579 |
else: |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
580 |
# use field's initial value |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
581 |
value = field.initial |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
582 |
if callable(value): |
f5aca5c5f6ca
set __errorurl, fix retreiving of field's value
sylvain.thenault@logilab.fr
parents:
847
diff
changeset
|
583 |
values = value() |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
584 |
return field.format_value(self.req, value) |
844 | 585 |
|
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
586 |
def form_field_name(self, field): |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
587 |
if field.eidparam: |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
588 |
return eid_param(field.name, self.entity.eid) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
589 |
return field.name |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
590 |
|
849
8591d896db7e
update some prototype, ChangeStateForm
sylvain.thenault@logilab.fr
parents:
848
diff
changeset
|
591 |
def form_field_id(self, field): |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
592 |
if field.eidparam: |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
593 |
return eid_param(field.id, self.entity.eid) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
594 |
return field.id |
844 | 595 |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
596 |
def form_field_vocabulary(self, field): |
844 | 597 |
choices = self.vocabfunc(entity) |
598 |
if self.sort: |
|
599 |
choices = sorted(choices) |
|
600 |
if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'): |
|
601 |
return zip((entity.req._(v) for v in choices), choices) |
|
602 |
return zip(choices, choices) |
|
603 |
||
604 |
||
605 |
# form renderers ############ |
|
606 |
||
607 |
class FormRenderer(object): |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
608 |
|
844 | 609 |
def render(self, form): |
610 |
data = [] |
|
611 |
w = data.append |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
612 |
# XXX form_needs_multipart |
844 | 613 |
w(u'<form action="%s" onsubmit="return freezeFormButtons(\'%s\');" method="post" id="%s">' |
614 |
% (form.req.build_url(form.action), form.id, form.id)) |
|
615 |
w(u'<div id="progress">%s</div>' % _('validating...')) |
|
616 |
w(u'<fieldset>') |
|
617 |
w(tags.input(type='hidden', name='__form_id', value=form.id)) |
|
618 |
if form.redirect_path: |
|
619 |
w(tags.input(type='hidden', name='__redirect_path', value=form.redirect_path)) |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
620 |
self.render_fields(w, form) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
621 |
self.render_buttons(w, form) |
844 | 622 |
w(u'</fieldset>') |
623 |
w(u'</form>') |
|
624 |
return '\n'.join(data) |
|
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
625 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
626 |
def render_fields(self, w, form): |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
627 |
fields = form.fields[:] |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
628 |
for field in form.fields: |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
629 |
if isinstance(field.widget, HiddenInput): |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
630 |
w(field.render(form)) |
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
631 |
fields.remove(field) |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
632 |
w(u'<table>') |
863
4fde01fc39ca
restore previous hidden input behaviour (edits- / edito- fields)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
849
diff
changeset
|
633 |
for field in fields: |
847
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
634 |
w(u'<tr>') |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
635 |
w('<th>%s</th>' % self.render_label(form, field)) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
636 |
w(u'<td style="width:100%;">') |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
637 |
w(field.render(form)) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
638 |
w(u'</td></tr>') |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
639 |
w(u'</table>') |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
640 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
641 |
def render_buttons(self, w, form): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
642 |
for button in form.buttons(): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
643 |
w(button) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
644 |
|
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
645 |
def render_label(self, form, field): |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
646 |
label = form.req._(field.label) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
647 |
attrs = {'for': form.context[field]['id']} |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
648 |
if field.required: |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
649 |
attrs['class'] = 'required' |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
650 |
return tags.label(label, **attrs) |
27c4ebe90d03
prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer
sylvain.thenault@logilab.fr
parents:
844
diff
changeset
|
651 |