web/form.py
branchtls-sprint
changeset 897 f5b91f11d8b6
parent 896 6e0379fc1988
child 898 583f64567256
equal deleted inserted replaced
896:6e0379fc1988 897:f5b91f11d8b6
    10 from simplejson import dumps
    10 from simplejson import dumps
    11 from mx.DateTime import today
    11 from mx.DateTime import today
    12 
    12 
    13 from logilab.common.compat import any
    13 from logilab.common.compat import any
    14 from logilab.mtconverter import html_escape
    14 from logilab.mtconverter import html_escape
       
    15 
       
    16 from yams.constraints import SizeConstraint, StaticVocabularyConstraint
    15 
    17 
    16 from cubicweb import typed_eid
    18 from cubicweb import typed_eid
    17 from cubicweb.utils import ustrftime
    19 from cubicweb.utils import ustrftime
    18 from cubicweb.selectors import match_form_params
    20 from cubicweb.selectors import match_form_params
    19 from cubicweb.view import NOINDEX, NOFOLLOW, View, EntityView, AnyRsetView
    21 from cubicweb.view import NOINDEX, NOFOLLOW, View, EntityView, AnyRsetView
   248 # widgets ############
   250 # widgets ############
   249 
   251 
   250 class FieldWidget(object):
   252 class FieldWidget(object):
   251     def __init__(self, attrs=None):
   253     def __init__(self, attrs=None):
   252         self.attrs = attrs or {}
   254         self.attrs = attrs or {}
   253     
   255 
   254     def render(self, form, field):
   256     def render(self, form, field):
   255         raise NotImplementedError
   257         raise NotImplementedError
   256     
   258     
   257 class Input(FieldWidget):
   259 class Input(FieldWidget):
   258     type = None
   260     type = None
   286         name = form.context[field]['name'] # qualified name
   288         name = form.context[field]['name'] # qualified name
   287         return name, None, {}
   289         return name, None, {}
   288 
   290 
   289 class HiddenInput(Input):
   291 class HiddenInput(Input):
   290     type = 'hidden'
   292     type = 'hidden'
   291 
   293     
   292 class Button(Input):
   294 class Button(Input):
   293     type = 'button'
   295     type = 'button'
   294 
   296 
   295 class TextArea(FieldWidget):
   297 class TextArea(FieldWidget):
   296     def render(self, form, field):
   298     def render(self, form, field):
   439 class StringField(Field):
   441 class StringField(Field):
   440     def __init__(self, max_length=None, **kwargs):
   442     def __init__(self, max_length=None, **kwargs):
   441         super(StringField, self).__init__(**kwargs)
   443         super(StringField, self).__init__(**kwargs)
   442         self.max_length = max_length
   444         self.max_length = max_length
   443 
   445 
   444         
       
   445 class TextField(Field):
   446 class TextField(Field):
   446     widget = TextArea
   447     widget = TextArea
   447     def __init__(self, row=None, col=None, **kwargs):
   448     def __init__(self, row=None, col=None, **kwargs):
   448         super(TextField, self).__init__(**kwargs)
   449         super(TextField, self).__init__(**kwargs)
   449         self.row = row
   450         self.row = row
   528 class HiddenInitialValueField(Field):
   529 class HiddenInitialValueField(Field):
   529     def __init__(self, visible_field, name):
   530     def __init__(self, visible_field, name):
   530         super(HiddenInitialValueField, self).__init__(name=name,
   531         super(HiddenInitialValueField, self).__init__(name=name,
   531                                                       widget=HiddenInput)
   532                                                       widget=HiddenInput)
   532         self.visible_field = visible_field
   533         self.visible_field = visible_field
       
   534     
   533                  
   535                  
   534 class RelationField(Field):
   536 class RelationField(Field):
   535     def __init__(self, role='subject', **kwargs):
   537     def __init__(self, role='subject', **kwargs):
   536         super(RelationField, self).__init__(**kwargs)
   538         super(RelationField, self).__init__(**kwargs)
   537         self.role = role
   539 
       
   540     @staticmethod
       
   541     def fromcardinality(card, role, **kwargs):
       
   542         return RelationField(widget=Select(multiple=card in '*+'),
       
   543                              **kwargs)
   538         
   544         
   539 # forms ############
   545 # forms ############
   540 class metafieldsform(type):
   546 class metafieldsform(type):
   541     def __new__(mcs, name, bases, classdict):
   547     def __new__(mcs, name, bases, classdict):
   542         allfields = []
   548         allfields = []
   619             value = values[field.name]
   625             value = values[field.name]
   620         elif field.name in self.req.form:
   626         elif field.name in self.req.form:
   621             value = self.req.form[field.name]
   627             value = self.req.form[field.name]
   622         else:
   628         else:
   623             value = field.initial
   629             value = field.initial
   624         return value # field.format_value(self.req, value)
   630         return value
   625     
   631 
   626     def form_format_field_value(self, field, values):
   632     def form_format_field_value(self, field, values):
   627         return self.req.property_value('ui.default-text-format')
   633         return self.req.property_value('ui.default-text-format')
   628     
   634     
   629     def form_field_name(self, field):
   635     def form_field_name(self, field):
   630         return field.name
   636         return field.name
   723                 else:
   729                 else:
   724                     # use field's initial value
   730                     # use field's initial value
   725                     value = field.initial
   731                     value = field.initial
   726             if callable(value):
   732             if callable(value):
   727                 values = value()
   733                 values = value()
   728         return value # field.format_value(self.req, value)
   734         return value
   729     
   735     
   730     def form_format_field_value(self, field, values):
   736     def form_format_field_value(self, field, values):
   731         entity = self.entity
   737         entity = self.entity
   732         if field.eidparam and entity.has_format(field.name) and (
   738         if field.eidparam and entity.has_format(field.name) and (
   733             entity.has_eid() or '%s_format' % field.name in entity):
   739             entity.has_eid() or '%s_format' % field.name in entity):
   838         label = form.req._(field.label)
   844         label = form.req._(field.label)
   839         attrs = {'for': form.context[field]['id']}
   845         attrs = {'for': form.context[field]['id']}
   840         if field.required:
   846         if field.required:
   841             attrs['class'] = 'required'
   847             attrs['class'] = 'required'
   842         return tags.label(label, **attrs)
   848         return tags.label(label, **attrs)
   843         
   849 
       
   850 
       
   851 def stringfield_from_constraints(constraints, **kwargs):
       
   852     field = None
       
   853     for cstr in constraints:
       
   854         if isinstance(cstr, StaticVocabularyConstraint):
       
   855             return StringField(widget=Select(vocabulary=cstr.vocabulary),
       
   856                                **kwargs)
       
   857         if isinstance(cstr, SizeConstraint) and cstr.max is not None:
       
   858             if cstr.max > 257:
       
   859                 field = textfield_from_constraint(cstr, **kwargs)
       
   860             else:
       
   861                 field = StringField(max_length=cstr.max, **kwargs)
       
   862     return field or TextField(**kwargs)
       
   863         
       
   864 
       
   865 def textfield_from_constraint(constraint, **kwargs):
       
   866     if 256 < constraint.max < 513:
       
   867         rows, cols = 5, 60
       
   868     else:
       
   869         rows, cols = 10, 80
       
   870     return TextField(rows, cols, **kwargs)
       
   871 
       
   872 
       
   873 def find_field(eclass, subjschema, rschema, role='subject'):
       
   874     """return the most adapated widget to edit the relation
       
   875     'subjschema rschema objschema' according to information found in the schema
       
   876     """
       
   877     fieldclass = None
       
   878     if role == 'subject':
       
   879         objschema = rschema.objects(subjschema)[0]
       
   880         cardidx = 0
       
   881     else:
       
   882         objschema = rschema.subjects(subjschema)[0]
       
   883         cardidx = 1
       
   884     card = rschema.rproperty(subjschema, objschema, 'cardinality')[cardidx]
       
   885     required = card in '1+'
       
   886     if rschema in eclass.widgets:
       
   887         fieldclass = eclass.widgets[rschema]
       
   888         if isinstance(fieldclass, basestring):
       
   889             return StringField(name=rschema.type)
       
   890     elif not rschema.is_final():
       
   891         return RelationField.fromcardinality(card, role,name=rschema.type,
       
   892                                              required=required)
       
   893     else:
       
   894         fieldclass = FIELDS[objschema]
       
   895     if fieldclass is StringField:
       
   896         constraints = rschema.rproperty(subjschema, objschema, 'constraints')
       
   897         return stringfield_from_constraints(constraints, name=rschema.type,
       
   898                                             required=required)
       
   899     return fieldclass(name=rschema.type, required=required)
       
   900 
       
   901 FIELDS = {
       
   902     'Boolean':  BooleanField,
       
   903     'Bytes':    FileField,
       
   904     'Date':     DateField,
       
   905     'Datetime': DateTimeField,
       
   906     'Int':      IntField,
       
   907     'Float':    FloatField,
       
   908     'Decimal':  StringField,
       
   909     'Password': StringField,
       
   910     'String' :  StringField,
       
   911     'Time':     TimeField,
       
   912     }