node-focusmanager-debug.js revision 33238af221f82ed28e0724a5ca7fbf93b241157a
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* <p>The Focus Manager Node Plugin makes it easy to manage focus among
b34025e1e963e60c0f81c01af0f25f1984b9ca54James Phillpotts* a Node's descendants. Primarily intended to help with widget development,
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* the Focus Manager Node Plugin can be used to improve the keyboard
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* accessibility of widgets.</p>
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* When designing widgets that manage a set of descendant controls (i.e. buttons
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* in a toolbar, tabs in a tablist, menuitems in a menu, etc.) it is important to
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* limit the number of descendants in the browser's default tab flow. The fewer
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington* number of descendants in the default tab flow, the easier it is for keyboard
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington* users to navigate between widgets by pressing the tab key. When a widget has
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* focus it should provide a set of shortcut keys (typically the arrow keys)
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* to move focus among its descendants.
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* To this end, the Focus Manager Node Plugin makes it easy to define a Node's
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* focusable descendants, define which descendant should be in the default tab
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* flow, and define the keys that move focus among each descendant.
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* Additionally, as the CSS
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* <a href="http://www.w3.org/TR/CSS21/selector.html#x38"><code>:focus</code></a>
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* pseudo class is not supported on all elements in all
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* <a href="http://developer.yahoo.com/yui/articles/gbs/">A-Grade browsers</a>,
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* the Focus Manager Node Plugin provides an easy, cross-browser means of
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* styling focus.
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* @module node-focusmanager
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Frequently used strings
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Collection of keys that, when pressed, cause the browser viewport
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // to scroll.
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Library shortcuts
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington* The NodeFocusManager class is a plugin for a Node instance. The class is used
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* via the <a href="Node.html#method_plug"><code>plug</code></a> method of Node
57dbf0bab2990776a4836cd12f10f2fb6af9352cEugenia Sergueeva* and should not be instantiated directly.
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden* @namespace plugin
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* @class NodeFocusManager
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavitvar NodeFocusManager = function () {
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit NodeFocusManager.superclass.constructor.apply(this, arguments);
hasFocus: {
value: false,
readOnly: true
descendants: {
if (descendants) {
return returnValue;
keys: {
value: {
next: null,
previous: null
focusClass: { },
circular: {
value: true
_stopped: true,
_descendants: null,
_descendantsMap: null,
_focusedNode: null,
_eventHandlers: null,
_initDescendants: function () {
descendantsMap = {},
sID,
if (descendants) {
nFirstEnabled = i;
nActiveDescendant = i;
if (!sID) {
_removeFocusClass: function () {
_detachKeyHandler: function () {
if (prevKeyHandler) {
if (nextKeyHandler) {
if (keyPressHandler) {
_attachKeyHandler: function () {
this._detachKeyHandler();
if (sPreviousKey) {
this._prevKeyHandler =
if (sNextKey) {
this._nextKeyHandler =
this._keyPressHandler =
_detachEventHandlers: function () {
this._detachKeyHandler();
if (aHandlers) {
this._eventHandlers = null;
_attachEventHandlers: function () {
this._afterActiveDescendantChange));
this._attachKeyHandler();
if (this._focusTarget) {
this._focusTarget = null;
bHasFocus = true;
bHasFocus = false;
bHasFocus = false;
if (sClassName) {
this._removeFocusClass();
this._attachEventHandlers();
if (oNode) {
if (oNode) {
this.start();
destructor: function () {
this.stop();
if (oNode) {
blur: function () {
var oNode;
if (oNode) {
this._removeFocusClass();
start: function () {
if (this._stopped) {
this._initDescendants();
this._attachEventHandlers();
this._stopped = false;
stop: function () {
if (!this._stopped) {
this._detachEventHandlers();
this._descendants = null;
this._focusedNode = null;
this._stopped = true;
refresh: function () {
this._initDescendants();