Added Select2 and TextLineList widgets
authorThierry Florac <thierry.florac@onf.fr>
Thu, 08 Oct 2015 09:14:52 +0200
changeset 26 a55e6f2b27ba
parent 25 c4ca1e3e6085
child 27 5c2f8344b85d
Added Select2 and TextLineList widgets
src/pyams_form/interfaces/form.py
src/pyams_form/widget/__init__.py
src/pyams_form/widget/configure.zcml
src/pyams_form/widget/templates/orderedselect-input.pt
src/pyams_form/widget/templates/select-input.pt
src/pyams_form/widget/templates/textlinelist-display.pt
src/pyams_form/widget/templates/textlinelist-input.pt
--- a/src/pyams_form/interfaces/form.py	Tue Sep 08 17:14:58 2015 +0200
+++ b/src/pyams_form/interfaces/form.py	Thu Oct 08 09:14:52 2015 +0200
@@ -15,10 +15,11 @@
 # import standard library
 
 # import interfaces
+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
+    ITextWidget, ITextAreaWidget, ISelectWidget
 from zope.interface.interfaces import IObjectEvent, ObjectEvent
 from zope.lifecycleevent.interfaces import IObjectCreatedEvent, IObjectModifiedEvent
 
@@ -28,7 +29,7 @@
 from z3c.form import button
 from zope.interface import implementer, Interface, Attribute
 from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
-from zope.schema import TextLine, List, Object, Bool, Choice, Dict
+from zope.schema import Text, TextLine, List, Object, Bool, Int, Choice, Dict
 
 from pyams_form import _
 
@@ -71,7 +72,7 @@
 
     edit_permission = TextLine(title="Required edit permission",
                                required=False,
-                               default='manage')
+                               default=MANAGE_PERMISSION)
 
     def get_skin(self):
         """Get skin associated with this form"""
@@ -301,6 +302,8 @@
 
     tab_label = TextLine(title="Tab label")
 
+    tab_target = Attribute("View name of tab content target")
+
 
 class IViewletSubForm(ISubForm):
     """Inner viewlet form interface"""
@@ -344,10 +347,37 @@
 # Form viewlets
 #
 
+class IFormHelp(Interface):
+    """Form help interface"""
+
+    permission = TextLine(title='Required permission',
+                          required=False)
+
+    mode = TextLine(title='Required mode',
+                    required=False)
+
+    outer_margin = Int(title='Outer margin size',
+                       default=0)
+
+    status = TextLine(title='Help status',
+                      default='info')
+
+    header = TextLine(title='Help header')
+
+    message = Text(title='Help message')
+
+    message_format = Choice(title='Help message format',
+                            vocabulary='PyAMS HTML renderers')
+
+
 class IFormViewletsManager(IViewletManager):
     """Base forms viewlets manager interface"""
 
 
+class IFormHeaderViewletsManager(IFormViewletsManager):
+    """Form header viewlets manager interface"""
+
+
 class IFormPrefixViewletsManager(IFormViewletsManager):
     """Form prefix viewlets manager interface"""
 
@@ -393,7 +423,7 @@
 class IModalAddFormButtons(Interface):
     """Modal add form buttons"""
 
-    close = CloseButton(name='close', title=_("Close"))
+    close = CloseButton(name='close', title=_("Cancel"))
     add = button.Button(name='add', title=_("Add"), condition=check_submit_button)
 
 
@@ -407,7 +437,7 @@
 class IModalEditFormButtons(Interface):
     """Modal edit form buttons"""
 
-    close = CloseButton(name='close', title=_("Close"))
+    close = CloseButton(name='close', title=_("Cancel"))
     submit = button.Button(name='submit', title=_("Submit"), condition=check_submit_button)
 
 
@@ -449,6 +479,14 @@
     """HTML editor widget interface"""
 
 
+class ISelect2Widget(ISelectWidget):
+    """New select2 based widget"""
+
+
+class ITextLineListWidget(ITextWidget):
+    """Text line list widget"""
+
+
 #
 # Form events
 #
