Commit | Line | Data |
---|---|---|
6a1aa64f DV |
1 | .. title:: MochiKit.Signal - Simple universal event handling |
2 | .. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace | |
3 | :trim: | |
4 | ||
5 | Name | |
6 | ==== | |
7 | ||
8 | MochiKit.Signal - Simple universal event handling | |
9 | ||
10 | ||
11 | Synopsis | |
12 | ======== | |
13 | ||
14 | Signal for DOM events:: | |
15 | ||
16 | // DOM events are also signals. Connect freely! The functions will be | |
17 | // called with the custom event as a parameter. | |
18 | ||
19 | // calls myClicked.apply(getElement('myID'), [event]) | |
20 | connect('myID', 'onclick', myClicked); | |
21 | ||
22 | // calls wasClicked.apply(myObject, [event]) | |
23 | connect('myID', 'onclick', myObject, wasClicked); | |
24 | ||
25 | // calls myObject.wasClicked(event) | |
26 | connect('myID', 'onclick', myObject, 'wasClicked'); | |
27 | ||
28 | // the event is normalized, no more e = e || window.event! | |
29 | myObject.wasClicked = function(e) { | |
30 | var crossBrowserCoordinates = e.mouse().page; | |
31 | // e.mouse().page is a MochiKit.Style.Coordinates object | |
32 | } | |
33 | ||
34 | ||
35 | Signal for non-DOM events:: | |
36 | ||
37 | // otherObject.gotFlash() will be called when 'flash' signalled. | |
38 | connect(myObject, 'flash', otherObject, 'gotFlash'); | |
39 | ||
40 | // gotBang.apply(otherObject, [...]) will be called when 'bang' signalled. | |
41 | // You can access otherObject from within gotBang as 'this'. | |
42 | connect(myObject, 'bang', otherObject, gotBang); | |
43 | ||
44 | // myFunc.apply(myObject, [...]) will be called when 'flash' signalled. | |
45 | // You can access myObject from within myFunc as 'this'. | |
46 | var ident = connect(myObject, 'flash', myFunc); | |
47 | ||
48 | // You may disconnect with the return value from connect | |
49 | disconnect(ident); | |
50 | ||
51 | // Signal can take parameters. These will be passed along to the | |
52 | // connected functions. | |
53 | signal(myObject, 'flash'); | |
54 | signal(myObject, 'bang', 'BANG!'); | |
55 | ||
56 | ||
57 | Description | |
58 | =========== | |
59 | ||
60 | Event handling was never so easy! | |
61 | ||
62 | This module takes care of all the hard work |---| figuring out which | |
63 | event model to use, trying to retrieve the event object, and handling | |
64 | your own internal events, as well as cleanup when the page is unloaded | |
65 | to clean up IE's nasty memory leakage. | |
66 | ||
67 | This event system is largely based on Qt's signal/slot system. Read | |
68 | more on how that is handled and also how it is used in model/view | |
69 | programming at: http://doc.trolltech.com/ | |
70 | ||
71 | ||
72 | Dependencies | |
73 | ============ | |
74 | ||
75 | - :mochiref:`MochiKit.Base` | |
76 | - :mochiref:`MochiKit.DOM` | |
77 | ||
78 | ||
79 | Overview | |
80 | ======== | |
81 | ||
82 | Using Signal for DOM Events | |
83 | --------------------------- | |
84 | ||
85 | When using MochiKit.Signal, do not use the browser's native event | |
86 | API. That means, no ``onclick="blah"``, no | |
87 | ``elem.addEventListener(...)``, and certainly no | |
88 | ``elem.attachEvent(...)``. This also means that | |
89 | :mochiref:`MochiKit.DOM.addToCallStack` and | |
90 | :mochiref:`MochiKit.DOM.addLoadEvent` should not be used in | |
91 | combination with this module. | |
92 | ||
93 | Signals for DOM objects are named with the ``'on'`` prefix, e.g.: | |
94 | ``'onclick'``, ``'onkeyup'``, etc. | |
95 | ||
96 | When the signal fires, your slot will be called with one parameter, | |
97 | the custom event object. | |
98 | ||
99 | ||
100 | Custom Event Objects for DOM events | |
101 | ----------------------------------- | |
102 | ||
103 | Signals triggered by DOM events are called with a custom event object | |
104 | as a parameter. The custom event object presents a consistent view of | |
105 | the event across all supported platforms and browsers, and provides | |
106 | many conveniences not available even in a correct W3C implementation. | |
107 | ||
108 | See the `DOM Custom Event Object Reference`_ for a detailed API | |
109 | description of this object. | |
110 | ||
111 | If you find that you're accessing the native event for any reason, | |
112 | create a `new ticket`_ and we'll look into normalizing the behavior | |
113 | you're looking for. | |
114 | ||
115 | .. _`new ticket`: http://trac.mochikit.com/newticket | |
116 | .. _`Safari bug 6595`: http://bugs.webkit.org/show_bug.cgi?id=6595 | |
117 | .. _`Safari bug 7790`: http://bugs.webkit.org/show_bug.cgi?id=7790 | |
118 | .. _`Safari bug 8707`: http://bugs.webkit.org/show_bug.cgi?id=8707 | |
119 | .. _`stopPropagation()`: http://developer.mozilla.org/en/docs/DOM:event.stopPropagation | |
120 | .. _`preventDefault()`: http://developer.mozilla.org/en/docs/DOM:event.preventDefault | |
121 | ||
122 | ||
123 | Memory Usage | |
124 | ------------ | |
125 | ||
126 | Any object that has connected slots (via :mochiref:`connect()`) is | |
127 | referenced by the Signal mechanism until it is disconnected via | |
128 | :mochiref:`disconnect()` or :mochiref:`disconnectAll()`. | |
129 | ||
130 | Signal does not leak. It registers an ``'onunload'`` event that | |
131 | disconnects all objects on the page when the browser leaves the | |
132 | page. However, memory usage will grow during the page view for every | |
133 | connection made until it is disconnected. Even if the DOM object is | |
134 | removed from the document, it will still be referenced by Signal until | |
135 | it is explicitly disconnected. | |
136 | ||
137 | In order to conserve memory during the page view, | |
138 | :mochiref:`disconnectAll()` any DOM elements that are about to be | |
139 | removed from the document. | |
140 | ||
141 | ||
142 | Synthesized Events | |
143 | ------------------ | |
144 | ||
145 | Certain events supported by MochiKit are not generated natively by all | |
146 | browsers. MochiKit can synthesize these events even for non-supporting | |
147 | browsers, however, by watching for related events and triggering the | |
148 | appropriate signals at the right times. | |
149 | ||
150 | These events include: | |
151 | ||
152 | ``onmouseenter`` | |
153 | ||
154 | Similar to ``'onmouseover'``, but does not "bubble" up to parent | |
155 | nodes. Such bubbling is often a cause of confusion. On an | |
156 | ``'onmouseenter'`` event, you can be certain that the mouse has | |
157 | left the node attached to the event. | |
158 | ||
159 | *Availability:* | |
160 | Available in MochiKit 1.4+ | |
161 | ||
162 | ``onmouseleave`` | |
163 | ||
164 | Similar to ``'onmouseout'``, but does not "bubble" up to parent | |
165 | nodes. This is the analog to ``'onmouseenter'``. | |
166 | ||
167 | *Availability:* | |
168 | Available in MochiKit 1.4+ | |
169 | ||
170 | ||
171 | Using Signal for non-DOM objects | |
172 | -------------------------------- | |
173 | ||
174 | Signals are triggered with the :mochiref:`signal(src, 'signal', ...)` | |
175 | function. Additional parameters passed to this are passed onto the | |
176 | connected slots. Explicit signals are not required for DOM events. | |
177 | ||
178 | Slots that are connected to a signal are called in the following | |
179 | manner when that signal is signalled: | |
180 | ||
181 | - If the slot was a single function, then it is called with ``this`` | |
182 | set to the object originating the signal with whatever parameters | |
183 | it was signalled with. | |
184 | ||
185 | - If the slot was an object and a function, then it is called with | |
186 | ``this`` set to the object, and with whatever parameters it was | |
187 | signalled with. | |
188 | ||
189 | - If the slot was an object and a string, then ``object[string]`` is | |
190 | called with the parameters to the signal. | |
191 | ||
192 | ||
193 | API Reference | |
194 | ============= | |
195 | ||
196 | ||
197 | Signal API Reference | |
198 | -------------------- | |
199 | ||
200 | :mochidef:`connect(src, signal, dest[, func])`: | |
201 | ||
202 | Connects a signal to a slot, and return a unique identifier that | |
203 | can be used to disconnect that signal. | |
204 | ||
205 | ``src`` is the object that has the signal. You may pass in a | |
206 | string, in which case, it is interpreted as an id for an HTML | |
207 | element. | |
208 | ||
209 | ``signal`` is a string that represents a signal name. If 'src' is | |
210 | an HTML Element, ``window``, or the ``document``, then it can be | |
211 | one of the 'on-XYZ' events. You must include the 'on' prefix, and | |
212 | it must be all lower-case. | |
213 | ||
214 | ``dest`` and ``func`` describe the slot, or the action to take | |
215 | when the signal is triggered. | |
216 | ||
217 | - If ``dest`` is an object and ``func`` is a string, then | |
218 | ``dest[func].apply(dest, [...])`` will be called when the | |
219 | signal is signalled. | |
220 | ||
221 | - If ``dest`` is an object and ``func`` is a function, then | |
222 | ``func.apply(dest, [...])`` will be called when the signal | |
223 | is signalled. | |
224 | ||
225 | - If ``func`` is undefined and ``dest`` is a function, then | |
226 | ``dest.apply(src, [...])`` will be called when the signal is | |
227 | signalled. | |
228 | ||
229 | No other combinations are allowed and will raise an exception. | |
230 | ||
231 | The return value can be passed to :mochiref:`disconnect` to | |
232 | disconnect the signal. | |
233 | ||
234 | In MochiKit 1.4+, if ``src`` is an object that has a ``__connect__`` | |
235 | method, then ``src.__connect__(ident, signal, objOrFunc, funcOrStr)`` | |
236 | will be called. This method may be used to disconnect the signal. | |
237 | DOM objects can not implement this feature. | |
238 | ||
239 | *Availability*: | |
240 | Available in MochiKit 1.3.1+ | |
241 | ||
242 | ||
243 | :mochidef:`disconnect(ident)`: | |
244 | ||
245 | To disconnect a signal, pass its ident returned by | |
246 | :mochiref:`connect()`. This is similar to how the browser's | |
247 | ``setTimeout`` and ``clearTimeout`` works. | |
248 | ||
249 | *Availability*: | |
250 | Available in MochiKit 1.3.1+ | |
251 | ||
252 | ||
253 | :mochidef:`disconnectAll(src[, signal, ...])`: | |
254 | ||
255 | ``disconnectAll(src)`` removes all signals from src. | |
256 | ||
257 | ``disconnectAll(src, 'onmousedown', 'mySignal')`` will remove all | |
258 | ``'onmousedown'`` and ``'mySignal'`` signals from src. | |
259 | ||
260 | *Availability*: | |
261 | Available in MochiKit 1.3.1+ | |
262 | ||
263 | ||
264 | :mochidef:`disconnectAllTo(dest[, func])`: | |
265 | ||
266 | ``disconnectAllTo(dest)`` removes all signals connected to dest. | |
267 | ||
268 | ``disconnectAllTo(dest, func)`` will remove all | |
269 | signals connected to dest using func. | |
270 | ||
271 | *Availability*: | |
272 | Available in MochiKit 1.4+ | |
273 | ||
274 | ||
275 | :mochidef:`signal(src, signal, ...)`: | |
276 | ||
277 | This will signal a signal, passing whatever additional parameters | |
278 | on to the connected slots. ``src`` and ``signal`` are the same as | |
279 | for :mochiref:`connect()`. | |
280 | ||
281 | *Availability*: | |
282 | Available in MochiKit 1.3.1+ | |
283 | ||
284 | ||
285 | DOM Custom Event Object Reference | |
286 | --------------------------------- | |
287 | ||
288 | :mochidef:`event()`: | |
289 | ||
290 | The native event produced by the browser. You should not need to | |
291 | use this. | |
292 | ||
293 | *Availability*: | |
294 | Available in MochiKit 1.3.1+ | |
295 | ||
296 | ||
297 | :mochidef:`src()`: | |
298 | ||
299 | The element that this signal is connected to. | |
300 | ||
301 | *Availability*: | |
302 | Available in MochiKit 1.3.1+ | |
303 | ||
304 | ||
305 | :mochidef:`type()`: | |
306 | ||
307 | The event type (``'click'``, ``'mouseover'``, ``'keypress'``, | |
308 | etc.) as a string. Does not include the ``'on'`` prefix. | |
309 | ||
310 | *Availability*: | |
311 | Available in MochiKit 1.3.1+ | |
312 | ||
313 | ||
314 | :mochidef:`target()`: | |
315 | ||
316 | The element that triggered the event. This may be a child of | |
317 | :mochiref:`src()`. | |
318 | ||
319 | *Availability*: | |
320 | Available in MochiKit 1.3.1+ | |
321 | ||
322 | ||
323 | :mochidef:`modifier()`: | |
324 | ||
325 | Returns ``{shift, ctrl, meta, alt, any}``, where each property is | |
326 | ``true`` if its respective modifier key was pressed, ``false`` | |
327 | otherwise. ``any`` is ``true`` if any modifier is pressed, | |
328 | ``false`` otherwise. | |
329 | ||
330 | *Availability*: | |
331 | Available in MochiKit 1.3.1+ | |
332 | ||
333 | ||
334 | :mochidef:`stopPropagation()`: | |
335 | ||
336 | Works like W3C's `stopPropagation()`_. | |
337 | ||
338 | *Availability*: | |
339 | Available in MochiKit 1.3.1+ | |
340 | ||
341 | ||
342 | :mochidef:`preventDefault()`: | |
343 | ||
344 | Works like W3C's `preventDefault()`_. | |
345 | ||
346 | *Availability*: | |
347 | Available in MochiKit 1.3.1+ | |
348 | ||
349 | ||
350 | :mochidef:`stop()`: | |
351 | ||
352 | Shortcut that calls ``stopPropagation()`` and | |
353 | ``preventDefault()``. | |
354 | ||
355 | *Availability*: | |
356 | Available in MochiKit 1.3.1+ | |
357 | ||
358 | ||
359 | :mochidef:`key()`: | |
360 | ||
361 | Returns ``{code, string}``. | |
362 | ||
363 | Use ``'onkeydown'`` and ``'onkeyup'`` handlers to detect control | |
364 | characters such as ``'KEY_F1'``. Use the ``'onkeypress'`` | |
365 | handler to detect "printable" characters, such as ``'é'``. | |
366 | ||
367 | When a user presses F1, in ``'onkeydown'`` and ``'onkeyup'`` this | |
368 | method returns ``{code: 122, string: 'KEY_F1'}``. In | |
369 | ``'onkeypress'``, it returns ``{code: 0, string: ''}``. | |
370 | ||
371 | If a user presses Shift+2 on a US keyboard, this method returns | |
372 | ``{code: 50, string: 'KEY_2'}`` in ``'onkeydown'`` and | |
373 | ``'onkeyup'``. In ``'onkeypress'``, it returns ``{code: 64, | |
374 | string: '@'}``. | |
375 | ||
376 | See ``_specialKeys`` in the source code for a comprehensive list | |
377 | of control characters. | |
378 | ||
379 | *Availability*: | |
380 | Available in MochiKit 1.3.1+ | |
381 | ||
382 | ||
383 | :mochidef:`mouse()`: | |
384 | ||
385 | Properties for ``'onmouse*'``, ``'onclick'``, ``'ondblclick'``, | |
386 | and ``'oncontextmenu'``: | |
387 | ||
388 | - ``page`` is a :mochiref:`MochiKit.Style.Coordinates` object | |
389 | that represents the cursor position relative to the HTML | |
390 | document. Equivalent to ``pageX`` and ``pageY`` in | |
391 | Safari, Mozilla, and Opera. | |
392 | ||
393 | - ``client`` is a :mochiref:`MochiKit.Style.Coordinates` | |
394 | object that represents the cursor position relative to the | |
395 | visible portion of the HTML document. Equivalent to | |
396 | ``clientX`` and ``clientY`` on all browsers. Current versions of | |
397 | Safari incorrectly return clientX as relative to the canvas | |
398 | instead of relative to the viewport (`Safari Bug 8707`_). | |
399 | ||
400 | Properties for ``'onmouseup'``, ``'onmousedown'``, ``'onclick'``, | |
401 | and ``'ondblclick'``: | |
402 | ||
403 | - ``mouse().button`` returns ``{left, right, middle}`` where | |
404 | each property is ``true`` if the mouse button was pressed, | |
405 | ``false`` otherwise. | |
406 | ||
407 | Known browser bugs: | |
408 | ||
409 | - Current versions of Safari won't signal ``'ondblclick'`` | |
410 | when attached via ``connect()`` (`Safari Bug 7790`_). | |
411 | ||
412 | - In Safari < 2.0.4, calling ``preventDefault()`` or ``stop()`` | |
413 | in ``'onclick'`` events signalled from ``<a>`` tags does not | |
414 | prevent the browser from following those links. | |
415 | ||
416 | - Mac browsers don't report right-click consistently. Firefox | |
417 | signals the slot and sets ``modifier().ctrl`` to true, | |
418 | Opera signals the slot and sets ``modifier().meta`` to | |
419 | ``true``, and Safari doesn't signal the slot at all | |
420 | (`Safari Bug 6595`_). | |
421 | ||
422 | To find a right-click in Safari, Firefox, and IE, you can | |
423 | connect an element to ``'oncontextmenu'``. This doesn't | |
424 | work in Opera. | |
425 | ||
426 | *Availability*: | |
427 | Available in MochiKit 1.3.1+ | |
428 | ||
429 | ||
430 | :mochidef:`relatedTarget()`: | |
431 | ||
432 | Returns the document element that the mouse has moved to. This is | |
433 | generated for ``'onmouseover'`` and ``'onmouseout'`` events. | |
434 | ||
435 | *Availability*: | |
436 | Available in MochiKit 1.3.1+ | |
437 | ||
438 | ||
439 | :mochidef:`confirmUnload(msg)`: | |
440 | ||
441 | In browsers that support the ``'onbeforeunload'`` event (IE and | |
442 | Firefox), calling this in the event handler will show a dialog box | |
443 | that allows the user to confirm or cancel the navigation away from | |
444 | the page. | |
445 | ||
446 | *Availability*: | |
447 | Available in MochiKit 1.4+ | |
448 | ||
449 | ||
450 | Authors | |
451 | ======= | |
452 | ||
453 | - Jonathan Gardner <jgardner@jonathangardner.net> | |
454 | - Beau Hartshorne <beau@hartshornesoftware.com> | |
455 | - Bob Ippolito <bob@redivi.com> | |
456 | ||
457 | ||
458 | Copyright | |
459 | ========= | |
460 | ||
461 | Copyright 2006 Jonathan Gardner <jgardner@jonathangardner.net>, Beau | |
462 | Hartshorne <beau@hartshornesoftware.com>, and Bob Ippolito | |
463 | <bob@redivi.com>. This program is dual-licensed free software; you | |
464 | can redistribute it and/or modify it under the terms of the `MIT | |
465 | License`_ or the `Academic Free License v2.1`_. | |
466 | ||
467 | .. _`MIT License`: http://www.opensource.org/licenses/mit-license.php | |
468 | .. _`Academic Free License v2.1`: http://www.opensource.org/licenses/afl-2.1.php |