Package com.smartgwt.client.widgets

# Class TabIndexManager

java.lang.Object
com.smartgwt.client.widgets.TabIndexManager

public class TabIndexManager extends Object
Singleton class with static APIs for managing automatically assigned tab order for Smart GWT components and other focusable elements.

The TabIndexManager separates the logic required to maintain a sensible tab-order for a page's components from the logic to handle allocation of actual tab index values. It is common to have non-focusable components with an implied position in the page's tab order - for example Layouts containing focusable buttons, or DynamicForms containing focusable items, and this class handles maintaining relative tab order within such groups, and supplying explicit TabIndex values for the items which actually need them.

Entries are registered with the TabIndexManager via the `addTarget()` API. A numeric tab index for each entry will be lazily generated when requested via `getTabIndex()`. The class provides APIs to modify the position of entries in the tab tree. When a target is registered, a couple of custom callback functions can be provided. The first is a notification method for the tab index being updated (due to, for example, a parent being repositioned and all its children having new tab indices assigned), and can be used to take an appropriate action such as updating the tab index of an element in the DOM. The second callback will be fired when a call to the special `focusInTarget()` or `shiftFocus()` API requests focus be passed to an entry. This allows a developer to take an appropriate action (such as programmatically focussing in some DOM element).

For standard Smart GWT components (focusable `canvases` and `formItems`), developers will typically use APIs directly on the widget to customize tab sequence behavior rather than interacting with the TabIndexManager class. See the `tab order overview` topic for more information on tab order management for components in Smart GWT.
Developers wishing to embed focusable components into a page which are not Smart GWT components (native HTML elements and third party widgets), may use TabIndexManager APIs to do so. This process is described in `CustomTabElements`.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `TabIndexManager()`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static void`
  `addTarget(String ID, boolean canFocus)`
  Register a target to have its tab order position managed by the TabIndexManager.
  `static void`
  `addTarget(String ID, boolean canFocus, String parentID)`
  `static void`
  `addTarget(String ID, boolean canFocus, String parentID, Integer position)`
  `static void`
  `addTarget(String ID, boolean canFocus, String parentID, Integer position, TabIndexUpdatedCallback tabIndexUpdatedCallback)`
  `static void`
  `addTarget(String ID, boolean canFocus, String parentID, Integer position, TabIndexUpdatedCallback tabIndexUpdatedCallback, ShiftFocusCallback shiftFocusCallback)`
  Register a target to have its tab order position managed by the TabIndexManager.
  `static boolean`
  `focusInTarget(String ID)`
  Request the TabIndexManager shift focus to a registered focus target.
  `static String`
  `getAllocatedTabChain()`
  Get a report of the current hierarchy of targets passed to `addTarget()` together with current canFocus state and tabIndex (if assigned).
  `static Integer`
  `getTabIndex(String ID)`
  Returns a tabIndex number for some target ID registered via `addTarget()`.
  `static boolean`
  `hasTarget(String ID)`
  Has the specified target been added to this TabIndexManager via `addTarget()`?
  `static void`
  `moveTarget(String ID)`
  Move a target to the newly specified parent / position.
  `static void`
  `moveTarget(String ID, String parentID)`
  `static void`
  `moveTarget(String ID, String parentID, Integer position)`
  Move a target to the newly specified parent / position.
  `static void`
  `moveTargets(String[] IDs)`
  Move a list of targets to the newly specified parent / position.
  `static void`
  `moveTargets(String[] IDs, String parentID)`
  `static void`
  `moveTargets(String[] IDs, String parentID, Integer position)`
  Move a list of targets to the newly specified parent / position.
  `static void`
  `removeTarget(String ID)`
  Removes a target from this TabIndexManager.
  `static void`
  `resumeCallbacks(String[] targets)`
  Resume firing any callbacks suppressed by `suppressCallbacks()`
  `static void`
  `setAlwaysUseExplicitFocusNavigation(boolean newValue)`
  Should `useExplicitFocusNavigation()` to always return true?
  `static void`
  `setCanFocus(String ID, boolean canFocus)`
  Modifies whether or not some specified target should be treated as focusable and provide a meaningful TabIndex on a call to `getTabIndex()`.
  `static void`
  `setUseExplicitFocusNavigation(String ID, boolean newValue)`
  Mark the specified node (and its descendents) as using explicit focus navigation rather than relying on native browser Tab event handling behavior.
  `static boolean`
  `shiftFocus(String ID, boolean forward)`
  Method to shift focus to the next registered focusable target.
  `static boolean`
  `shiftFocusAfterGroup(String targetGroup, boolean forward)`
  Method to shift focus to the next registered focusable target beyond some registered target and any targets registered as children within its group via `addTarget()` or `moveTarget()`.
  `static boolean`
  `shiftFocusWithinGroup(String targetGroup, String currentTarget, boolean forward)`
  Method to shift focus to the next registered focusable target within some group.
  `static void`
  `showAllocatedTabChain()`
  Show the current hierarchy of targets passed to `addTarget()` together with current canFocus state and tabIndex (if assigned).
  `static void`
  `suppressCallbacks(String[] targets)`
  Temporarily suppress firing any tabIndexChanged callback passed into `addTarget()` for the specified targets should their tab index change.
  `static boolean`
  `useExplicitFocusNavigation(String ID)`
  Should focus navigation be achieved by explicitly calling the TabIndexManager `shiftFocus()` method for the specified node?

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Constructor Details

  - ### TabIndexManager

    public TabIndexManager()

- ## Method Details

  - ### addTarget

    public static void addTarget(String ID, boolean canFocus)
    Register a target to have its tab order position managed by the TabIndexManager.
    Parameters:
      `ID` - Unique ID to associate with a tab position. For a Canvas this would typically be the `Canvas.ID` but any unique string is valid.
      `canFocus` - Is this target directly focusable? Governs whether an explicit tabIndex will be created for this target. This parameter should be passed as `false` for targets which do not require an explicit tabIndex as they are not focusable, or not explicit tab-stops for the user tabbing through the page. They will still have an implicit tab order position which governs where descendants appear, and would be used to generate a tabIndex if canFocus is subsequently updated via `setCanFocus()`.

  - ### addTarget

    public static void addTarget(String ID, boolean canFocus, String parentID)
    See Also:
      - `addTarget(java.lang.String, boolean)`

  - ### addTarget

    public static void addTarget(String ID, boolean canFocus, String parentID, Integer position)
    See Also:
      - `addTarget(java.lang.String, boolean)`

  - ### addTarget

    public static void addTarget(String ID, boolean canFocus, String parentID, Integer position, TabIndexUpdatedCallback tabIndexUpdatedCallback)
    See Also:
      - `addTarget(java.lang.String, boolean)`

  - ### addTarget

    public static void addTarget(String ID, boolean canFocus, String parentID, Integer position, TabIndexUpdatedCallback tabIndexUpdatedCallback, ShiftFocusCallback shiftFocusCallback)
    Register a target to have its tab order position managed by the TabIndexManager.
    Parameters:
      `ID` - Unique ID to associate with a tab position. For a Canvas this would typically be the `Canvas.ID` but any unique string is valid.
      `canFocus` - Is this target directly focusable? Governs whether an explicit tabIndex will be created for this target. This parameter should be passed as `false` for targets which do not require an explicit tabIndex as they are not focusable, or not explicit tab-stops for the user tabbing through the page. They will still have an implicit tab order position which governs where descendants appear, and would be used to generate a tabIndex if canFocus is subsequently updated via `setCanFocus()`.
      `parentID` - For cases where the tab position should be treated part of a group to be moved together, the ID of the parent target containing all members of this group. An example of this would be a Layout managing the tab order of all its members. If present, the passed parentID must already be being managed by this TabIndexManager. May be updated for registered targets via `moveTarget()`.
      `position` - Position in the tab-order within the specified parent [or within top level widgets]. Omitting this parameter will add the target to the end of the specified parent's tab group. May be updated for registered targets via `moveTarget()`.
      `tabIndexUpdatedCallback` - This notification method will be fired when the tabIndex is actually updated, typically due to the target, or some parent of it being re-positioned in the managed Tab order. In some cases tab indices may also be updated to make space for unrelated entries being added to the TabIndexManager. This notification is typically used to update the appropriate element in the DOM to reflect a new tab index.
      `shiftFocusCallback` - This notification method will be fired when the special `shiftFocus()` method is called to programmatically move focus through the registered targets (simulating the user tabbing through elements in the tab index chain). The implementation should attempt to update the UI state by focusing in the appropriate UI for this target -- typically this means putting browser focus into a DOM element, and return true to indicate success.
      Returning false indicates the element is currently not focusable (disabled, masked, etc), and cause the TabIndexManager to call the shiftFocusCallback on the next registered entry (skipping over this entry).
      If this method was not supplied, calls to `shiftFocus()` will simply skip this entry.

  - ### focusInTarget

    public static boolean focusInTarget(String ID)
    Request the TabIndexManager shift focus to a registered focus target.

    This method does not directly change the focus within the DOM - instead it invokes the `shiftFocusCallback` registered for the specified target if it is marked as `canFocus:true`.

    Returns false if the target had no no `shiftFocusCallback`, the `shiftFocusCallback` returned false, or if the target is marked as not `canFocus:true`

    Parameters:
      `ID` - target to shift focus to
    Returns:
      returns false to indicate failure to shift focus.

  - ### getAllocatedTabChain

    public static String getAllocatedTabChain()
    Get a report of the current hierarchy of targets passed to `addTarget()` together with current canFocus state and tabIndex (if assigned).
    Returns:

  - ### getTabIndex

    public static Integer getTabIndex(String ID)
    Returns a tabIndex number for some target ID registered via `addTarget()`. Generated tab indices are guaranteed to be in order.

    As targets are added to, or moved within the TabIndexManager, their tab index may become invalid. The `tabIndexUpdated` notification will be fired when this occurs, giving developers a way to pick up the new tab index, and assign it to the appropriate DOM element if appropriate.

    Parameters:
      `ID` - ID of the target for which you want to get a numeric tabIndex.
    Returns:
      returns the numeric tabIndex value for the specified target

  - ### hasTarget

    public static boolean hasTarget(String ID)
    Has the specified target been added to this TabIndexManager via `addTarget()`?
    Parameters:
      `ID` - Unique ID to test for.
    Returns:
      true if we are managing the tab index for the specified target

  - ### moveTarget

    public static void moveTarget(String ID)
    Move a target to the newly specified parent / position. This method may change the calculated tab index for this entry, or other canFocus:true entries which already have a calculated tabIndex. The registered tabIndexUpdated notification method will for for any entry where this occurs.
    Parameters:
      `ID` - ID of the target to move

  - ### moveTarget

    public static void moveTarget(String ID, String parentID)
    See Also:
      - `moveTarget(java.lang.String)`

  - ### moveTarget

    public static void moveTarget(String ID, String parentID, Integer position)
    Move a target to the newly specified parent / position. This method may change the calculated tab index for this entry, or other canFocus:true entries which already have a calculated tabIndex. The registered tabIndexUpdated notification method will for for any entry where this occurs.
    Parameters:
      `ID` - ID of the target to move
      `parentID` - ID of the new parent (if null, will move to the top level)
      `position` - Position within the specified parent. If null will be the last entry.

  - ### moveTargets

    public static void moveTargets(String[] IDs)
    Move a list of targets to the newly specified parent / position. This method may change the calculated tab index for these entries, or other canFocus:true entries which already have a calculated tabIndex. The registered tabIndexUpdated notification method will for for any entry where this occurs.
    Parameters:
      `IDs` - IDs of the targets to move

  - ### moveTargets

    public static void moveTargets(String[] IDs, String parentID)
    See Also:
      - `moveTargets(java.lang.String[])`

  - ### moveTargets

    public static void moveTargets(String[] IDs, String parentID, Integer position)
    Move a list of targets to the newly specified parent / position. This method may change the calculated tab index for these entries, or other canFocus:true entries which already have a calculated tabIndex. The registered tabIndexUpdated notification method will for for any entry where this occurs.
    Parameters:
      `IDs` - IDs of the targets to move
      `parentID` - ID of the new parent (if null, will move to the top level)
      `position` - Position within the specified parent. If null will be added at the end

  - ### removeTarget

    public static void removeTarget(String ID)
    Removes a target from this TabIndexManager. Any children of this target will also be removed - developers wishing to preserve children should first call `moveTarget()` to move the children out of this parent
    Parameters:
      `ID` - target to remove

  - ### resumeCallbacks

    public static void resumeCallbacks(String[] targets)
    Resume firing any callbacks suppressed by `suppressCallbacks()`
    Parameters:
      `targets` - targets for which callbacks should be resumed
    See Also:
      - `suppressCallbacks(java.lang.String[])`

  - ### setAlwaysUseExplicitFocusNavigation

    public static void setAlwaysUseExplicitFocusNavigation(boolean newValue)
    Should `useExplicitFocusNavigation()` to always return true?
    Parameters:
      `newValue` - whether we should always use explicit focus navigation

  - ### setCanFocus

    public static void setCanFocus(String ID, boolean canFocus)
    Modifies whether or not some specified target should be treated as focusable and provide a meaningful TabIndex on a call to `getTabIndex()`.
    Parameters:
      `ID` - target ID
      `canFocus` - new value for canFocus

  - ### setUseExplicitFocusNavigation

    public static void setUseExplicitFocusNavigation(String ID, boolean newValue)
    Mark the specified node (and its descendents) as using explicit focus navigation rather than relying on native browser Tab event handling behavior. See `useExplicitFocusNavigation()` for more information.
    Parameters:
      `ID` - registered TabIndexManager target
      `newValue` - should explicit focus navigation be used for the specified target and its descendents

  - ### shiftFocus

    public static boolean shiftFocus(String ID, boolean forward)
    Method to shift focus to the next registered focusable target.

    This method does not directly change the focus within the DOM - instead it finds the next target marked as `canFocus:true`, and invokes the `shiftFocusCallback` registered for that target. This callback is expected to take the appropriate action (typically shifting native focus to an element in the DOM), and return true (or return false, if the target could not receieve focus for some reason, in which case we'll find the next `canFocus:true` target and repeat the action there.

    Targets with no `shiftFocusCallback` will be skipped entirely in this process.

    Parameters:
      `ID` - current focus target. If null, focus will be applied to the first focusable target (or the last if the `forward` parameter is false).
      `forward` - should focus move forward to the next focusable target, or backward to the previous focusable target.
    Returns:
      returns true to indicate focus was successfully shifted, false to indicate this method was unable to change focus.

  - ### shiftFocusAfterGroup

    public static boolean shiftFocusAfterGroup(String targetGroup, boolean forward)
    Method to shift focus to the next registered focusable target beyond some registered target and any targets registered as children within its group via `addTarget()` or `moveTarget()`.

    This method does not directly change the focus within the DOM - instead it finds the next target marked as `canFocus:true`, and invokes the `shiftFocusCallback` registered for that target. This callback is expected to take the appropriate action (typically shifting native focus to an element in the DOM), and return true (or return false, if the target could not receieve focus for some reason, in which case we'll find the next `canFocus:true` target and repeat the action there.

    Targets with no `shiftFocusCallback` will be skipped entirely in this process.

    A return value of false indicates that this method was unable to shift focus to a new target.

    Parameters:
      `targetGroup` - ID of registered target. Focus will be shifted to the next registered focusable element, skipping this group and its descendants.
      `forward` - should focus move forward to the next focusable target, or backward to the previous focusable target.
    Returns:
      returns true to indicate focus was successfully shifted, false to indicate this method was unable to change focus.

  - ### shiftFocusWithinGroup

    public static boolean shiftFocusWithinGroup(String targetGroup, String currentTarget, boolean forward)
    Method to shift focus to the next registered focusable target within some group. This method will move focus forward or backward, considering only the specified target and any targets within its group (registered as children of the target via `addTarget()` or `moveTarget()`).

    The second parameter can be passed to specify an explicit starting position to shift focus from. If this is not present, this method will attempt to focus into the group target itself if moving forward (or its last child, if moving backward) and failing that, shift focus from there.

    This method does not directly change the focus within the DOM - instead it finds the next target marked as `canFocus:true`, and invokes the `shiftFocusCallback` registered for that target. This callback is expected to take the appropriate action (typically shifting native focus to an element in the DOM), and return true (or return false, if the target could not receieve focus for some reason, in which case we'll find the next `canFocus:true` target and repeat the action there.

    Targets with no `shiftFocusCallback` will be skipped entirely in this process.

    A return value of false indicates that this method was unable to shift focus to a new target.

    Parameters:
      `targetGroup` - ID of registered target. Focus will be shifted within this target and its descendants only.
      `currentTarget` - Optional ID of current focus target within the group focus will be shifted in the specified direction from this node.
      `forward` - should focus move forward to the next focusable target, or backward to the previous focusable target.
    Returns:
      returns true to indicate focus was successfully shifted, false to indicate this method was unable to change focus.

  - ### showAllocatedTabChain

    public static void showAllocatedTabChain()
    Show the current hierarchy of targets passed to `addTarget()` together with current canFocus state and tabIndex (if assigned). Results are output to the developer console.

  - ### suppressCallbacks

    public static void suppressCallbacks(String[] targets)
    Temporarily suppress firing any tabIndexChanged callback passed into `addTarget()` for the specified targets should their tab index change.

    This is useful for cases where a developer is managing a list of items and wants to avoid any potential for multiple notifications until the entire list has been managed

    Parameters:
      `targets` - targets for which callbacks should be suppressed
    See Also:
      - `resumeCallbacks(java.lang.String[])`

  - ### useExplicitFocusNavigation

    public static boolean useExplicitFocusNavigation(String ID)
    Should focus navigation be achieved by explicitly calling the TabIndexManager `shiftFocus()` method for the specified node?

    Developers integrating custom focusable element's into a Smart GWT based application can use this method to ensure the elements in question interact correctly with `click masks` and `grid editing`. See the `tab order overview` topic for more information on integrating custom focusable UI into a Smart GWT application.

    This method will return true if the `setAlwaysUseExplicitFocusNavigation()` has been set to true (typically because a `click mask` is showing), or if the entry or some ancestor has been marked as `useExplicitFocusNavigation:true`. Note that this is the case for entries registered under a canvas with `Canvas.alwaysManageFocusNavigation` set to true.

    Parameters:
      `ID` - TabIndexManager registered target ID
    Returns:
      true if explicit focus navigation should be used