[Checkins] SVN: z3c.formjs/trunk/src/z3c/formjs/ Now you can click on the label to switch the widget into input mode.

Stephan Richter srichter at cosmos.phy.tufts.edu
Thu Aug 23 21:52:26 EDT 2007


Log message for revision 79201:
  Now you can click on the label to switch the widget into input mode. 
  This is helpful for optional fields that have an empty value.
  

Changed:
  U   z3c.formjs/trunk/src/z3c/formjs/interfaces.py
  U   z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.py
  U   z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.txt
  U   z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.zcml
  U   z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt
  U   z3c.formjs/trunk/src/z3c/formjs/jsswitch.py
  U   z3c.formjs/trunk/src/z3c/formjs/jsswitch.txt
  U   z3c.formjs/trunk/src/z3c/formjs/testing.py

-=-
Modified: z3c.formjs/trunk/src/z3c/formjs/interfaces.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/interfaces.py	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/interfaces.py	2007-08-24 01:52:26 UTC (rev 79201)
@@ -299,6 +299,23 @@
     def render():
         """Render the switcher into JavaScript."""
 
+class ILabelWidgetSwitcher(zope.interface.Interface):
+    """Switches the widget to an input widget when clicking on the label."""
+
+    form = zope.schema.Field(
+        title=u"Form",
+        description=u"The form.",
+        required=True)
+
+    mode = zope.schema.TextLine(
+        title=u"Mode",
+        description=u"The mode to which to switch to.",
+        required=True)
+
+    def render():
+        """Render the switcher into JavaScript."""
+
+
 class IWidgetSaver(zope.interface.Interface):
     """Saves a widget's value to the server."""
 

Modified: z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.py	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.py	2007-08-24 01:52:26 UTC (rev 79201)
@@ -40,6 +40,21 @@
         return u'#' + self.selector.id
 
 
+class JQueryCSSSelectorRenderer(object):
+    zope.interface.implements(interfaces.IRenderer)
+    zope.component.adapts(
+        interfaces.ICSSSelector, IJQueryJavaScriptBrowserLayer)
+
+    def __init__(self, selector, request):
+        self.selector = selector
+
+    def update(self):
+        pass
+
+    def render(self):
+        return self.selector.expr
+
+
 class JQuerySubscriptionRenderer(object):
     zope.interface.implements(interfaces.IRenderer)
     zope.component.adapts(
@@ -159,6 +174,36 @@
         return '$.get(%s,\nfunction(html){%s}\n)' % (ajaxURL, switcherCall)
 
 
+class JQueryLabelWidgetSwitcherRenderer(object):
+    zope.component.adapts(
+        interfaces.ILabelWidgetSwitcher, IJQueryJavaScriptBrowserLayer)
+    zope.interface.implements(interfaces.IRenderer)
+
+    function = 'switchWidget'
+    widgetIdExpr = 'event.target.parentNode.attributes["for"].value'
+
+    def __init__(self, switcher, request):
+        self.context = switcher
+        self.request = request
+
+    def _ajaxURL(self):
+        # build a js expression that joins valueString expression
+        queryString = '?widget-id=' + self.widgetIdExpr
+        mode = self.context.mode.title()
+        # build a js expression
+        return '"%s/@@ajax/get%sWidget?widget-id=" + %s' % (
+            self.request.getURL(), mode, self.widgetIdExpr)
+
+    def update(self):
+        pass
+
+    def render(self):
+        ajaxURL = self._ajaxURL()
+        switcherCall = '%s(%s, "%s", html)' % (
+            self.function, self.widgetIdExpr, self.context.mode)
+        return '$.get(%s,\nfunction(html){%s}\n)' % (ajaxURL, switcherCall)
+
+
 class JQueryWidgetSaverRenderer(object):
     zope.component.adapts(
         interfaces.IWidgetSaver, IJQueryJavaScriptBrowserLayer)

Modified: z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.txt
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.txt	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.txt	2007-08-24 01:52:26 UTC (rev 79201)
@@ -38,6 +38,35 @@
   #form-id
 
 
+``CSSSelector`` Renderer
+------------------------
+
+Since JQuery uses CSS selectors, we can simply pass through the CSS expression:
+
+  >>> from z3c.formjs import jsevent
+  >>> cssSelector = jsevent.CSSSelector('label')
+
+  >>> from z3c.form.testing import TestRequest
+  >>> request = TestRequest()
+
+  >>> from jquery.layer import IJQueryJavaScriptBrowserLayer
+  >>> import zope.interface
+  >>> zope.interface.alsoProvides(request, IJQueryJavaScriptBrowserLayer)
+
+Let's now register the renderer:
+
+  >>> import zope.component
+  >>> zope.component.provideAdapter(jqueryrenderer.JQueryCSSSelectorRenderer)
+
+Like any view component, the renderer must be updated before being rendered:
+
+  >>> renderer = zope.component.getMultiAdapter(
+  ...     (cssSelector, request), interfaces.IRenderer)
+  >>> renderer.update()
+  >>> print renderer.render()
+  label
+
+
 ``JSSubscription`` Renderer
 ---------------------------
 
@@ -175,6 +204,36 @@
     function(html){switchWidget("form-zip", "display", html)}
   )
 
