[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("form-widgets-age", 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("form-widgets-age", 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