I have a behavior with some RelationChoice and RelationList Fields.
In the end i have "related_items", "related_news", "related_events" and "related_contacts" fields.
My goal:
- related_items: you can select many items in a site via contentbrowser and respect the INavigationRoot
- related_news: you can select only one collection in a site via contentbrowser and respect the INavigationRoot
- related_events: you can select only one collection in a site via contentbrowser and respect the INavigationRoot
- related_contacts: you can select many items of type "Person" in a site via contentbrowser and respect the INavigationRoot
The Problem:
Some RelationChoice and RelationList Fields in one Form. How can i customize the pattern options in a clean way?
Solution:
- Subclassing the fields
- implement a specific interface
- for this specific interface register an adapter to modify the pattern options
Sample:
class ICollectionRelationChoice(Interface):
"""Marker for pattern option."""
pass
class IContactRelationList(Interface):
"""Marker for pattern option."""
@implementer(ICollectionRelationChoice)
class CollectionRelationChoice(RelationChoice):
""" Subclassing RelationChoice Field """
pass
@implementer(IContactRelationList)
class ContactRelationList(RelationList):
""" Subclassing RelationList Field """
pass
@provider(IFormFieldProvider)
class IContentListingBehavior(model.Schema):
""" Schema of behavior """
related_news = CollectionRelationChoice(
title=_("News Collection"),
vocabulary="plone.app.vocabularies.Catalog",
required=False,
)
related_contacts = ContactRelationList(
title=_("Contact Box"),
required=False,
value_type=RelationChoice(
title="contacts",
vocabulary="plone.app.vocabularies.Catalog",
),
)
@implementer(IValue)
@adapter(IContentListingMarker, IRequest, IForm, ICollectionRelationChoice, IContentBrowserWidget,)
class CollectionContentbrowserPatternOptions:
""" Adapter class for custon pattern options """
def __init__(self, context, request, form, field, widget):
self.context = context
self.request = request
self.form = form
self.field = field
self.widget = widget
def get(self):
portal_state = getMultiAdapter( (self.context, self.request), name="plone_portal_state")
return {
"rootPath": portal_state.navigation_root_path(),
"selectableTypes": "Collection",
}
@implementer(IValue)
@adapter(IContentListingMarker, IRequest, IForm, IContactRelationList, ContentBrowserWidget)
class PersonContentbrowserPatternOptions:
""" Adapter class for custon pattern options """
def __init__(self, context, request, form, field, widget):
self.context = context
self.request = request
self.form = form
self.field = field
self.widget = widget
def get(self):
portal_state = getMultiAdapter((self.context, self.request), name="plone_portal_state")
return {
"rootPath": portal_state.navigation_root_path(),
"selectableTypes": "Person",
}
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:z3c="http://namespaces.zope.org/z3c"
xmlns:zcml="http://namespaces.zope.org/zcml"
>
<!-- override pattern options for contentbrowser-->
<!-- set the root path and selectable types 'Collection'-->
<adapter
factory=".patterns.CollectionContentbrowserPatternOptions"
name="pattern_options"
/>
<!-- set the root path and selectable types 'Person'-->
<adapter
factory=".patterns.PersonContentbrowserPatternOptions"
name="pattern_options"
/>
</configure>
No JS Hacking needed... I love it.. ![]()