+
+``ILabelWidgetSwitcher`` Renderer
+---------------------------------
+
+This renderer defines how JavaScript switches the widget to input mode when
+clicking on the label.
+
+So let's create a label widget switcher instance:
+
+  >>> from z3c.formjs import jsswitch
+  >>> switcher = jsswitch.LabelWidgetSwitcher(request, 'input')
+
+Let's now register the renderer:
+
+  >>> zope.component.provideAdapter(
+  ...     jqueryrenderer.JQueryLabelWidgetSwitcherRenderer)
+
+Now we can render the script:
+
+  >>> renderer = zope.component.getMultiAdapter(
+  ...     (switcher, request), interfaces.IRenderer)
+  >>> renderer.update()
+  >>> print renderer.render()
+  $.get("http://127.0.0.1/@@ajax/getInputWidget?widget-id=" +
+    event.target.parentNode.attributes["for"].value,
+    function(html){switchWidget(event.target.parentNode.attributes["for"].value,
+    "input", html)}
+  )
+
+
 ``IWidgetSaver`` Renderer
 -------------------------
 

Modified: z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.zcml
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.zcml	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jqueryrenderer.zcml	2007-08-24 01:52:26 UTC (rev 79201)
@@ -6,6 +6,9 @@
       factory=".jqueryrenderer.JQueryIdSelectorRenderer"
       />
   <adapter
+      factory=".jqueryrenderer.JQueryCSSSelectorRenderer"
+      />
+  <adapter
       factory=".jqueryrenderer.JQuerySubscriptionRenderer"
       />
   <adapter
@@ -18,6 +21,9 @@
       factory=".jqueryrenderer.JQueryWidgetSwitcherRenderer"
       />
   <adapter
+      factory=".jqueryrenderer.JQueryLabelWidgetSwitcherRenderer"
+      />
+  <adapter
       factory=".jqueryrenderer.JQueryWidgetSaverRenderer"
       />
 

Modified: z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt	2007-08-24 01:52:26 UTC (rev 79201)
@@ -127,6 +127,9 @@
   >>> request = TestRequest(form={'form.widgets.title':u'New Title',
   ...                             'form.buttons.apply':u'Apply'})
 
+  >>> from zope.security import management
+  >>> management.endInteraction()
+
   >>> form = ArticleEditForm(article, request)
   >>> form.update()
 
@@ -137,9 +140,6 @@
   >>> request = TestRequest(form={'form.widgets.title':u'New Title 2',
   ...                             'form.buttons.apply':u'Apply'})
 
-  >>> from zope.security import management
-  >>> from zope.security.testing import Participation
-  >>> management.endInteraction()
   >>> management.newInteraction(request)
 
   >>> form = ArticleEditForm(article, request)

Modified: z3c.formjs/trunk/src/z3c/formjs/jsswitch.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsswitch.py	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jsswitch.py	2007-08-24 01:52:26 UTC (rev 79201)
@@ -39,7 +39,19 @@
             (self, self.form.request), interfaces.IRenderer)
         return renderer.render()
 
+class LabelWidgetSwitcher(object):
+    zope.interface.implements(interfaces.ILabelWidgetSwitcher)
 
+    def __init__(self, request, mode):
+        self.request = request
+        self.mode = mode
+
+    def render(self):
+        renderer = zope.component.getMultiAdapter(
+            (self, self.request), interfaces.IRenderer)
+        return renderer.render()
+
+
 class WidgetSaver(object):
     zope.interface.implements(interfaces.IWidgetSaver)
 
@@ -58,7 +70,8 @@
 
 class WidgetModeSwitcher(ajax.AJAXRequestHandler):
     """A mix-in to forms to allow switching between widget modes."""
-    zope.interface.implements(interfaces.IWidgetModeSwitcher)
+    zope.interface.implements(interfaces.IWidgetModeSwitcher,
+                              interfaces.IHaveJSSubscriptions)
     buttons = button.Buttons()
     mode = DISPLAY_MODE
 
@@ -70,11 +83,33 @@
     def saveWidgetValue(self, event, selector):
         return WidgetSaver(self, selector.widget).render()
 
