node-focusmanager-debug.js revision 33238af221f82ed28e0724a5ca7fbf93b241157a
80802511792d4e59a4ac67ad19677009d332b37dBruno LavitYUI.add('node-focusmanager', function(Y) {
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit/**
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*
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* <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* </p>
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington*
e8de1e738afe1a537edb414b90c477e85e7905cfJake Feasel* <p>
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* </p>
b34025e1e963e60c0f81c01af0f25f1984b9ca54James Phillpotts*
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit* @module node-focusmanager
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit*/
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Frequently used strings
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavitvar ACTIVE_DESCENDANT = "activeDescendant",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit ID = "id",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit DISABLED = "disabled",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit TAB_INDEX = "tabIndex",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit HAS_FOCUS = "hasFocus",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit FOCUS_CLASS = "focusClass",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit CIRCULAR = "circular",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit UI = "UI",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit KEY = "key",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit FOCUS_MANAGER = "focusManager",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit HOST = "host",
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Collection of keys that, when pressed, cause the browser viewport
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // to scroll.
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit scrollKeys = {
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit 37: true,
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden 38: true,
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit 39: true,
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden 40: true
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden },
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit // Library shortcuts
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit Lang = Y.Lang,
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit UA = Y.UA;
5caa48b139aecab3a2df366a8d71954a0d9f2247Neil Madden
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit/**
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
e8de1e738afe1a537edb414b90c477e85e7905cfJake Feasel*/
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavitvar NodeFocusManager = function () {
685810e390056c123842842f5104daa3179cf2c9Phill Cunnington
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit NodeFocusManager.superclass.constructor.apply(this, arguments);
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit};
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
80802511792d4e59a4ac67ad19677009d332b37dBruno Lavit
NodeFocusManager.ATTRS = {
/**
* Boolean indicating that one of the descendants is focused.
*
* @attribute hasFocus
* @readOnly
* @default false
* @type boolean
*/
hasFocus: {
value: false,
readOnly: true
},
/**
* String representing the CSS selector used to define the descendant Nodes
* whose focus should be managed.
*
* @attribute descendants
* @type string
*/
descendants: {
getter: function (value) {
return this.get(HOST).queryAll(value);
}
},
/**
* <p>Node, or index of the Node, representing the descendant that is either
* focused or is focusable (<code>tabIndex</code> attribute is set to 0).
* The value cannot represent a disabled descendant Node. Use a value of -1
* to remove all descendant Nodes from the default tab flow.
* If no value is specified, the active descendant will be inferred using
* the following criteria:</p>
* <ol>
* <li>Examining the <code>tabIndex</code> attribute of each descendant and
* using the first descendant whose <code>tabIndex</code> attribute is set
* to 0</li>
* <li>If no default can be inferred then the value is set to either 0 or
* the index of the first enabled descendant.</li>
* </ol>
*
* @attribute activeDescendant
* @type Number
*/
activeDescendant: {
setter: function (value) {
var isNumber = Lang.isNumber,
INVALID_VALUE = Y.Attribute.INVALID_VALUE,
descendantsMap = this._descendantsMap,
descendants = this._descendants,
nodeIndex,
returnValue,
oNode;
if (isNumber(value)) {
nodeIndex = value;
returnValue = nodeIndex;
}
else if ((value instanceof Y.Node) && descendantsMap) {
nodeIndex = descendantsMap[value.get(ID)];
if (isNumber(nodeIndex)) {
returnValue = nodeIndex;
}
else {
// The user passed a reference to a Node that wasn't one
// of the descendants.
returnValue = INVALID_VALUE;
}
}
else {
returnValue = INVALID_VALUE;
}
if (descendants) {
oNode = descendants.item(nodeIndex);
if (oNode && oNode.get("disabled")) {
// Setting the "activeDescendant" attribute to the index
// of a disabled descendant is invalid.
returnValue = INVALID_VALUE;
}
}
return returnValue;
}
},
/**
* Object literal representing the keys to be used to navigate between the
* next/previous decendant. The format for the attribute's value is
* <code>{ next: "down:40", previous: "down:38" }</code>. The value for the
* "next" and "previous" properties are used to attach
* <a href="event/#keylistener"><code>key</code></a> event listeners. See
* the <a href="event/#keylistener">Using the key Event</a> section of
* the Event documentation for more information on "key" event listeners.
*
* @attribute keys
* @type Object
*/
keys: {
value: {
next: null,
previous: null
}
},
/**
* String representing the CSS class name used to indicate the Node instance
* that currently has DOM focus.
*
* @attribute focusClass
* @type String
*/
focusClass: { },
/**
* Boolean indicating if focus should be set to the first/last descendant
* when the end or beginning of the descendants has been reached.
*
* @attribute circular
* @type Boolean
*/
circular: {
value: true
}
};
Y.extend(NodeFocusManager, Y.Plugin.Base, {
// Protected properties
// Boolean indicating if the NodeFocusManager is active.
_stopped: true,
// NodeList representing the descendants selected via the
// "descendants" attribute.
_descendants: null,
// Object literal mapping the IDs of each descendant to its index in the
// "_descendants" NodeList.
_descendantsMap: null,
// Reference to the Node instance to which the focused CSS class (defined
// by the "focusClass" attribute) is currently applied.
_focusedNode: null,
// Number representing the index of the last descendant Node.
_lastNodeIndex: 0,
// Array of handles for event handlers used for a NodeFocusManager instance.
_eventHandlers: null,
// Protected methods
/**
* @method _initDescendants
* @description Sets the <code>tabIndex</code> attribute of all of the
* descendants to -1, except the active descendant, whose
* <code>tabIndex</code> attribute is set to 0.
* @protected
*/
_initDescendants: function () {
var descendants = this.get("descendants"),
descendantsMap = {},
nFirstEnabled = -1,
nDescendants,
nActiveDescendant = this.get(ACTIVE_DESCENDANT),
oNode,
sID,
i = 0;
if (Lang.isUndefined(nActiveDescendant)) {
nActiveDescendant = -1;
}
if (descendants) {
nDescendants = descendants.size();
if (nDescendants > 1) {
for (i = 0; i < nDescendants; i++) {
oNode = descendants.item(i);
if (nFirstEnabled === -1 && !oNode.get(DISABLED)) {
nFirstEnabled = i;
}
// If the user didn't specify a value for the
// "activeDescendant" attribute try to infer it from
// the markup.
if (nActiveDescendant < 0 &&
oNode.getAttribute(TAB_INDEX) === "0") {
nActiveDescendant = i;
}
oNode.set(TAB_INDEX, -1);
sID = oNode.get(ID);
if (!sID) {
sID = Y.guid();
oNode.set(ID, sID);
}
descendantsMap[sID] = i;
}
// If the user didn't specify a value for the
// "activeDescendant" attribute and no default value could be
// determined from the markup, then default to 0.
if (nActiveDescendant < 0) {
nActiveDescendant = 0;
}
oNode = descendants.item(nActiveDescendant);
// Check to make sure the active descendant isn't disabled,
// and fall back to the first enabled descendant if it is.
if (!oNode || oNode.get(DISABLED)) {
oNode = descendants.item(nFirstEnabled);
nActiveDescendant = nFirstEnabled;
}
this._lastNodeIndex = nDescendants - 1;
this._descendants = descendants;
this._descendantsMap = descendantsMap;
this.set(ACTIVE_DESCENDANT, nActiveDescendant);
// Need to set the "tabIndex" attribute here, since the
// "activeDescendantChange" event handler used to manage
// the setting of the "tabIndex" attribute isn't wired up yet.
oNode.set(TAB_INDEX, 0);
}
}
},
/**
* @method _isDescendant
* @description Determines if the specified Node instance is a descendant
* managed by the Focus Manager.
* @param node {Node} Node instance to be checked.
* @return {Boolean} Boolean indicating if the specified Node instance is a
* descendant managed by the Focus Manager.
* @protected
*/
_isDescendant: function (node) {
return (node.get(ID) in this._descendantsMap);
},
/**
* @method _removeFocusClass
* @description Removes the CSS class representing focus (as specified by
* the "focusClass" attribute) from the Node instance to which it is
* currently applied.
* @protected
*/
_removeFocusClass: function () {
var oFocusedNode = this._focusedNode,
sClassName = this.get(FOCUS_CLASS);
if (oFocusedNode && sClassName) {
oFocusedNode.removeClass(sClassName);
}
},
/**
* @method _detachKeyHandler
* @description Detaches the "key" event handlers used to support the "keys"
* attribute.
* @protected
*/
_detachKeyHandler: function () {
var prevKeyHandler = this._prevKeyHandler,
nextKeyHandler = this._nextKeyHandler,
keyPressHandler = this._keyPressHandler;
if (prevKeyHandler) {
prevKeyHandler.detach();
}
if (nextKeyHandler) {
nextKeyHandler.detach();
}
if (keyPressHandler) {
keyPressHandler.detach();
}
},
/**
* @method _preventScroll
* @description Prevents the viewport from scolling when the user presses
* the up, down, left, or right key.
* @protected
*/
_preventScroll: function (event) {
if (scrollKeys[event.keyCode]) {
event.preventDefault();
}
},
/**
* @method _attachKeyHandler
* @description Attaches the "key" event handlers used to support the "keys"
* attribute.
* @protected
*/
_attachKeyHandler: function () {
this._detachKeyHandler();
var sNextKey = this.get("keys.next"),
sPreviousKey = this.get("keys.previous"),
oNode = this.get(HOST);
if (sPreviousKey) {
this._prevKeyHandler =
Y.on(KEY, Y.bind(this._focusPrevious, this), oNode, sPreviousKey);
}
if (sNextKey) {
this._nextKeyHandler =
Y.on(KEY, Y.bind(this._focusNext, this), oNode, sNextKey);
}
// For Opera and Firefox 2: In these browsers it is necessary to
// call the "preventDefault" method on a "keypress" event in order
// to prevent the viewport from scrolling.
if (UA.opera || (UA.gecko && UA.gecko < 1.9)) {
this._keyPressHandler =
oNode.on("keypress", Y.bind(this._preventScroll, this));
}
},
/**
* @method _detachEventHandlers
* @description Detaches all event handlers used by the Focus Manager.
* @protected
*/
_detachEventHandlers: function () {
this._detachKeyHandler();
var aHandlers = this._eventHandlers;
if (aHandlers) {
Y.Array.each(aHandlers, function (handle) {
handle.detach();
});
this._eventHandlers = null;
}
},
/**
* @method _detachEventHandlers
* @description Attaches all event handlers used by the Focus Manager.
* @protected
*/
_attachEventHandlers: function () {
var descendants = this._descendants,
aHandlers,
oDocument;
if (descendants && descendants.size() > 1) {
aHandlers = this._eventHandlers || [];
oDocument = this.get(HOST).get("ownerDocument");
// For performance: defer attaching all event handlers until the
// first time one of the specified descendants receives focus
if (aHandlers.length === 0) {
aHandlers.push(
Y.on("focus", Y.bind(this._onDocFocus, this), oDocument));
aHandlers.push(
Y.on("mousedown",
Y.bind(this._onDocMouseDown, this), oDocument));
aHandlers.push(
this.after("keysChange", this._attachKeyHandler));
aHandlers.push(
this.after("descendantsChange", this._initDescendants));
aHandlers.push(
this.after(ACTIVE_DESCENDANT_CHANGE,
this._afterActiveDescendantChange));
}
else {
this._attachKeyHandler();
}
this._eventHandlers = aHandlers;
}
},
// Protected event handlers
/**
* @method _onDocMouseDown
* @description "mousedown" event handler for the owner document of the
* Focus Manager's Node.
* @protected
* @param event {Object} Object representing the DOM event.
*/
_onDocMouseDown: function (event) {
var oTarget = event.target,
bChildNode = this.get(HOST).contains(oTarget);
if (bChildNode && this._isDescendant(oTarget)) {
// Fix general problem in Webkit: mousing down on a button or an
// anchor element doesn't focus it.
// For all browsers: makes sure that the descendant that
// was the target of the mousedown event is now considered the
// active descendant.
this.focus(oTarget);
}
else if (UA.webkit && this.get(HAS_FOCUS) &&
(!bChildNode || (bChildNode && !this._isDescendant(oTarget)))) {
// Fix for Webkit:
// Document doesn't receive focus in Webkit when the user mouses
// down on it, so the "hasFocus" attribute won't get set to the
// correct value.
this._set(HAS_FOCUS, false);
this._onDocFocus(event);
}
},
/**
* @method _onDocFocus
* @description "focus" event handler for the owner document of the
* Focus Manager's Node.
* @protected
* @param event {Object} Object representing the DOM event.
*/
_onDocFocus: function (event) {
var oTarget = this._focusTarget || event.target,
bHasFocus = this.get(HAS_FOCUS),
sClassName = this.get(FOCUS_CLASS),
oFocusedNode = this._focusedNode,
bInCollection;
if (this._focusTarget) {
this._focusTarget = null;
}
if (this.get(HOST).contains(oTarget)) {
// The target is a descendant of the root Node.
bInCollection = this._isDescendant(oTarget);
if (!bHasFocus && bInCollection) {
// The user has focused a focusable descendant.
bHasFocus = true;
}
else if (bHasFocus && !bInCollection) {
// The user has focused a child of the root Node that is
// not one of the descendants managed by this Focus Manager
// so clear the currently focused descendant.
bHasFocus = false;
}
}
else {
// The target is some other node in the document.
bHasFocus = false;
}
if (sClassName) {
if (oFocusedNode && (oFocusedNode !== oTarget || !bHasFocus)) {
this._removeFocusClass();
}
if (bInCollection && bHasFocus) {
oTarget.addClass(sClassName);
this._focusedNode = oTarget;
}
}
if (bHasFocus && this._eventHandlers.length === 5) {
this._attachEventHandlers();
}
this._set(HAS_FOCUS, bHasFocus);
},
/**
* @method _focusNext
* @description Keydown event handler that moves focus to the next
* enabled descendant.
* @protected
* @param event {Object} Object representing the DOM event.
* @param activeDescendant {Number} Number representing the index of the
* next descendant to be focused
*/
_focusNext: function (event, activeDescendant) {
var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
oNode;
if (this._isDescendant(event.target) &&
(nActiveDescendant <= this._lastNodeIndex)) {
nActiveDescendant = nActiveDescendant + 1;
if (nActiveDescendant === (this._lastNodeIndex + 1) &&
this.get(CIRCULAR)) {
nActiveDescendant = 0;
}
oNode = this._descendants.item(nActiveDescendant);
if (oNode.get(DISABLED)) {
this._focusNext(event, nActiveDescendant);
}
else {
this.focus(nActiveDescendant);
}
}
this._preventScroll(event);
},
/**
* @method _focusPrevious
* @description Keydown event handler that moves focus to the previous
* enabled descendant.
* @protected
* @param event {Object} Object representing the DOM event.
* @param activeDescendant {Number} Number representing the index of the
* next descendant to be focused.
*/
_focusPrevious: function (event, activeDescendant) {
var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
oNode;
if (this._isDescendant(event.target) && nActiveDescendant >= 0) {
nActiveDescendant = nActiveDescendant - 1;
if (nActiveDescendant === -1 && this.get(CIRCULAR)) {
nActiveDescendant = this._lastNodeIndex;
}
oNode = this._descendants.item(nActiveDescendant);
if (oNode.get(DISABLED)) {
this._focusPrevious(event, nActiveDescendant);
}
else {
this.focus(nActiveDescendant);
}
}
this._preventScroll(event);
},
/**
* @method _afterActiveDescendantChange
* @description afterChange event handler for the
* "activeDescendant" attribute.
* @protected
* @param event {Object} Object representing the change event.
*/
_afterActiveDescendantChange: function (event) {
var oNode = this._descendants.item(event.prevVal);
if (oNode) {
oNode.set(TAB_INDEX, -1);
}
oNode = this._descendants.item(event.newVal);
if (oNode) {
oNode.set(TAB_INDEX, 0);
}
},
// Public methods
initializer: function (config) {
this.start();
},
destructor: function () {
this.stop();
this.get(HOST).focusManager = null;
},
/**
* @method focus
* @description Focuses the active descendant and sets the
* <code>hasFocus</code> attribute to true.
* @param index {Number} Optional. Number representing the index of the
* descendant to be set as the active descendant.
* @param index {Node} Optional. Node instance representing the
* descendant to be set as the active descendant.
*/
focus: function (index) {
if (Lang.isUndefined(index)) {
index = this.get(ACTIVE_DESCENDANT);
}
this.set(ACTIVE_DESCENDANT, index, { src: UI });
var oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT));
if (oNode) {
// In Opera focusing a <BUTTON> element programmatically
// will result in the document object getting focus first,
// immediately followed by the <BUTTON> element.
// This results in the "_onDocFocus" handler incorrectly
// setting the "hasFocus" Attribute to false. To fix this,
// set a flag ("_focusTarget") that the "_onDocFocus" method
// can look for to properly handle this edge case.
if (UA.opera && oNode.get("nodeName").toLowerCase() === "button") {
this._focusTarget = oNode;
}
oNode.focus();
}
},
/**
* @method blur
* @description Blurs the current active descendant and sets the
* <code>hasFocus</code> attribute to false.
*/
blur: function () {
var oNode;
if (this.get(HAS_FOCUS)) {
oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT));
if (oNode) {
oNode.blur();
// For Opera and Webkit: Blurring an element in either browser
// doesn't result in another element (such as the document)
// being focused. Therefore, the "_onDocFocus" method
// responsible for managing the application and removal of the
// focus indicator CSS class name is never called.
this._removeFocusClass();
}
this._set(HAS_FOCUS, false, { src: UI });
}
},
/**
* @method start
* @description Enables the Focus Manager.
*/
start: function () {
if (this._stopped) {
this._initDescendants();
this._attachEventHandlers();
this._stopped = false;
}
},
/**
* @method stop
* @description Disables the Focus Manager by detaching all event handlers.
*/
stop: function () {
if (!this._stopped) {
this._detachEventHandlers();
this._descendants = null;
this._focusedNode = null;
this._lastNodeIndex = 0;
this._stopped = true;
}
},
/**
* @method refresh
* @description Refreshes the Focus Manager's descendants by re-executing the
* CSS selector query specified by the <code>descendants</code> attribute.
*/
refresh: function () {
this._initDescendants();
}
});
NodeFocusManager.NAME = "NodeFocusManager";
NodeFocusManager.NS = "focusManager";
Y.namespace("Plugin");
Y.Plugin.NodeFocusManager = NodeFocusManager;
}, '@VERSION@' ,{requires:['node', 'plugin']});