--- a/.installed.cfg Wed May 20 12:24:59 2015 +0200
+++ b/.installed.cfg Wed Jun 17 09:56:38 2015 +0200
@@ -1,16 +1,21 @@
[buildout]
-installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-utils.egg-link
+installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-file.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/lingua.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-viewlet.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-i18n.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-catalog.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-utils.egg-link
parts = package i18n pyflakes test
[package]
-__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pcreate
- /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/ptweens
+__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pserve
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pshell
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pcreate
/home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/prequest
/home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pdistreport
- /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pserve
- /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pshell
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pviews
/home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/proutes
- /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/pviews
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/ptweens
__buildout_signature__ = zc.recipe.egg-2.0.1-py3.4.egg setuptools-12.0.5-py3.4.egg zc.buildout-2.3.1-py3.4.egg
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs
@@ -60,7 +65,7 @@
[test]
__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_form/parts/test
/home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/test
-__buildout_signature__ = zc.recipe.testrunner-2.0.0-py3.4.egg zc.recipe.egg-2.0.1-py3.4.egg setuptools-12.0.5-py3.4.egg zope.testrunner-4.4.6-py3.4.egg zc.buildout-2.3.1-py3.4.egg zope.interface-4.1.2-py3.4-linux-x86_64.egg zope.exceptions-4.0.7-py3.4.egg six-1482e89f68d85eea27f4ed7749df2819
+__buildout_signature__ = zc.recipe.testrunner-2.0.0-py3.4.egg zc.recipe.egg-2.0.1-py3.4.egg setuptools-12.0.5-py3.4.egg zope.testrunner-4.4.6-py3.4.egg zc.buildout-2.3.1-py3.4.egg zope.interface-4.1.2-py3.4-linux-x86_64.egg zope.exceptions-4.0.7-py3.4.egg six-e6b62e54b4df360c40dfcbb76c1ecf1a
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs
_e = /var/local/env/pyams/eggs
@@ -71,3 +76,23 @@
location = /home/tflorac/Dropbox/src/PyAMS/pyams_form/parts/test
recipe = zc.recipe.testrunner
script = /home/tflorac/Dropbox/src/PyAMS/pyams_form/bin/test
+
+[buildout]
+installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-file.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/lingua.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-viewlet.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-i18n.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-catalog.egg-link
+ /home/tflorac/Dropbox/src/PyAMS/pyams_form/develop-eggs/pyams-utils.egg-link
+
+[buildout]
+parts = i18n pyflakes test package
+
+[buildout]
+parts = pyflakes test package i18n
+
+[buildout]
+parts = test package i18n pyflakes
+
+[buildout]
+parts = package i18n pyflakes test
--- a/buildout.cfg Wed May 20 12:24:59 2015 +0200
+++ b/buildout.cfg Wed Jun 17 09:56:38 2015 +0200
@@ -17,9 +17,15 @@
#allow-picked-versions = false
src = src
-develop = .
- ../pyams_skin
- ../pyams_utils
+develop =
+ .
+ ../ext/lingua
+ ../pyams_catalog
+ ../pyams_file
+ ../pyams_i18n
+ ../pyams_skin
+ ../pyams_utils
+ ../pyams_viewlet
parts =
package
--- a/setup.py Wed May 20 12:24:59 2015 +0200
+++ b/setup.py Wed Jun 17 09:56:38 2015 +0200
@@ -56,7 +56,9 @@
install_requires=[
'setuptools',
# -*- Extra requirements: -*-
+ 'pyams_i18n',
'pyams_skin',
+ 'pyams_utils',
'pyramid',
'pyramid_zope_request',
'z3c.form',
--- a/src/pyams_form.egg-info/SOURCES.txt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form.egg-info/SOURCES.txt Wed Jun 17 09:56:38 2015 +0200
@@ -9,6 +9,7 @@
src/pyams_form/include.py
src/pyams_form/schema.py
src/pyams_form/search.py
+src/pyams_form/security.py
src/pyams_form/terms.py
src/pyams_form/viewlet.py
src/pyams_form.egg-info/PKG-INFO
@@ -40,8 +41,11 @@
src/pyams_form/widget/templates/checkbox-input.pt
src/pyams_form/widget/templates/close-display.pt
src/pyams_form/widget/templates/close-input.pt
+src/pyams_form/widget/templates/color-input.pt
src/pyams_form/widget/templates/date-input.pt
src/pyams_form/widget/templates/datetime-input.pt
+src/pyams_form/widget/templates/html-input.pt
+src/pyams_form/widget/templates/orderedselect-input.pt
src/pyams_form/widget/templates/radio-display.pt
src/pyams_form/widget/templates/radio-input.pt
src/pyams_form/widget/templates/reset-display.pt
--- a/src/pyams_form.egg-info/requires.txt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form.egg-info/requires.txt Wed Jun 17 09:56:38 2015 +0200
@@ -1,5 +1,7 @@
setuptools
+pyams_i18n
pyams_skin
+pyams_utils
pyramid
pyramid_zope_request
z3c.form
--- a/src/pyams_form/form.py Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/form.py Wed Jun 17 09:56:38 2015 +0200
@@ -18,11 +18,12 @@
# import interfaces
from pyams_form.interfaces.form import IFormLayer, IForm, IAJAXForm, IInnerSubForm, IInnerTabForm, \
- ICustomUpdateSubForm, IFormCreatedEvent, FormCreatedEvent, IInnerForm
+ ICustomUpdateSubForm, IFormCreatedEvent, FormCreatedEvent, IInnerForm, IFormContextPermissionChecker
from pyams_form.interfaces.form import IAddFormButtons, IModalAddFormButtons, IEditFormButtons, \
IModalEditFormButtons, IModalDisplayFormButtons
from pyams_form.interfaces.form import FormObjectCreatedEvent, FormObjectModifiedEvent
-from pyams_skin.interfaces import IDialog, ISkinnable
+from pyams_i18n.interfaces import II18n
+from pyams_skin.interfaces import IDialog, ISkinnable, IContentTitle
from pyams_template.interfaces import IContentTemplate, ILayoutTemplate
from pyramid_chameleon.interfaces import IChameleonTranslate
from z3c.form.interfaces import DISPLAY_MODE, IErrorViewSnippet
@@ -32,6 +33,8 @@
from pyams_form.group import GroupsBasedForm
from pyams_pagelet.interfaces import PageletCreatedEvent
from pyams_skin.skin import apply_skin
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from pyams_utils.list import unique
from pyams_utils.url import absolute_url
from pyramid.decorator import reify
from pyramid.events import subscriber
@@ -70,7 +73,6 @@
edit_permission = FieldProperty(IForm['edit_permission'])
- title = FieldProperty(IForm['title'])
legend = FieldProperty(IForm['legend'])
css_class = FieldProperty(IForm['css_class'])
icon_css_class = FieldProperty(IForm['icon_css_class'])
@@ -93,12 +95,39 @@
alsoProvides(req, self.layer)
request.registry.notify(FormCreatedEvent(self))
+ @property
+ def title(self):
+ registry = self.request.registry
+ adapter = registry.queryMultiAdapter((self.context, self.request, self), IContentTitle)
+ if adapter is None:
+ adapter = registry.queryAdapter(self.context, IContentTitle)
+ if adapter is not None:
+ return adapter.title
+ else:
+ return II18n(self.context).query_attribute('title', request=self.request)
+
def update(self):
+ # check form permission to get form mode
if self.edit_permission and not self.request.has_permission(self.edit_permission, self.getContent()):
self.mode = DISPLAY_MODE
- Form.update(self)
+ # check form mode based on context checker
+ registry = self.request.registry
+ permission = None
+ for content in unique((self.getContent(), self.context)):
+ checker = registry.queryMultiAdapter((content, self.request, self), IFormContextPermissionChecker)
+ if checker is None:
+ checker = registry.queryAdapter(content, IFormContextPermissionChecker)
+ if checker is not None:
+ permission = checker.edit_permission
+ break
+ if permission != self.edit_permission:
+ if (permission == 'system.forbidden') or \
+ not self.request.has_permission(permission, self.getContent()):
+ self.mode = DISPLAY_MODE
+ # update form and sub-forms
[subform.update() for subform in self.subforms]
[tabform.update() for tabform in self.tabforms]
+ Form.update(self)
def get_form_action(self):
return self.action
@@ -278,6 +307,15 @@
return object
+@adapter_config(context=(Interface, Interface, AddForm), provides=IFormContextPermissionChecker)
+class AddFormContextPermissionChecker(ContextRequestViewAdapter):
+ """Add form context permission checker"""
+
+ @property
+ def edit_permission(self):
+ return self.view.edit_permission
+
+
class AJAXAddForm(AddForm):
"""AJAX add form"""
@@ -427,6 +465,24 @@
dialog_class = 'modal-medium'
+@implementer(IInnerForm)
+class InnerDisplayForm(DisplayForm):
+ """Inner display form"""
+
+ @property
+ def id(self):
+ return self.__class__.__name__
+
+ buttons = Buttons(Interface)
+
+ def __init__(self, context, request, view):
+ super(InnerDisplayForm, self).__init__(context, request)
+ self.parent_form = view
+
+ def get_form_action(self):
+ return None
+
+
#
# Form events subscribers
#
--- a/src/pyams_form/interfaces/form.py Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/interfaces/form.py Wed Jun 17 09:56:38 2015 +0200
@@ -17,10 +17,10 @@
# import interfaces
from pyams_viewlet.interfaces import IViewletManager
from pyramid.interfaces import IView
-from z3c.form.interfaces import INPUT_MODE, ISubForm, IWidget, IFormLayer as IBaseFormLayer, ISubmitWidget, ITextWidget
+from z3c.form.interfaces import INPUT_MODE, ISubForm, IWidget, IFormLayer as IBaseFormLayer, ISubmitWidget, \
+ ITextWidget, ITextAreaWidget
from zope.interface.interfaces import IObjectEvent, ObjectEvent
from zope.lifecycleevent.interfaces import IObjectCreatedEvent, IObjectModifiedEvent
-from zope.schema.interfaces import IField
# import packages
from pyams_form.schema import ResetButton, CloseButton
@@ -41,6 +41,22 @@
"""Base PyAMS form layer"""
+class IFormSecurityContext(Interface):
+ """Interface used to get security context of a given object"""
+
+ context = Attribute("Object security context")
+
+
+class IFormContextPermissionChecker(Interface):
+ """Interface used to check form context access rights
+
+ May be implemented as a context adapter or as a
+ (context, request, form) multi-adapter
+ """
+
+ edit_permission = Attribute("Permission required to modify content")
+
+
class IBaseForm(IView):
"""Base form interface"""
@@ -266,6 +282,8 @@
class IInnerTabForm(IInnerForm, ISubForm):
"""Inner tab-form interface"""
+ tab_label = TextLine(title="Tab label")
+
class IViewletSubForm(ISubForm):
"""Inner viewlet form interface"""
@@ -341,10 +359,11 @@
if widget.mode == INPUT_MODE:
return True
if IForm.providedBy(form):
- for subform in form.subforms:
- for widget in subform.widgets.values():
+ for subform in (form.subforms + form.tabforms):
+ for widget in (subform.widgets or {}).values():
if widget.mode == INPUT_MODE:
return True
+ return False
class IAddFormButtons(Interface):
@@ -409,6 +428,10 @@
"""Color widget interface"""
+class IHTMLWidget(ITextAreaWidget):
+ """HTML editor widget interface"""
+
+
#
# Form events
#
Binary file src/pyams_form/locales/fr/LC_MESSAGES/pyams_form.mo has changed
--- a/src/pyams_form/locales/fr/LC_MESSAGES/pyams_form.po Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/locales/fr/LC_MESSAGES/pyams_form.po Wed Jun 17 09:56:38 2015 +0200
@@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2015-01-29 22:41+0100\n"
+"POT-Creation-Date: 2015-06-01 14:37+0200\n"
"PO-Revision-Date: 2015-01-29 17:17+0100\n"
"Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
"Language-Team: French <traduc@traduc.org>\n"
@@ -16,6 +16,19 @@
"Generated-By: Lingua 3.8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+#: src/pyams_form/search.py:56 src/pyams_form/search.py:49
+msgid "Search"
+msgstr "Chercher"
+
+#: src/pyams_form/search.py:41
+msgid "Search query"
+msgstr "Texte recherché"
+
+#: src/pyams_form/search.py:48 src/pyams_form/interfaces/form.py:356
+#: src/pyams_form/interfaces/form.py:370
+msgid "Reset"
+msgstr "Annuler"
+
#: src/pyams_form/terms.py:36
msgid "yes"
msgstr "oui"
@@ -24,55 +37,52 @@
msgid "no"
msgstr "non"
-#: src/pyams_form/form.py:212
+#: src/pyams_form/form.py:269
msgid "Add form"
-msgstr ""
+msgstr "Formulaire de création"
-#: src/pyams_form/form.py:213 src/pyams_form/form.py:264
+#: src/pyams_form/form.py:270 src/pyams_form/form.py:350
msgid "There were some errors."
msgstr "Des erreurs se sont produites."
-#: src/pyams_form/form.py:263
+#: src/pyams_form/form.py:349
msgid "Edit form"
-msgstr ""
+msgstr "Formulaire de mise à jour"
-#: src/pyams_form/form.py:265
+#: src/pyams_form/form.py:351
msgid "Data successfully updated."
msgstr "Les modifications ont été enregistrées."
-#: src/pyams_form/form.py:266
+#: src/pyams_form/form.py:352
msgid "No changes were applied."
msgstr "Aucune modification effectuée."
-#: src/pyams_form/form.py:353
-msgid "My legend"
-msgstr "Ma légende"
-
-#: src/pyams_form/templates/radio-input.pt:7
+#: src/pyams_form/widget/templates/checkbox-input.pt:66
+#: src/pyams_form/widget/templates/radio-input.pt:34
+#: src/pyams_form/widget/templates/checkbox-display.pt:62
msgid "Label"
-msgstr ""
+msgstr "Libellé"
-#: src/pyams_form/templates/inner-form.pt:89
-msgid "legend"
-msgstr ""
+#: src/pyams_form/widget/templates/orderedselect-input.pt:4
+msgid "Clear selected values"
+msgstr "Enlever les valeurs sélectionnées"
-#: src/pyams_form/templates/inner-form.pt:108
-msgid "Tab label"
-msgstr ""
+#: src/pyams_form/templates/search.pt:6
+msgid "Search results"
+msgstr "Résultats de la recherche"
-#: src/pyams_form/interfaces/form.py:295 src/pyams_form/interfaces/form.py:309
-msgid "Reset"
-msgstr "Annuler"
-
-#: src/pyams_form/interfaces/form.py:296 src/pyams_form/interfaces/form.py:303
+#: src/pyams_form/interfaces/form.py:357 src/pyams_form/interfaces/form.py:364
msgid "Add"
msgstr "Ajouter"
-#: src/pyams_form/interfaces/form.py:302 src/pyams_form/interfaces/form.py:316
-#: src/pyams_form/interfaces/form.py:323
+#: src/pyams_form/interfaces/form.py:363 src/pyams_form/interfaces/form.py:377
+#: src/pyams_form/interfaces/form.py:384
msgid "Close"
msgstr "Fermer"
-#: src/pyams_form/interfaces/form.py:310 src/pyams_form/interfaces/form.py:317
+#: src/pyams_form/interfaces/form.py:371 src/pyams_form/interfaces/form.py:378
msgid "Submit"
msgstr "Enregistrer"
+
+#~ msgid "My legend"
+#~ msgstr "Ma légende"
--- a/src/pyams_form/locales/pyams_form.pot Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/locales/pyams_form.pot Wed Jun 17 09:56:38 2015 +0200
@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2015-01-29 22:41+0100\n"
+"POT-Creation-Date: 2015-06-01 14:37+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -14,7 +14,20 @@
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Lingua 3.8\n"
+"Generated-By: Lingua 3.10.dev0\n"
+
+#: ./src/pyams_form/search.py:56 ./src/pyams_form/search.py:49
+msgid "Search"
+msgstr ""
+
+#: ./src/pyams_form/search.py:41
+msgid "Search query"
+msgstr ""
+
+#: ./src/pyams_form/search.py:48 ./src/pyams_form/interfaces/form.py:356
+#: ./src/pyams_form/interfaces/form.py:370
+msgid "Reset"
+msgstr ""
#: ./src/pyams_form/terms.py:36
msgid "yes"
@@ -24,59 +37,52 @@
msgid "no"
msgstr ""
-#: ./src/pyams_form/form.py:212
+#: ./src/pyams_form/form.py:269
msgid "Add form"
msgstr ""
-#: ./src/pyams_form/form.py:213 ./src/pyams_form/form.py:264
+#: ./src/pyams_form/form.py:270 ./src/pyams_form/form.py:350
msgid "There were some errors."
msgstr ""
-#: ./src/pyams_form/form.py:263
+#: ./src/pyams_form/form.py:349
msgid "Edit form"
msgstr ""
-#: ./src/pyams_form/form.py:265
+#: ./src/pyams_form/form.py:351
msgid "Data successfully updated."
msgstr ""
-#: ./src/pyams_form/form.py:266
+#: ./src/pyams_form/form.py:352
msgid "No changes were applied."
msgstr ""
-#: ./src/pyams_form/form.py:353
-msgid "My legend"
-msgstr ""
-
-#: ./src/pyams_form/templates/radio-input.pt:7
+#: ./src/pyams_form/widget/templates/checkbox-input.pt:66
+#: ./src/pyams_form/widget/templates/radio-input.pt:34
+#: ./src/pyams_form/widget/templates/checkbox-display.pt:62
msgid "Label"
msgstr ""
-#: ./src/pyams_form/templates/inner-form.pt:89
-msgid "legend"
-msgstr ""
-
-#: ./src/pyams_form/templates/inner-form.pt:108
-msgid "Tab label"
+#: ./src/pyams_form/widget/templates/orderedselect-input.pt:4
+msgid "Clear selected values"
msgstr ""
-#: ./src/pyams_form/interfaces/form.py:295
-#: ./src/pyams_form/interfaces/form.py:309
-msgid "Reset"
+#: ./src/pyams_form/templates/search.pt:6
+msgid "Search results"
msgstr ""
-#: ./src/pyams_form/interfaces/form.py:296
-#: ./src/pyams_form/interfaces/form.py:303
+#: ./src/pyams_form/interfaces/form.py:357
+#: ./src/pyams_form/interfaces/form.py:364
msgid "Add"
msgstr ""
-#: ./src/pyams_form/interfaces/form.py:302
-#: ./src/pyams_form/interfaces/form.py:316
-#: ./src/pyams_form/interfaces/form.py:323
+#: ./src/pyams_form/interfaces/form.py:363
+#: ./src/pyams_form/interfaces/form.py:377
+#: ./src/pyams_form/interfaces/form.py:384
msgid "Close"
msgstr ""
-#: ./src/pyams_form/interfaces/form.py:310
-#: ./src/pyams_form/interfaces/form.py:317
+#: ./src/pyams_form/interfaces/form.py:371
+#: ./src/pyams_form/interfaces/form.py:378
msgid "Submit"
msgstr ""
--- a/src/pyams_form/search.py Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/search.py Wed Jun 17 09:56:38 2015 +0200
@@ -38,7 +38,8 @@
class ISearchFields(Interface):
"""Default search form interface"""
- query = TextLine(title=_("Search query"))
+ query = TextLine(title=_("Search query"),
+ required=False)
class ISearchButtons(Interface):
@@ -68,7 +69,12 @@
self.actions['search'].addClass('btn-primary')
def get_search_results(self):
- search = IContentSearch(self.context, None)
+ registry = self.request.registry
+ search = registry.queryMultiAdapter((self.context, self.request, self), IContentSearch)
+ if search is None:
+ search = registry.queryMultiAdapter((self.context, self.request), IContentSearch)
+ if search is None:
+ search = IContentSearch(self.context, None)
if search is not None:
self.updateWidgets()
data, errors = self.extractData()
@@ -97,7 +103,7 @@
return Response(self.renderTable())
-@adapter_config(context=(Interface, IPyAMSLayer, SearchResultsView), provides=IValues)
+@adapter_config(context=(IContentSearch, IPyAMSLayer, SearchResultsView), provides=IValues)
class SearchResultsViewValuesAdapter(ContextRequestViewAdapter):
"""Search results view values adapter"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_form/security.py Wed Jun 17 09:56:38 2015 +0200
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_form.interfaces.form import IFormSecurityContext, IFormContextPermissionChecker
+
+# import packages
+
+
+class ProtectedFormObjectMixin(object):
+ """Form object protected by a given permission"""
+
+ @property
+ def permission(self):
+ registry = self.request.registry
+ checker = None
+ context = IFormSecurityContext(self, None)
+ if context is None:
+ context = self.context
+ view = getattr(self, '__parent__', None) or getattr(self, 'view', None) or getattr(self, 'table', None)
+ if view is not None:
+ checker = registry.queryMultiAdapter((context, self.request, view), IFormContextPermissionChecker)
+ if checker is None:
+ checker = registry.queryAdapter(context, IFormContextPermissionChecker)
+ if checker is not None:
+ return checker.edit_permission
--- a/src/pyams_form/templates/form.pt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/templates/form.pt Wed Jun 17 09:56:38 2015 +0200
@@ -30,7 +30,7 @@
data-ams-form-download-target view.download_target | nothing;
data-ams-warn-on-change view.warn_on_change;">
<div class="modal-viewport">
- <fieldset>
+ <fieldset tal:attributes="class view.fieldset_class | default">
<legend tal:define="legend view.legend"
tal:condition="legend">
<i tal:attributes="class view.icon_css_class | nothing"></i>
@@ -120,7 +120,7 @@
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>
+ tal:content="tabform.tab_label" i18n:translate="">Tab label</a>
</li>
</ul>
<div class="tab-content bordered padding-x-10">
--- a/src/pyams_form/templates/inner-form.pt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/templates/inner-form.pt Wed Jun 17 09:56:38 2015 +0200
@@ -1,4 +1,5 @@
-<div class="no-padding">
+<div class="no-padding"
+ tal:attributes="class string:${view.css_class} no-padding">
<div tal:define="prefix provider:form_prefix"
tal:replace="structure prefix">Form prefix</div>
<form method="post"
@@ -110,7 +111,7 @@
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>
+ tal:content="tabform.tab_label" i18n:translate="">Tab label</a>
</li>
</ul>
<div class="tab-content">
--- a/src/pyams_form/templates/search.pt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/templates/search.pt Wed Jun 17 09:56:38 2015 +0200
@@ -1,9 +1,9 @@
-<div id="search-form" data-ams-widget-sortable="false">
+<div id="search-form" data-ams-widget-sortable="false" i18n:domain="pyams_form">
<tal:var content="structure view.search_form.render()" />
<div class="ams-widget hidden">
<header>
<span class="widget-icon"><i class="fa fa-flash"></i></span>
- <h2>Search results</h2>
+ <h2 i18n:translate="">Search results</h2>
</header>
<div class="widget-body no-padding alerts-container">
<div class="widget-body-toolbar"></div>
--- a/src/pyams_form/templates/widget-form.pt Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/templates/widget-form.pt Wed Jun 17 09:56:38 2015 +0200
@@ -4,6 +4,7 @@
class="widget-icon"><i tal:attributes="class view.widget_icon_class"></i>
</span>
<h2 tal:content="view.legend"></h2>
+ <tal:var content="structure provider:pyams.widget_title" />
<tal:var content="structure provider:pyams.toolbar" />
</header>
<div class="widget-body no-padding">
@@ -112,7 +113,7 @@
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>
+ tal:content="tabform.tab_label" i18n:translate="">Tab label</a>
</li>
</ul>
<div class="tab-content">
--- a/src/pyams_form/widget/__init__.py Wed May 20 12:24:59 2015 +0200
+++ b/src/pyams_form/widget/__init__.py Wed Jun 17 09:56:38 2015 +0200
@@ -15,14 +15,16 @@
# import standard library
import inspect
+import json
import os
import venusian
# import interfaces
from pyams_form.interfaces.form import IFormLayer, IResetWidget, ICloseWidget, IDateWidget, IDatetimeWidget, ITimeWidget, \
- IColorWidget
+ IColorWidget, IHTMLWidget
from pyams_form.schema import IResetButton, ICloseButton
-from pyams_utils.schema import IColorField
+from pyams_skin.interfaces.tinymce import ITinyMCEConfiguration
+from pyams_utils.schema import IColorField, IHTMLField
from pyramid.interfaces import IRequest
from z3c.form.interfaces import INPUT_MODE, IFieldWidget, IButtonAction, IWidgetLayoutTemplate, IDataConverter
from zope.pagetemplate.interfaces import IPageTemplate
@@ -34,6 +36,7 @@
from z3c.form.action import Action
from z3c.form.browser.submit import SubmitWidget
from z3c.form.browser.text import TextWidget
+from z3c.form.browser.textarea import TextAreaWidget
from z3c.form.button import ButtonAction
from z3c.form.converter import BaseDataConverter
from z3c.form.widget import FieldWidget, WidgetTemplateFactory, WidgetLayoutFactory
@@ -276,3 +279,34 @@
@adapter_config(context=(IColorField, IFormLayer), provides=IFieldWidget)
def ColorFieldWidget(field, request):
return FieldWidget(field, ColorWidget(request))
+
+
+#
+# HTML widget
+#
+
+@widgettemplate_config(mode='input', template='templates/html-input.pt', layer=IFormLayer)
+@implementer_only(IHTMLWidget)
+class HTMLWidget(TextAreaWidget):
+ """HTML editor widget"""
+
+ label_css_class = 'textarea'
+
+ @property
+ def editor_data(self):
+ registry = self.request.registry
+ config = registry.queryMultiAdapter((self.form, self.request), ITinyMCEConfiguration, name=self.name)
+ if config is None:
+ config = registry.queryMultiAdapter((self.form, self.request), ITinyMCEConfiguration)
+ if config is None:
+ config = getattr(self, 'editor_config_data', None)
+ if config is not None:
+ return json.dumps(config)
+ else:
+ return json.dumps(config.configuration)
+
+
+@adapter_config(context=(IHTMLField, IFormLayer), provides=IFieldWidget)
+def HTMLFieldWidget(field, request):
+ return FieldWidget(field, HTMLWidget(request))
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_form/widget/templates/html-input.pt Wed Jun 17 09:56:38 2015 +0200
@@ -0,0 +1,31 @@
+<textarea id="" name="" class="" cols="" rows=""
+ tabindex="" disabled="" readonly="" accesskey=""
+ i18n:domain=""
+ tal:attributes="id view/id;
+ name view/name;
+ class string:${view/klass} tinymce;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup;
+ disabled view/disabled;
+ tabindex view/tabindex;
+ onfocus view/onfocus;
+ onblur view/onblur;
+ onchange view/onchange;
+ cols view/cols;
+ rows view/rows;
+ readonly view/readonly;
+ accesskey view/accesskey;
+ onselect view/onselect;
+ data-ams-data view/editor_data;"
+ tal:content="view/value"></textarea>