src/pyams_form/interfaces/form.py
changeset 0 7a0b409fd4b8
child 1 dfa0508e4055
equal deleted inserted replaced
-1:000000000000 0:7a0b409fd4b8
       
     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