|
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 from pyams_template.template import template_config |
|
13 |
|
14 __docformat__ = 'restructuredtext' |
|
15 |
|
16 # import standard library |
|
17 |
|
18 # import interfaces |
|
19 from pyams_viewlet.interfaces import IViewletManager |
|
20 from pyramid.interfaces import IView |
|
21 from z3c.form.interfaces import INPUT_MODE, ISubForm, IWidget, IFormLayer as IBaseFormLayer, ISubmitWidget |
|
22 from zope.interface.interfaces import IObjectEvent, ObjectEvent |
|
23 from zope.lifecycleevent.interfaces import IObjectCreatedEvent, IObjectModifiedEvent |
|
24 |
|
25 # import packages |
|
26 from pyams_form.schema import ResetButton, CloseButton |
|
27 from z3c.form import button |
|
28 from zope.interface import implementer, Interface, Attribute |
|
29 from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent |
|
30 from zope.schema import TextLine, List, Object, Bool, Choice, Dict |
|
31 |
|
32 from pyams_form import _ |
|
33 |
|
34 |
|
35 # |
|
36 # Form interfaces |
|
37 # |
|
38 |
|
39 class IFormLayer(IBaseFormLayer): |
|
40 """Base PyAMS form layer""" |
|
41 |
|
42 |
|
43 class IBaseForm(IView): |
|
44 """Base form interface""" |
|
45 |
|
46 |
|
47 @template_config(template='../templates/form.pt', layer=IFormLayer) |
|
48 class IForm(IBaseForm): |
|
49 """Default form interface""" |
|
50 |
|
51 skin = TextLine(title="Skin name", |
|
52 default="PyAMS default skin", |
|
53 required=False) |
|
54 |
|
55 edit_permission = TextLine(title="Required edit permission", |
|
56 required=False, |
|
57 default='manage') |
|
58 |
|
59 def get_skin(self): |
|
60 """Get skin associated with this form""" |
|
61 |
|
62 title = TextLine(title="Form title") |
|
63 |
|
64 legend = TextLine(title="Form legend", |
|
65 required=False) |
|
66 |
|
67 css_class = TextLine(title="CSS class", |
|
68 default='ams-form form-horizontal') |
|
69 |
|
70 icon_css_class = TextLine(title="Legend CSS class", |
|
71 required=False) |
|
72 |
|
73 autocomplete = Choice(title="Auto-complete", |
|
74 values=('on', 'off'), |
|
75 default='on') |
|
76 |
|
77 warn_on_change = Choice(title="Warn on unsaved change?", |
|
78 values=('default', True, False), |
|
79 default='default') |
|
80 |
|
81 label_css_class = TextLine(title="Labels CSS class", |
|
82 required=False, |
|
83 default='control-label col-md-3') |
|
84 |
|
85 input_css_class = TextLine(title="Inputs CSS class", |
|
86 required=False, |
|
87 default='col-md-9') |
|
88 |
|
89 display_hints_on_widgets = Bool(title="Display hints on input widgets?", |
|
90 required=True, |
|
91 default=False) |
|
92 |
|
93 handle_upload = Bool(title="Handle uploads in form?", |
|
94 description="Set to true when form handle uploads to get progress bar", |
|
95 required=True, |
|
96 default=False) |
|
97 |
|
98 callbacks = Dict(title="Widgets validation callbacks", |
|
99 key_type=TextLine(), |
|
100 value_type=TextLine(), |
|
101 required=False) |
|
102 |
|
103 subforms = List(title="Sub-forms", |
|
104 value_type=Object(schema=ISubForm), |
|
105 required=False, |
|
106 readonly=True) |
|
107 |
|
108 subforms_legend = TextLine(title="Sub-forms legend", |
|
109 required=False) |
|
110 |
|
111 tabforms = List(title="Tab-forms", |
|
112 value_type=Object(schema=ISubForm), |
|
113 required=False, |
|
114 readonly=True) |
|
115 |
|
116 is_dialog = Attribute("Check to know if current form is in a modal dialog") |
|
117 |
|
118 def get_form_action(self): |
|
119 """Get form action URL""" |
|
120 |
|
121 def get_widget_callback(self, widget): |
|
122 """Get submit callback associated with a given widget""" |
|
123 |
|
124 def update_content(self, object, data): |
|
125 """Update given object with form data""" |
|
126 |
|
127 def get_submit_output(self, writer, changes): |
|
128 """Get submit output""" |
|
129 |
|
130 |
|
131 class IAJAXForm(Interface): |
|
132 """AJAX form attributes""" |
|
133 |
|
134 ajax_handler = TextLine(title="AJAX handler", |
|
135 description="Name of a JSON view handling AJAX requests", |
|
136 required=False) |
|
137 |
|
138 form_options = Dict(title="AJAX data options", |
|
139 required=False) |
|
140 |
|
141 form_target = TextLine(title="Form submit target", |
|
142 description="Form content target for HTML and text content types", |
|
143 required=False, |
|
144 default='#content') |
|
145 |
|
146 ajax_callback = TextLine(title="AJAX submit callback", |
|
147 description="Name of a custom form submit callback", |
|
148 required=False) |
|
149 |
|
150 def get_form_options(self): |
|
151 """Get form options in JSON format""" |
|
152 |
|
153 def get_ajax_handler(self): |
|
154 """Get absolute URL of AJAX handler""" |
|
155 |
|
156 def get_ajax_errors(self): |
|
157 """Get AJAX errors""" |
|
158 |
|
159 def get_ajax_output(self, changes): |
|
160 """Get AJAX POST output""" |
|
161 |
|
162 |
|
163 class IFormWidgetsGroup(Interface): |
|
164 """Form widgets group interface""" |
|
165 |
|
166 id = TextLine(title="Group ID", |
|
167 required=False) |
|
168 |
|
169 widgets = List(title="Group's widgets list", |
|
170 value_type=Object(schema=IWidget)) |
|
171 |
|
172 legend = TextLine(title="Group legend", |
|
173 required=False) |
|
174 |
|
175 help = TextLine(title="Group help", |
|
176 required=False) |
|
177 |
|
178 css_class = TextLine(title="CSS class", |
|
179 required=False, |
|
180 readonly=True) |
|
181 |
|
182 switch = Bool(title="Switchable group?", |
|
183 required=True, |
|
184 default=False) |
|
185 |
|
186 checkbox_switch = Bool(title="Group switched via checkbox?", |
|
187 required=True, |
|
188 default=False) |
|
189 |
|
190 checkbox_field = TextLine(title="Field name matching switch checkbox?", |
|
191 required=False) |
|
192 |
|
193 checkbox_widget = Object(schema=IWidget, |
|
194 required=False, |
|
195 readonly=True) |
|
196 |
|
197 hide_if_empty = Bool(title="Hide group if empty?", |
|
198 description="""If 'Yes', a switchable group containing only """ |
|
199 """widgets with default values is hidden""", |
|
200 required=True, |
|
201 default=False) |
|
202 |
|
203 visible = Attribute("Visible group?") |
|
204 |
|
205 visible_widgets = Attribute("Visible widgets") |
|
206 |
|
207 switchable = Attribute("Switchable group?") |
|
208 |
|
209 switcher_state = Attribute("Switcher state") |
|
210 |
|
211 checker_state = Attribute("Checker state") |
|
212 |
|
213 |
|
214 class IGroupsBasedForm(IBaseForm): |
|
215 """Groups based form""" |
|
216 |
|
217 groups = List(title="Form widgets groups", |
|
218 value_type=Object(IFormWidgetsGroup)) |
|
219 |
|
220 def add_group(self, group): |
|
221 """Add given group to form groups""" |
|
222 |
|
223 |
|
224 class IViewletsBasedForm(IBaseForm): |
|
225 """Viewlets based form""" |
|
226 |
|
227 providers = List(title="List of content providers names included in this form", |
|
228 value_type=TextLine(), |
|
229 required=True) |
|
230 |
|
231 |
|
232 class IInnerSubForm(ISubForm): |
|
233 """Inner sub-form interface""" |
|
234 |
|
235 |
|
236 class IInnerTabForm(ISubForm): |
|
237 """Inner tab-form interface""" |
|
238 |
|
239 |
|
240 class IViewletSubForm(ISubForm): |
|
241 """Inner viewlet form interface""" |
|
242 |
|
243 legend = Attribute("Sub-form legend") |
|
244 |
|
245 switchable = Attribute("Can the sub-form be hidden ?") |
|
246 |
|
247 visible = Attribute("Is the sub-form initially visible ?") |
|
248 |
|
249 callbacks = Dict(title="Widgets callbacks", |
|
250 key_type=TextLine(), |
|
251 value_type=TextLine()) |
|
252 |
|
253 def get_widget_callback(self, widget): |
|
254 """Get submit callback associated with a given widget""" |
|
255 |
|
256 |
|
257 class ICustomExtractSubForm(ISubForm): |
|
258 """SubForm interface with custom extract method""" |
|
259 |
|
260 def extract(self): |
|
261 """Custom data and errors extraction method""" |
|
262 |
|
263 |
|
264 class ICustomUpdateSubForm(ISubForm): |
|
265 """SubForm interface with custom update method""" |
|
266 |
|
267 def update_content(self, object, data): |
|
268 """Custom content update method""" |
|
269 |
|
270 |
|
271 class ISearchForm(Interface): |
|
272 """Default search form interface""" |
|
273 |
|
274 def get_search_results(self): |
|
275 """Get search results""" |
|
276 |
|
277 |
|
278 # |
|
279 # Form viewlets |
|
280 # |
|
281 |
|
282 class IFormViewletsManager(IViewletManager): |
|
283 """Base forms viewlets manager interface""" |
|
284 |
|
285 |
|
286 class IFormPrefixViewletsManager(IFormViewletsManager): |
|
287 """Form prefix viewlets manager interface""" |
|
288 |
|
289 |
|
290 class IWidgetsPrefixViewletsManager(IFormViewletsManager): |
|
291 """Form widgets prefix viewlets manager interface""" |
|
292 |
|
293 |
|
294 class IWidgetsSuffixViewletsManager(IFormViewletsManager): |
|
295 """Form widgets suffix viewlets manager interface""" |
|
296 |
|
297 |
|
298 class IFormSuffixViewletsManager(IFormViewletsManager): |
|
299 """Form suffix viewlets manager interface""" |
|
300 |
|
301 |
|
302 # |
|
303 # Form buttons |
|
304 # |
|
305 |
|
306 def check_submit_button(form): |
|
307 """Check form and widgets mode before displaying submit button""" |
|
308 if form.mode != INPUT_MODE: |
|
309 return False |
|
310 for widget in form.widgets.values(): |
|
311 if widget.mode == INPUT_MODE: |
|
312 return True |
|
313 if IForm.providedBy(form): |
|
314 for subform in form.subforms: |
|
315 for widget in subform.widgets.values(): |
|
316 if widget.mode == INPUT_MODE: |
|
317 return True |
|
318 |
|
319 |
|
320 class IAddFormButtons(Interface): |
|
321 """Default add form buttons""" |
|
322 |
|
323 reset = ResetButton(name='reset', title=_("Reset")) |
|
324 add = button.Button(name='add', title=_("Add"), condition=check_submit_button) |
|
325 |
|
326 |
|
327 class IModalAddFormButtons(Interface): |
|
328 """Modal add form buttons""" |
|
329 |
|
330 close = CloseButton(name='close', title=_("Close")) |
|
331 add = button.Button(name='add', title=_("Add"), condition=check_submit_button) |
|
332 |
|
333 |
|
334 class IEditFormButtons(Interface): |
|
335 """Default edit form buttons""" |
|
336 |
|
337 reset = ResetButton(name='reset', title=_("Reset")) |
|
338 submit = button.Button(name='submit', title=_("Submit"), condition=check_submit_button) |
|
339 |
|
340 |
|
341 class IModalEditFormButtons(Interface): |
|
342 """Modal edit form buttons""" |
|
343 |
|
344 close = CloseButton(name='close', title=_("Close")) |
|
345 submit = button.Button(name='submit', title=_("Submit"), condition=check_submit_button) |
|
346 |
|
347 |
|
348 class IModalDisplayFormButtons(Interface): |
|
349 """Modal display form buttons""" |
|
350 |
|
351 close = CloseButton(name='close', title=_("Close")) |
|
352 |
|
353 |
|
354 # |
|
355 # Inner form interface |
|
356 # |
|
357 |
|
358 @template_config(template='../templates/inner-form.pt', layer=IFormLayer) |
|
359 class IInnerForm(Interface): |
|
360 """Inner form marker interface""" |
|
361 |
|
362 |
|
363 @template_config(template='../templates/widget-form.pt', layer=IFormLayer) |
|
364 class IWidgetForm(Interface): |
|
365 """Widget form marker interface""" |
|
366 |
|
367 widget_icon_class = TextLine(title="Widget icon class", |
|
368 default="fa fa-edit") |
|
369 |
|
370 |
|
371 # |
|
372 # Form buttons widgets |
|
373 # |
|
374 |
|
375 class IResetWidget(ISubmitWidget): |
|
376 """Reset button widget interface""" |
|
377 |
|
378 |
|
379 class ICloseWidget(ISubmitWidget): |
|
380 """Close button widget interface""" |
|
381 |
|
382 |
|
383 # |
|
384 # Form events |
|
385 # |
|
386 |
|
387 class IFormCreatedEvent(IObjectEvent): |
|
388 """Form created event interface""" |
|
389 |
|
390 |
|
391 @implementer(IFormCreatedEvent) |
|
392 class FormCreatedEvent(ObjectEvent): |
|
393 """Form created event""" |
|
394 |
|
395 |
|
396 class IViewObjectEvent(IObjectEvent): |
|
397 """View object event interface""" |
|
398 |
|
399 view = Attribute("View in which event was fired") |
|
400 |
|
401 |
|
402 class IFormObjectCreatedEvent(IObjectCreatedEvent, IViewObjectEvent): |
|
403 """Event fired after final object creation""" |
|
404 |
|
405 |
|
406 @implementer(IFormObjectCreatedEvent) |
|
407 class FormObjectCreatedEvent(ObjectCreatedEvent): |
|
408 """Form object created event""" |
|
409 |
|
410 def __init__(self, object, view): |
|
411 self.object = object |
|
412 self.view = view |
|
413 |
|
414 |
|
415 class IFormObjectModifiedEvent(IObjectModifiedEvent, IViewObjectEvent): |
|
416 """Event fired after object modification""" |
|
417 |
|
418 |
|
419 @implementer(IFormObjectModifiedEvent) |
|
420 class FormObjectModifiedEvent(ObjectModifiedEvent): |
|
421 """Form object modified event""" |
|
422 |
|
423 def __init__(self, object, view, *descriptions): |
|
424 ObjectModifiedEvent.__init__(self, object, *descriptions) |
|
425 self.view = view |