17 from cubicweb.common import tags, uilib |
17 from cubicweb.common import tags, uilib |
18 from cubicweb.web import INTERNAL_FIELD_VALUE |
18 from cubicweb.web import INTERNAL_FIELD_VALUE |
19 from cubicweb.web.formwidgets import ( |
19 from cubicweb.web.formwidgets import ( |
20 HiddenInput, TextInput, FileInput, PasswordInput, TextArea, FCKEditor, |
20 HiddenInput, TextInput, FileInput, PasswordInput, TextArea, FCKEditor, |
21 Radio, Select, DateTimePicker) |
21 Radio, Select, DateTimePicker) |
|
22 |
22 |
23 |
23 class Field(object): |
24 class Field(object): |
24 """field class is introduced to control what's displayed in forms. It makes |
25 """field class is introduced to control what's displayed in forms. It makes |
25 the link between something to edit and its display in the form. Actual |
26 the link between something to edit and its display in the form. Actual |
26 display is handled by a widget associated to the field. |
27 display is handled by a widget associated to the field. |
78 self.name = name |
79 self.name = name |
79 self.id = id or name |
80 self.id = id or name |
80 self.label = label or name |
81 self.label = label or name |
81 self.help = help |
82 self.help = help |
82 self.required = required |
83 self.required = required |
83 if widget is not None: |
|
84 self.widget = widget |
|
85 if isinstance(self.widget, type): |
|
86 self.widget = self.widget() |
|
87 self.initial = initial |
84 self.initial = initial |
88 self.choices = choices |
85 self.choices = choices |
89 self.sort = sort |
86 self.sort = sort |
90 self.internationalizable = internationalizable |
87 self.internationalizable = internationalizable |
91 self.eidparam = eidparam |
88 self.eidparam = eidparam |
92 self.role = role |
89 self.role = role |
|
90 self.init_widget(widget) |
93 # ordering number for this field instance |
91 # ordering number for this field instance |
94 self.creation_rank = Field.__creation_rank |
92 self.creation_rank = Field.__creation_rank |
95 Field.__creation_rank += 1 |
93 Field.__creation_rank += 1 |
96 |
94 |
97 def __unicode__(self): |
95 def __unicode__(self): |
99 self.__class__.__name__, self.name, self.label, |
97 self.__class__.__name__, self.name, self.label, |
100 self.id, self.initial, self.is_visible(), id(self)) |
98 self.id, self.initial, self.is_visible(), id(self)) |
101 |
99 |
102 def __repr__(self): |
100 def __repr__(self): |
103 return self.__unicode__().encode('utf-8') |
101 return self.__unicode__().encode('utf-8') |
|
102 |
|
103 def init_widget(self, widget): |
|
104 if widget is not None: |
|
105 self.widget = widget |
|
106 if isinstance(self.widget, type): |
|
107 self.widget = self.widget() |
104 |
108 |
105 def set_name(self, name): |
109 def set_name(self, name): |
106 """automatically set .id and .label when name is set""" |
110 """automatically set .id and .label when name is set""" |
107 assert name |
111 assert name |
108 self.name = name |
112 self.name = name |
175 """method called before by form_build_context to trigger potential field |
179 """method called before by form_build_context to trigger potential field |
176 initialization requiring the form instance |
180 initialization requiring the form instance |
177 """ |
181 """ |
178 pass |
182 pass |
179 |
183 |
|
184 |
180 class StringField(Field): |
185 class StringField(Field): |
|
186 widget = TextArea |
|
187 |
181 def __init__(self, max_length=None, **kwargs): |
188 def __init__(self, max_length=None, **kwargs): |
|
189 self.max_length = max_length # must be set before super call |
182 super(StringField, self).__init__(**kwargs) |
190 super(StringField, self).__init__(**kwargs) |
183 self.max_length = max_length |
191 |
|
192 def init_widget(self, widget): |
|
193 if widget is None: |
|
194 if self.choices: |
|
195 self.widget = Select() |
|
196 elif self.max_length and self.max_length < 257: |
|
197 self.widget = TextInput() |
|
198 super(StringField, self).init_widget(widget) |
184 if isinstance(self.widget, TextArea): |
199 if isinstance(self.widget, TextArea): |
185 self.init_text_area(self.widget) |
200 self.init_text_area(self.widget) |
|
201 elif isinstance(self.widget, Select): |
|
202 self.widget.attrs.setdefault('size', 1) |
186 |
203 |
187 def init_text_area(self, widget): |
204 def init_text_area(self, widget): |
188 if self.max_length < 513: |
205 if self.max_length < 513: |
189 widget.attrs.setdefault('cols', 60) |
206 widget.attrs.setdefault('cols', 60) |
190 widget.attrs.setdefault('rows', 5) |
207 widget.attrs.setdefault('rows', 5) |
340 self.max = max |
357 self.max = max |
341 if isinstance(self.widget, TextInput): |
358 if isinstance(self.widget, TextInput): |
342 self.widget.attrs.setdefault('size', 5) |
359 self.widget.attrs.setdefault('size', 5) |
343 self.widget.attrs.setdefault('maxlength', 15) |
360 self.widget.attrs.setdefault('maxlength', 15) |
344 |
361 |
|
362 |
345 class BooleanField(Field): |
363 class BooleanField(Field): |
346 widget = Radio |
364 widget = Radio |
347 |
365 |
348 def vocabulary(self, form): |
366 def vocabulary(self, form): |
349 if self.choices: |
367 if self.choices: |
378 |
396 |
379 |
397 |
380 class TimeField(DateField): |
398 class TimeField(DateField): |
381 format_prop = 'ui.datetime-format' |
399 format_prop = 'ui.datetime-format' |
382 widget = TextInput |
400 widget = TextInput |
|
401 |
383 |
402 |
384 class HiddenInitialValueField(Field): |
403 class HiddenInitialValueField(Field): |
385 def __init__(self, visible_field): |
404 def __init__(self, visible_field): |
386 name = 'edit%s-%s' % (visible_field.role[0], visible_field.name) |
405 name = 'edit%s-%s' % (visible_field.role[0], visible_field.name) |
387 super(HiddenInitialValueField, self).__init__( |
406 super(HiddenInitialValueField, self).__init__( |
468 return RichTextField(**kwargs) |
487 return RichTextField(**kwargs) |
469 constraints = rschema.rproperty(eschema, targetschema, 'constraints') |
488 constraints = rschema.rproperty(eschema, targetschema, 'constraints') |
470 # init StringField parameters according to constraints |
489 # init StringField parameters according to constraints |
471 for cstr in constraints: |
490 for cstr in constraints: |
472 if isinstance(cstr, StaticVocabularyConstraint): |
491 if isinstance(cstr, StaticVocabularyConstraint): |
473 kwargs.setdefault('widget', Select()) |
|
474 kwargs.setdefault('choices', cstr.vocabulary) |
492 kwargs.setdefault('choices', cstr.vocabulary) |
475 if card in '?1': |
493 break |
476 if isinstance(kwargs['widget'], type): |
|
477 kwargs['widget'] = kwargs['widget']() |
|
478 kwargs['widget'].attrs.setdefault('size', 1) |
|
479 for cstr in constraints: |
494 for cstr in constraints: |
480 if isinstance(cstr, SizeConstraint) and cstr.max is not None: |
495 if isinstance(cstr, SizeConstraint) and cstr.max is not None: |
481 if cstr.max < 257: |
|
482 kwargs.setdefault('widget', TextInput()) |
|
483 kwargs['max_length'] = cstr.max |
496 kwargs['max_length'] = cstr.max |
484 kwargs.setdefault('widget', TextArea()) |
|
485 return StringField(**kwargs) |
497 return StringField(**kwargs) |
486 if fieldclass is FileField: |
498 if fieldclass is FileField: |
487 for metadata in ('format', 'encoding'): |
499 for metadata in ('format', 'encoding'): |
488 metaschema = eschema.has_metadata(rschema, metadata) |
500 metaschema = eschema.has_metadata(rschema, metadata) |
489 if metaschema is not None: |
501 if metaschema is not None: |
490 kwargs['%s_field' % metadata] = guess_field(eschema, metaschema, |
502 kwargs['%s_field' % metadata] = guess_field(eschema, metaschema, |
491 skip_meta_attr=False) |
503 skip_meta_attr=False) |
492 return fieldclass(**kwargs) |
504 return fieldclass(**kwargs) |
493 kwargs['role'] = role |
505 kwargs['role'] = role |
494 return RelationField.fromcardinality(card, **kwargs) |
506 return RelationField.fromcardinality(card, **kwargs) |
|
507 |
495 |
508 |
496 FIELDS = { |
509 FIELDS = { |
497 'Boolean': BooleanField, |
510 'Boolean': BooleanField, |
498 'Bytes': FileField, |
511 'Bytes': FileField, |
499 'Date': DateField, |
512 'Date': DateField, |