src/pyams_form/widget/__init__.py
changeset 186 ddd454de3d32
parent 179 f9147cd3fe5b
child 196 893cf2088818
--- 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
 #