| 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 |