happstack-yui-7373.5.2: bundle/node-focusmanager/node-focusmanager-coverage.js
/*
YUI 3.7.3 (build 5687)
Copyright 2012 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
http://yuilibrary.com/license/
*/
if (typeof _yuitest_coverage == "undefined"){
_yuitest_coverage = {};
_yuitest_coverline = function(src, line){
var coverage = _yuitest_coverage[src];
if (!coverage.lines[line]){
coverage.calledLines++;
}
coverage.lines[line]++;
};
_yuitest_coverfunc = function(src, name, line){
var coverage = _yuitest_coverage[src],
funcId = name + ":" + line;
if (!coverage.functions[funcId]){
coverage.calledFunctions++;
}
coverage.functions[funcId]++;
};
}
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"] = {
lines: {},
functions: {},
coveredLines: 0,
calledLines: 0,
coveredFunctions: 0,
calledFunctions: 0,
path: "build/node-focusmanager/node-focusmanager.js",
code: []
};
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"].code=["YUI.add('node-focusmanager', function (Y, NAME) {","","/**","* <p>The Focus Manager Node Plugin makes it easy to manage focus among","* a Node's descendants. Primarily intended to help with widget development,","* the Focus Manager Node Plugin can be used to improve the keyboard","* accessibility of widgets.</p>","*","* <p>","* When designing widgets that manage a set of descendant controls (i.e. buttons","* in a toolbar, tabs in a tablist, menuitems in a menu, etc.) it is important to","* limit the number of descendants in the browser's default tab flow. The fewer","* number of descendants in the default tab flow, the easier it is for keyboard","* users to navigate between widgets by pressing the tab key. When a widget has","* focus it should provide a set of shortcut keys (typically the arrow keys)","* to move focus among its descendants.","* </p>","*","* <p>","* To this end, the Focus Manager Node Plugin makes it easy to define a Node's","* focusable descendants, define which descendant should be in the default tab","* flow, and define the keys that move focus among each descendant.","* Additionally, as the CSS","* <a href=\"http://www.w3.org/TR/CSS21/selector.html#x38\"><code>:focus</code></a>","* pseudo class is not supported on all elements in all","* <a href=\"http://developer.yahoo.com/yui/articles/gbs/\">A-Grade browsers</a>,","* the Focus Manager Node Plugin provides an easy, cross-browser means of","* styling focus.","* </p>","*","* @module node-focusmanager","*/",""," // Frequently used strings","","var ACTIVE_DESCENDANT = \"activeDescendant\","," ID = \"id\","," DISABLED = \"disabled\","," TAB_INDEX = \"tabIndex\","," FOCUSED = \"focused\","," FOCUS_CLASS = \"focusClass\","," CIRCULAR = \"circular\","," UI = \"UI\","," KEY = \"key\","," ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + \"Change\","," HOST = \"host\",",""," // Collection of keys that, when pressed, cause the browser viewport"," // to scroll."," scrollKeys = {"," 37: true,"," 38: true,"," 39: true,"," 40: true"," },",""," clickableElements = {"," \"a\": true,"," \"button\": true,"," \"input\": true,"," \"object\": true"," },",""," // Library shortcuts",""," Lang = Y.Lang,"," UA = Y.UA,",""," /**"," * The NodeFocusManager class is a plugin for a Node instance. The class is used"," * via the <a href=\"Node.html#method_plug\"><code>plug</code></a> method of Node"," * and should not be instantiated directly."," * @namespace plugin"," * @class NodeFocusManager"," */"," NodeFocusManager = function () {",""," NodeFocusManager.superclass.constructor.apply(this, arguments);",""," };","","","NodeFocusManager.ATTRS = {",""," /**"," * Boolean indicating that one of the descendants is focused."," *"," * @attribute focused"," * @readOnly"," * @default false"," * @type boolean"," */"," focused: {",""," value: false,"," readOnly: true",""," },","",""," /**"," * String representing the CSS selector used to define the descendant Nodes"," * whose focus should be managed."," *"," * @attribute descendants"," * @type Y.NodeList"," */"," descendants: {",""," getter: function (value) {",""," return this.get(HOST).all(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 descendant. 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 name of class applied to the focused active"," * descendant Node. Can also be an object literal used to define both the"," * class name, and the Node to which the class should be applied. If using"," * an object literal, the format is:"," * <code>{ className: \"focus\", fn: myFunction }</code>. The function"," * referenced by the <code>fn</code> property in the object literal will be"," * passed a reference to the currently focused active descendant Node."," *"," * @attribute focusClass"," * @type String|Object"," */"," 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"," * @default true"," */"," 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 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();","",""," 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.",""," // Need to pass \"2\" when using \"getAttribute\" for IE to get"," // the attribute value as it is set in the markup."," // Need to use \"parseInt\" because IE always returns the"," // value as a number, whereas all other browsers return"," // the attribute as a string when accessed"," // via \"getAttribute\".",""," if (nActiveDescendant < 0 &&"," parseInt(oNode.getAttribute(TAB_INDEX, 2), 10) === 0) {",""," nActiveDescendant = i;",""," }",""," if (oNode) {"," 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.",""," if (oNode) {"," 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 class name 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,"," focusClass = this.get(FOCUS_CLASS),"," sClassName;",""," if (focusClass) {"," sClassName = Lang.isString(focusClass) ?"," focusClass : focusClass.className;"," }",""," 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;",""," if (prevKeyHandler) {"," prevKeyHandler.detach();"," }",""," if (nextKeyHandler) {"," nextKeyHandler.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] && this._isDescendant(event.target)) {"," event.preventDefault();"," }",""," },","",""," /**"," * @method _fireClick"," * @description Fires the click event if the enter key is pressed while"," * focused on an HTML element that is not natively clickable."," * @protected"," */"," _fireClick: function (event) {",""," var oTarget = event.target,"," sNodeName = oTarget.get(\"nodeName\").toLowerCase();",""," if (event.keyCode === 13 && (!clickableElements[sNodeName] ||"," (sNodeName === \"a\" && !oTarget.getAttribute(\"href\")))) {","",""," oTarget.simulate(\"click\");",""," }",""," },","",""," /**"," * @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\"),"," sPrevKey = this.get(\"keys.previous\"),"," oNode = this.get(HOST),"," aHandlers = this._eventHandlers;",""," if (sPrevKey) {"," this._prevKeyHandler ="," Y.on(KEY, Y.bind(this._focusPrevious, this), oNode, sPrevKey);"," }",""," if (sNextKey) {"," this._nextKeyHandler ="," Y.on(KEY, Y.bind(this._focusNext, this), oNode, sNextKey);"," }","",""," // In Opera it is necessary to call the \"preventDefault\" method in"," // response to the user pressing the arrow keys in order to prevent"," // the viewport from scrolling when the user is moving focus among"," // the focusable descendants.",""," if (UA.opera) {"," aHandlers.push(oNode.on(\"keypress\", this._preventScroll, this));"," }","",""," // For all browsers except Opera: HTML elements that are not natively"," // focusable but made focusable via the tabIndex attribute don't"," // fire a click event when the user presses the enter key. It is"," // possible to work around this problem by simplying dispatching a"," // click event in response to the user pressing the enter key.",""," if (!UA.opera) {"," aHandlers.push(oNode.on(\"keypress\", this._fireClick, 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,"," handle;",""," if (descendants && descendants.size()) {",""," aHandlers = this._eventHandlers || [];"," oDocument = this.get(HOST).get(\"ownerDocument\");","",""," if (aHandlers.length === 0) {","",""," aHandlers.push(oDocument.on(\"focus\", this._onDocFocus, this));",""," aHandlers.push(oDocument.on(\"mousedown\","," this._onDocMouseDown, this));",""," aHandlers.push("," this.after(\"keysChange\", this._attachKeyHandler));",""," aHandlers.push("," this.after(\"descendantsChange\", this._initDescendants));",""," aHandlers.push("," this.after(ACTIVE_DESCENDANT_CHANGE,"," this._afterActiveDescendantChange));","",""," // For performance: defer attaching all key-related event"," // handlers until the first time one of the specified"," // descendants receives focus.",""," handle = this.after(\"focusedChange\", Y.bind(function (event) {",""," if (event.newVal) {","",""," this._attachKeyHandler();",""," // Detach this \"focusedChange\" handler so that the"," // key-related handlers only get attached once.",""," handle.detach();",""," }",""," }, this));",""," aHandlers.push(handle);",""," }","",""," 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 oHost = this.get(HOST),"," oTarget = event.target,"," bChildNode = oHost.contains(oTarget),"," node,",""," getFocusable = function (node) {",""," var returnVal = false;",""," if (!node.compareTo(oHost)) {",""," returnVal = this._isDescendant(node) ? node :"," getFocusable.call(this, node.get(\"parentNode\"));",""," }",""," return returnVal;",""," };","",""," if (bChildNode) {",""," // Check to make sure that the target isn't a child node of one"," // of the focusable descendants.",""," node = getFocusable.call(this, oTarget);",""," if (node) {"," oTarget = node;"," }"," else if (!node && this.get(FOCUSED)) {",""," // The target was a non-focusable descendant of the root"," // node, so the \"focused\" attribute should be set to false.",""," this._set(FOCUSED, false);"," this._onDocFocus(event);",""," }",""," }","",""," 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(FOCUSED) &&"," (!bChildNode || (bChildNode && !this._isDescendant(oTarget)))) {",""," // Fix for Webkit:",""," // Document doesn't receive focus in Webkit when the user mouses"," // down on it, so the \"focused\" attribute won't get set to the"," // correct value.",""," // The goal is to force a blur if the user moused down on"," // either: 1) A descendant node, but not one that managed by"," // the FocusManager, or 2) an element outside of the"," // FocusManager",""," this._set(FOCUSED, 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,"," bFocused = this.get(FOCUSED),"," focusClass = 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 (!bFocused && bInCollection) {",""," // The user has focused a focusable descendant.",""," bFocused = true;",""," }"," else if (bFocused && !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.",""," bFocused = false;",""," }",""," }"," else {",""," // The target is some other node in the document.",""," bFocused = false;",""," }","",""," if (focusClass) {",""," if (oFocusedNode && (!oFocusedNode.compareTo(oTarget) || !bFocused)) {"," this._removeFocusClass();"," }",""," if (bInCollection && bFocused) {",""," if (focusClass.fn) {"," oTarget = focusClass.fn(oTarget);"," oTarget.addClass(focusClass.className);"," }"," else {"," oTarget.addClass(focusClass);"," }",""," this._focusedNode = oTarget;",""," }",""," }","",""," this._set(FOCUSED, bFocused);",""," },","",""," /**"," * @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) {",""," 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) {",""," 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>focused</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) {",""," oNode.focus();",""," // In Opera focusing a <BUTTON> element programmatically"," // will result in the document-level focus event handler"," // \"_onDocFocus\" being called, resulting in the handler"," // incorrectly setting the \"focused\" 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;"," }",""," }",""," },","",""," /**"," * @method blur"," * @description Blurs the current active descendant and sets the"," * <code>focused</code> attribute to false."," */"," blur: function () {",""," var oNode;",""," if (this.get(FOCUSED)) {",""," 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 class name is never called.",""," this._removeFocusClass();",""," }",""," this._set(FOCUSED, 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();",""," if (!this._eventHandlers) {"," this._attachEventHandlers();"," }",""," }","","});","","","NodeFocusManager.NAME = \"nodeFocusManager\";","NodeFocusManager.NS = \"focusManager\";","","Y.namespace(\"Plugin\");","Y.Plugin.NodeFocusManager = NodeFocusManager;","","","}, '3.7.3', {\"requires\": [\"attribute\", \"node\", \"plugin\", \"node-event-simulate\", \"event-key\", \"event-focus\"]});"];
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"].lines = {"1":0,"36":0,"78":0,"83":0,"112":0,"141":0,"150":0,"151":0,"152":0,"154":0,"156":0,"158":0,"159":0,"165":0,"171":0,"175":0,"177":0,"179":0,"183":0,"189":0,"250":0,"288":0,"299":0,"300":0,"304":0,"306":0,"309":0,"311":0,"313":0,"314":0,"329":0,"332":0,"336":0,"337":0,"340":0,"342":0,"343":0,"344":0,"347":0,"356":0,"357":0,"361":0,"366":0,"367":0,"368":0,"371":0,"372":0,"373":0,"375":0,"381":0,"382":0,"401":0,"415":0,"419":0,"420":0,"424":0,"425":0,"439":0,"442":0,"443":0,"446":0,"447":0,"461":0,"462":0,"476":0,"479":0,"483":0,"498":0,"500":0,"505":0,"506":0,"510":0,"511":0,"521":0,"522":0,"532":0,"533":0,"546":0,"548":0,"550":0,"552":0,"553":0,"556":0,"570":0,"575":0,"577":0,"578":0,"581":0,"584":0,"586":0,"589":0,"592":0,"595":0,"604":0,"606":0,"609":0,"614":0,"620":0,"625":0,"643":0,"650":0,"652":0,"654":0,"659":0,"664":0,"669":0,"671":0,"672":0,"674":0,"679":0,"680":0,"687":0,"696":0,"698":0,"712":0,"713":0,"729":0,"735":0,"736":0,"740":0,"744":0,"746":0,"750":0,"753":0,"759":0,"768":0,"773":0,"775":0,"776":0,"779":0,"781":0,"782":0,"783":0,"786":0,"789":0,"796":0,"812":0,"816":0,"819":0,"821":0,"824":0,"828":0,"830":0,"832":0,"833":0,"836":0,"843":0,"859":0,"862":0,"864":0,"866":0,"867":0,"870":0,"872":0,"874":0,"875":0,"878":0,"885":0,"899":0,"901":0,"902":0,"905":0,"907":0,"908":0,"919":0,"925":0,"926":0,"942":0,"943":0,"946":0,"948":0,"950":0,"952":0,"961":0,"962":0,"977":0,"979":0,"981":0,"983":0,"985":0,"993":0,"997":0,"1009":0,"1011":0,"1012":0,"1014":0,"1027":0,"1029":0,"1031":0,"1032":0,"1033":0,"1034":0,"1048":0,"1050":0,"1051":0,"1059":0,"1060":0,"1062":0,"1063":0};
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"].functions = {"NodeFocusManager:76":0,"getter:110":0,"setter:139":0,"_initDescendants:286":0,"_isDescendant:399":0,"_removeFocusClass:413":0,"_detachKeyHandler:437":0,"_preventScroll:459":0,"_fireClick:474":0,"_attachKeyHandler:496":0,"(anonymous 2):552":0,"_detachEventHandlers:544":0,"(anonymous 3):604":0,"_attachEventHandlers:568":0,"getFocusable:648":0,"_onDocMouseDown:641":0,"_onDocFocus:727":0,"_focusNext:810":0,"_focusPrevious:857":0,"_afterActiveDescendantChange:897":0,"initializer:917":0,"destructor:923":0,"focus:940":0,"blur:975":0,"start:1007":0,"stop:1025":0,"refresh:1046":0,"(anonymous 1):1":0};
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"].coveredLines = 199;
_yuitest_coverage["build/node-focusmanager/node-focusmanager.js"].coveredFunctions = 28;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1);
YUI.add('node-focusmanager', function (Y, NAME) {
/**
* <p>The Focus Manager Node Plugin makes it easy to manage focus among
* a Node's descendants. Primarily intended to help with widget development,
* the Focus Manager Node Plugin can be used to improve the keyboard
* accessibility of widgets.</p>
*
* <p>
* When designing widgets that manage a set of descendant controls (i.e. buttons
* in a toolbar, tabs in a tablist, menuitems in a menu, etc.) it is important to
* limit the number of descendants in the browser's default tab flow. The fewer
* number of descendants in the default tab flow, the easier it is for keyboard
* users to navigate between widgets by pressing the tab key. When a widget has
* focus it should provide a set of shortcut keys (typically the arrow keys)
* to move focus among its descendants.
* </p>
*
* <p>
* To this end, the Focus Manager Node Plugin makes it easy to define a Node's
* focusable descendants, define which descendant should be in the default tab
* flow, and define the keys that move focus among each descendant.
* Additionally, as the CSS
* <a href="http://www.w3.org/TR/CSS21/selector.html#x38"><code>:focus</code></a>
* pseudo class is not supported on all elements in all
* <a href="http://developer.yahoo.com/yui/articles/gbs/">A-Grade browsers</a>,
* the Focus Manager Node Plugin provides an easy, cross-browser means of
* styling focus.
* </p>
*
* @module node-focusmanager
*/
// Frequently used strings
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "(anonymous 1)", 1);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 36);
var ACTIVE_DESCENDANT = "activeDescendant",
ID = "id",
DISABLED = "disabled",
TAB_INDEX = "tabIndex",
FOCUSED = "focused",
FOCUS_CLASS = "focusClass",
CIRCULAR = "circular",
UI = "UI",
KEY = "key",
ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
HOST = "host",
// Collection of keys that, when pressed, cause the browser viewport
// to scroll.
scrollKeys = {
37: true,
38: true,
39: true,
40: true
},
clickableElements = {
"a": true,
"button": true,
"input": true,
"object": true
},
// Library shortcuts
Lang = Y.Lang,
UA = Y.UA,
/**
* The NodeFocusManager class is a plugin for a Node instance. The class is used
* via the <a href="Node.html#method_plug"><code>plug</code></a> method of Node
* and should not be instantiated directly.
* @namespace plugin
* @class NodeFocusManager
*/
NodeFocusManager = function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "NodeFocusManager", 76);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 78);
NodeFocusManager.superclass.constructor.apply(this, arguments);
};
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 83);
NodeFocusManager.ATTRS = {
/**
* Boolean indicating that one of the descendants is focused.
*
* @attribute focused
* @readOnly
* @default false
* @type boolean
*/
focused: {
value: false,
readOnly: true
},
/**
* String representing the CSS selector used to define the descendant Nodes
* whose focus should be managed.
*
* @attribute descendants
* @type Y.NodeList
*/
descendants: {
getter: function (value) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "getter", 110);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 112);
return this.get(HOST).all(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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "setter", 139);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 141);
var isNumber = Lang.isNumber,
INVALID_VALUE = Y.Attribute.INVALID_VALUE,
descendantsMap = this._descendantsMap,
descendants = this._descendants,
nodeIndex,
returnValue,
oNode;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 150);
if (isNumber(value)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 151);
nodeIndex = value;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 152);
returnValue = nodeIndex;
}
else {_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 154);
if ((value instanceof Y.Node) && descendantsMap) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 156);
nodeIndex = descendantsMap[value.get(ID)];
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 158);
if (isNumber(nodeIndex)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 159);
returnValue = nodeIndex;
}
else {
// The user passed a reference to a Node that wasn't one
// of the descendants.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 165);
returnValue = INVALID_VALUE;
}
}
else {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 171);
returnValue = INVALID_VALUE;
}}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 175);
if (descendants) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 177);
oNode = descendants.item(nodeIndex);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 179);
if (oNode && oNode.get("disabled")) {
// Setting the "activeDescendant" attribute to the index
// of a disabled descendant is invalid.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 183);
returnValue = INVALID_VALUE;
}
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 189);
return returnValue;
}
},
/**
* Object literal representing the keys to be used to navigate between the
* next/previous descendant. 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 name of class applied to the focused active
* descendant Node. Can also be an object literal used to define both the
* class name, and the Node to which the class should be applied. If using
* an object literal, the format is:
* <code>{ className: "focus", fn: myFunction }</code>. The function
* referenced by the <code>fn</code> property in the object literal will be
* passed a reference to the currently focused active descendant Node.
*
* @attribute focusClass
* @type String|Object
*/
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
* @default true
*/
circular: {
value: true
}
};
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 250);
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 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 () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_initDescendants", 286);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 288);
var descendants = this.get("descendants"),
descendantsMap = {},
nFirstEnabled = -1,
nDescendants,
nActiveDescendant = this.get(ACTIVE_DESCENDANT),
oNode,
sID,
i = 0;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 299);
if (Lang.isUndefined(nActiveDescendant)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 300);
nActiveDescendant = -1;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 304);
if (descendants) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 306);
nDescendants = descendants.size();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 309);
for (i = 0; i < nDescendants; i++) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 311);
oNode = descendants.item(i);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 313);
if (nFirstEnabled === -1 && !oNode.get(DISABLED)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 314);
nFirstEnabled = i;
}
// If the user didn't specify a value for the
// "activeDescendant" attribute try to infer it from
// the markup.
// Need to pass "2" when using "getAttribute" for IE to get
// the attribute value as it is set in the markup.
// Need to use "parseInt" because IE always returns the
// value as a number, whereas all other browsers return
// the attribute as a string when accessed
// via "getAttribute".
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 329);
if (nActiveDescendant < 0 &&
parseInt(oNode.getAttribute(TAB_INDEX, 2), 10) === 0) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 332);
nActiveDescendant = i;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 336);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 337);
oNode.set(TAB_INDEX, -1);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 340);
sID = oNode.get(ID);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 342);
if (!sID) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 343);
sID = Y.guid();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 344);
oNode.set(ID, sID);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 347);
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.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 356);
if (nActiveDescendant < 0) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 357);
nActiveDescendant = 0;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 361);
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.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 366);
if (!oNode || oNode.get(DISABLED)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 367);
oNode = descendants.item(nFirstEnabled);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 368);
nActiveDescendant = nFirstEnabled;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 371);
this._lastNodeIndex = nDescendants - 1;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 372);
this._descendants = descendants;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 373);
this._descendantsMap = descendantsMap;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 375);
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.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 381);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 382);
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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_isDescendant", 399);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 401);
return (node.get(ID) in this._descendantsMap);
},
/**
* @method _removeFocusClass
* @description Removes the class name representing focus (as specified by
* the "focusClass" attribute) from the Node instance to which it is
* currently applied.
* @protected
*/
_removeFocusClass: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_removeFocusClass", 413);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 415);
var oFocusedNode = this._focusedNode,
focusClass = this.get(FOCUS_CLASS),
sClassName;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 419);
if (focusClass) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 420);
sClassName = Lang.isString(focusClass) ?
focusClass : focusClass.className;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 424);
if (oFocusedNode && sClassName) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 425);
oFocusedNode.removeClass(sClassName);
}
},
/**
* @method _detachKeyHandler
* @description Detaches the "key" event handlers used to support the "keys"
* attribute.
* @protected
*/
_detachKeyHandler: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_detachKeyHandler", 437);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 439);
var prevKeyHandler = this._prevKeyHandler,
nextKeyHandler = this._nextKeyHandler;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 442);
if (prevKeyHandler) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 443);
prevKeyHandler.detach();
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 446);
if (nextKeyHandler) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 447);
nextKeyHandler.detach();
}
},
/**
* @method _preventScroll
* @description Prevents the viewport from scolling when the user presses
* the up, down, left, or right key.
* @protected
*/
_preventScroll: function (event) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_preventScroll", 459);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 461);
if (scrollKeys[event.keyCode] && this._isDescendant(event.target)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 462);
event.preventDefault();
}
},
/**
* @method _fireClick
* @description Fires the click event if the enter key is pressed while
* focused on an HTML element that is not natively clickable.
* @protected
*/
_fireClick: function (event) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_fireClick", 474);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 476);
var oTarget = event.target,
sNodeName = oTarget.get("nodeName").toLowerCase();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 479);
if (event.keyCode === 13 && (!clickableElements[sNodeName] ||
(sNodeName === "a" && !oTarget.getAttribute("href")))) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 483);
oTarget.simulate("click");
}
},
/**
* @method _attachKeyHandler
* @description Attaches the "key" event handlers used to support the "keys"
* attribute.
* @protected
*/
_attachKeyHandler: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_attachKeyHandler", 496);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 498);
this._detachKeyHandler();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 500);
var sNextKey = this.get("keys.next"),
sPrevKey = this.get("keys.previous"),
oNode = this.get(HOST),
aHandlers = this._eventHandlers;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 505);
if (sPrevKey) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 506);
this._prevKeyHandler =
Y.on(KEY, Y.bind(this._focusPrevious, this), oNode, sPrevKey);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 510);
if (sNextKey) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 511);
this._nextKeyHandler =
Y.on(KEY, Y.bind(this._focusNext, this), oNode, sNextKey);
}
// In Opera it is necessary to call the "preventDefault" method in
// response to the user pressing the arrow keys in order to prevent
// the viewport from scrolling when the user is moving focus among
// the focusable descendants.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 521);
if (UA.opera) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 522);
aHandlers.push(oNode.on("keypress", this._preventScroll, this));
}
// For all browsers except Opera: HTML elements that are not natively
// focusable but made focusable via the tabIndex attribute don't
// fire a click event when the user presses the enter key. It is
// possible to work around this problem by simplying dispatching a
// click event in response to the user pressing the enter key.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 532);
if (!UA.opera) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 533);
aHandlers.push(oNode.on("keypress", this._fireClick, this));
}
},
/**
* @method _detachEventHandlers
* @description Detaches all event handlers used by the Focus Manager.
* @protected
*/
_detachEventHandlers: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_detachEventHandlers", 544);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 546);
this._detachKeyHandler();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 548);
var aHandlers = this._eventHandlers;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 550);
if (aHandlers) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 552);
Y.Array.each(aHandlers, function (handle) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "(anonymous 2)", 552);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 553);
handle.detach();
});
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 556);
this._eventHandlers = null;
}
},
/**
* @method _detachEventHandlers
* @description Attaches all event handlers used by the Focus Manager.
* @protected
*/
_attachEventHandlers: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_attachEventHandlers", 568);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 570);
var descendants = this._descendants,
aHandlers,
oDocument,
handle;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 575);
if (descendants && descendants.size()) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 577);
aHandlers = this._eventHandlers || [];
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 578);
oDocument = this.get(HOST).get("ownerDocument");
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 581);
if (aHandlers.length === 0) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 584);
aHandlers.push(oDocument.on("focus", this._onDocFocus, this));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 586);
aHandlers.push(oDocument.on("mousedown",
this._onDocMouseDown, this));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 589);
aHandlers.push(
this.after("keysChange", this._attachKeyHandler));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 592);
aHandlers.push(
this.after("descendantsChange", this._initDescendants));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 595);
aHandlers.push(
this.after(ACTIVE_DESCENDANT_CHANGE,
this._afterActiveDescendantChange));
// For performance: defer attaching all key-related event
// handlers until the first time one of the specified
// descendants receives focus.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 604);
handle = this.after("focusedChange", Y.bind(function (event) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "(anonymous 3)", 604);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 606);
if (event.newVal) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 609);
this._attachKeyHandler();
// Detach this "focusedChange" handler so that the
// key-related handlers only get attached once.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 614);
handle.detach();
}
}, this));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 620);
aHandlers.push(handle);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 625);
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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_onDocMouseDown", 641);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 643);
var oHost = this.get(HOST),
oTarget = event.target,
bChildNode = oHost.contains(oTarget),
node,
getFocusable = function (node) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "getFocusable", 648);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 650);
var returnVal = false;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 652);
if (!node.compareTo(oHost)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 654);
returnVal = this._isDescendant(node) ? node :
getFocusable.call(this, node.get("parentNode"));
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 659);
return returnVal;
};
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 664);
if (bChildNode) {
// Check to make sure that the target isn't a child node of one
// of the focusable descendants.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 669);
node = getFocusable.call(this, oTarget);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 671);
if (node) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 672);
oTarget = node;
}
else {_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 674);
if (!node && this.get(FOCUSED)) {
// The target was a non-focusable descendant of the root
// node, so the "focused" attribute should be set to false.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 679);
this._set(FOCUSED, false);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 680);
this._onDocFocus(event);
}}
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 687);
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.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 696);
this.focus(oTarget);
}
else {_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 698);
if (UA.webkit && this.get(FOCUSED) &&
(!bChildNode || (bChildNode && !this._isDescendant(oTarget)))) {
// Fix for Webkit:
// Document doesn't receive focus in Webkit when the user mouses
// down on it, so the "focused" attribute won't get set to the
// correct value.
// The goal is to force a blur if the user moused down on
// either: 1) A descendant node, but not one that managed by
// the FocusManager, or 2) an element outside of the
// FocusManager
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 712);
this._set(FOCUSED, false);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 713);
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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_onDocFocus", 727);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 729);
var oTarget = this._focusTarget || event.target,
bFocused = this.get(FOCUSED),
focusClass = this.get(FOCUS_CLASS),
oFocusedNode = this._focusedNode,
bInCollection;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 735);
if (this._focusTarget) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 736);
this._focusTarget = null;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 740);
if (this.get(HOST).contains(oTarget)) {
// The target is a descendant of the root Node.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 744);
bInCollection = this._isDescendant(oTarget);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 746);
if (!bFocused && bInCollection) {
// The user has focused a focusable descendant.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 750);
bFocused = true;
}
else {_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 753);
if (bFocused && !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.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 759);
bFocused = false;
}}
}
else {
// The target is some other node in the document.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 768);
bFocused = false;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 773);
if (focusClass) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 775);
if (oFocusedNode && (!oFocusedNode.compareTo(oTarget) || !bFocused)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 776);
this._removeFocusClass();
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 779);
if (bInCollection && bFocused) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 781);
if (focusClass.fn) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 782);
oTarget = focusClass.fn(oTarget);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 783);
oTarget.addClass(focusClass.className);
}
else {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 786);
oTarget.addClass(focusClass);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 789);
this._focusedNode = oTarget;
}
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 796);
this._set(FOCUSED, bFocused);
},
/**
* @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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_focusNext", 810);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 812);
var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
oNode;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 816);
if (this._isDescendant(event.target) &&
(nActiveDescendant <= this._lastNodeIndex)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 819);
nActiveDescendant = nActiveDescendant + 1;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 821);
if (nActiveDescendant === (this._lastNodeIndex + 1) &&
this.get(CIRCULAR)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 824);
nActiveDescendant = 0;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 828);
oNode = this._descendants.item(nActiveDescendant);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 830);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 832);
if (oNode.get("disabled")) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 833);
this._focusNext(event, nActiveDescendant);
}
else {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 836);
this.focus(nActiveDescendant);
}
}
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 843);
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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_focusPrevious", 857);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 859);
var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
oNode;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 862);
if (this._isDescendant(event.target) && nActiveDescendant >= 0) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 864);
nActiveDescendant = nActiveDescendant - 1;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 866);
if (nActiveDescendant === -1 && this.get(CIRCULAR)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 867);
nActiveDescendant = this._lastNodeIndex;
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 870);
oNode = this._descendants.item(nActiveDescendant);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 872);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 874);
if (oNode.get("disabled")) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 875);
this._focusPrevious(event, nActiveDescendant);
}
else {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 878);
this.focus(nActiveDescendant);
}
}
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 885);
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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "_afterActiveDescendantChange", 897);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 899);
var oNode = this._descendants.item(event.prevVal);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 901);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 902);
oNode.set(TAB_INDEX, -1);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 905);
oNode = this._descendants.item(event.newVal);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 907);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 908);
oNode.set(TAB_INDEX, 0);
}
},
// Public methods
initializer: function (config) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "initializer", 917);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 919);
this.start();
},
destructor: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "destructor", 923);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 925);
this.stop();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 926);
this.get(HOST).focusManager = null;
},
/**
* @method focus
* @description Focuses the active descendant and sets the
* <code>focused</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) {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "focus", 940);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 942);
if (Lang.isUndefined(index)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 943);
index = this.get(ACTIVE_DESCENDANT);
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 946);
this.set(ACTIVE_DESCENDANT, index, { src: UI });
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 948);
var oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 950);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 952);
oNode.focus();
// In Opera focusing a <BUTTON> element programmatically
// will result in the document-level focus event handler
// "_onDocFocus" being called, resulting in the handler
// incorrectly setting the "focused" Attribute to false. To fix
// this, set a flag ("_focusTarget") that the "_onDocFocus" method
// can look for to properly handle this edge case.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 961);
if (UA.opera && oNode.get("nodeName").toLowerCase() === "button") {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 962);
this._focusTarget = oNode;
}
}
},
/**
* @method blur
* @description Blurs the current active descendant and sets the
* <code>focused</code> attribute to false.
*/
blur: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "blur", 975);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 977);
var oNode;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 979);
if (this.get(FOCUSED)) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 981);
oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT));
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 983);
if (oNode) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 985);
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 class name is never called.
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 993);
this._removeFocusClass();
}
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 997);
this._set(FOCUSED, false, { src: UI });
}
},
/**
* @method start
* @description Enables the Focus Manager.
*/
start: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "start", 1007);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1009);
if (this._stopped) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1011);
this._initDescendants();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1012);
this._attachEventHandlers();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1014);
this._stopped = false;
}
},
/**
* @method stop
* @description Disables the Focus Manager by detaching all event handlers.
*/
stop: function () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "stop", 1025);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1027);
if (!this._stopped) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1029);
this._detachEventHandlers();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1031);
this._descendants = null;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1032);
this._focusedNode = null;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1033);
this._lastNodeIndex = 0;
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1034);
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 () {
_yuitest_coverfunc("build/node-focusmanager/node-focusmanager.js", "refresh", 1046);
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1048);
this._initDescendants();
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1050);
if (!this._eventHandlers) {
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1051);
this._attachEventHandlers();
}
}
});
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1059);
NodeFocusManager.NAME = "nodeFocusManager";
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1060);
NodeFocusManager.NS = "focusManager";
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1062);
Y.namespace("Plugin");
_yuitest_coverline("build/node-focusmanager/node-focusmanager.js", 1063);
Y.Plugin.NodeFocusManager = NodeFocusManager;
}, '3.7.3', {"requires": ["attribute", "node", "plugin", "node-event-simulate", "event-key", "event-focus"]});