Skip to content

Commit

Permalink
doc: Merge/update old Event observe/stopObserving docs into source [p…
Browse files Browse the repository at this point in the history
…rototypejs#95 state:fixed_in_branch]
  • Loading branch information
dandean authored and samleb committed Feb 15, 2010
1 parent 6f85bc9 commit 5f61261
Showing 1 changed file with 86 additions and 72 deletions.
158 changes: 86 additions & 72 deletions src/dom/event.js
Expand Up @@ -480,71 +480,77 @@
/**
* Event.observe(element, eventName, handler) -> Element
* - element (Element | String): The DOM element to observe, or its ID.
* - eventName (String): The name of the event, in all lower case, without the "on"
* prefix — e.g., "click" (not "onclick").
* - eventName (String): The name of the event, in all lower case, without
* the "on" prefix — e.g., "click" (not "onclick").
* - handler (Function): The function to call when the event occurs.
*
* Registers an event handler on a DOM element. Aliased as [[Element#observe]].
*
* `Event.observe` smooths out a variety of differences between browsers and provides
* some handy additional features as well. Key features in brief:
* [[Event.observe]] smooths out a variety of differences between browsers
* and provides some handy additional features as well. Key features in brief:
* * Several handlers can be registered for the same event on the same element.
* * Prototype figures out whether to use `addEventListener` (W3C standard) or
* `attachEvent` (MSIE); you don't have to worry about it.
* * The handler is passed an _extended_ [[Event]] object (even on MSIE).
* * The handler's context (`this` value) is set to the extended element being observed
* (even if the event actually occurred on a descendent element and bubbled up).
* * Prototype handles cleaning up the handler when leaving the page (important for MSIE memory
* leak prevention).
* * `observe` makes it possible to stop observing the event easily via [[Event.stopObserving]].
* * Adds support for `mouseenter` / `mouseleave` in all browsers.
*
* Although you can use `Event.observe` directly and there are times when that's the most
* convenient or direct way, it's more common to use its alias [[Element#observe]]. These two
* statements have the same effect:
* * The handler's context (`this` value) is set to the extended element
* being observed (even if the event actually occurred on a descendent
* element and bubbled up).
* * Prototype handles cleaning up the handler when leaving the page
* (important for MSIE memory leak prevention).
* * [[Event.observe]] makes it possible to stop observing the event easily
* via [[Event.stopObserving]].
* * Adds support for `mouseenter` / `mouseleave` events in all browsers.
*
* Although you can use [[Event.observe]] directly and there are times when
* that's the most convenient or direct way, it's more common to use its
* alias [[Element#observe]]. These two statements have the same effect:
*
* Event.observe('foo', 'click', myHandler);
* $('foo').observe('click', myHandler);
*
* The examples in this documentation use the [[Element#observe]] form.
*
* <h5>The Handler</h5>
* ##### The Handler
*
* Signature:
*
* function handler(event) {
* // `this` = the element being observed
* }
*
* So for example, this will turn the background of the element 'foo' blue when it's clicked:
* So for example, this will turn the background of the element 'foo' blue
* when it's clicked:
*
* $('foo').observe('click', function(event) {
* this.setStyle({backgroundColor: 'blue'});
* });
*
* Note that we used `this` to refer to the element, and that we received the `event` object
* as a parameter (even on MSIE).
* Note that we used `this` to refer to the element, and that we received the
* `event` object as a parameter (even on MSIE).
*
* <h5>It's All About Timing</h5>
* ##### It's All About Timing
*
* One of the most common errors trying to observe events is trying to do it before the element
* exists in the DOM. Don't try to observe elements until after the
* [[document.observe dom:loaded]] event or `window` `load` event has been fired.
* One of the most common errors trying to observe events is trying to do it
* before the element exists in the DOM. Don't try to observe elements until
* after the [[document.observe dom:loaded]] event or `window` `load` event
* has been fired.
*
* <h5>Preventing the Default Event Action and Bubbling</h5>
* ##### Preventing the Default Event Action and Bubbling
*
* If we want to stop the event (e.g., prevent its default action and stop it bubbling), we can
* do so with the extended event object's [[Event#stop]] method:
* If we want to stop the event (e.g., prevent its default action and stop it
* bubbling), we can do so with the extended event object's [[Event#stop]]
* method:
*
* $('foo').observe('click', function(event) {
* event.stop();
* });
*
* <h5>Finding the Element Where the Event Occurred</h5>
* ##### Finding the Element Where the Event Occurred
*
* Since most events bubble from descendant elements up through the hierarchy until they're
* handled, we can observe an event on a container rather than individual elements within the
* container. This is sometimes called "event delegation". It's particularly handy for tables:
* Since most events bubble from descendant elements up through the hierarchy
* until they're handled, we can observe an event on a container rather than
* individual elements within the container. This is sometimes called "event
* delegation". It's particularly handy for tables:
*
* <table id='records'>
* <thead>
Expand All @@ -560,27 +566,27 @@
* Instead of observing each cell or row, we can simply observe the table:
*
* $('records').observe('click', function(event) {
* var clickedRow;
* clickedRow = event.findElement('tr');
* var clickedRow = event.findElement('tr');
* if (clickedRow) {
* this.down('th').update("You clicked record #" + clickedRow.readAttribute("data-recnum"));
* }
* });
*
* When any row in the table is clicked, we update the table's first header cell saying which
* record was clicked. [[Event#findElement]] finds the row that was clicked, and `this` refers
* to the table we were observing.
* When any row in the table is clicked, we update the table's first header
* cell saying which record was clicked. [[Event#findElement]] finds the row
* that was clicked, and `this` refers to the table we were observing.
*
* <h5>Stopping Observing the Event</h5>
* ##### Stopping Observing the Event
*
* If we don't need to observe the event anymore, we can stop observing it with
* [[Event.stopObserving]] (aka [[Element#stopObserving]]).
* If we don't need to observe the event anymore, we can stop observing it
* with [[Event.stopObserving]] or its [[Element#stopObserving]] alias.
*
* <h5>Using an Instance Method as a Handler</h5>
* ##### Using an Instance Method as a Handler
*
* If we want to use an instance method as a handler, we will probably want to use
* [[Function#bind]] to set the handler's context; otherwise, the context will be lost and
* `this` won't mean what we expect it to mean within the handler function. E.g.:
* If we want to use an instance method as a handler, we will probably want
* to use [[Function#bind]] to set the handler's context; otherwise, the
* context will be lost and `this` won't mean what we expect it to mean
* within the handler function. E.g.:
*
* var MyClass = Class.create({
* initialize: function(name, element) {
Expand All @@ -595,28 +601,31 @@
* },
* });
*
* Without the `bind`, when `handleClick` was triggered by the event, `this` wouldn't
* refer to the instance and so the alert wouldn't show the name. Because we used `bind`, it
* works correctly. See [[Function#bind]] for
* details. There's also [[Function#bindAsEventListener]], which is handy for certain very
* specific situations. (Normally, `bind` is all you need.)
* Without the [[Function#bind]], when `handleClick` was triggered by the
* event, `this` wouldn't refer to the instance and so the alert wouldn't
* show the name. Because we used [[Function#bind]], it works correctly. See
* [[Function#bind]] for details. There's also [[Function#bindAsEventListener]],
* which is handy for certain very specific situations. (Normally,
* [[Function#bind]] is all you need.)
*
* <h5>Side Notes</h5>
* ##### Side Notes
*
* Although Prototype smooths out most of the differences between browsers, the fundamental
* behavior of a browser implementation isn't changed. For example, the timing of the `change`
* or `blur` events varies a bit from browser to browser.
* Although Prototype smooths out most of the differences between browsers,
* the fundamental behavior of a browser implementation isn't changed. For
* example, the timing of the `change` or `blur` events varies a bit from
* browser to browser.
*
* <h5>Changes in 1.6.x</h5>
* ##### Changes in 1.6.x
*
* Prior to Prototype 1.6, `observe` supported a fourth argument (`useCapture`), a boolean that
* indicated whether to use the browser's capturing phase or its bubbling phase. Since MSIE does
* not support the capturing phase, we removed this argument from 1.6, lest it give users the
* Prior to Prototype 1.6, [[Event.observe]] supported a fourth argument
* (`useCapture`), a boolean that indicated whether to use the browser's
* capturing phase or its bubbling phase. Since MSIE does not support the
* capturing phase, we removed this argument from 1.6, lest it give users the
* false impression that they can use the capturing phase in all browsers.
*
* 1.6 also introduced setting the `this` context to the element being observed, automatically
* extending the [[Event]] object, and the [[Event#findElement]] method.
*
* 1.6 also introduced setting the `this` context to the element being
* observed, automatically extending the [[Event]] object, and the
* [[Event#findElement]] method.
**/
function observe(element, eventName, handler) {
element = $(element);
Expand Down Expand Up @@ -651,18 +660,20 @@
/**
* Event.stopObserving(element[, eventName[, handler]]) -> Element
* - element (Element | String): The element to stop observing, or its ID.
* - eventName (String): _(Optional)_ The name of the event to stop observing, in all lower case,
* without the "on"&nbsp;&mdash; e.g., "click" (not "onclick").
* - handler (Function): _(Optional)_ The handler to remove; must be the _exact same_ reference
* that was passed to [[Event.observe]] (see below.).
* - eventName (String): _(Optional)_ The name of the event to stop
* observing, in all lower case, without the "on"&nbsp;&mdash; e.g.,
* "click" (not "onclick").
* - handler (Function): _(Optional)_ The handler to remove; must be the
* _exact same_ reference that was passed to [[Event.observe]].
*
* Unregisters one or more event handlers.
*
* If `handler` is omitted, unregisters all event handlers on `element`
* for that `eventName`. If `eventName` is also omitted, unregisters _all_
* event handlers on `element`. (In each case, only affects handlers registered via Prototype.)
* event handlers on `element`. (In each case, only affects handlers
* registered via Prototype.)
*
* <h5>Examples</h5>
* ##### Examples
*
* Assuming:
*
Expand All @@ -672,28 +683,32 @@
*
* $('foo').stopObserving('click', myHandler);
*
* If we want to remove _all_ 'click' handlers from 'foo', we leave off the handler argument:
* If we want to remove _all_ 'click' handlers from 'foo', we leave off the
* handler argument:
*
* $('foo').stopObserving('click');
*
* If we want to remove _all_ handlers for _all_ events from 'foo' (perhaps we're about to remove
* it from the DOM), we simply omit both the handler and the event name:
* If we want to remove _all_ handlers for _all_ events from 'foo' (perhaps
* we're about to remove it from the DOM), we simply omit both the handler
* and the event name:
*
* $('foo').stopObserving();
*
* <h5>A Common Error</h5>
* ##### A Common Error
*
* When using instance methods as observers, it's common to use [[Function#bind]] on them, e.g.:
* When using instance methods as observers, it's common to use
* [[Function#bind]] on them, e.g.:
*
* $('foo').observe('click', this.handlerMethod.bind(this));
*
* If you do that, __this will not work__ to unregister the handler:
*
* $('foo').stopObserving('click', this.handlerMethod.bind(this)); // <== WRONG
*
* [[Function#bind]] returns a _new_ function every time it's called, and so if you don't retain
* the reference you used when observing, you can't unhook that function specifically. (You can
* still unhook __all__ handlers for an event, or all handlers on the element entirely.)
* [[Function#bind]] returns a _new_ function every time it's called, and so
* if you don't retain the reference you used when observing, you can't
* unhook that function specifically. (You can still unhook __all__ handlers
* for an event, or all handlers on the element entirely.)
*
* To do this, you need to keep a reference to the bound function:
*
Expand All @@ -703,7 +718,6 @@
* ...and then to remove:
*
* $('foo').stopObserving('click', this.boundHandlerMethod); // <== Right
*
**/
function stopObserving(element, eventName, handler) {
element = $(element);
Expand Down

0 comments on commit 5f61261

Please sign in to comment.