]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/a11y.js.uncompressed.js
make precache_headlines_idle() start slower
[tt-rss.git] / lib / dijit / a11y.js.uncompressed.js
1 define("dijit/a11y", [
2 "dojo/_base/array", // array.forEach array.map
3 "dojo/_base/config", // defaultDuration
4 "dojo/_base/declare", // declare
5 "dojo/dom", // dom.byId
6 "dojo/dom-attr", // domAttr.attr domAttr.has
7 "dojo/dom-style", // style.style
8 "dojo/_base/sniff", // has("ie")
9 "./_base/manager", // manager._isElementShown
10 "." // for exporting methods to dijit namespace
11 ], function(array, config, declare, dom, domAttr, domStyle, has, manager, dijit){
12
13 // module:
14 // dijit/a11y
15 // summary:
16 // Accessibility utility functions (keyboard, tab stops, etc.)
17
18 var shown = (dijit._isElementShown = function(/*Element*/ elem){
19 var s = domStyle.get(elem);
20 return (s.visibility != "hidden")
21 && (s.visibility != "collapsed")
22 && (s.display != "none")
23 && (domAttr.get(elem, "type") != "hidden");
24 });
25
26 dijit.hasDefaultTabStop = function(/*Element*/ elem){
27 // summary:
28 // Tests if element is tab-navigable even without an explicit tabIndex setting
29
30 // No explicit tabIndex setting, need to investigate node type
31 switch(elem.nodeName.toLowerCase()){
32 case "a":
33 // An <a> w/out a tabindex is only navigable if it has an href
34 return domAttr.has(elem, "href");
35 case "area":
36 case "button":
37 case "input":
38 case "object":
39 case "select":
40 case "textarea":
41 // These are navigable by default
42 return true;
43 case "iframe":
44 // If it's an editor <iframe> then it's tab navigable.
45 var body;
46 try{
47 // non-IE
48 var contentDocument = elem.contentDocument;
49 if("designMode" in contentDocument && contentDocument.designMode == "on"){
50 return true;
51 }
52 body = contentDocument.body;
53 }catch(e1){
54 // contentWindow.document isn't accessible within IE7/8
55 // if the iframe.src points to a foreign url and this
56 // page contains an element, that could get focus
57 try{
58 body = elem.contentWindow.document.body;
59 }catch(e2){
60 return false;
61 }
62 }
63 return body && (body.contentEditable == 'true' ||
64 (body.firstChild && body.firstChild.contentEditable == 'true'));
65 default:
66 return elem.contentEditable == 'true';
67 }
68 };
69
70 var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
71 // summary:
72 // Tests if an element is tab-navigable
73
74 // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
75 if(domAttr.get(elem, "disabled")){
76 return false;
77 }else if(domAttr.has(elem, "tabIndex")){
78 // Explicit tab index setting
79 return domAttr.get(elem, "tabIndex") >= 0; // boolean
80 }else{
81 // No explicit tabIndex setting, so depends on node type
82 return dijit.hasDefaultTabStop(elem);
83 }
84 });
85
86 dijit._getTabNavigable = function(/*DOMNode*/ root){
87 // summary:
88 // Finds descendants of the specified root node.
89 //
90 // description:
91 // Finds the following descendants of the specified root node:
92 // * the first tab-navigable element in document order
93 // without a tabIndex or with tabIndex="0"
94 // * the last tab-navigable element in document order
95 // without a tabIndex or with tabIndex="0"
96 // * the first element in document order with the lowest
97 // positive tabIndex value
98 // * the last element in document order with the highest
99 // positive tabIndex value
100 var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
101
102 function radioName(node){
103 // If this element is part of a radio button group, return the name for that group.
104 return node && node.tagName.toLowerCase() == "input" &&
105 node.type && node.type.toLowerCase() == "radio" &&
106 node.name && node.name.toLowerCase();
107 }
108
109 var walkTree = function(/*DOMNode*/parent){
110 for(var child = parent.firstChild; child; child = child.nextSibling){
111 // Skip text elements, hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
112 // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
113 if(child.nodeType != 1 || (has("ie") && child.scopeName !== "HTML") || !shown(child)){
114 continue;
115 }
116
117 if(isTabNavigable(child)){
118 var tabindex = domAttr.get(child, "tabIndex");
119 if(!domAttr.has(child, "tabIndex") || tabindex == 0){
120 if(!first){
121 first = child;
122 }
123 last = child;
124 }else if(tabindex > 0){
125 if(!lowest || tabindex < lowestTabindex){
126 lowestTabindex = tabindex;
127 lowest = child;
128 }
129 if(!highest || tabindex >= highestTabindex){
130 highestTabindex = tabindex;
131 highest = child;
132 }
133 }
134 var rn = radioName(child);
135 if(domAttr.get(child, "checked") && rn){
136 radioSelected[rn] = child;
137 }
138 }
139 if(child.nodeName.toUpperCase() != 'SELECT'){
140 walkTree(child);
141 }
142 }
143 };
144 if(shown(root)){
145 walkTree(root);
146 }
147 function rs(node){
148 // substitute checked radio button for unchecked one, if there is a checked one with the same name.
149 return radioSelected[radioName(node)] || node;
150 }
151
152 return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
153 };
154 dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
155 // summary:
156 // Finds the descendant of the specified root node
157 // that is first in the tabbing order
158 var elems = dijit._getTabNavigable(dom.byId(root));
159 return elems.lowest ? elems.lowest : elems.first; // DomNode
160 };
161
162 dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
163 // summary:
164 // Finds the descendant of the specified root node
165 // that is last in the tabbing order
166 var elems = dijit._getTabNavigable(dom.byId(root));
167 return elems.last ? elems.last : elems.highest; // DomNode
168 };
169
170 return {
171 hasDefaultTabStop: dijit.hasDefaultTabStop,
172 isTabNavigable: dijit.isTabNavigable,
173 _getTabNavigable: dijit._getTabNavigable,
174 getFirstInTabbingOrder: dijit.getFirstInTabbingOrder,
175 getLastInTabbingOrder: dijit.getLastInTabbingOrder
176 };
177 });