diff --git a/composer/schema/field.py b/composer/schema/field.py index 4c07eff..deea6fa 100644 --- a/composer/schema/field.py +++ b/composer/schema/field.py @@ -24,9 +24,11 @@ $Id$ from zope.interface import implements from zope.component import adapts +from zope import component from cybertools.composer.base import Component from cybertools.composer.schema.interfaces import IField, IFieldInstance +from cybertools.composer.schema.interfaces import fieldTypes from cybertools.composer.schema.schema import formErrors from cybertools.util.format import toStr, toUnicode @@ -37,11 +39,11 @@ class Field(Component): required = False - def __init__(self, name, title=None, renderFactory=None, **kw): + def __init__(self, name, title=None, fieldType='textline', **kw): assert name self.__name__ = name title = title or u'' - self.renderFactory = renderFactory # use for rendering field content + self.fieldType = fieldType super(Field, self).__init__(title, __name__=name, **kw) self.title = title for k, v in kw.items(): @@ -54,6 +56,13 @@ class Field(Component): def getTitleValue(self): return self.title or self.name + def getFieldTypeInfo(self): + return fieldTypes.getTerm(self.fieldType) + + def getFieldInstance(self): + instanceName = self.getFieldTypeInfo().instanceName + return component.getAdapter(self, IFieldInstance, name=instanceName) + class FieldInstance(object): @@ -79,10 +88,38 @@ class FieldInstance(object): return toUnicode(strValue) or u'' def validate(self, value): - errors = [] - severity = 0 if not value and self.context.required: - error = formErrors['required_missing'] - self.errors.append(error) - self.severity = error.severity + self.setError('required_missing') + def setError(self, errorName): + error = formErrors[errorName] + self.errors.append(error) + self.severity = max(error.severity, self.severity) + + +class NumberFieldInstance(FieldInstance): + + def marshall(self, value): + if value is None: + return '' + return str(value) + + def display(self, value): + if value is None: + return '-' + return str(value) + + def unmarshall(self, strValue): + if not strValue: + return None + return int(strValue) + + def validate(self, value): + if value in ('', None): + if self.context.required: + self.setError('required_missing') + else: + try: + int(value) + except (TypeError, ValueError): + self.setError('invalid_number') diff --git a/composer/schema/instance.py b/composer/schema/instance.py index c6b876c..1d3c063 100644 --- a/composer/schema/instance.py +++ b/composer/schema/instance.py @@ -28,7 +28,7 @@ from zope.interface import implements from cybertools.composer.instance import Instance from cybertools.composer.interfaces import IInstance -from cybertools.composer.schema.interfaces import IClient, IFieldInstance +from cybertools.composer.schema.interfaces import IClient from cybertools.composer.schema.schema import FormState @@ -75,7 +75,11 @@ class ClientInstance(object): values = attrs.setdefault(self.aspect, {}) if template is not None: for f in template.fields: - fi = IFieldInstance(f) + fieldType = f.getFieldTypeInfo() + if not fieldType.storeData: + # a dummy field, e.g. a spacer + continue + fi = f.getFieldInstance() name = f.name value = values.get(name, u'') value = mode == 'view' and fi.display(value) or fi.marshall(value) @@ -104,8 +108,11 @@ class ClientInstanceEditor(ClientInstance): setattr(self.context, self.attrsName, attrs) values = attrs.setdefault(self.aspect, OOBTree()) for f in template.fields: - #fi = IFieldInstance(f) name = f.name + fieldType = f.getFieldTypeInfo() + if not fieldType.storeData: + # a dummy field, e.g. a spacer + continue fi = formState.fieldInstances[name] value = fi.unmarshall(data.get(name)) if name in data: @@ -119,8 +126,9 @@ class ClientInstanceEditor(ClientInstance): def validate(self, data): formState = FormState() for f in self.template.fields: - fi = IFieldInstance(f) - value = fi.unmarshall(data.get(f.name)) + fi = f.getFieldInstance() + #value = fi.unmarshall(data.get(f.name)) + value = data.get(f.name) fi.validate(value) formState.fieldInstances.append(fi) formState.severity = max(formState.severity, fi.severity) diff --git a/composer/schema/interfaces.py b/composer/schema/interfaces.py index e8a58c2..c3fd152 100644 --- a/composer/schema/interfaces.py +++ b/composer/schema/interfaces.py @@ -25,6 +25,7 @@ $Id$ from zope import schema from zope.interface import Interface, Attribute from zope.i18nmessageid import MessageFactory +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from cybertools.composer.interfaces import ITemplate, IComponent @@ -57,6 +58,30 @@ class ISchema(ITemplate): 'with this schema.') +class FieldType(SimpleTerm): + + def __init__(self, value, token=None, title=None, **kw): + super(FieldType, self).__init__(value, token, title) + self.name = value + self.fieldMacro = 'field' + self.inputMacro = 'input_' + self.name + self.storeData = True + self.instanceName = '' + for k, v in kw.items(): + setattr(self, k, v) + + +fieldTypes = SimpleVocabulary(( + FieldType('textline', 'textline', u'Textline'), + FieldType('textarea', 'textarea', u'Textarea'), + FieldType('number', 'number', u'Number', inputMacro='input_textline', + instanceName='number'), + #FieldType('date', 'date', u'Date'), + #FieldType('checkbox', 'checkbox', u'Checkbox'), + FieldType('spacer', 'spacer', u'Spacer', fieldMacro='field_spacer', + storeData=False), +)) + class IField(IComponent): """ May be used for data entry or display. """ @@ -78,8 +103,7 @@ class IField(IComponent): description=_(u'The type of the field'), required=True, default='textline', - values=('textline', 'textarea', 'number', - 'date', 'checkbox', 'spacer')) + vocabulary=fieldTypes,) defaultValue = schema.TextLine( title=_(u'Default'), description=_(u'Value with which to pre-set the field contents'), diff --git a/composer/schema/schema.py b/composer/schema/schema.py index c75230b..146d19a 100644 --- a/composer/schema/schema.py +++ b/composer/schema/schema.py @@ -83,5 +83,7 @@ class FormError(object): formErrors = dict( required_missing=FormError(u'Missing data for required field', - u'Please enter data for required field.') + u'Please enter data for required field.'), + invalid_number=FormError(u'Invalid number', + u'Please enter a number, only digits allowed.'), )