def validate(self, values): if values is None: return super(VocabularyValuesValidator, self).validate(values) by_value = {} by_token = {} for value in values: term = vocabulary.SimpleTerm(token=value.encode('unicode_escape'), value=value, title=value) if term.value in by_value: raise interface.Invalid( _('field_edit_error_conflicting_values', default= u"The '${value1}' vocabulary value conflicts with '${value2}'.", mapping={ 'value1': value, 'value2': by_value[term.value].value })) if term.token in by_token: raise interface.Invalid( _('field_edit_error_conflicting_values', default= u"The '${value1}' vocabulary value conflicts with '${value2}'.", mapping={ 'value1': value, 'value2': by_value[term.token].value })) by_value[term.value] = term by_token[term.token] = term return super(VocabularyValuesValidator, self).validate(values)
def validate(self, values): if values is None: return super(VocabularyValuesValidator, self).validate( values) by_value = {} by_token = {} for value in values: term = vocabulary.SimpleTerm(token=value.encode('unicode_escape'), value=value, title=value) if term.value in by_value: raise interface.Invalid( _('field_edit_error_conflicting_values', default=u"The '${value1}' vocabulary value conflicts with '${value2}'.", mapping={'value1': value, 'value2': by_value[term.value].value})) if term.token in by_token: raise interface.Invalid( _('field_edit_error_conflicting_values', default=u"The '${value1}' vocabulary value conflicts with '${value2}'.", mapping={'value1': value, 'value2': by_value[term.token].value})) by_value[term.value] = term by_token[term.token] = term return super(VocabularyValuesValidator, self).validate(values)
def label(self): if self.context.Title() != self.context.__name__: return _(u'Edit ${title} (${name})', mapping={'title': self.context.Title(), 'name': self.context.__name__}) else: return _(u'Edit ${name}', mapping={'name': self.context.__name__})
def checkTitleAndDescriptionTypes(data): if data.__name__ is not None and data.factory is not None: if data.__name__ == 'title' and data.factory.fieldcls is not TextLine: raise Invalid( _(u"The 'title' field must be a Text line (string) field.")) if data.__name__ == 'description' and data.factory.fieldcls is not Text: raise Invalid( _(u"The 'description' field must be a Text field."))
def isValidFieldName(value): if not ID_RE.match(value): raise Invalid( _(u'Please use only letters, numbers and the following characters: _.')) if value in RESERVED_NAMES: raise Invalid( _(u"'${name}' is a reserved field name.", mapping={'name': value})) return True
def label(self): if self.context.Title() != self.context.__name__: return _(u'Edit ${title} (${name})', mapping={ 'title': self.context.Title(), 'name': self.context.__name__ }) else: return _(u'Edit ${name}', mapping={'name': self.context.__name__})
def add(self, field): schema = IEditableSchema(self.context.schema) try: schema.addField(field) except ValueError: raise WidgetActionExecutionError('__name__', Invalid(_(u'Please select a field name that is not already used.'))) notify(ObjectAddedEvent(field, self.context.schema)) notify(SchemaModifiedEvent(self.context)) self.status = _(u"Field added successfully.")
class INewFieldset(Interface): label = TextLine(title=_(u'Title'), required=True) __name__ = ASCIILine( title=_(u'Short Name'), description=_(u'Used for programmatic access to the fieldset.'), required=True, constraint=isValidFieldName, )
def add(self, new_fieldset): schema = self.context.schema fieldsets = schema.getTaggedValue(FIELDSETS_KEY) for fieldset in fieldsets: if fieldset.__name__ == new_fieldset.__name__: raise WidgetActionExecutionError('__name__', Invalid(_(u'Please select a fieldset name that is not already used.'))) fieldsets.append(new_fieldset) schema.setTaggedValue(FIELDSETS_KEY, fieldsets) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.context)) self.status = _(u"Fieldset added successfully.")
def label(self): """ In a dexterity schema editing context, we need to construct a label that will specify the field being edited. Outside that context (e.g., plone.app.users), we should respect the label if specified. """ context_label = getattr(self.context, "label", None) if context_label is not None: return context_label if self.context.Title() != self.context.__name__: return _(u"Edit ${title} (${name})", mapping={"title": self.context.Title(), "name": self.context.__name__}) else: return _(u"Edit ${name}", mapping={"name": self.context.__name__})
def __call__(self): """Handle AJAX save post. """ if not authorized(self.context, self.request): raise Unauthorized source = self.request.form.get('source') if source: # Is it valid XML? try: root = etree.fromstring(source) except etree.XMLSyntaxError, e: return json.dumps({ 'success': False, 'message': "XMLSyntaxError: %s" % e.message.encode('utf8') }) # a little more sanity checking, look at first two element levels if root.tag != NAMESPACE + 'model': return json.dumps({ 'success': False, 'message': _(u"Error: root tag must be 'model'") }) for element in root.getchildren(): if element.tag != NAMESPACE + 'schema': return json.dumps({ 'success': False, 'message': _(u"Error: all model elements must be 'schema'") }) # can supermodel parse it? # This is mainly good for catching bad dotted names. try: plone.supermodel.loadString(source, policy=u"dexterity") except SupermodelParseError, e: message = e.args[0].replace('\n File "<unknown>"', '') return json.dumps({ 'success': False, 'message': u"SuperModelParseError: %s" % message })
class FieldsetAddForm(form.AddForm): fields = field.Fields(INewFieldset) label = _('Add new fieldset') id = 'add-fieldset-form' def create(self, data): return Fieldset(**data) def add(self, new_fieldset): schema = self.context.schema fieldsets = schema.queryTaggedValue(FIELDSETS_KEY, []) for fieldset in fieldsets: if fieldset.__name__ == new_fieldset.__name__: msg = _( u'Please select a fieldset name that is not already used.' ) raise WidgetActionExecutionError( '__name__', Invalid(msg) ) fieldsets.append(new_fieldset) schema.setTaggedValue(FIELDSETS_KEY, fieldsets) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.context)) IStatusMessage(self.request).addStatusMessage( _(u'Fieldset added successfully.'), type='info') def nextURL(self): return '@@add-fieldset'
def label(self): """ In a dexterity schema editing context, we need to construct a label that will specify the field being edited. Outside that context (e.g., plone.app.users), we should respect the label if specified. """ context_label = getattr(self.context, 'label', None) if context_label is not None: return context_label if self.context.Title() != self.context.__name__: return _(u'Edit ${title} (${name})', mapping={'title': self.context.Title(), 'name': self.context.__name__}) else: return _(u'Edit ${name}', mapping={'name': self.context.__name__})
class FieldsetAddForm(form.AddForm): fields = field.Fields(INewFieldset) label = _("Add new fieldset") id = 'add-fieldset-form' def create(self, data): return Fieldset(**data) def add(self, new_fieldset): schema = self.context.schema fieldsets = schema.getTaggedValue(FIELDSETS_KEY) for fieldset in fieldsets: if fieldset.__name__ == new_fieldset.__name__: raise WidgetActionExecutionError('__name__', Invalid(_(u'Please select a fieldset name that is not already used.'))) fieldsets.append(new_fieldset) schema.setTaggedValue(FIELDSETS_KEY, fieldsets) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.context)) self.status = _(u"Fieldset added successfully.") def nextURL(self): url = self.context.absolute_url() if getattr(self.context, 'schemaEditorView', None) is not None: url += '/@@' + self.context.schemaEditorView return url
def add(self, field): context = self.context schema = IEditableSchema(context.schema) # move it after the last field that is not in a fieldset # or at top if there is no field yet in "default" fieldset ordered_fields = [name for (name, f) in sortedFields(context.schema)] default_fields = non_fieldset_fields(context.schema) if len(default_fields) > 0: position = ordered_fields.index(default_fields[-1]) + 1 else: position = 0 try: schema.addField(field) except ValueError: raise WidgetActionExecutionError('__name__', Invalid( u'Please select a field name that is not already used.' )) schema.moveField(field.__name__, position) notify(ObjectAddedEvent(field, context.schema)) notify(FieldAddedEvent(context, field)) IStatusMessage(self.request).addStatusMessage( _(u"Field added successfully."), type='info')
class ITextLineChoice(interfaces.IField): values = schema.List(title=_(u'Possible values'), description=_(u'Enter allowed choices one per line.'), required=interfaces.IChoice['vocabulary'].required, default=interfaces.IChoice['vocabulary'].default, value_type=schema.TextLine()) interface.alsoProvides(values, ITextLinesField) vocabularyName = schema.Choice( title=interfaces.IChoice['vocabularyName'].title, description=interfaces.IChoice['vocabularyName'].description, default=interfaces.IChoice['vocabularyName'].default, required=False, vocabulary="plone.schemaeditor.VocabulariesVocabulary", )
def __call__(self): """Handle AJAX save post. """ if not authorized(self.context, self.request): raise Unauthorized source = self.request.form.get('source') if source: # Is it valid XML? try: root = etree.fromstring(source) except etree.XMLSyntaxError, e: return json.dumps({ 'success': False, 'message': "XMLSyntaxError: %s" % e.message.encode('utf8') }) # a little more sanity checking, look at first two element levels if root.tag != NAMESPACE + 'model': return json.dumps({ 'success': False, 'message': _(u"Error: root tag must be 'model'") }) for element in root.getchildren(): if element.tag != NAMESPACE + 'schema': return json.dumps({ 'success': False, 'message': _( u"Error: all model elements must be 'schema'" ) }) # can supermodel parse it? # This is mainly good for catching bad dotted names. try: plone.supermodel.loadString(source, policy=u"dexterity") except SupermodelParseError, e: message = e.args[0].replace('\n File "<unknown>"', '') return json.dumps({ 'success': False, 'message': u"SuperModelParseError: %s" % message })
def add(self, new_fieldset): schema = self.context.schema fieldsets = schema.queryTaggedValue(FIELDSETS_KEY, []) for fieldset in fieldsets: if fieldset.__name__ == new_fieldset.__name__: msg = _( u'Please select a fieldset name that is not already used.' ) raise WidgetActionExecutionError( '__name__', Invalid(msg) ) fieldsets.append(new_fieldset) schema.setTaggedValue(FIELDSETS_KEY, fieldsets) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.context)) IStatusMessage(self.request).addStatusMessage( _(u'Fieldset added successfully.'), type='info')
def validate(self, values): if values is None: return super(VocabularyNameValidator, self).validate(values) if values and self.request.form.get('form.widgets.values', None): raise interface.Invalid( _('field_edit_error_values_and_name', default= u"You can't set a vocabulary name AND vocabulary values. " u"Please clear values field or set no value here.")) return super(VocabularyNameValidator, self).validate(values)
def validate(self, values): if values is None: return super(VocabularyNameValidator, self).validate( values) if values and self.request.form.get('form.widgets.values', None): raise interface.Invalid( _('field_edit_error_values_and_name', default=u"You can't set a vocabulary name AND vocabulary values. " u"Please clear values field or set no value here.")) return super(VocabularyNameValidator, self).validate(values)
class INewField(Interface): title = TextLine(title=_(u'Title'), required=True) __name__ = ASCIILine( title=_(u'Short Name'), description=_(u'Used for programmatic access to the field.'), required=True, constraint=isValidFieldName, ) description = Text( title=_(u'Help Text'), description=_(u'Shows up in the form as help text for the field.'), required=False) factory = Choice( title=_(u"Field type"), vocabulary="Fields", required=True, # This can't be done yet or we'll create circular import problem. # So it will be injected from fields.py # default=TextLineFactory, ) @invariant def checkTitleAndDescriptionTypes(data): if data.__name__ is not None and data.factory is not None: if data.__name__ == 'title' and data.factory.fieldcls is not TextLine: raise Invalid( _(u"The 'title' field must be a Text line (string) field.") ) if data.__name__ == 'description' and data.factory.fieldcls is not Text: raise Invalid( _(u"The 'description' field must be a Text field."))
class FieldAddForm(form.AddForm): fields = field.Fields(INewField) label = _("Add new field") id = 'add-field-form' def create(self, data): factory = data.pop('factory') return factory(**data) def add(self, field): context = self.context schema = IEditableSchema(context.schema) # move it after the last field that is not in a fieldset # or at top if there is no field yet in "default" fieldset ordered_fields = [name for (name, f) in sortedFields(context.schema)] default_fields = non_fieldset_fields(context.schema) if len(default_fields) > 0: position = ordered_fields.index(default_fields[-1]) + 1 else: position = 0 try: schema.addField(field) except ValueError: raise WidgetActionExecutionError( '__name__', Invalid( u'Please select a field name that is not already used.')) schema.moveField(field.__name__, position) notify(ObjectAddedEvent(field, context.schema)) notify(FieldAddedEvent(context, field)) self.status = _(u"Field added successfully.") def nextURL(self): url = self.context.absolute_url() if getattr(self.context, 'schemaEditorView', None) is not None: url += '/@@' + self.context.schemaEditorView return url
def add(self, new_field): schema = self.context.schema fieldset_id = int(self.request.form.get('fieldset_id', 0)) position = new_field_position(schema, fieldset_id) editable_schema = IEditableSchema(schema) try: editable_schema.addField(new_field) except ValueError: raise WidgetActionExecutionError( '__name__', Invalid( u'Please select a field name that is not already used.')) if fieldset_id: fieldset = get_fieldset_from_index(schema, fieldset_id) editable_schema.changeFieldFieldset(new_field.__name__, fieldset) editable_schema.moveField(new_field.__name__, position) notify(ObjectAddedEvent(new_field, schema)) notify(FieldAddedEvent(self.context, new_field)) IStatusMessage(self.request).addStatusMessage( _(u'Field added successfully.'), type='info')
def add(self, field): context = self.context schema = IEditableSchema(context.schema) # move it after the last field that is not in a fieldset # or at top if there is no field yet in "default" fieldset ordered_fields = [name for (name, f) in sortedFields(context.schema)] default_fields = non_fieldset_fields(context.schema) if len(default_fields) > 0: position = ordered_fields.index(default_fields[-1]) + 1 else: position = 0 try: schema.addField(field) except ValueError: raise WidgetActionExecutionError('__name__', Invalid(u'Please select a field name that is not already used.')) schema.moveField(field.__name__, position) notify(ObjectAddedEvent(field, context.schema)) notify(FieldAddedEvent(context, field)) self.status = _(u"Field added successfully.")
def handleSave(self, action): data, errors = self.extractData() # For choice fields, make sure default is in the valid values if "values" in data: values = data["values"] or [] if "default" in data and data["default"]: default = data["default"] if type(default) is not list: default = [default] for value in default: if value not in values: raise WidgetActionExecutionError( "default", Invalid(_(u"Please enter a valid vocabulary value.")) ) if errors: self.status = self.formErrorsMessage return # clear current min/max to avoid range errors if "min" in data: self.field.min = None if "max" in data: self.field.max = None default = data.pop("default", _marker) changes = self.applyChanges(data) # make sure we can report invalid defaults if default is not _marker: try: changes2 = self.applyChanges({"default": default}) except schema.ValidationError, e: raise WidgetActionExecutionError("default", e) else: changes = changes or changes2
def add(self, new_field): schema = self.context.schema fieldset_id = int(self.request.form.get('fieldset_id', 0)) position = new_field_position(schema, fieldset_id) editable_schema = IEditableSchema(schema) try: editable_schema.addField(new_field) except ValueError: raise WidgetActionExecutionError( '__name__', Invalid( u'Please select a field name that is not already used.' ) ) if fieldset_id: fieldset = get_fieldset_from_index(schema, fieldset_id) editable_schema.changeFieldFieldset(new_field.__name__, fieldset) editable_schema.moveField(new_field.__name__, position) notify(ObjectAddedEvent(new_field, schema)) notify(FieldAddedEvent(self.context, new_field)) IStatusMessage(self.request).addStatusMessage( _(u'Field added successfully.'), type='info')
class FieldAddForm(AutoExtensibleForm, form.AddForm): fields = field.Fields(interfaces.INewField) label = _('Add new field') id = 'add-field-form' # This is a trick: we want autoform to handle the additionalSchemata, # but want to provide our own base schema below in updateFields. schema = Interface @lazy_property def _schema(self): return interfaces.INewField @lazy_property def additionalSchemata(self): return [ v for k, v in getAdapters(( self.context, ), interfaces.IFieldEditorExtender) ] def create(self, data): extra = {} factory = data.pop('factory') # split regular attributes and extra ones for key in data.keys(): if key not in self._schema: extra[key] = data[key] data.pop(key) # create the field with regular attributes field_obj = factory(**data) # set the extra attributes using the proper adapter for schemata in self.additionalSchemata: for key in extra: (interface_name, property_name) = key.split('.') if interface_name != schemata.__name__: continue setattr(schemata(field_obj), property_name, extra[key]) return field_obj def add(self, new_field): schema = self.context.schema fieldset_id = int(self.request.form.get('fieldset_id', 0)) position = new_field_position(schema, fieldset_id) editable_schema = IEditableSchema(schema) try: editable_schema.addField(new_field) except ValueError: raise WidgetActionExecutionError( '__name__', Invalid( u'Please select a field name that is not already used.')) if fieldset_id: fieldset = get_fieldset_from_index(schema, fieldset_id) editable_schema.changeFieldFieldset(new_field.__name__, fieldset) editable_schema.moveField(new_field.__name__, position) notify(ObjectAddedEvent(new_field, schema)) notify(FieldAddedEvent(self.context, new_field)) IStatusMessage(self.request).addStatusMessage( _(u'Field added successfully.'), type='info') def updateWidgets(self): super(FieldAddForm, self).updateWidgets() fieldset_id = int(self.request.form.get('fieldset_id', 0)) if fieldset_id: # add fieldset_id from GET parameter as hidden field, so that # ``add`` method at the end of the form lifecycle can read it. fieldset_id_widget = TextWidget(self.request) fieldset_id_widget.name = 'fieldset_id' fieldset_id_widget.value = fieldset_id fieldset_id_widget.mode = HIDDEN_MODE # Uhm. z3c.form widgets doesn't have an API for extending a # schema-generated form. Using internal ``_data_values``... self.widgets._data_values.append(fieldset_id_widget) def nextURL(self): return '@@add-field'
def label(self): return _(u"Edit Field '${fieldname}'", mapping={'fieldname': self.field.__name__})
class FieldAddForm(AutoExtensibleForm, form.AddForm): fields = field.Fields(interfaces.INewField) label = _("Add new field") id = 'add-field-form' # This is a trick: we want autoform to handle the additionalSchemata, # but want to provide our own base schema below in updateFields. schema = Interface @lazy_property def _schema(self): return interfaces.INewField @lazy_property def additionalSchemata(self): return [v for k, v in getAdapters((self.context, ), interfaces.IFieldEditorExtender)] def create(self, data): extra = {} factory = data.pop('factory') all = data.keys() # split regular attributes and extra ones for key in all: if key not in self._schema: extra[key] = data[key] data.pop(key) # create the field with regular attributes field_obj = factory(**data) # set the extra attributes using the proper adapter for schemata in self.additionalSchemata: for key in extra: (interface_name, property_name) = key.split('.') if interface_name != schemata.__name__: continue setattr(schemata(field_obj), property_name, extra[key]) return field_obj def add(self, field): context = self.context schema = IEditableSchema(context.schema) # move it after the last field that is not in a fieldset # or at top if there is no field yet in "default" fieldset ordered_fields = [name for (name, f) in sortedFields(context.schema)] default_fields = non_fieldset_fields(context.schema) if len(default_fields) > 0: position = ordered_fields.index(default_fields[-1]) + 1 else: position = 0 try: schema.addField(field) except ValueError: raise WidgetActionExecutionError('__name__', Invalid( u'Please select a field name that is not already used.' )) schema.moveField(field.__name__, position) notify(ObjectAddedEvent(field, context.schema)) notify(FieldAddedEvent(context, field)) IStatusMessage(self.request).addStatusMessage( _(u"Field added successfully."), type='info') def nextURL(self): return "@@add-field"
class AjaxSaveHandler(BrowserView): """Handle AJAX save posts. """ def __call__(self): """Handle AJAX save post. """ if not authorized(self.context, self.request): raise Unauthorized source = self.request.form.get('source') if source: # Is it valid XML? try: root = etree.fromstring(source) except etree.XMLSyntaxError, e: return json.dumps({ 'success': False, 'message': "XMLSyntaxError: %s" % e.message.encode('utf8') }) # a little more sanity checking, look at first two element levels if root.tag != NAMESPACE + 'model': return json.dumps({ 'success': False, 'message': _(u"Error: root tag must be 'model'") }) for element in root.getchildren(): if element.tag != NAMESPACE + 'schema': return json.dumps({ 'success': False, 'message': _(u"Error: all model elements must be 'schema'") }) # can supermodel parse it? # This is mainly good for catching bad dotted names. try: plone.supermodel.loadString(source, policy=u"dexterity") except SupermodelParseError, e: message = e.args[0].replace('\n File "<unknown>"', '') return json.dumps({ 'success': False, 'message': u"SuperModelParseError: %s" % message }) # clean up formatting sins source = etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='utf8') # and save to FTI fti = self.context.fti fti.manage_changeProperties(model_source=source) self.request.response.setHeader('Content-Type', 'application/json') return json.dumps({'success': True, 'message': _(u"Saved")})
field_factories = [(id, factory) for id, factory in field_factories if id in context.allowedFields] terms = [] for (field_id, factory) in field_factories: terms.append( SimpleVocabulary.createTerm( factory, factory.title, translate(factory.title, context=request))) terms = sorted(terms, key=operator.attrgetter('title')) return SimpleVocabulary(terms) # TextLineFactory is the default. We need to set that here to avoid a # circular import. TextLineFactory = FieldFactory( schema.TextLine, _(u'label_textline_field', default=u'Text line (String)')) interfaces.INewField['factory'].__dict__['default'] = TextLineFactory TextFactory = FieldFactory(schema.Text, _(u'label_text_field', default=u'Text')) IntFactory = FieldFactory(schema.Int, _(u'label_integer_field', default=u'Integer')) FloatFactory = FieldFactory( schema.Float, _(u'label_float_field', default=u'Floating-point number')) BoolFactory = FieldFactory(schema.Bool, _(u'label_boolean_field', default=u'Yes/No')) PasswordFactory = FieldFactory(schema.Password, _(u'label_password_field', default=u'Password')) DatetimeFactory = FieldFactory( schema.Datetime, _(u'label_datetime_field', default=u'Date/Time')) DateFactory = FieldFactory(schema.Date, _(u'label_date_field',
try: changes2 = self.applyChanges({"default": default}) except schema.ValidationError, e: raise WidgetActionExecutionError("default", e) else: changes = changes or changes2 if changes: self.status = self.successMessage else: self.status = self.noChangesMessage notify(SchemaModifiedEvent(self.context.aq_parent)) self.redirectToParent() @button.buttonAndHandler(_(u"Cancel"), name="cancel") def handleCancel(self, action): self.redirectToParent() def redirectToParent(self): self.request.response.redirect(aq_parent(aq_inner(self.context)).absolute_url()) # form wrapper to use Plone form template class EditView(layout.FormWrapper): form = FieldEditForm def __init__(self, context, request): super(EditView, self).__init__(context, request) self.field = context.field
kwargs = copy.deepcopy(self.kw) kwargs.update(**kw) return self.fieldcls(*(self.args+args), **kwargs) def FieldsVocabularyFactory(context): field_factories = getUtilitiesFor(IFieldFactory) terms = [] for (field_id, factory) in field_factories: terms.append(SimpleVocabulary.createTerm(factory, translate(factory.title), factory.title)) return SimpleVocabulary(terms) # TextLineFactory is the default. We need to set that here to avoid a circular import. TextLineFactory = FieldFactory(schema.TextLine, _(u'label_textline_field', default=u'Text line (String)')) interfaces.INewField['factory'].__dict__['default'] = TextLineFactory TextFactory = FieldFactory(schema.Text, _(u'label_text_field', default=u'Text')) IntFactory = FieldFactory(schema.Int, _(u'label_integer_field', default=u'Integer')) FloatFactory = FieldFactory(schema.Float, _(u'label_float_field', default=u'Floating-point number')) BoolFactory = FieldFactory(schema.Bool, _(u'label_boolean_field', default=u'Yes/No')) PasswordFactory = FieldFactory(schema.Password, _(u'label_password_field', default=u'Password')) DatetimeFactory = FieldFactory(schema.Datetime, _(u'label_datetime_field', default=u'Date/Time')) DateFactory = FieldFactory(schema.Date, _(u'label_date_field', default=u'Date')) @interface.implementer(interfaces.IFieldEditFormSchema) @component.adapter(schema_ifaces.IChoice) def getChoiceFieldSchema(field): return se_schema.ITextLineChoice
""" test whether a given instance of a field is editable """ return True def FieldsVocabularyFactory(context): field_factories = getUtilitiesFor(IFieldFactory) terms = [] for (field_id, factory) in field_factories: terms.append(SimpleVocabulary.createTerm(factory, translate(factory.title), factory.title)) return SimpleVocabulary(terms) # TextLineFactory is the default. We need to set that here to avoid a # circular import. TextLineFactory = FieldFactory(schema.TextLine, _(u"label_textline_field", default=u"Text line (String)")) interfaces.INewField["factory"].__dict__["default"] = TextLineFactory TextFactory = FieldFactory(schema.Text, _(u"label_text_field", default=u"Text")) IntFactory = FieldFactory(schema.Int, _(u"label_integer_field", default=u"Integer")) FloatFactory = FieldFactory(schema.Float, _(u"label_float_field", default=u"Floating-point number")) BoolFactory = FieldFactory(schema.Bool, _(u"label_boolean_field", default=u"Yes/No")) PasswordFactory = FieldFactory(schema.Password, _(u"label_password_field", default=u"Password")) DatetimeFactory = FieldFactory(schema.Datetime, _(u"label_datetime_field", default=u"Date/Time")) DateFactory = FieldFactory(schema.Date, _(u"label_date_field", default=u"Date")) @interface.implementer(interfaces.IFieldEditFormSchema) @component.adapter(schema_ifaces.IChoice) def getChoiceFieldSchema(field): return se_schema.ITextLineChoice
class SchemaListing(AutoExtensibleForm, form.Form): implements(IEditForm) ignoreContext = True ignoreRequest = True showEmptyGroups = True template = ViewPageTemplateFile('schema_listing.pt') @property def schema(self): return self.context.schema @property def additionalSchemata(self): return self.context.additionalSchemata def _iterateOverWidgets(self): for widget in self.widgets.values(): yield widget for group in self.groups: for widget in group.widgets.values(): yield widget def render(self): for widget in self._iterateOverWidgets(): # disable fields from behaviors if widget.field.interface is not self.context.schema: widget.disabled = 'disabled' # limit size of the preview for text areas if hasattr(widget, 'rows'): if widget.rows is None or widget.rows > 5: widget.rows = 5 return super(SchemaListing, self).render() @memoize def _field_factory(self, field): field_identifier = u'%s.%s' % (field.__module__, field.__class__.__name__) if self.context.allowedFields is not None: if field_identifier not in self.context.allowedFields: return None return queryUtility(IFieldFactory, name=field_identifier) def field_type(self, field): field_factory = self._field_factory(field) if field_factory is not None: return field_factory.title else: return field.__class__.__name__ def edit_url(self, field): field_factory = self._field_factory(field) if field_factory is not None and field_factory.editable(field): return '%s/%s' % (self.context.absolute_url(), field.__name__) def delete_url(self, field): return '%s/%s/@@delete' % (self.context.absolute_url(), field.__name__) @button.buttonAndHandler(_(u'Save Defaults')) def handleSaveDefaults(self, action): # ignore fields from behaviors by setting their widgets' modes # to the display mode while we extract the form values (hack!) widget_modes = {} for widget in self._iterateOverWidgets(): if widget.field.interface is not self.context.schema: widget_modes[widget] = widget.mode widget.mode = DISPLAY_MODE data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return for fname, value in data.items(): self.context.schema[fname].default = value notify(SchemaModifiedEvent(self.context)) # restore the actual widget modes so they render a preview for widget, mode in widget_modes.items(): widget.mode = mode # update widgets to take the new defaults into account self.updateWidgets()
class FieldEditForm(AutoExtensibleForm, form.EditForm): implements(IFieldEditForm) id = 'edit-field-form' def __init__(self, context, request): super(form.EditForm, self).__init__(context, request) self.field = FieldProxy(context.field) def getContent(self): return self.field # This is a trick: we want autoform to handle the additionalSchemata, # but want to provide our own base schema below in updateFields. schema = Interface @lazy_property def _schema(self): return interfaces.IFieldEditFormSchema(self.field) @lazy_property def additionalSchemata(self): schema_context = self.context.aq_parent return [v for k, v in getAdapters((schema_context, self.field), interfaces.IFieldEditorExtender)] @lazy_property def label(self): return _(u"Edit Field '${fieldname}'", mapping={'fieldname': self.field.__name__}) def updateFields(self): # use a custom 'title' field to make sure it is required fields = field.Fields(IFieldTitle) # omit the order attribute since it's managed elsewhere fields += field.Fields(self._schema).omit( 'order', 'title', 'default', 'missing_value', 'readonly') self.fields = fields self.updateFieldsFromSchemata() @button.buttonAndHandler(_(u'Save'), name='save') def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return # clear current min/max to avoid range errors if 'min' in data: self.field.min = None if 'max' in data: self.field.max = None changes = self.applyChanges(data) if changes: IStatusMessage(self.request).addStatusMessage( self.successMessage, type='info') else: IStatusMessage(self.request).addStatusMessage( self.noChangesMessage, type='info') notify(SchemaModifiedEvent(self.context.aq_parent)) @button.buttonAndHandler(_(u'Cancel'), name='cancel') def handleCancel(self, action): self.redirectToParent() def redirectToParent(self): parent = aq_parent(aq_inner(self.context)) url = parent.absolute_url() if hasattr(parent, 'schemaEditorView') and parent.schemaEditorView: url += '/@@' + parent.schemaEditorView self.request.response.redirect(url)
class SchemaListing(AutoExtensibleForm, form.Form): ignoreContext = True ignoreRequest = True showEmptyGroups = True template = ViewPageTemplateFile('schema_listing.pt') ignoreRequiredOnExtract = True @property def schema(self): return self.context.schema @property def additionalSchemata(self): return self.context.additionalSchemata def _iterateOverWidgets(self): for widget in self.widgets.values(): yield widget for group in self.groups: for widget in group.widgets.values(): yield widget def render(self): for widget in self._iterateOverWidgets(): # disable fields from behaviors if widget.field.interface is not self.context.schema: widget.disabled = 'disabled' # limit size of the preview for text areas if hasattr(widget, 'rows'): if widget.rows is None or widget.rows > 5: widget.rows = 5 return super(SchemaListing, self).render() @memoize def _field_factory(self, field): field_identifier = u'{0}.{1}'.format( field.__module__, field.__class__.__name__, ) if self.context.allowedFields is not None: if field_identifier not in self.context.allowedFields: return None return queryUtility(IFieldFactory, name=field_identifier) def field_type(self, field): field_factory = self._field_factory(field) if field_factory is not None: return field_factory.title else: return field.__class__.__name__ def protected_field(self, field): field_identifier = u'{0}.{1}'.format( field.__module__, field.__class__.__name__, ) field_factory = queryUtility(IFieldFactory, name=field_identifier) return field_factory and field_factory.protected(field) def edit_url(self, field): field_factory = self._field_factory(field) if field_factory is not None and field_factory.editable(field): return '{0}/{1}'.format( self.context.absolute_url(), field.__name__, ) def delete_url(self, field): if field.__name__ in self.context.fieldsWhichCannotBeDeleted: return url = '{0}/{1}/@@delete'.format( self.context.absolute_url(), field.__name__, ) if addTokenToUrl: url = addTokenToUrl(url, self.request) return url @button.buttonAndHandler( _(u'Save Defaults'), condition=lambda form: getattr(form.context, 'showSaveDefaults', True)) def handleSaveDefaults(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return for widget in self._iterateOverWidgets(): widget_name = widget.field.getName() if (widget.field.interface is self.context.schema and widget_name in data): self.context.schema[widget_name].default = data[widget_name] notify(SchemaModifiedEvent(self.context)) # update widgets to take the new defaults into account self.updateWidgets()