Compose Event
This is a unified events framework handling standard events, keyboard events, cross-browser animation events, and tap events (for touch screen devices).
- Easy DOM event management, powered by bean.
- Cross-browser animation events.
- Custom
tap
event for properly discerning touch events. - Simple keyboard events, powered by keymaster.
If you want to trigger events on DOM ready, when a page changes, or during a scroll or resize event, use these event managers to register your functions.
DOM Listeners - Use these functions to attach DOM event listeners.
Keyboard Listeners - Use these functions to attach keyboard event listeners.
Media Query Listeners - trigger callbacks when media queries become true/untrue.
- event.
media.width()
- event.
media.minWidth()
- event.
media.maxWidth()
- event.
media.height()
- event.
media.minHeight()
- event.
media.maxHeight()
Timing functions - Control when functions are executed and how frequently.
Helpers - These are tiny event utilities which make things a bit nicer.
- event.
bubbleFormEvents()
- event.
scroll.disablePointer()
- event.
resize.disableAnimation()
- event.
submit()
Event managers
These event managers make it easier to handle event listeners for DOM ready, page transitions, and window scroll. This triggeres event callbacks efficiently and adds some other niceities.
ready( callback )
event.ready()
lets you add callbacks to be fired whenever the browser's DOMContentLoaded
event is fired. For a site which
uses ajax to fetch subsequent pages, it's important to note that this is only fired once with each full page load.
event
This adds callbacks to an array and fires them each from a single event listener. If an event callback is added after the page has already loaded, it will fire immediately.
This will also fire events registered with the change function below, unless you are using Turbolinks which triggers page:change
on its own.
change( callback )
event.change()
lets you add callbacks to be fired whenever a page:chage
event is fired. This is the sort
of even that is used in pjax or Turbolinks to signal that the DOM has loaded new content, likely via ajax which means you
may need to remove listeners, bootstrap widgets, or whatever you do when content changes.
event
Just like ready
, this adds your callback to an array, fired from a single listener. If a function is added after page:change
has been fired, it will fire immediately.
scroll( callback )
event.scroll()
lets you add callbacks to be fired whenever the window
's scroll
event is fired (throttled by requestAnimationFrame
).
eventeventscrollstart { /* scrolling has started */ } eventscroll
This fires all callbacks at with requestAnimationFrame()
ensuring that events are fired during the
browser's natural repaint cycle (every 16ms at 60fps). This helps prevent scattered repaints and jittery graphics performance.
Pause & Resume Callbacks
You may want to deactivate a callback and later reactivate it. To do so, save a reference to
the callback when registering it. Then call stop()
or start()
on the callback reference.
var scrollWatch = eventscrollWatch // prevent callback from executingscrollWatchstart // allow callback to execute again
resize( function )
event.resize()
lets you add callbacks to be fired whenever the window
's resize
event is fired (throttled by requestAnimationFrame
).
eventeventresizestart { /* resizing just started */ } eventresize
This fires all callbacks at with requestAnimationFrame()
ensuring that events are fired during the
browser's natural repaint cycle (every 16ms at 60fps). This helps prevent scattered repaints and jittery graphics performance.
Pause & Resume Callbacks
Just like with the scroll event manager, you may want to deactivate a callback and later reactivate it. To do so, save a reference to the callback when registering it. Then call stop()
or start()
on the callback reference.
var resizeWatch = eventresizeWatch // prevent callback from executingresizeWatchstart // allow callback to execute again
Custom Event Managers
You can use a custom event manager to fire start
, end
and requestAnimationFrame
throttled events for any type of event. This can be simpler than managing throttling and debouncing manually.
eventManager
For example, if you want to trigger callbacks when scrolling a panel
panelScroll = eventeventManager panelScrollstart{ /* panel scrolling has started */ } panelScroll
Event Listeners
Much of the documentation below has been copied from dependent libraries and modified where necessary. To dig deeper be sure to reference the documentation for bean and keymaster.
on( element, eventType[, selector], handler[, args ] )
bean.on()
lets you attach event listeners to both elements and objects.
Arguments
- element / object (DOM Element or Object) - an HTML DOM element or any JavaScript Object
- event type(s) (String) - an event (or multiple events, space separated) to listen to
- selector (optional String) - a CSS DOM Element selector string to bind the listener to child elements matching the selector
- handler (Function) - the callback function
- args (optional) - additional arguments to pas to the callback function when triggered
Optionally, event types and handlers can be passed in an object of the form { 'eventType': handler }
as the second argument.
Examples
event = // simpleevent; // optional arguments passed to handlerevent; // multiple eventsevent; // multiple handlersevent;
Delegation
// event delegated eventsevent; // Alternatively, you can pass an array of elements.// This cuts down on selector engine work, and is a more performant means of// delegation if you know your DOM won't be changing:event;event;
Differences to Bean events
Even though with Bean (the core of the events system) using an object to register multiple events at once means you cannot have cannot have delegation or optional arguments, compose-event processes arguments to allow these features without issue. Here's what that looks like.
// Multiple events + delegation + optional argumentsevent;
Another difference is that you can create a new 'tap' event which looks like this.
event
This attaches a touchstart
event and watches for movement or additional fingers, which would indicate a canceled or uninteneded tap. If a
user does not move their finger or add an additional finger, their intent is determined as a tap, and the callback function is executed.
Note: Remember to stop propagation on a tap event if you do not want it to also fire a click event, since mobile devices typically fire a click event a part of the touch event lifecycle.
one( element, eventType[, selector], handler[, args ] )
event.one()
is an alias for event.on()
except that the handler will only be executed once and then the listener
will be removed. If you use one
for multiple events, the listener will be removed as each event is fired.
off( element[, eventType[, handler ]] )
event.off()
is how you get rid of handlers once you no longer want them active. It's also a good idea to call off on elements before removing them from your DOM; this helps prevent memory leaks.
Arguments
- element / object (DOM Element or Object) - an HTML DOM element or any JavaScript Object
- event type(s) (optional String) - an event (or multiple events, space separated) to remove
- handler (optional Function) - the specific callback function to remove
Optionally, event types and handlers can be passed in an object of the form { 'eventType': handler }
as the second argument, just like on()
.
Examples
// remove a single event handlersevent; // remove all click handlersevent; // remove handler for all eventsevent; // remove multiple eventsevent; // remove all eventsevent; // remove handlers for events using object literalevent
clone( destElement, srcElement[, eventType ] )
event.clone()
is a method for cloning events from one DOM element or object to another.
Examples
// clone all events at once by doing this:event; // clone events of a specific typeevent;
fire( element, eventType[, args ] )
event.fire()
gives you the ability to trigger events.
Examples
// fire a single event on an elementevent; // fire multiple typesevent;
Event
object
The Bean implements a variant of the standard DOM Event
object, supplied as the argument to your DOM event handler functions. Bean wraps and fixes the native Event
object where required, providing a consistent interface across browsers.
// prevent default behavior and propagation (even works on old IE)event; // a simple shortcut version of the above codeevent; // prevent all subsequent handlers from being triggered for this particular eventevent;
Note: Your mileage with the Event
methods (preventDefault
etc.) may vary with delegated events as the events are not intercepted at the element in question.
object support
Everything you can do with an element, you can also do with an object. this is particularly useful for working with classes or plugins.
var inst = ;event; //later on...event;
afterAnimation( element, callback, [startTimeout] )
event.afterAnimation()
, a better animation event queue.
This will trigger a callback:
- After animation completes, or
- After a timeout if animation is delayed or never starts, or
- Immediately if animation is not supported by the browser.
This works like event.one( el, 'animationend', callback)
but is safe to use on elements which may not have animations, or in browsers which may not support them.
For example:
var el = documentelclassList event
In the example above the optional startTimeout
was set. This will trigger the callback if animation has not begun after 50
miliseconds.
startTimeout
can also be set to true
which will wait for 32ms
about two animation frames before aborting and triggering the callback.
Keybaord events
keyOn( 'key', handler )
event.keyOn()
gives you the ability to trigger events from keypresses.
Examples
// simpleevent; // You can also chain modifier keys and stop events like this.event; // multiple shortcuts that do the same thingevent;
The handler method is called with two arguments set, the keydown event
fired, and
an object containing, among others, the following two properties:
shortcut
: a string that contains the shortcut used, e.g. ctrl+r
scope
: a string describing the scope (or all
)
event; // "ctrl+r", "all"
Special Key support
Supported modifier keys:
⇧
, shift
, option
, ⌥
, alt
, ctrl
, control
, command
, and ⌘
.
The following special keys can be used for shortcuts:
backspace
, tab
, clear
, enter
, return
, esc
, escape
, space
,
up
, down
, left
, right
, home
, end
, pageup
, pagedown
, del
, delete
and f1
through f19
.
keyOne( 'key', handler )
event.keyOne()
is an alias for key()
but it fires once and removes its listener.
This will execute the callback and stop listening for the escape key.
// simpleevent;
keyOff( 'key', handler )
event.keyOff()
removes event listeners for keys.
// unbind 'a' handlerkey; // unbind a key only for a single scope// when no scope is specified it defaults to the current scope (key.getScope())key;key;
key
event.key
gives you access to the key object for querying key states and managing scope.
Examples
You can query the key
object for the state of any key at any point (even in code other than the key shortcut handlers)
Querying Modifier Keys
For example, key.shift
is true
if the shift key is currently pressed. This allows easy implementation of things like shift+click handlers.
if eventkeyshift ;
Other key Queries
key.isPressed( 77 )
is true
if the M key is currently pressed.
if eventkey ;if eventkey ;
You can also get these as an array using...
eventkey // returns an array of key codes currently pressed
Key Scopes
If you want to reuse the same shortcut for separate areas in your single page app,
Keymaster supports switching between scopes. Use the key.setScope
method to set scope.
// define shortcuts with a scopeevent;event; // set the scope (only 'all' and 'issues' shortcuts will be honored)eventkey; // default scope is 'all'
Media Query Listeners
media.width( sizes, [callback] )
event.media.width()
Check a width
media query and register a callback to be triggered when that media query becomes true/untrue.
{ if querymatches /* query is true */ else /* query is true */ } // Triggler handler when viewport width is between 400px and 800pxqueryList = eventmediawidth min: 400 max: 800 handleQuery
media.minWidth( size, [callback] )
event.media.minWidth()
Check a min-width
media query and register a callback to be triggered when that media query becomes true/untrue.
// Triggler handler when viewport width is greater than 400pxqueryList = eventmedia
media.maxWidth( size, [callback] )
event.media.maxWidth()
Check a min-width
media query and register a callback to be triggered when that media query becomes true/untrue.
// Triggler handler when viewport width is less than 800pxqueryList = eventmedia
media.height( sizes, [callback] )
event.media.height()
Check a height
media query and register a callback to be triggered when that media query becomes true/untrue.
// Triggler handler when viewport height is between than 400px and 800pxqueryList = eventmediaheight min: 400 max: 800 handleQuery
media.minHeight( size, [callback] )
event.media.minHeight()
Check a min-height
media query and register a callback to be triggered when that media query becomes true/untrue.
// Triggler handler when viewport height is greater than 400pxqueryList = eventmedia
media.maxHeight( size, [callback] )
event.media.maxHeight()
Check a max-height
media query and register a callback to be triggered when that media query becomes true/untrue.
// Triggler handler when viewport height is less than 800pxqueryList = eventmedia
Timing functions
delay( function, [wait, arguments] )
event.dealy()
lets you call functions after a period of time. Execution is queued with requestAnimationFrame()
which ensures that callbacks
are triggered optimally to prevent unnecessary repainting. If your callback doesn't change the DOM and you need to execute a function more precicely, use
setTimeout()
instead.
Here we'll call scat()
during the browser's repaint cycle immediately following 500ms.
{ console }event
We can also pass arugments to the delayed function, and even stop it from being executed.
var handle = event // stop the delayed callhandle
repeat( function, [wait, limit, arguments] )
event.repeat()
lets you call functions on a regular interval with requestAnimationFrame()
, ensuring that callbacks
are triggered optimally to prevent unnecessary repainting. If your callback doesn't change the DOM and you need to execute a function more precicely, use
setInterval()
instead. This adds a helpful limit
option which stops repeating after a set number of times.
Here we'll call scat()
during the repaint cycle closest to 200ms.
{ console }event
This will call scat()
10 times, during the repaint cycle closest to 200ms.
var handle = event // Or you can manually stop the repeatinghandle
You can even execute a function after repeating stops.
var handle = event // Assign a function to trigger when the repeating stops.handle { console }
This will trigger a callback with each repaint cycle.
// These are all equivilenteventeventevent
You can also pass arguments to the callback function like this.
event
throttle( function, [wait, options] )
event.throttle()
prevents functions from being called except on the repaint cycle after every wait
miliseconds. This uses requestAnimationFrame()
to prevent callbacks from triggering unnecessary repaints. If your callbacks will not affect the DOM and you need more assurance of their execution time, you'll want to use a different throttle function.
var { // modify the DOM}// Create a throttled version of the resizevar throttledResize = // Only executes on the repait cycle after every 200ms event
To allow a callback to execute with every repaint cycle don't provide a wait time.
var throttledResize =
To stop a throttled callback from being executed:
// Remove it from the animation queue and prevent it from executingthrottledResize
Throttled functions pass arguments through to the original callback.
var { console} event
debounce( function, [wait, options] )
event.debounce()
prevents functions from being called except on the repaint cycle after every wait
miliseconds since the last time the function was executed. This is similar to throttle, exept rather than executing on a regular interval, callbacks are only triggered wait
miliseconds after the last time they were called.
For example if you want to validate a form input after someone finishes typing, you'd do this.
var { // some awesome code } event
This will wait 200ms after the last keyup
event to trigger the script js. You'll notice that the
validate function accepts the event argument, this is because arguments are passed through to the
callback.
Debounce also accepts an object as the first parameter.
These are equivilent ways to create a trailing-only debounced function.
// Equivilent ways to create a trailing-only debounce.
These are equivilent ways to create a leading-only debounced function.
Understanding Leading & Trailing debounce callbacks
As noted above, debounce fires callbacks wait
miliseconds from the last call. This is called a trailing
callback. This is the default, but you can also
fire leading
callbacks which fire immediately after the first call but not again until it has been wait
miliseconds from the last callback call.
Here's an example where debounce is leading and trailing and set to 150 miliseconds.
// Track leading and trailing by enabling leading in the options var leadingAndTrailing = event
Here is what it looks like when the debounced function is triggered. The *
represents times a scroll has occured.
(150 ms after) (150 ms after)
----------------|------------------•------------|-------------•-------------
scroll: *** * * * *** *
leading: A A
trailing: Ω Ω
To fire leading callbacks only, disable trailing in the options.
var leadingOnly =
For a simple example, lets consider what happens if a click
event is fired twice (a double click).
- When
leading
the callback fires immediately. - When
trailing
the callback fireswait
ms after the last click. - When both, the callback fires immediately and then
wait
ms after the last click.
Different leading and trailing callbacks
You can trigger different leading and trailing callbacks to mark the start and end of a barrage of debounced calls. For example, you might track the beginning and ending of a user scrolling.
Note: To aid in clarity, you can pass an options block first (instead of a function) to the debounce function as demonstrated below.
var watchScroll =
Setting a maximum wait time
Set the optional max
value to prevent a function from going more than max
miliseconds without being executed.
var debouncedFunc =
In the example above if the debounced function is called every 100ms
, someFunc
will never be
executed since the wait is set to 200ms
. By setting max
to 1000ms
, we ensure that someFunc
will be called at least once a
second.
bubbleFormEvents()
By default, input focus
, blur
, and form submit
events do not bubble up the DOM. You can add bubbling support for these events like this.
event
Here's what this does.
- On page change, event listeners for
focus
,blur
andsubmit
are added to input and form elements. - When events are fired, a custom event (which will bubble up the DOM) is fired on the target's parent element, passing along the original event object.
- Ajax page changes remove and re-add event listeners automatically.
This means you can attach a single listener to the document
or a form
and respond to these events wihtout having to manage a host of listeners.
scroll.disablePointer()
While scrolling down a page, your pointer may interact with elements which pass under it. This may cause unnecessary repaints, causing a jittery scrolling experience. This little utility simply watches scroll events and disables pointer events while scrolling.
eventscroll
This registers itself with scroll.start
and scroll.stop
event managers to optimize event listener usage and
offer the best performance possible.
resize.disableAnimation()
This prevents transitions and animations from being triggered when resizing the window, preventing unnecessary repaints, causing a jittery resize experience. This little utility simply watches resize events and disables pointer events while resizing.
eventresize
This registers itself with resize.start
and resize.stop
event managers to optimize event listener usage and
submit()
Triggers a DOM bubbling, cancelable form submsision event.
event
Event listeners watching submit
on that form element will be able to do their work, or even preventDefault()
.
Why? Because form.submit()
doesn't fire events which can trigger listeners or be canceled.
How? This triggers a CustomEvent
and if the event is not defaultPrevented
it will then fire form.submit()
.