Added widget to display JSON dict
authorThierry Florac <tflorac@ulthar.net>
Tue, 17 Sep 2019 11:56:41 +0200
changeset 186 ddd454de3d32
parent 185 8030eca2abf3
child 187 cc168a57df8d
Added widget to display JSON dict
src/pyams_form/interfaces/form.py
src/pyams_form/widget/__init__.py
src/pyams_form/widget/templates/json-dict-display.pt
--- a/src/pyams_form/interfaces/form.py	Tue Sep 17 11:55:32 2019 +0200
+++ b/src/pyams_form/interfaces/form.py	Tue Sep 17 11:56:41 2019 +0200
@@ -10,26 +10,23 @@
 # FOR A PARTICULAR PURPOSE.
 #
 
-__docformat__ = 'restructuredtext'
+from pyramid.interfaces import IView
+from z3c.form import button
+from z3c.form.interfaces import IButtonWidget, IFormLayer as IBaseFormLayer, INPUT_MODE, \
+    ISelectWidget, ISubForm, ISubmitWidget, ITextAreaWidget, ITextWidget, IWidget
+from zope.interface import Attribute, Interface, implementer
+from zope.interface.interfaces import IObjectEvent, ObjectEvent
+from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
+from zope.lifecycleevent.interfaces import IObjectCreatedEvent, IObjectModifiedEvent
+from zope.schema import Bool, Choice, Dict, Int, List, Object, Text, TextLine
 
-# import standard library
-
-# import interfaces
+from pyams_form.schema import CloseButton, ResetButton
+from pyams_template.template import template_config
 from pyams_utils.interfaces import MANAGE_PERMISSION
 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, ITextAreaWidget, ISelectWidget, IButtonWidget
-from zope.interface.interfaces import IObjectEvent, ObjectEvent
-from zope.lifecycleevent.interfaces import IObjectCreatedEvent, IObjectModifiedEvent
+
 
-# import packages
-from pyams_form.schema import ResetButton, CloseButton
-from pyams_template.template import template_config
-from z3c.form import button
-from zope.interface import implementer, Interface, Attribute
-from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
-from zope.schema import Text, TextLine, List, Object, Bool, Int, Choice, Dict
+__docformat__ = 'restructuredtext'
 
 from pyams_form import _
 
@@ -582,6 +579,10 @@
     """HTML editor widget interface"""
 
 
+class IJSONDictWidget(IWidget):
+    """JSON dict widget interface"""
+
+
 class ISelect2Widget(ISelectWidget):
     """New select2 based widget"""
 
@@ -625,7 +626,7 @@
     """Form object created event"""
 
     def __init__(self, object, form):
-        self.object = object
+        super(FormObjectCreatedEvent, self).__init__(object)
         self.form = form
 
 
--- a/src/pyams_form/widget/__init__.py	Tue Sep 17 11:55:32 2019 +0200
+++ b/src/pyams_form/widget/__init__.py	Tue Sep 17 11:56:41 2019 +0200
@@ -24,26 +24,29 @@
 from z3c.form.browser.submit import SubmitWidget
 from z3c.form.browser.text import TextWidget
 from z3c.form.browser.textarea import TextAreaWidget
+from z3c.form.browser.widget import HTMLInputWidget
 from z3c.form.button import ButtonAction
-from z3c.form.converter import BaseDataConverter, DatetimeDataConverter as BaseDatetimeDataConverter, \
-    FormatterValidationError
-from z3c.form.interfaces import DISPLAY_MODE, IButtonAction, IDataConverter, IFieldWidget, INPUT_MODE, ITextAreaWidget, \
-    IWidgetLayoutTemplate, NO_VALUE
-from z3c.form.widget import FieldWidget, WidgetLayoutFactory, WidgetTemplateFactory
+from z3c.form.converter import BaseDataConverter, \
+    DatetimeDataConverter as BaseDatetimeDataConverter, FormatterValidationError
+from z3c.form.interfaces import DISPLAY_MODE, IButtonAction, IDataConverter, IFieldWidget, \
+    INPUT_MODE, ITextAreaWidget, IWidgetLayoutTemplate, NO_VALUE
+from z3c.form.widget import FieldWidget, Widget, WidgetLayoutFactory, WidgetTemplateFactory
 from zope.component import getGlobalSiteManager
 from zope.interface import Interface, directlyProvides, implementer, implementer_only
 from zope.pagetemplate.interfaces import IPageTemplate
 from zope.schema.fieldproperty import FieldProperty
