|
1 # |
|
2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net> |
|
3 # All Rights Reserved. |
|
4 # |
|
5 # This software is subject to the provisions of the Zope Public License, |
|
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
|
10 # FOR A PARTICULAR PURPOSE. |
|
11 # |
|
12 |
|
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 |
|
16 # import standard library |
|
17 from collections import OrderedDict |
|
18 |
|
19 # import interfaces |
|
20 from pyams_content.shared.form.interfaces import IFormFieldFactory, IFormField, IFormFieldContainer, \ |
|
21 IFormFieldContainerTarget, FORM_FIELD_CONTAINER_KEY |
|
22 from pyams_i18n.interfaces import II18n |
|
23 from zope.annotation.interfaces import IAnnotations |
|
24 from zope.location.interfaces import ISublocations |
|
25 from zope.traversing.interfaces import ITraversable |
|
26 |
|
27 # import packages |
|
28 from persistent import Persistent |
|
29 from pyams_utils.adapter import adapter_config, ContextAdapter |
|
30 from pyams_utils.registry import utility_config |
|
31 from pyams_utils.request import check_request |
|
32 from pyams_utils.schema import MailAddressField |
|
33 from pyams_utils.vocabulary import vocabulary_config |
|
34 from pyramid.threadlocal import get_current_registry |
|
35 from zope.component.globalregistry import getGlobalSiteManager |
|
36 from zope.container.contained import Contained |
|
37 from zope.container.ordered import OrderedContainer |
|
38 from zope.interface import implementer |
|
39 from zope.lifecycleevent import ObjectCreatedEvent |
|
40 from zope.location import locate |
|
41 from zope.schema import TextLine, Text, Bool, Int, Decimal, URI, Date, Choice, List |
|
42 from zope.schema.fieldproperty import FieldProperty |
|
43 from zope.componentvocabulary.vocabulary import UtilityVocabulary, UtilityTerm |
|
44 |
|
45 from pyams_content import _ |
|
46 |
|
47 |
|
48 @implementer(IFormField) |
|
49 class FormField(Persistent, Contained): |
|
50 """Form field definition persistent class""" |
|
51 |
|
52 name = FieldProperty(IFormField['name']) |
|
53 field_type = FieldProperty(IFormField['field_type']) |
|
54 label = FieldProperty(IFormField['label']) |
|
55 description = FieldProperty(IFormField['description']) |
|
56 placeholder = FieldProperty(IFormField['placeholder']) |
|
57 values = FieldProperty(IFormField['values']) |
|
58 default = FieldProperty(IFormField['default']) |
|
59 required = FieldProperty(IFormField['required']) |
|
60 visible = FieldProperty(IFormField['visible']) |
|
61 |
|
62 |
|
63 @implementer(IFormFieldContainer) |
|
64 class FormFieldContainer(OrderedContainer): |
|
65 """Form fields container persistent class""" |
|
66 |
|
67 def get_fields(self): |
|
68 registry = getGlobalSiteManager() |
|
69 fields = [] |
|
70 for field in self.values(): |
|
71 if field.visible: |
|
72 factory = registry.queryUtility(IFormFieldFactory, name=field.field_type) |
|
73 if factory is not None: |
|
74 fields.append(factory.get_schema_field(field)) |
|
75 return fields |
|
76 |
|
77 |
|
78 @adapter_config(context=IFormFieldContainerTarget, provides=IFormFieldContainer) |
|
79 def FormFieldContainerFactory(context): |
|
80 """Form fields container factory""" |
|
81 annotations = IAnnotations(context) |
|
82 container = annotations.get(FORM_FIELD_CONTAINER_KEY) |
|
83 if container is None: |
|
84 container = annotations[FORM_FIELD_CONTAINER_KEY] = FormFieldContainer() |
|
85 get_current_registry().notify(ObjectCreatedEvent(container)) |
|
86 locate(container, context, '++fields++') |
|
87 return container |
|
88 |
|
89 |
|
90 @adapter_config(name='fields', context=IFormFieldContainerTarget, provides=ITraversable) |
|
91 class FormFieldContainerNamespace(ContextAdapter): |
|
92 """Form fields container ++fields++ namespace""" |
|
93 |
|
94 def traverse(self, name, firtherpath=None): |
|
95 return IFormFieldContainer(self.context) |
|
96 |
|
97 |
|
98 @adapter_config(name='fields', context=IFormFieldContainerTarget, provides=ISublocations) |
|
99 class FormFieldsContainerSublocations(ContextAdapter): |
|
100 """Form fields container sub-locations adapter""" |
|
101 |
|
102 def sublocations(self): |
|
103 return IFormFieldContainer(self.context).values() |
|
104 |
|
105 |
|
106 # |
|
107 # Form fields factories |
|
108 # |
|
109 |
|
110 @vocabulary_config(name='PyAMS form field types') |
|
111 class FormFieldTypesVocabulary(UtilityVocabulary): |
|
112 """Form field types vocabulary""" |
|
113 |
|
114 interface = IFormFieldFactory |
|
115 |
|
116 def __init__(self, context, **kw): |
|
117 request = check_request() |
|
118 registry = request.registry |
|
119 translate = request.localizer.translate |
|
120 utils = [(name, translate(util.label)) |
|
121 for (name, util) in sorted(registry.getUtilitiesFor(self.interface), |
|
122 key=lambda x: x[1].weight)] |
|
123 self._terms = OrderedDict((title, UtilityTerm(name, title)) for name, title in utils) |
|
124 |
|
125 def __iter__(self): |
|
126 return iter(self._terms.values()) |
|
127 |
|
128 |
|
129 class BaseFormFieldFactory(object): |
|
130 """Base form field factory""" |
|
131 |
|
132 field_factory = None |
|
133 |
|
134 def get_schema_field(self, field): |
|
135 i18n = II18n(field) |
|
136 result = self.field_factory(title=i18n.query_attribute('label'), |
|
137 description=i18n.query_attribute('description'), |
|
138 required=field.required, |
|
139 default=i18n.query_attribute('default')) |
|
140 result.__name__ = field.name |
|
141 return result |
|
142 |
|
143 |
|
144 @utility_config(name='textline', provides=IFormFieldFactory) |
|
145 class TextLineFieldFactory(BaseFormFieldFactory): |
|
146 """Textline field factory""" |
|
147 |
|
148 label = _("Text") |
|
149 weight = 1 |
|
150 |
|
151 field_factory = TextLine |
|
152 |
|
153 |
|
154 @utility_config(name='text', provides=IFormFieldFactory) |
|
155 class TextFieldFactory(BaseFormFieldFactory): |
|
156 """Text field factory""" |
|
157 |
|
158 label = _("Multi-lines text") |
|
159 weight = 2 |
|
160 |
|
161 field_factory = Text |
|
162 |
|
163 |
|
164 @utility_config(name='bool', provides=IFormFieldFactory) |
|
165 class BooleanFieldFactory(BaseFormFieldFactory): |
|
166 """Boolean field factory""" |
|
167 |
|
168 label = _("Boolean") |
|
169 weight = 3 |
|
170 |
|
171 field_factory = Bool |
|
172 |
|
173 |
|
174 @utility_config(name='integer', provides=IFormFieldFactory) |
|
175 class IntegerFieldFactory(BaseFormFieldFactory): |
|
176 """Integer field factory""" |
|
177 |
|
178 label = _("Integer") |
|
179 weight = 4 |
|
180 |
|
181 field_factory = Int |
|
182 |
|
183 |
|
184 @utility_config(name='decimal', provides=IFormFieldFactory) |
|
185 class DecimalFieldFactory(BaseFormFieldFactory): |
|
186 """Decimal field factory""" |
|
187 |
|
188 label = _("Decimal") |
|
189 weight = 5 |
|
190 |
|
191 field_factory = Decimal |
|
192 |
|
193 |
|
194 @utility_config(name='mail', provides=IFormFieldFactory) |
|
195 class MailFieldFactory(BaseFormFieldFactory): |
|
196 """Mail field factory""" |
|
197 |
|
198 label = _("E-mail address") |
|
199 weight = 10 |
|
200 |
|
201 field_factory = MailAddressField |
|
202 |
|
203 |
|
204 @utility_config(name='uri', provides=IFormFieldFactory) |
|
205 class URIFieldFactory(BaseFormFieldFactory): |
|
206 """URI field factory""" |
|
207 |
|
208 label = _("URI") |
|
209 weight = 11 |
|
210 |
|
211 field_factory = URI |
|
212 |
|
213 |
|
214 @utility_config(name='date', provides=IFormFieldFactory) |
|
215 class DateFieldFactory(BaseFormFieldFactory): |
|
216 """Date field factory""" |
|
217 |
|
218 label = _("Date") |
|
219 weight = 15 |
|
220 |
|
221 field_factory = Date |
|
222 |
|
223 |
|
224 class ValuesFieldFactory(BaseFormFieldFactory): |
|
225 """Values-based field factory""" |
|
226 |
|
227 |
|
228 @utility_config(name='choice', provides=IFormFieldFactory) |
|
229 class ChoiceFieldFactory(ValuesFieldFactory): |
|
230 """Choice field factory""" |
|
231 |
|
232 label = _("Choice") |
|
233 weight = 20 |
|
234 |
|
235 field_factory = Choice |
|
236 |
|
237 def get_schema_field(self, field): |
|
238 i18n = II18n(field) |
|
239 result = self.field_factory(title=i18n.query_attribute('label'), |
|
240 description=i18n.query_attribute('description'), |
|
241 required=field.required, |
|
242 default=i18n.query_attribute('default'), |
|
243 values=field.values) |
|
244 result.__name__ = field.name |
|
245 return result |
|
246 |
|
247 |
|
248 @utility_config(name='list', provides=IFormFieldFactory) |
|
249 class ListFieldFactory(ValuesFieldFactory): |
|
250 """List field factory""" |
|
251 |
|
252 label = _("List") |
|
253 weight = 51 |
|
254 |
|
255 field_factory = List |
|
256 |
|
257 def get_schema_field(self, field): |
|
258 i18n = II18n(field) |
|
259 result = self.field_factory(title=i18n.query_attribute('label'), |
|
260 description=i18n.query_attribute('description'), |
|
261 required=field.required, |
|
262 default=[i18n.query_attribute('default')], |
|
263 value_type=Choice(values=field.values)) |
|
264 result.__name__ = field.name |
|
265 return result |