Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions castle/cms/easyform/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@
name="castle.cms.easyform.field.QueryChoice"
/>

<!-- Castle specific override for choice field -->
<utility
name="castle.cms.easyform.field.CastleChoice"
component=".field.CastleChoiceFactory"
/>
<adapter factory=".field.getCastleChoiceFieldSchema" />
<adapter factory=".field.TextLineCastleChoiceField"
provides=".field.ICastleChoiceFieldSchema" />

<!-- supermodel integration to be able to (de)?serialize field -->
<utility
component=".supermodel.CastleChoiceImportExportHandler"
name="castle.cms.easyform.field.CastleChoice"
/>

<!--
Tweak toolbar so when you're on fields, you can click the "View Page" button
and go back
Expand Down
110 changes: 110 additions & 0 deletions castle/cms/easyform/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from plone.uuid.interfaces import IUUID

from castle.cms.utils import parse_query_from_data
from castle.cms.vocabularies import castle_vocabularies
from castle.cms.widgets import QueryFieldWidget
from plone.autoform import directives as form
from plone.schemaeditor.fields import FieldFactory
Expand All @@ -14,6 +15,8 @@
from zope.i18nmessageid import MessageFactory
from zope.interface import alsoProvides
from zope.interface import implementer
from zope.interface import Invalid
from zope.interface import invariant
from zope.schema.interfaces import IChoice
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.interfaces import IField
Expand Down Expand Up @@ -163,3 +166,110 @@ def getQueryChoiceFieldSchema(field):
@adapter(IQueryChoice)
class TextLineQueryChoiceField(TextLineChoiceField):
pass


@implementer(IContextSourceBinder)
class CastleChoiceSource(object):
__name__ = 'CastleChoiceSource'

def __init__(self, field):
self.field = field

def get_cache_key(self, context):
return 'easyform-source-value--{}-{}'.format(
IUUID(context, 'default'), self.field.__name__)

def __call__(self, context):
default_none_val = SimpleVocabulary.createTerm(None, None, None)
if self.field.possible_values == []:
if self.field.vocabulary_name == None:
return SimpleVocabulary([])
else:
try:
vocab = castle_vocabularies[self.field.vocabulary_name](context)
except TypeError:
vocab = castle_vocabularies[self.field.vocabulary_name]
vocab._terms.insert(0, default_none_val)
return vocab
else:
terms = [default_none_val]
for term in self.field.possible_values:
terms.append(
SimpleVocabulary.createTerm(term, term, term))

return SimpleVocabulary(terms)


# so we can still resolve correctly
alsoProvides(CastleChoiceSource, IContextSourceBinder)


class ICastleChoice(IChoice):
possible_values = schema.List(
title=u'Possible values',
description=u'Enter allowed choices one per line.',
value_type=schema.TextLine(),
required=False
)

vocabulary_name = schema.Choice(
title=u'Vocabulary name',
description=u'Vocabulary name to lookup in the vocabulary registry',
values=castle_vocabularies.keys(),
required=False
)

@invariant
def validate(data):
if data.possible_values and data.vocabulary_name:
msg = 'You can not set a vocabulary name AND vocabulary values. Please clear values field or set "No value" for vocabulary name.'
raise Invalid(_(msg))


@implementer(ICastleChoice)
class CastleChoice(schema.Choice):

def __init__(self, possible_values=[], vocabulary_name=None, **kw):
self.possible_values = possible_values
self.vocabulary_name = vocabulary_name
kw['source'] = CastleChoiceSource(self) # bind to field
super(CastleChoice, self).__init__(**kw)


CastleChoiceFactory = FieldFactory(
CastleChoice, _(u'label_castle_choice_field', default=u'Choice (no default value)'),
source=CastleChoiceSource)


class ICastleChoiceFieldSchema(IField):
possible_values = schema.List(
title=u'Possible values',
description=u'Enter allowed choices one per line.',
value_type=schema.TextLine(),
required=False
)