--- a/src/pyams_form/widget/__init__.py	Tue Sep 08 17:14:58 2015 +0200
+++ b/src/pyams_form/widget/__init__.py	Thu Oct 08 09:14:52 2015 +0200
@@ -21,27 +21,31 @@
 
 # import interfaces
 from pyams_form.interfaces.form import IFormLayer, IResetWidget, ICloseWidget, IDateWidget, IDatetimeWidget, ITimeWidget, \
-    IColorWidget, IHTMLWidget
+    IColorWidget, IHTMLWidget, ISelect2Widget, ITextLineListWidget
 from pyams_form.schema import IResetButton, ICloseButton
 from pyams_skin.interfaces.tinymce import ITinyMCEConfiguration
-from pyams_utils.schema import IColorField, IHTMLField
+from pyams_utils.schema import IColorField, IHTMLField, ITextLineListField
 from pyramid.interfaces import IRequest
 from z3c.form.interfaces import INPUT_MODE, IFieldWidget, IButtonAction, IWidgetLayoutTemplate, IDataConverter
 from zope.pagetemplate.interfaces import IPageTemplate
-from zope.schema.interfaces import IDate, IDatetime, ITime
+from zope.schema.interfaces import IDate, IDatetime, ITime, IChoice
 
 # import packages
 from pyams_utils.adapter import adapter_config
+from pyams_utils.timezone import tztime, gmtime, localgmtime
 from pyramid.exceptions import ConfigurationError
 from z3c.form.action import Action
+from z3c.form.browser.select import SelectWidget
 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.converter import BaseDataConverter, DatetimeDataConverter as BaseDatetimeDataConverter
 from z3c.form.widget import FieldWidget, WidgetTemplateFactory, WidgetLayoutFactory
 from zope.interface import implementer_only, directlyProvides, Interface
 
+from pyams_form import _
+
 
 #
 # Widget template configuration
@@ -224,6 +228,19 @@
 # Datetime widget
 #
 
+@adapter_config(context=(IDatetime, IDatetimeWidget), provides=IDataConverter)
+class DatetimeDataConverter(BaseDatetimeDataConverter):
+    """Datetime field data converter"""
+
+    def toWidgetValue(self, value):
+        value = tztime(value)
+        return super(DatetimeDataConverter, self).toWidgetValue(value)
+
+    def toFieldValue(self, value):
+        value = super(DatetimeDataConverter, self).toFieldValue(value)
+        return localgmtime(value)
+
+
 @widgettemplate_config(mode='input', template='templates/datetime-input.pt', layer=IFormLayer)
 @implementer_only(IDatetimeWidget)
 class DatetimeWidget(TextWidget):
@@ -310,3 +327,54 @@
 def HTMLFieldWidget(field, request):
     return FieldWidget(field, HTMLWidget(request))
 
+
+#
+# Select2 widget
+#
+
+@widgettemplate_config(mode='input', template='templates/select-input.pt', layer=IFormLayer)
+@implementer_only(ISelect2Widget)
+class Select2Widget(SelectWidget):
+    """Select2 widget"""
+
+    noValueMessage = _("(no selected value)")
+
+    def get_content(self, entry):
+        translate = self.request.localizer.translate
+        return translate(entry['content'])
+
+
+@adapter_config(context=(IChoice, IFormLayer), provides=IFieldWidget)
+def ChoiceFieldWidget(field, request):
+    return FieldWidget(field, Select2Widget(request))
+
+
+#
+# TextLineList widget
+#
+
+@adapter_config(context=(ITextLineListField, ITextLineListWidget), provides=IDataConverter)
+class TextLineListFieldDataConverter(BaseDataConverter):
+    """Text line list field data converter"""
+
+    def toWidgetValue(self, value):
+        return '|'.join(value or [])
+
+    def toFieldValue(self, value):
+        return value.split('|') if value else None
+
+
+@widgettemplate_config(mode='input', template='templates/textlinelist-input.pt', layer=IFormLayer)
+@widgettemplate_config(mode='display', template='templates/textlinelist-display.pt', layer=IFormLayer)
+@implementer_only(ITextLineListWidget)
+class TextLineListWidget(TextWidget):
+    """Text line list widget"""
+
+    @property
+    def tags(self):
+        return json.dumps((self.value or '').split('|'))
+
+
+@adapter_config(context=(ITextLineListField, IFormLayer), provides=IFieldWidget)
+def TextLineListFieldWidget(field, request):
+    return FieldWidget(field, TextLineListWidget(request))
--- a/src/pyams_form/widget/configure.zcml	Tue Sep 08 17:14:58 2015 +0200
+++ b/src/pyams_form/widget/configure.zcml	Thu Oct 08 09:14:52 2015 +0200
@@ -68,14 +68,14 @@
 
 	<z3c:widgetTemplate
 		mode="input"
