focusable

caph.focus. focusable

An attribute directive which represents the focusable element. When you want to use key navigation, just add this directive to target element's attribute.

 <div focusable></div>

All elements which are specified by this directive automatically have three additional properties such as depth, group and name. By default, depth value will be 0 and group value will be 'default' and name value will be sequential string like 'focusable-0'.

These properties and their values are also stored in the element's data object through jQuery's .data() API. jQuery's .data() API will be automatically associated with HTML5 data attributes. (So this module depends on jQuery 1.7 above.) So you can change these values like below. (Note that each property has 'focusable' prefix.)

 <div focusable data-focusable-depth="0" data-focusable-group="default" data-focusable-name="focusable-0"></div>

Of course, you can set these values to whatever you want.

 <div focusable data-focusable-depth="1" data-focusable-group="test" data-focusable-name="focus1"></div>

You can set all of these values by using expressions.

 <div focusable data-focusable-depth="{{depth}}" data-focusable-group="{{group}}" data-focusable-name="{{name}}"></div>

But, these are not changed when the corresponding interpolated value is changed. (It means do not observe the attribute value.)

This directive provides another way to set focusable data. Pass the focusable option object without 'focusable' prefix to the focusable attribute value.

 <div focusable="{depth: 1, group: 'test', name: 'focus1'}"></div>

This usage is equivalent to the above HTML5 data attributes usage. These values are also stored in the element's data object through jQuery's .data() API.

So then, what is 'depth', 'group' and 'name'?

The 'depth' is used when moving focus to another focusable element. The focus will be changed only between the same depth. So if there is no same depth focusable element, the focus will not be changed.

The 'group' separates focusable area semantically. Even if group is not equal to each other, the focus can be changed if each depth is same. Separating groups is useful when you manage each group's previous focusable element history by calling focus controller's 'setGroup' API.

The 'name' is used when setting the next focus to the specific element, or changing focus to another focusable element by calling focus controller's 'focus' API. Each name should be an unique value.

If you need more information about the focus controller API, refer to the focus controller documentation.

This module automatically finds the nearest focusable element from the given direction using 'nearestFocusableFinder'. If you want to set the next focusable element manually, you can do it by using 'next-focus-direction' option. The direction values are 'left', 'right', 'up', 'down'.

 <div focusable data-focusable-name="focus1" data-focusable-next-focus-right="focus2"></div>
 <div focusable data-focusable-name="focus2"></div>

Of course, you can use the focusable option object to set the next focusable value.

 <div focusable="{name: 'focus1', nextFocus: {right: 'focus2'}}"></div>
 <div focusable="{name: 'focus2'}"></div>

It seems to be similar with 'depth', 'group' and 'name' setting. But, it uses the 'nextFocus' for option name and each direction is used to that name's property.

The 'next-focus-direction' option supports to change the group. You can change the group easily by concatenating 'group:' prefix and option value. (You can also change the group by using 'setGroup' API.)

 <div focusable data-focusable-group="test1" data-focusable-next-focus-down="group:test2"></div>
 <div focusable data-focusable-group="test2" data-focusable-next-focus-up="group:test1"></div>

If you do not want to change the focus to the specific direction anymore, set the corresponding 'next-focus-direction' option to null.

 <div focusable data-focusable-next-focus-left="null"></div>

You can set auto focus element by setting 'initial-focus' option to true.

 <div focusable data-focusable-initial-focus="true"></div>

You can use the focusable option object, like the previous usage. It uses the camelcase instead of the snakecase like the next focusable setting.

 <div focusable="{initialFocus: true}"></div>

The initial focus element should be only one per depth and group. If you set multiple initial focus, the last compiled focusable element will become an initial focus.

Every focusable element receives event when focused, blurred or selected. So you can attach the event handler to receive corresponding events. The event handler function should be able to be referred by the current scope.

 <div focusable on-focused="focus($event, $originalEvent)" on-blurred="blur($event, $originalEvent)" on-selected="select($event, $originalEvent)"></div>

Every event handler function has two arguments such as '$event' and '$originalEvent'. The '$event' parameter is a custom jQuery event object such as 'focused', 'blurred' and 'selected'. So if you want to know where this event comes from, you should refer to the '$originalEvent'. The '$originalEvent' is real DOM jQuery event object such as 'keydown', 'mouseover', 'mouseout' and 'click'.

You can receive the events through attaching event handler to DOM directly.

 $('[focusable]').on('focused blurred selected', function(event) {
     // your code here
 });

Note that you should properly detach the appended event handlers by yourself when DOM is removed.

By default, add 'focused' class to focusable element when focused. If blurred, 'focused' class will be removed. So, if you define the corresponding 'focused' style, will be able to make focus effect without attaching event handlers.

All focusable elements are able to be disabled or enabled. If you want to enable or disable focusable element, change the 'disabled' option.

 <div focusable data-focusable-disabled="true"></div>

If you want to change the status, use focus controller's APIs. The focus controller conveniently provides 'enable' and 'disable' APIs for these functionality. See the focus controller documentation for more API details.

 <div focusable="{name: 'test', disabled: true}"></div>
 angular.module('myApp', ['caph.focus']).controller('myController', ['focusController', function(focusController) {
     focusController.enable('test');
 }]);

When focusable element is disabled, 'disabled' class is added to it. If enabled, 'disabled' class will be removed.

By default, if a focusable element is disabled, it will no longer receive a focus event. But you can get a focus event even if focusable element is disabled, using the focus controller provider's 'setFocusWhenDisabled' API. See the focus controller provider documentation for more API details.