|
||||||||
PREV NEXT | FRAMES NO FRAMES |
No overview generated for 'pendingEvents.js'
// This implements a "pending event" handling system. It wraps // window.setTimeout with an interface that manages the cancellation // or subsequent overriding transparently. // While this copy of pendingEvents.js is distributed with xblinjs, // this has a seperate license: pendingEvents.js is placed into the // public domain by the author, Jeremy Bowers in 2005. /** Maintains the list of pending event objects, used for correlating the numeric ids to the actual events. @private */ pendingEvents = {}; /** Used to give each event a unique id. @private */ uniqueEventIdentifier = 1; /** A constant, defining the Javascript function type. */ FUNCTION_TYPE = typeof(function () {}); /** A constant, defining the Javascript number type. */ NUMBER_TYPE = typeof(5); /** A constant, defining the Javascript string type. */ STRING_TYPE = typeof(""); /** Creates a new pending event. <p>A "pending event" is in essense a more intelligent version of the .setTimeout call (which is used to implement pending events). The best way to understand it is to start with a canonical example of one: Suppose you are writing a drop-down box attached to a text box, and you want the dropdown box to fire after the user is idle for some amount of time. (Most browser address bars are like this.)</p> <p>The way to do that is to create a pendingEvent every time the user enters a character, with the same key used for each one; for concreteness let's call the key "dropDown". Each subsequent "dropDown" pendingEvent will <i>cancel</i> the previous one, so if each one is created with a half second delay, the net effect is that only the final half-second delay will fire the event handling code. As long as the user types more quickly than that, the handler never fires. This turns out to be very useful in UI code.</p> <p>Each pendingEvent can also have a cancel function which will be called every time it is cancelled, and pendingEvents can be manually cancelled by calling <tt>cancelEvent</tt>. In the dropdown example, that would most likely be done every time the user leaves the text box, so the dropdown won't suddenly appear a half second later when the user's attention is on another widget entirely.</p> @param key The unique key that identifies this pending event. Use this key to cancel the event with cancelEvent, or supercede the event with later calls to pendingEvent. (Only the last pendingEvent call for a given key will be used.) @param ms When to fire this pending event in milliseconds from the call time, as long as it is not cancelled or superceded. This is of course build on window.setTimeout, and subject to the same timing considerations: You are guaranteed to not have the event fire before the time has passed, but it can occur arbitrarily far into the future. @param exeStatement The statement to execute when the event fires. Can either be a string, or a closure function taking no arguments. @param cancelStatement The statement to execute when the event is cancelled, either by a call to cancelEvent or a superceding call to pendingEvent. Can either be a string, or a closure function taking no arguments. */ function pendingEvent ( key, ms, exeStatement, cancelStatement ) { cancelPendingEvent ( key ); if (typeof(ms) != NUMBER_TYPE) { throw ("Can't use '" + ms + "' as the millisecond parameter; must" + " use a number."); } if (typeof(exeStatement) != STRING_TYPE && typeof(exeStatement) != FUNCTION_TYPE) { throw ("Can't use '" + exeStatement + "' as the statement to " + "execute; must be either string or function/closure."); } if (cancelStatement && typeof(cancelStatement) != STRING_TYPE && typeof(cancelStatement) != FUNCTION_TYPE) { throw ("Can't use '" + cancelStatement + "' as the statement to " + "cancel with; must be either string or function/closure."); } this.exeStatement = exeStatement; this.cancelStatement = cancelStatement; this.identifier = uniqueEventIdentifier++; pendingEvents[key] = this; window.setTimeout ( "executePendingEvent(\"" + key + "\", " + pendingEvents[key].identifier + ");", ms ); } /** Manages actually executing the pending event. @private */ function executePendingEvent ( key, eventIdentifier ) { if ( pendingEvents[key] && pendingEvents[key].identifier == eventIdentifier ) { statement = pendingEvents[key].exeStatement; if (typeof(statement) == typeof("")) { eval ( statement ); } else { statement(); } delete pendingEvents[key]; } } /** Cancels the pending event indicated by "key". If the event had a cancelStatement, the cancel statement will be executed. @param key The key of the pending event to cancel. */ function cancelPendingEvent ( key ) { if ( pendingEvents[key] && pendingEvents[key].cancelStatement ) { statement = pendingEvents[key].cancelStatement; if (typeof(statement) == typeof("")) { eval ( statement ); } else { statement(); } } delete pendingEvents[key]; }
|
||||||||
PREV NEXT | FRAMES NO FRAMES |