+		template="templates/select-input.pt"
 		widget="z3c.form.interfaces.ISelectWidget"
-		layer="pyams_form.interfaces.form.IFormLayer"
-		template="templates/select-input.pt" />
+		layer="pyams_form.interfaces.form.IFormLayer" />
 
 	<z3c:widgetTemplate
 		mode="input"
+		template="templates/orderedselect-input.pt"
 		widget="z3c.form.interfaces.IOrderedSelectWidget"
-		layer="pyams_form.interfaces.form.IFormLayer"
-		template="templates/orderedselect-input.pt" />
+		layer="pyams_form.interfaces.form.IFormLayer" />
 
 </configure>
--- a/src/pyams_form/widget/templates/orderedselect-input.pt	Tue Sep 08 17:14:58 2015 +0200
+++ b/src/pyams_form/widget/templates/orderedselect-input.pt	Thu Oct 08 09:14:52 2015 +0200
@@ -3,6 +3,7 @@
 	<i class="icon-append fa fa-trash-o hint opaque"
 		title="Clear selected values" i18n:attributes="title"
 		tal:omit-tag="view/required"
+		data-ams-hint-gravity="se"
 		data-ams-click-handler="MyAMS.helpers.select2ClearSelection"
 		tal:attributes="data-ams-select2-target string:${view/name}:list"></i>
 	<div class="select2-parent"
--- a/src/pyams_form/widget/templates/select-input.pt	Tue Sep 08 17:14:58 2015 +0200
+++ b/src/pyams_form/widget/templates/select-input.pt	Thu Oct 08 09:14:52 2015 +0200
@@ -25,5 +25,5 @@
 	<option tal:repeat="entry view/items"
 			tal:attributes="value entry/value;
 						    selected python:entry['value'] in view.value;"
-			tal:content="entry/content"></option>
+			tal:content="python:view.get_content(entry) if hasattr(view, 'get_content') else entry['content']"></option>
 </select>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_form/widget/templates/textlinelist-display.pt	Thu Oct 08 09:14:52 2015 +0200
@@ -0,0 +1,34 @@
+<input type="hidden" readonly="readonly"
+	   class="select2"
+	   multiple="multiple"
+	   tal:attributes="id view/id;
+						name string:${view/name};
+						class string:${view/klass} select2;
+						style view/style;
+						title view/title;
+						value view/value;
+						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;
+						size view/size;
+						data-ams-select2-tags view/tags;"
+	   data-ams-select2-multiple="true"
+	   data-ams-select2-minimum-input-length="3"
+	   data-ams-select2-enable-free-tags="true"
+	   data-ams-select2-separator="|"
+	   data-ams-select2-tokens-separators="|"
+	   data-ams-select2-values='{}'>
+</input>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_form/widget/templates/textlinelist-input.pt	Thu Oct 08 09:14:52 2015 +0200
@@ -0,0 +1,37 @@
+<input type="hidden"
+	   class="select2"
+	   multiple="multiple"
+	   tal:attributes="id view/id;
+						name string:${view/name};
+						class string:${view/klass} select2;
+						style view/style;
+						title view/title;
+						value view/value;
+						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;
+						size view/size;
+						data-ams-select2-tags view/tags;"
+	   data-ams-select2-multiple="true"
+	   data-ams-select2-minimum-input-length="3"
+	   data-ams-select2-enable-free-tags="true"
+	   data-ams-select2-free-tags-prefix="New keyword: "
+	   data-ams-select2-separator="|"
+	   data-ams-select2-tokens-separators="|"
+	   data-ams-select2-values='{}'
+	   i18n:domain="pyams_form"
+	   i18n:attributes="data-ams-select2-free-tags-prefix">
+</input>