-from zope.schema.interfaces import IBytes, IChoice, IDate, IDatetime, IFloat, IInt, IList, ISet, ITime, ITuple
+from zope.schema.interfaces import IBytes, IChoice, IDate, IDatetime, IFloat, IInt, IList, ISet, \
+    ITime, ITuple
 
-from pyams_form.interfaces.form import IActionWidget, ICloseWidget, IColorWidget, IDateWidget, IDatetimeWidget, \
-    IFloatWidget, IFormLayer, IHTMLWidget, IIntegerWidget, IResetWidget, ISEOTextLineWidget, ISelect2Widget, \
-    ITextLineListWidget, ITimeWidget
+from pyams_form.interfaces.form import IActionWidget, ICloseWidget, IColorWidget, IDateWidget, \
+    IDatetimeWidget, IFloatWidget, IFormLayer, IHTMLWidget, IIntegerWidget, IJSONDictWidget, \
+    IResetWidget, ISEOTextLineWidget, ISelect2Widget, ITextLineListWidget, ITimeWidget
 from pyams_form.schema import IActionButton, ICloseButton, IResetButton
 from pyams_skin.interfaces.tinymce import ITinyMCEConfiguration
 from pyams_utils.adapter import adapter_config
 from pyams_utils.interfaces.data import IObjectData
-from pyams_utils.schema import IColorField, IHTMLField, ITextLineListField
+from pyams_utils.schema import IColorField, IHTMLField, IJSONDictField, ITextLineListField, \
+    IJSONDictFieldsGetter
 from pyams_utils.timezone import localgmtime, tztime
 
 
@@ -110,7 +113,7 @@
     This function can be used to override a widget template without using ZCML.
     Settings are the same as for @widgettemplate_config decorator.
     """
-    stack = inspect.stack()[-1]
+    stack = inspect.stack()[1]
     template = os.path.join(os.path.dirname(inspect.getfile(inspect.getmodule(stack[0]))),
                             settings.get('template'))
     if not os.path.isfile(template):
@@ -184,7 +187,7 @@
     This function can be used to override a widget layout template without using ZCML.
     Settings are the same as for @widgetlayout_config decorator.
     """
-    stack = inspect.stack()[-1]
+    stack = inspect.stack()[1]
     template = os.path.join(os.path.dirname(inspect.getfile(inspect.getmodule(stack[0]))),
                             settings.get('template'))
     if not os.path.isfile(template):
@@ -548,6 +551,42 @@
 
 
 #
+# JSON dict widget
+#
+
+@adapter_config(context=(IJSONDictField, IJSONDictWidget), provides=IDataConverter)
+class JSONDictDataConverter(BaseDataConverter):
+    """JSON dict data converter"""
+
+    def toWidgetValue(self, value):
+        return value
+
+    def toFieldValue(self, value):
+        return json.loads(value)
+
+
+@widgettemplate_config(mode='display', template='templates/json-dict-display.pt', layer=IFormLayer)
+@implementer_only(IJSONDictWidget)
+class JSONDictWidget(HTMLInputWidget, Widget):
+    """JSON dict field widget"""
+
+    def get_fields(self):
+        form = self.__parent__.form
+        getter = self.request.registry.queryMultiAdapter((form.getContent(), self.request, form),
+                                                         IJSONDictFieldsGetter)
+        if getter is not None:
+            yield from getter.get_fields(self.value)
+        else:
+            yield from map(lambda item: (item[0], item[0], item[1]), self.value.items())
+
+
+@adapter_config(context=(IJSONDictField, IFormLayer), provides=IFieldWidget)
+def JSONDictFieldWidget(field, request):
+    """JSON dict field widget factory"""
+    return FieldWidget(field, JSONDictWidget(request))
+
+
+#
 # Select2 widget
 #
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_form/widget/templates/json-dict-display.pt	Tue Sep 17 11:56:41 2019 +0200
@@ -0,0 +1,6 @@
+<div class="padding-5">
+	<div tal:repeat="(key,label,value) python:view.get_fields()">
+		<strong>${label} (${key})</strong>
+		<div class="padding-left-5">${value}</div>
+	</div>
+</div>
\ No newline at end of file