[Checkins] SVN: z3c.formjs/trunk/src/z3c/formjs/jsclientevent.
Improved doctest prose relating to client event handlers and
Paul Carduner
paulcarduner at gmail.com
Sat Aug 25 01:56:16 EDT 2007
Log message for revision 79246:
Improved doctest prose relating to client event handlers and
posed a few questions which still need to be answered.
I'm also wondering if we should be testing that relevant objects
really implement what they say they do.
Changed:
U z3c.formjs/trunk/src/z3c/formjs/jsclientevent.py
U z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt
-=-
Modified: z3c.formjs/trunk/src/z3c/formjs/jsclientevent.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsclientevent.py 2007-08-24 18:36:24 UTC (rev 79245)
+++ z3c.formjs/trunk/src/z3c/formjs/jsclientevent.py 2007-08-25 05:56:14 UTC (rev 79246)
@@ -32,6 +32,8 @@
class ClientEventHandlers(object):
"""Client Handlers for server side events."""
+ zope.interface.implements(interfaces.IClientEventHandlers)
+
def __init__(self):
self._registry = adapter.AdapterRegistry()
self._handlers = ()
Modified: z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt 2007-08-24 18:36:24 UTC (rev 79245)
+++ z3c.formjs/trunk/src/z3c/formjs/jsclientevent.txt 2007-08-25 05:56:14 UTC (rev 79246)
@@ -1,57 +1,128 @@
========================================
-Mapping Events Between Server and Client
+Propogating Events from Server to Client
========================================
The ``jsclientevent`` module of this package provides an extremely minimal
event framework whereby events that occur on the server, such as
-``IObjectModifiedEvent`` events, propagate to a client's browser through
-injected JavaScript function calls. This is not to be confused with "action
+``IObjectModifiedEvent``s, propagate to a client's browser through
+injected JavaScript code. This is not to be confused with "action
events" that occur on the client such as "onClick".
>>> from z3c.formjs import jsclientevent
-There are several components to these types of interactions. First there are
-the *server events*, which, for example, are thrown on a state change. Next
-there is a *client listener*, which is just a javascript function that gets
-called when the event occurs, and finally there is the *event transport* which
-allows the server to call a function defined on the client side.
+There are several components that must work together to propagate the
+events to the client:
+ 1. Server Events - These are events that get notified by server side code such as
+ ``IObjectEvent`` and its many derivatives.
-Client Side Handler
---------------------
+ 2. Server Event Handlers - These are server side functions that get
+ called immediately when an event is notified in the order that the
+ functions were registered as handlers.
-The client side event handler is just a snippet of JavaScript that gets
-executed when the event occurs. The server injects this javascript onto the
-page via an ajax response.
+ 3. Client Event Handlers - these are snippets of javascript code which
+ get rendered for each occurance of an event and are inlined into the
+ DOM at some later time (when requested by an HTTP call, or placed
+ into a page template).
-Let's create a simple view class with an event listener for the
-``IObjectModifiedEvent`` event:
+The first two components are handled for us by Zope's
+notification/subscription event model. This module serves to connect
+the second and third components in such a way that events which occur
+during an interaction (a request and repsonse cycle) can be caught and
+stored in memory so that JavaScript handlers can be rendered for
+these events along with all other form elements.
+Client Event Handlers
+---------------------
+
+The client side event handler is just a snippet of JavaScript that
+gets evaluated when an appropriate event occurs. To be precise, JavaScript is
+evaluated when the client's web browser first sees it in the DOM,
+wrapped in the appropriate ``script`` tags. In fact, the client
+browser will also immediately evaluate JavaScript inserted into the
+DOM long after the DOM has been originally initialized -- such as when
+data is inserted into the DOM after an asynchronous HTTP request.
+
+Client event handlers are defined in much the same way that server
+event handlers are defined. That is, they are python function which
+adapt an event object and perform actions based on the event. In our
+use case, the action to be performed is the rendering of JavaScript.
+
+Let's create a simple view class with an event handler for the
+``IObjectModifiedEvent`` event.
+
+ >>> from zope.interface import Interface
>>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent
>>> class View(object):
...
- ... @jsclientevent.listener((IObjectModifiedEvent,))
+ ... @jsclientevent.listener((Interface, IObjectModifiedEvent,))
... def modifiedListener(self, event):
... return 'alert("object modified: %s");' % event.object
-The argument passed to the ``listener`` decorator is a list (or tuple) of the
-required interfaces for the event handler. This is just like the set of
-interfaces one would pass to the ``zope.component.provideHandler()`` function.
+The argument passed to the ``listener`` decorator is a list (or tuple)
+of the required interfaces for the event handler. These are, the
+interface implemented by the object given to the event's constructor,
+and the interface for the event itself. This is just like the set of
+interfaces one would pass to the ``zope.component.provideHandler``
+function.
+XXX: should we rename this decorator to simply ``handler``? Or maybe
+ ``subscribe``? ``listener`` seems out of place and inconsistent with
+ the other types of handlers we have defined.
+
The decorator also registers this client side event handler with a local
component registry that is accessed through the ``jsClientListeners``
-attribute, which is now available on the view class itself.
+attribute.
>>> View.jsClientListeners
<ClientEventHandlers
- [<ClientEventHandler for (<InterfaceClass ...IObjectModifiedEvent>,)>]>
+ [<ClientEventHandler for
+ (<InterfaceClass zope.interface.Interface>,
+ <InterfaceClass ...IObjectModifiedEvent>)>]>
-Client Event Handlers instances can be copied,
+The component registry used to store the client event handlers takes
+the form of a ``ClientEventHandlers`` instance, which provides the
+following methods:
+The ``getHandlers`` method takes an instance of an event and returns
+a list of all the handlers for that event and its associated object.
+
+ >>> from zope.lifecycleevent import ObjectModifiedEvent
+ >>> objectEvent = ObjectModifiedEvent("some context")
+ >>> View.jsClientListeners.getHandlers(objectEvent)
+ [<ClientEventHandler for
+ (<InterfaceClass zope.interface.Interface>,
+ <InterfaceClass ...IObjectModifiedEvent>)>]
+
+Of course, we do not get any handlers if there are none registered for
+the event in question.
+
+ >>> from zope.component.interfaces import ObjectEvent
+ >>> objectEvent2 = ObjectEvent("some context")
+ >>> View.jsClientListeners.getHandlers(objectEvent2)
+ []
+
+The ``addHandler`` method takes an event specification (a tuple of two
+interfaces representing the object type and the event type) and the
+handler function itself.
+
+ >>> def someHandler(event): return str(event)
+ >>> from zope.component.interfaces import IObjectEvent
+ >>> View.jsClientListeners.addHandler((Interface, IObjectEvent), someHandler)
+ >>> View.jsClientListeners.getHandlers(objectEvent2)
+ [<function someHandler at ...>]
+
+XXX: do we want to allow plain functions to be registerd as handlers?
+ Or only things that implement IClientEventHandler (which must be
+ a callable that takes two parameters, a form and an event).
+
+``ClientEventHandlers`` instances can be copied,
+
>>> copy = View.jsClientListeners.copy()
>>> copy
- <ClientEventHandlers
- [<ClientEventHandler for (<InterfaceClass ...IObjectModifiedEvent>,)>]>
+ <ClientEventHandlers [<ClientEventHandler for (<InterfaceClass ...Interface>,
+ <InterfaceClass ...IObjectModifiedEvent>)>,
+ <function someHandler at ...>]>
>>> copy is View.jsClientListeners
False
@@ -60,10 +131,14 @@
>>> View.jsClientListeners + copy
<ClientEventHandlers
- [<ClientEventHandler for (<InterfaceClass ...IObjectModifiedEvent>,)>,
- <ClientEventHandler for (<InterfaceClass ...IObjectModifiedEvent>,)>]>
+ [<ClientEventHandler for (<InterfaceClass ...Interface>,
+ <InterfaceClass ...IObjectModifiedEvent>)>,
+ <function someHandler at ...>,
+ <ClientEventHandler for (<InterfaceClass ...Interface>,
+ <InterfaceClass ...IObjectModifiedEvent>)>,
+ <function someHandler at ...>]>
-Other objects cannot be added to those handlers instances:
+Other objects cannot be added to these ``ClientEventHandlers`` instances:
>>> View.jsClientListeners + 1
Traceback (most recent call last):
More information about the Checkins
mailing list