vocabulary_name = schema.Choice(
title=u'Vocabulary name',
description=u'Vocabulary name to lookup in the vocabulary registry',
values=castle_vocabularies.keys(),
required=False
)

@invariant
def validate(data):
if data.possible_values and data.vocabulary_name:
msg = 'You can not set a vocabulary name AND vocabulary values. Please clear values field or set "No value" for vocabulary name.'
raise Invalid(_(msg))


@implementer(IFieldEditFormSchema)
@adapter(ICastleChoice)
def getCastleChoiceFieldSchema(field):
return ICastleChoiceFieldSchema


@implementer(ICastleChoiceFieldSchema)
@adapter(ICastleChoice)
class TextLineCastleChoiceField(TextLineChoiceField):
pass
58 changes: 57 additions & 1 deletion castle/cms/easyform/supermodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from zope.schema.interfaces import ISource

from .field import QueryChoice
from .field import CastleChoice, QueryChoice


class QueryChoiceHandler(plone.supermodel.exportimport.ChoiceHandler):
Expand Down Expand Up @@ -63,3 +63,59 @@ def write(self, field, name, type, elementName='field'):


QueryChoiceImportExportHandler = QueryChoiceHandler(QueryChoice)


class CastleChoiceHandler(plone.supermodel.exportimport.ChoiceHandler):
"""
Extend/override ChoiceHandler to work for CastleChoice field
"""

def _constructField(self, attributes):
if 'vocabulary' in attributes:
try:
component = resolve(attributes['vocabulary'])
if IBaseVocabulary.providedBy(component):
attributes['vocabulary'] = component
elif (ISource.providedBy(component) or
IContextSourceBinder.providedBy(component)):
attributes['source'] = component
del attributes['vocabulary']
except ImportError:
# regular named vocabulary, leave as is
pass
return super(CastleChoiceHandler, self)._constructField(attributes)

def write(self, field, name, type, elementName='field'):
element = super(plone.supermodel.exportimport.ChoiceHandler, self).write(
field,
name,
type,
elementName
)
if field.vocabulary is not None:
value = "{}.{}".format(
field.vocabulary.__module__,
field.vocabulary.__name__)
child = valueToElement(
self.fieldAttributes['vocabulary'],
value,
name='vocabulary',
force=True
)
element.append(child)
else:
value = "{}.{}".format(
field.source.__module__,
field.source.__name__)
child = valueToElement(
self.fieldAttributes['source'],
value,
name='source',
force=True
)
element.append(child)

return element


CastleChoiceImportExportHandler = CastleChoiceHandler(CastleChoice)
4 changes: 2 additions & 2 deletions castle/cms/easyform/terms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from castle.cms.interfaces import ICastleLayer
from z3c.form.interfaces import ITerms
from z3c.form.interfaces import IWidget
from z3c.form.term import ChoiceTerms
from z3c.form import term
from zope.component import adapter
from zope.interface import Interface
from zope.interface import implementer
Expand All @@ -17,4 +17,4 @@
IQueryChoice,
IWidget)
def QueryChoiceTerms(context, request, form, field, widget):
return ChoiceTerms(context, request, form, field, widget)
return term.ChoiceTerms(context, request, form, field, widget)
11 changes: 11 additions & 0 deletions castle/cms/vocabularies.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,14 @@ def make_terms(brains1, brains2):
included_brains.append(brain['UID'])

return [SimpleTerm(value=result[0], token=result[0], title=result[1]) for result in results]


castle_vocabularies = {
'Countries': CountriesVocabularyFactory,
'Friendly Types': ReallyUserFriendlyTypesVocabularyFactory,
'Business Types': BusinessTypesVocabulary,
'Survey': SurveyVocabulary,
'Email Category': EmailCategoryVocabulary,
'Mime Types': MimeTypeVocabulary,
'Locations': LocationsVocabulary
}