+    @jsevent.subscribe(jsevent.CSSSelector('label'), jsevent.CLICK)
+    def labelClickSwitchesToInputWidget(event, selector, request):
+        return LabelWidgetSwitcher(request, 'input').render()
+
     def _getWidget(self, mode):
-        # Step 1: Determine the name of the widget.
-        shortName = self.request.form['widget-name']
-        # Step 2: Limit the form fields only to this one widget.
-        self.fields = self.fields.select(shortName)
+        """Get the widget in the given mode."""
+        # There are two possibilities to extract the wdget, either by widget
+        # short name or by widget id. The latter is significantly more
+        # inefficient, but needed.
+        if 'widget-id' in self.request.form:
+            # Step 1: Determine the full name of the widget
+            name = self.request.form['widget-id'].replace('-', '.')
+            # Step 2: Limit the form fields only to this one widget.
+            # Note: This algorithm might not be fully reliable, but should
+            #       work for now.
+            for shortName in self.fields:
+                if name.endswith(shortName):
+                    break
+        else:
+            # Step 1: Determine the name of the widget.
+            shortName = self.request.form['widget-name']
+            # Step 2: Limit the form fields only to this one widget.
+            self.fields = self.fields.select(shortName)
+            # Step 3: Instantiate the widget manager, set the correct mode and
+            #         update it.
+            self.widgets = zope.component.getMultiAdapter(
+                (self, self.request, self.getContent()), IWidgets)
         # Step 3: Instantiate the widget manager, set the correct mode and
         #         update it.
         self.widgets = zope.component.getMultiAdapter(

Modified: z3c.formjs/trunk/src/z3c/formjs/jsswitch.txt
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsswitch.txt	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/jsswitch.txt	2007-08-24 01:52:26 UTC (rev 79201)
@@ -136,6 +136,10 @@
           $("#form-widgets-age").bind("click", function(){$.get('/switchWidget',
             function(html){switchWidget("form-widgets-age", html)}
           )});
+          $("label").bind("click",
+            function(){$.get('/switchWidget',
+              function(html){switchWidget(event.target...value, html)}
+    )});
         })
       </script>
     </head>
@@ -227,3 +231,18 @@
           function(html){switchWidget(&quot;form-widgets-age&quot;, html)} )">
     25
   </span>
+
+Alternatively to selecting the widget by name, you can also specify the widget
+id:
+
+  >>> showPerson = ShowPerson(stephan, TestRequest(form={
+  ...     'widget-id': 'form-widgets-age',
+  ...     }))
+  >>> showPerson.update()
+  >>> print showPerson.getInputWidget(showPerson)
+  <input type="text" id="form-widgets-age"
+         name="form.widgets.age"
+         class="text-widget required int-field"
+         onblur="$.get('saveValue',
+                 function(msg){saveWidget(&quot;form-widgets-age&quot;, msg)} )"
+         value="25" />

Modified: z3c.formjs/trunk/src/z3c/formjs/testing.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/testing.py	2007-08-24 00:58:00 UTC (rev 79200)
+++ z3c.formjs/trunk/src/z3c/formjs/testing.py	2007-08-24 01:52:26 UTC (rev 79201)
@@ -125,6 +125,25 @@
         return "$.get('/switchWidget', function(html){%s}\n)" % switcherCall
 
 
+class LabelWidgetSwitcherRenderer(object):
+    zope.component.adapts(
+        interfaces.ILabelWidgetSwitcher, IBrowserRequest)
+    zope.interface.implements(interfaces.IRenderer)
+
+    widgetIdExpr = 'event.target.parentNode.attributes["for"].value'
+
+    def __init__(self, switcher, request):
+        self.context = switcher
+        self.request = request
+
+    def update(self):
+        pass
+
+    def render(self):
+        switcherCall = 'switchWidget(%s, html)' % (self.widgetIdExpr)
+        return "$.get('/switchWidget', function(html){%s}\n)" % switcherCall
+
+
 class WidgetSaverRenderer(object):
     zope.component.adapts(
         interfaces.IWidgetSaver, IBrowserRequest)
@@ -145,10 +164,12 @@
 
 def setupRenderers():
     zope.component.provideAdapter(IdSelectorRenderer)
+    zope.component.provideAdapter(CSSSelectorRenderer)
     zope.component.provideAdapter(SubscriptionRenderer)
     zope.component.provideAdapter(ManagerRenderer)
     zope.component.provideAdapter(MessageValidationScriptRenderer)
     zope.component.provideAdapter(WidgetSwitcherRenderer)
+    zope.component.provideAdapter(LabelWidgetSwitcherRenderer)
     zope.component.provideAdapter(WidgetSaverRenderer)
 
 



More information about the Checkins mailing list