FocusCycler
A utility class that helps cycling over focusable views in a ViewCollection when the focus is tracked by the FocusTracker instance. It helps implementing keyboard navigation in HTML forms, toolbars, lists and the like.
To work properly it requires:
- a collection of focusable (HTML
tabindexattribute) views that implement thefocus()method, - an associated focus tracker to determine which view is focused.
A simple cycler setup can look like this:
const focusables = new ViewCollection<FocusableView>();
const focusTracker = new FocusTracker();
// Add focusable views to the focus tracker.
focusTracker.add( ... );
Then, the cycler can be used manually:
const cycler = new FocusCycler( { focusables, focusTracker } );
// Will focus the first focusable view in #focusables.
cycler.focusFirst();
// Will log the next focusable item in #focusables.
console.log( cycler.next );
Alternatively, it can work side by side with the KeystrokeHandler:
const keystrokeHandler = new KeystrokeHandler();
// Activate the keystroke handler.
keystrokeHandler.listenTo( sourceOfEvents );
const cycler = new FocusCycler( {
focusables, focusTracker, keystrokeHandler,
actions: {
// When arrowup of arrowleft is detected by the #keystrokeHandler,
// focusPrevious() will be called on the cycler.
focusPrevious: [ 'arrowup', 'arrowleft' ],
}
} );
Check out the "Deep dive into focus tracking" guide to learn more.
Properties
actions : FocusCyclerActions | undefinedreadonlymodule:ui/focuscycler~FocusCycler#actionsActions that the cycler can take when a keystroke is pressed. Requires
options.keystrokeHandlerto be passed and working. When an action is performed,preventDefaultandstopPropagationwill be called on the event the keystroke fired in the DOM.actions: { // Will call #focusPrevious() when arrowleft or arrowup is pressed. focusPrevious: [ 'arrowleft', 'arrowup' ], // Will call #focusNext() when arrowdown is pressed. focusNext: 'arrowdown' }Copy codecurrent : null | numberreadonlymodule:ui/focuscycler~FocusCycler#currentAn index of the view in the
focusableswhich is focused according tofocusTracker. Returnsnullwhen there is no such view.first : null | FocusableViewreadonlymodule:ui/focuscycler~FocusCycler#firstReturns the first focusable view in
focusables. Returnsnullif there is none.Note: Hidden views (e.g. with
display: none) are ignored.focusTracker : FocusTrackerreadonlymodule:ui/focuscycler~FocusCycler#focusTrackerA focus tracker instance that the cycler uses to determine the current focus state in
focusables.focusables : ViewCollection<FocusableView>readonlymodule:ui/focuscycler~FocusCycler#focusablesA focusable views collection that the cycler operates on.
keystrokeHandler : KeystrokeHandler | undefinedreadonlymodule:ui/focuscycler~FocusCycler#keystrokeHandlerAn instance of the
KeystrokeHandlerwhich can respond to certain keystrokes and cycle the focus.last : null | FocusableViewreadonlymodule:ui/focuscycler~FocusCycler#lastReturns the last focusable view in
focusables. Returnsnullif there is none.Note: Hidden views (e.g. with
display: none) are ignored.next : null | FocusableViewreadonlymodule:ui/focuscycler~FocusCycler#nextReturns the next focusable view in
focusablesbased oncurrent. Returnsnullif there is none.Note: Hidden views (e.g. with
display: none) are ignored.previous : null | FocusableViewreadonlymodule:ui/focuscycler~FocusCycler#previousReturns the previous focusable view in
focusablesbased oncurrent. Returnsnullif there is none.Note: Hidden views (e.g. with
display: none) are ignored.
Methods
constructor( options = { [options.actions], options.focusables, options.focusTracker, [options.keystrokeHandler], [options.keystrokeHandlerOptions] } )module:ui/focuscycler~FocusCycler#constructorCreates an instance of the focus cycler utility.
Parameters
options : objectConfiguration options.
Properties[ options.actions ] : FocusCyclerActionsoptions.focusables : ViewCollection<FocusableView>options.focusTracker : FocusTracker[ options.keystrokeHandler ] : KeystrokeHandler[ options.keystrokeHandlerOptions ] : KeystrokeHandlerOptions
chain( chainedFocusCycler ) → voidmodule:ui/focuscycler~FocusCycler#chainAllows for creating continuous focus cycling across multiple focus cyclers and their collections of
focusables.It starts listening to the
FocusCyclerForwardCycleEventandFocusCyclerBackwardCycleEventevents of the chained focus cycler and engages, whenever the user reaches the last (forwards navigation) or first (backwards navigation) focusable view and would normally start over. Instead, the navigation continues on the higher level (flattens).For instance, for the following nested focus navigation structure, the focus would get stuck the moment the AB gets focused and its focus cycler starts managing it:
┌────────────┐ ┌──────────────────────────────────┐ ┌────────────┐ │ AA │ │ AB │ │ AC │ │ │ │ │ │ │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ │ │ │ ┌──► ABA ├──► ABB ├──► ABC ├───┐ │ │ │ │ ├───► │ └─────┘ └─────┘ └─────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────────────────────────┘ │ │ │ │ │ │ │ │ │ └────────────┘ └──────────────────────────────────┘ └────────────┘Copy codeChaining a focus tracker that manages AA, AB, and AC with the focus tracker that manages ABA, ABB, and ABC creates a seamless navigation experience instead:
┌────────────┐ ┌──────────────────────────────────┐ ┌────────────┐ │ AA │ │ AB │ │ AC │ │ │ │ │ │ │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ │ │ │ ┌──► ABA ├──► ABB ├──► ABC ├──┐ │ │ │ ┌──► ├───┼─┘ └─────┘ └─────┘ └─────┘ └──┼───► ├──┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────────┘ └──────────────────────────────────┘ └────────────┘ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘Copy codeSee
unchainto reverse the chaining.Parameters
chainedFocusCycler : FocusCycler
Returns
void
delegate( events ) → EmitterMixinDelegateChaininheritedmodule:ui/focuscycler~FocusCycler#delegateDelegates selected events to another
Emitter. For instance:emitterA.delegate( 'eventX' ).to( emitterB ); emitterA.delegate( 'eventX', 'eventY' ).to( emitterC );Copy codethen
eventXis delegated (fired by)emitterBandemitterCalong withdata:emitterA.fire( 'eventX', data );Copy codeand
eventYis delegated (fired by)emitterCalong withdata:emitterA.fire( 'eventY', data );Copy codeParameters
events : Array<string>Event names that will be delegated to another emitter.
Returns
fire( eventOrInfo, args ) → GetEventInfo<TEvent>[ 'return' ]inheritedmodule:ui/focuscycler~FocusCycler#fireFires an event, executing all callbacks registered for it.
The first parameter passed to callbacks is an
EventInfoobject, followed by the optionalargsprovided in thefire()method call.Type parameters
Parameters
eventOrInfo : GetNameOrEventInfo<TEvent>The name of the event or
EventInfoobject if event is delegated.args : TEvent[ 'args' ]Additional arguments to be passed to the callbacks.
Returns
GetEventInfo<TEvent>[ 'return' ]By default the method returns
undefined. However, the return value can be changed by listeners through modification of theevt.return's property (the event info is the first param of every callback).
focusFirst() → voidmodule:ui/focuscycler~FocusCycler#focusFirstFocuses the
firstitem infocusables.Note: Hidden views (e.g. with
display: none) are ignored.Returns
void
focusLast() → voidmodule:ui/focuscycler~FocusCycler#focusLastFocuses the
lastitem infocusables.Note: Hidden views (e.g. with
display: none) are ignored.Returns
void
focusNext() → voidmodule:ui/focuscycler~FocusCycler#focusNextFocuses the
nextitem infocusables.Note: Hidden views (e.g. with
display: none) are ignored.Returns
void
focusPrevious() → voidmodule:ui/focuscycler~FocusCycler#focusPreviousFocuses the
previousitem infocusables.Note: Hidden views (e.g. with
display: none) are ignored.Returns
void
listenTo( emitter, event, callback, [ options ] ) → voidinheritedmodule:ui/focuscycler~FocusCycler#listenTo:BASE_EMITTERRegisters a callback function to be executed when an event is fired in a specific (emitter) object.
Events can be grouped in namespaces using
:. When namespaced event is fired, it additionally fires all callbacks for that namespace.// myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ). myEmitter.on( 'myGroup', genericCallback ); myEmitter.on( 'myGroup:myEvent', specificCallback ); // genericCallback is fired. myEmitter.fire( 'myGroup' ); // both genericCallback and specificCallback are fired. myEmitter.fire( 'myGroup:myEvent' ); // genericCallback is fired even though there are no callbacks for "foo". myEmitter.fire( 'myGroup:foo' );Copy codeAn event callback can stop the event and set the return value of the
firemethod.Type parameters
Parameters
emitter : EmitterThe object that fires the event.
event : TEvent[ 'name' ]The name of the event.
callback : GetCallback<TEvent>The function to be called on event.
[ options ] : GetCallbackOptions<TEvent>Additional options.
Returns
void
off( event, callback ) → voidinheritedmodule:ui/focuscycler~FocusCycler#offStops executing the callback on the given event. Shorthand for
this.stopListening( this, event, callback ).Parameters
event : stringThe name of the event.
callback : FunctionThe function to stop being called.
Returns
void
on( event, callback, [ options ] ) → voidinheritedmodule:ui/focuscycler~FocusCycler#onRegisters a callback function to be executed when an event is fired.
Shorthand for
this.listenTo( this, event, callback, options )(it makes the emitter listen on itself).Type parameters
Parameters
event : TEvent[ 'name' ]The name of the event.
callback : GetCallback<TEvent>The function to be called on event.
[ options ] : GetCallbackOptions<TEvent>Additional options.
Returns
void
once( event, callback, [ options ] ) → voidinheritedmodule:ui/focuscycler~FocusCycler#onceRegisters a callback function to be executed on the next time the event is fired only. This is similar to calling
onfollowed byoffin the callback.Type parameters
Parameters
event : TEvent[ 'name' ]The name of the event.
callback : GetCallback<TEvent>The function to be called on event.
[ options ] : GetCallbackOptions<TEvent>Additional options.
Returns
void
stopDelegating( [ event ], [ emitter ] ) → voidinheritedmodule:ui/focuscycler~FocusCycler#stopDelegatingStops delegating events. It can be used at different levels:
- To stop delegating all events.
- To stop delegating a specific event to all emitters.
- To stop delegating a specific event to a specific emitter.
Parameters
[ event ] : stringThe name of the event to stop delegating. If omitted, stops it all delegations.
[ emitter ] : Emitter(requires
event) The object to stop delegating a particular event to. If omitted, stops delegation ofeventto all emitters.
Returns
void
stopListening( [ emitter ], [ event ], [ callback ] ) → voidinheritedmodule:ui/focuscycler~FocusCycler#stopListening:BASE_STOPStops listening for events. It can be used at different levels:
- To stop listening to a specific callback.
- To stop listening to a specific event.
- To stop listening to all events fired by a specific object.
- To stop listening to all events fired by all objects.
Parameters
[ emitter ] : EmitterThe object to stop listening to. If omitted, stops it for all objects.
[ event ] : string(Requires the
emitter) The name of the event to stop listening to. If omitted, stops it for all events fromemitter.[ callback ] : Function(Requires the
event) The function to be removed from the call list for the givenevent.
Returns
void
unchain( otherFocusCycler ) → voidmodule:ui/focuscycler~FocusCycler#unchain_focus( view, direction ) → voidprivatemodule:ui/focuscycler~FocusCycler#_focusFocuses the given view if it exists.
Parameters
view : null | FocusableViewThe view to be focused
direction : 1 | 1The direction of the focus if the view has focusable children.
Returns
void
_getDomFocusableItem( step ) → null | FocusableViewprivatemodule:ui/focuscycler~FocusCycler#_getDomFocusableItemReturns the next or previous focusable view in
focusableswith respect tocurrent.Parameters
step : 1 | 1Either
1for checking forward fromcurrentor-1for checking backwards.
Returns
null | FocusableView
Events
backwardCycle( eventInfo )module:ui/focuscycler~FocusCycler#event:backwardCycleFired when the focus cycler is about to move the focus from the first focusable item to the last one.
Parameters
eventInfo : EventInfoAn object containing information about the fired event.
forwardCycle( eventInfo )module:ui/focuscycler~FocusCycler#event:forwardCycleFired when the focus cycler is about to move the focus from the last focusable item to the first one.
Parameters
eventInfo : EventInfoAn object containing information about the fired event.