--- a/src/pyams_form/form.py Sat Feb 28 13:33:20 2015 +0100
+++ b/src/pyams_form/form.py Sat Feb 28 15:10:46 2015 +0100
@@ -18,7 +18,7 @@
# import interfaces
from pyams_form.interfaces.form import IFormLayer, IForm, IAJAXForm, IInnerSubForm, IInnerTabForm, \
- ICustomUpdateSubForm, IFormCreatedEvent, FormCreatedEvent
+ ICustomUpdateSubForm, IFormCreatedEvent, FormCreatedEvent, IInnerForm
from pyams_form.interfaces.form import IAddFormButtons, IModalAddFormButtons, IEditFormButtons, \
IModalEditFormButtons, IModalDisplayFormButtons
from pyams_form.interfaces.form import FormObjectCreatedEvent, FormObjectModifiedEvent
@@ -30,6 +30,7 @@
# import packages
from pyams_form.group import GroupsBasedForm
+from pyams_pagelet.interfaces import PageletCreatedEvent
from pyams_skin.skin import apply_skin
from pyramid.decorator import reify
from pyramid.events import subscriber
@@ -40,7 +41,7 @@
from z3c.form.form import applyChanges, \
Form, AddForm as BaseAddForm, EditForm as BaseEditForm, DisplayForm as BaseDisplayForm
from zope.component import queryUtility
-from zope.interface import implementer, alsoProvides
+from zope.interface import implementer, alsoProvides, Interface
from zope.lifecycleevent import Attributes, ObjectCreatedEvent
from zope.schema.fieldproperty import FieldProperty
@@ -104,13 +105,15 @@
@reify
def subforms(self):
registry = self.request.registry
- return sorted((adapter[1] for adapter in registry.getAdapters((self,), IInnerSubForm)),
+ return sorted((adapter[1]
+ for adapter in registry.getAdapters((self.context, self.request, self), IInnerSubForm)),
key=get_form_weight)
@reify
def tabforms(self):
registry = self.request.registry
- return sorted((adapter[1] for adapter in registry.getAdapters((self,), IInnerTabForm)),
+ return sorted((adapter[1]
+ for adapter in registry.getAdapters((self.context, self.request, self), IInnerTabForm)),
key=get_form_weight)
@property
@@ -273,8 +276,13 @@
"""AJAX add form"""
def __call__(self):
- self.updateWidgets()
- data, errors = self.extractData()
+ self.request.registry.notify(PageletCreatedEvent(self))
+ data, errors = {}, ()
+ for form in self.forms:
+ form.updateWidgets()
+ form_data, form_errors = form.extractData()
+ data.update(form_data)
+ errors = errors + form_errors
if errors or self.errors:
return self.get_ajax_errors()
result = self.createAndAdd(data)
@@ -293,6 +301,24 @@
dialog_class = 'modal-medium'
+@implementer(IInnerForm)
+class InnerAddForm(AddForm):
+ """Inner add form"""
+
+ @property
+ def id(self):
+ return self.__class__.__name__
+
+ buttons = Buttons(Interface)
+
+ def __init__(self, context, request, view):
+ super(InnerAddForm, self).__init__(context, request)
+ self.parent_form = view
+
+ def get_form_action(self):
+ return None
+
+
#
# Edit forms
#
@@ -327,8 +353,13 @@
"""AJAX edit form"""
def __call__(self):
- self.updateWidgets()
- data, errors = self.extractData()
+ self.request.registry.notify(PageletCreatedEvent(self))
+ data, errors = {}, ()
+ for form in self.forms:
+ form.updateWidgets()
+ form_data, form_errors = form.extractData()
+ data.update(form_data)
+ errors = errors + form_errors
if errors or self.errors:
return self.get_ajax_errors()
changes = self.applyChanges(data)
@@ -354,6 +385,24 @@
dialog_class = 'modal-medium'
+@implementer(IInnerForm)
+class InnerEditForm(EditForm):
+ """Inner edit form"""
+
+ @property
+ def id(self):
+ return self.__class__.__name__
+
+ buttons = Buttons(Interface)
+
+ def __init__(self, context, request, view):
+ super(InnerEditForm, self).__init__(context, request)
+ self.parent_form = view
+
+ def get_form_action(self):
+ return None
+
+
#
# Display forms
#
--- a/src/pyams_form/group.py Sat Feb 28 13:33:20 2015 +0100
+++ b/src/pyams_form/group.py Sat Feb 28 15:10:46 2015 +0100
@@ -30,6 +30,7 @@
id = FieldProperty(IFormWidgetsGroup['id'])
widgets = FieldProperty(IFormWidgetsGroup['widgets'])
+ bordered = FieldProperty(IFormWidgetsGroup['bordered'])
legend = FieldProperty(IFormWidgetsGroup['legend'])
help = FieldProperty(IFormWidgetsGroup['help'])
_css_class = FieldProperty(IFormWidgetsGroup['css_class'])
@@ -39,11 +40,12 @@
checkbox_widget = FieldProperty(IFormWidgetsGroup['checkbox_widget'])
hide_if_empty = FieldProperty(IFormWidgetsGroup['hide_if_empty'])
- def __init__(self, id, widgets=None, legend=None, help=None, css_class='', switch=False,
+ def __init__(self, id, widgets=None, bordered=True, legend=None, help=None, css_class='', switch=False,
checkbox_switch=False, checkbox_field=None, hide_if_empty=False):
assert (not checkbox_switch) or checkbox_field, "You must define checkbox field when using checkbox switch"
self.id = id
self.widgets = widgets or []
+ self.bordered = bordered
self.legend = id if legend is None else legend
self.help = help
self._css_class = css_class
@@ -67,7 +69,7 @@
if self.checkbox_field is None:
return None
for widget in self.widgets:
- if widget.field is self.checkbox_field.field:
+ if widget.field is self.checkbox_field:
return widget
@reify
@@ -94,7 +96,7 @@
@property
def visible_widgets(self):
for widget in self.widgets:
- if (self.checkbox_field is None) or (widget.field is not self.checkbox_field.field):
+ if (self.checkbox_field is None) or (widget.field is not self.checkbox_field):
yield widget
@property
@@ -110,10 +112,10 @@
return 'on' if self.visible else 'off'
-def NamedWidgetsGroup(id, widgets, names=(), legend=None, help=None, css_class='', switch=False,
+def NamedWidgetsGroup(id, widgets, names=(), bordered=True, legend=None, help=None, css_class='', switch=False,
checkbox_switch=False, checkbox_field=None, hide_if_empty=False):
"""Create a widgets group based on widgets names"""
- return FormWidgetsGroup(id, [widgets.get(name) for name in names], legend, help, css_class, switch,
+ return FormWidgetsGroup(id, [widgets.get(name) for name in names], bordered, legend, help, css_class, switch,
checkbox_switch, checkbox_field, hide_if_empty)
--- a/src/pyams_form/templates/form.pt Sat Feb 28 13:33:20 2015 +0100
+++ b/src/pyams_form/templates/form.pt Sat Feb 28 15:10:46 2015 +0100
@@ -46,13 +46,18 @@
tal:content="structure prefix">Widgets prefix</div>
<tal:loop repeat="group view.groups">
<fieldset tal:define="legend group.legend"
- tal:omit-tag="not:legend">
+ tal:omit-tag="not:legend"
+ tal:attributes="class 'bordered' if group.bordered else None">
<tal:if condition="group.checkbox_switch">
- <legend tal:condition="legend"
- tal:content="legend"
+ <legend data-ams-checker-value="selected"
+ tal:condition="legend"
tal:attributes="class group.css_class;
- data-ams-checker-fieldname group.checker_field.getName();
- data-ams-checker-state group.checker_state;">Legend</legend>
+ data-ams-checker-fieldname '{0}:list'.format(group.checkbox_widget.name);
+ data-ams-checker-readonly 'readonly' if group.checkbox_widget.mode == 'display' else None;
+ data-ams-checker-marker '{0}-empty-marker'.format(group.checkbox_widget.name);
+ data-ams-checker-state group.checker_state;">
+ <label tal:content="legend">Legend</label>
+ </legend>
</tal:if>
<tal:if condition="not:group.checkbox_switch">
<legend tal:condition="legend"
@@ -73,7 +78,7 @@
<tal:if condition="widget.mode != 'hidden'">
<div tal:define="required 'required-field' if widget.required and (widget.mode != 'display') else ''"
tal:attributes="class string:form-group ${required}">
- <label tal:attributes="class view.label_css_class">
+ <label tal:attributes="class group.label_css_class | view.label_css_class">
<span>
<tal:var content="widget.label" />
<i class="fa fa-question-circle hint" title="Input hint"
@@ -83,7 +88,7 @@
data-ams-hint-html '<' in description;"></i>
</span>
</label>
- <div tal:attributes="class widget.input_css_class | view.input_css_class">
+ <div tal:attributes="class widget.input_css_class | group.input_css_class | view.input_css_class">
<label class="input"
tal:attributes="class widget.label_css_class | default;
data-ams-data extension:object_data(widget);
@@ -114,7 +119,8 @@
tal:condition="view.tabforms">
<ul class="nav nav-tabs">
<li tal:repeat="tabform view.tabforms"
- tal:attributes="class tabform.widgets.errors and 'state-error' or ''">
+ tal:attributes="class 'small {active} {errors}'.format(active='active' if repeat['tabform'].start() else '',
+ errors='state-error' if tabform.widgets.errors else '')">
<a data-toggle="tab"
tal:attributes="href string:#${tabform.id}"
tal:content="tabform.tabLabel" i18n:translate="">Tab label</a>
@@ -122,10 +128,10 @@
</ul>
<div class="tab-content">
<div class="tab-pane fade in"
- tal:repeat="tabform view.tabforms">
- tal:attributes="id tabform.id"
- tal:content="structure tabform.render()" />
- </div>
+ tal:repeat="tabform view.tabforms"
+ tal:attributes="id tabform.id;
+ class 'tab-pane {active} fade in'.format(active='active' if repeat['tabform'].start() else '');"
+ tal:content="structure tabform.render()"></div>
</div>
</div>
</fieldset>
--- a/src/pyams_form/templates/inner-form.pt Sat Feb 28 13:33:20 2015 +0100
+++ b/src/pyams_form/templates/inner-form.pt Sat Feb 28 15:10:46 2015 +0100
@@ -3,9 +3,11 @@
tal:replace="structure prefix">Form prefix</div>
<form method="post"
data-async
+ tal:define="action view.get_form_action()"
+ tal:omit-tag="not:action"
tal:attributes="id view.id;
name view.name;
- action view.get_form_action();
+ action action;
method view.method;
enctype view.enctype;
acceptCharset view.acceptCharset;
@@ -17,105 +19,109 @@
data-ams-form-options view.get_form_options() | nothing;
data-ams-form-submit-target view.form_target | nothing;
data-ams-warn-on-change view.warn_on_change;">
- <div class="modal-viewport">
- <fieldset>
- <legend tal:define="legend view.legend"
- tal:condition="legend">
- <i tal:attributes="class view.icon_css_class | nothing"></i>
- <tal:var content="legend">Legend</tal:var>
- </legend>
- <tal:var content="structure provider:content_help" />
- <div class="widgets-prefix"
- tal:define="prefix provider:widgets_prefix"
- tal:condition="prefix"
- tal:content="structure prefix">Widgets prefix</div>
- <tal:loop repeat="group view.groups">
- <fieldset tal:define="legend group.legend"
- tal:omit-tag="not:legend">
- <tal:if condition="group.checkbox_switch">
- <legend tal:condition="legend"
- tal:content="legend"
- tal:attributes="class group.css_class;
- data-ams-checker-fieldname group.checker_field.getName();
- data-ams-checker-state group.checker_state;">Legend</legend>
- </tal:if>
- <tal:if condition="not:group.checkbox_switch">
- <legend tal:condition="legend"
- tal:content="legend"
- tal:attributes="class group.css_class;
- data-ams-switcher-state group.switcher_state;">Legend</legend>
+ <fieldset tal:define="legend view.legend"
+ tal:omit-tag="not:legend">
+ <legend tal:condition="legend">
+ <i tal:attributes="class view.icon_css_class | nothing"></i>
+ <tal:var content="legend">Legend</tal:var>
+ </legend>
+ <tal:var content="structure provider:content_help" />
+ <div class="widgets-prefix"
+ tal:define="prefix provider:widgets_prefix"
+ tal:condition="prefix"
+ tal:content="structure prefix">Widgets prefix</div>
+ <tal:loop repeat="group view.groups">
+ <fieldset tal:define="legend group.legend"
+ tal:omit-tag="not:legend"
+ tal:attributes="class 'bordered' if group.bordered else None">
+ <tal:if condition="group.checkbox_switch">
+ <legend data-ams-checker-value="selected"
+ tal:condition="legend"
+ tal:attributes="class group.css_class;
+ data-ams-checker-fieldname '{0}:list'.format(group.checkbox_widget.name);
+ data-ams-checker-readonly 'readonly' if group.checkbox_widget.mode == 'display' else None;
+ data-ams-checker-marker '{0}-empty-marker'.format(group.checkbox_widget.name);
+ data-ams-checker-state group.checker_state;">
+ <label tal:content="legend">Legend</label>
+ </legend>
+ </tal:if>
+ <tal:if condition="not:group.checkbox_switch">
+ <legend tal:condition="legend"
+ tal:content="legend"
+ tal:attributes="class group.css_class;
+ data-ams-switcher-state group.switcher_state;">Legend</legend>
+ </tal:if>
+ <tal:var define="help group.help" condition="help">
+ <div class=""
+ tal:define="html import:pyams_utils.text.text_to_html;
+ i18n_help html(request.localizer.translate(help));"
+ tal:content="structure i18n_help"></div>
+ </tal:var>
+ <tal:loop repeat="widget group.visible_widgets">
+ <input type="hidden"
+ tal:condition="python:widget.mode == 'hidden'"
+ tal:replace="structure widget.render()" />
+ <tal:if condition="widget.mode != 'hidden'">
+ <div tal:define="required 'required-field' if widget.required and (widget.mode != 'display') else ''"
+ tal:attributes="class string:form-group ${required}">
+ <label tal:attributes="class group.label_css_class | view.label_css_class">
+ <span>
+ <tal:var content="widget.label" />
+ <i class="fa fa-question-circle hint" title="Input hint"
+ tal:define="description widget.field.description"
+ tal:condition="description"
+ tal:attributes="title description;
+ data-ams-hint-html '<' in description;"></i>
+ </span>
+ </label>
+ <div tal:attributes="class widget.input_css_class | group.input_css_class | view.input_css_class">
+ <label class="input"
+ tal:attributes="class widget.label_css_class | default;
+ data-ams-data extension:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <input tal:replace="structure widget.render()" />
+ </label>
+ </div>
+ </div>
</tal:if>
- <tal:var define="help group.help" condition="help">
- <div class=""
- tal:define="html import:pyams_utils.text.text_to_html;
- i18n_help html(request.localizer.translate(help));"
- tal:content="structure i18n_help"></div>
- </tal:var>
- <tal:loop repeat="widget group.visible_widgets">
- <input type="hidden"
- tal:condition="python:widget.mode == 'hidden'"
- tal:replace="structure widget.render()" />
- <tal:if condition="widget.mode != 'hidden'">
- <div tal:define="required 'required-field' if widget.required and (widget.mode != 'display') else ''"
- tal:attributes="class string:form-group ${required}">
- <label tal:attributes="class view.label_css_class">
- <span>
- <tal:var content="widget.label" />
- <i class="fa fa-question-circle hint" title="Input hint"
- tal:define="description widget.field.description"
- tal:condition="description"
- tal:attributes="title description;
- data-ams-hint-html '<' in description;"></i>
- </span>
- </label>
- <div tal:attributes="class widget.input_css_class | view.input_css_class">
- <label class="input"
- tal:attributes="class widget.label_css_class | default;
- data-ams-data extension:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
- <input tal:replace="structure widget.render()" />
- </label>
- </div>
- </div>
- </tal:if>
- </tal:loop>
- </fieldset>
- </tal:loop>
- <div class="widgets-suffix"
- tal:define="suffix provider:widgets_suffix"
- tal:condition="suffix"
- tal:content="structure suffix">Widgets suffix</div>
- <div class="subforms"
- tal:condition="view.subforms">
- <fieldset tal:define="title view.subforms_legend"
- tal:omit-tag="not:title">
- <legend tal:condition="title" tal:content="title" i18n:translate="">legend</legend>
- <tal:loop repeat="subform view.subforms">
- <tal:var replace="structure subform.render()" />
- </tal:loop>
- </fieldset>
+ </tal:loop>
+ </fieldset>
+ </tal:loop>
+ <div class="widgets-suffix"
+ tal:define="suffix provider:widgets_suffix"
+ tal:condition="suffix"
+ tal:content="structure suffix">Widgets suffix</div>
+ <div class="subforms"
+ tal:condition="view.subforms">
+ <fieldset tal:define="title view.subforms_legend"
+ tal:omit-tag="not:title">
+ <legend tal:condition="title" tal:content="title" i18n:translate="">legend</legend>
+ <tal:loop repeat="subform view.subforms">
+ <tal:var replace="structure subform.render()" />
+ </tal:loop>
+ </fieldset>
+ </div>
+ <div class="tabforms"
+ tal:condition="view.tabforms">
+ <ul class="nav nav-tabs">
+ <li tal:repeat="tabform view.tabforms"
+ tal:attributes="class '{active} {errors}'.format(active='active' if repeat['tabform'].start() else '',
+ errors='state-error' if tabform.widgets.errors else '')">
+ <a data-toggle="tab"
+ tal:attributes="href string:#${tabform.id}"
+ tal:content="tabform.tabLabel" i18n:translate="">Tab label</a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane fade in"
+ tal:repeat="tabform view.tabforms"
+ tal:attributes="id tabform.id;
+ class 'tab-pane {active} fade in'.format(active='active' if repeat['tabform'].start() else '');"
+ tal:content="structure tabform.render()"></div>
</div>
- <div class="tabforms"
- tal:condition="view.tabforms">
- <ul class="nav nav-tabs">
- <li tal:repeat="tabform view.tabforms"
- tal:attributes="class tabform.widgets.errors and 'state-error' or ''">
- <a data-toggle="tab"
- tal:attributes="href string:#${tabform.id}"
- tal:content="tabform.tabLabel" i18n:translate="">Tab label</a>
- </li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane fade in"
- tal:repeat="tabform view.tabforms">
- tal:attributes="id tabform.id"
- tal:content="structure tabform.render()" />
- </div>
- </div>
- </div>
- </fieldset>
- </div>
- <footer>
+ </div>
+ </fieldset>
+ <footer tal:condition="view.actions">
<button tal:repeat="action view.actions.values()"
tal:replace="structure action.render()">Action</button>
</footer>
--- a/src/pyams_form/templates/widget-form.pt Sat Feb 28 13:33:20 2015 +0100
+++ b/src/pyams_form/templates/widget-form.pt Sat Feb 28 15:10:46 2015 +0100
@@ -34,13 +34,18 @@
tal:content="structure prefix">Widgets prefix</div>
<tal:loop repeat="group view.groups">
<fieldset tal:define="legend group.legend"
- tal:omit-tag="not:legend">
+ tal:omit-tag="not:legend"
+ tal:attributes="class 'bordered' if group.bordered else None">
<tal:if condition="group.checkbox_switch">
- <legend tal:condition="legend"
- tal:content="legend"
+ <legend data-ams-checker-value="selected"
+ tal:condition="legend"
tal:attributes="class group.css_class;
- data-ams-checker-fieldname group.checker_field.getName();
- data-ams-checker-state group.checker_state;">Legend</legend>
+ data-ams-checker-fieldname '{0}:list'.format(group.checkbox_widget.name);
+ data-ams-checker-readonly 'readonly' if group.checkbox_widget.mode == 'display' else None;
+ data-ams-checker-marker '{0}-empty-marker'.format(group.checkbox_widget.name);
+ data-ams-checker-state group.checker_state;">
+ <label tal:content="legend">Legend</label>
+ </legend>
</tal:if>
<tal:if condition="not:group.checkbox_switch">
<legend tal:condition="legend"
@@ -61,7 +66,7 @@
<tal:if condition="widget.mode != 'hidden'">
<div tal:define="required 'required-field' if widget.required and (widget.mode != 'display') else ''"
tal:attributes="class string:form-group ${required}">
- <label tal:attributes="class view.label_css_class">
+ <label tal:attributes="class group.label_css_class | view.label_css_class">
<span>
<tal:var content="widget.label" />
<i class="fa fa-question-circle hint" title="Input hint"
@@ -71,7 +76,7 @@
data-ams-hint-html '<' in description;"></i>
</span>
</label>
- <div tal:attributes="class widget.input_css_class | view.input_css_class">
+ <div tal:attributes="class widget.input_css_class | group.input_css_class | view.input_css_class">
<label class="input"
tal:attributes="class widget.label_css_class | default;
data-ams-data extension:object_data(widget);
@@ -102,7 +107,8 @@
tal:condition="view.tabforms">
<ul class="nav nav-tabs">
<li tal:repeat="tabform view.tabforms"
- tal:attributes="class tabform.widgets.errors and 'state-error' or ''">
+ tal:attributes="class 'small {active} {errors}'.format(active='active' if repeat['tabform'].start() else '',
+ errors='state-error' if tabform.widgets.errors else '')">
<a data-toggle="tab"
tal:attributes="href string:#${tabform.id}"
tal:content="tabform.tabLabel" i18n:translate="">Tab label</a>
@@ -110,10 +116,10 @@
</ul>
<div class="tab-content">
<div class="tab-pane fade in"
- tal:repeat="tabform view.tabforms">
- tal:attributes="id tabform.id"
- tal:content="structure tabform.render()" />
- </div>
+ tal:repeat="tabform view.tabforms"
+ tal:attributes="id tabform.id;
+ class 'tab-pane {active} fade in'.format(active='active' if repeat['tabform'].start() else '');"
+ tal:content="structure tabform.render()"></div>
</div>
</div>
</fieldset>