ARIA Favlets

Runs accessibility checking against loaded page

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/383641/702363/ARIA%20Favlets.js

  1. // ARIA favlet via http://www.manateeroad.com/favelets/revealariaCheck.js
  2.  
  3. var ariaCheck = {
  4. start: function(myDocument){
  5.  
  6. //Instead of window. for global
  7. //we use aA. so that we don't have
  8. //variables that might get mixed in
  9. //with site-level js
  10.  
  11. var aA=[];
  12.  
  13. // counting
  14. aA.foundCount = 0;
  15.  
  16. //for id of added spans
  17. //so we can removed them
  18. aA.idi=0;
  19.  
  20. //for frames outside domain
  21. //so we can report them
  22. aA.framemsg='';
  23. aA.fi=0;
  24.  
  25. // for landmark outline styles
  26. // so we can keep switching them
  27. // even through frames
  28. aA.cx=-1;
  29. aA.bx=-1;
  30. aA.wx=-1;
  31.  
  32. //might as well have these here too
  33. aA.c=['#800000','#000080','#006D00','#800080','#202020'];
  34. aA.b=['solid','dotted','dashed','double','solid','double'];
  35. aA.w=['2','2','2','4','3','6'];
  36.  
  37.  
  38. //recursive through frames
  39. aA = ariaCheck.checkFrames(myDocument,aA);
  40.  
  41. //reporting
  42. ariaCheck.provideMessage(aA);
  43. },
  44. checkFrames: function(myDocument,aA){
  45.  
  46. //run ariaCheck.aria123 check for current document which might
  47. //have frames or aria or both
  48.  
  49. aA = ariaCheck.aria123(myDocument,aA);
  50.  
  51. //run ariaCheck.checkFrames for each frame's document if there
  52. //are any frames
  53. var frametypes=['frame','iframe','ilayer'];
  54. for (var x=0;x<frametypes.length;x++) {
  55. var myframes=myDocument.getElementsByTagName(frametypes[x]);
  56. for (var y=0;y<myframes.length;y++) {
  57. try {
  58. //alert('in try');
  59. ariaCheck.checkFrames(myframes[y].contentWindow.document,aA);
  60. } catch(e) {
  61. //errors are stored in aA too
  62. aA.framemsg=aA.framemsg + '\n' + myframes[y].src;
  63. aA.fi=aA.fi + 1;
  64. }
  65. }
  66. }
  67. return aA;
  68. },
  69. provideMessage: function(aA) {
  70. var pl, pl1, pl2;
  71. if(aA.foundCount!=1){
  72. pl='s';
  73. pl1='are indicated by';
  74. pl2='were';
  75. } else {
  76. pl='';
  77. pl1='is indicated by an';
  78. pl2='was';
  79. }
  80.  
  81. var m = [
  82. 'No ARIA attributes were found.',
  83. 'No aria attributes were found and by that we mean no roles, no tabindex of -1, and no attributes starting with ariaCheck.',
  84. 'No, no ARIA attributes here.',
  85. 'Not a single aria attribute was found - not one!',
  86. 'Nope, no aria attributes here either! The spec isnt even final yet, you know.'
  87. ];
  88. var mx = Math.floor(Math.random()*5);
  89. if(aA.foundCount==0) {
  90. alert(m[mx]);
  91. } else {
  92. alert(aA.foundCount + ' element' + pl + ' with ARIA ' + pl2 + ' found and ' + pl1 + ' h6 heading' + pl + '.');
  93. }
  94.  
  95. // alert(alertmessage);
  96. },
  97. inArray: function(arr, obj) {
  98. for(var i=0; i<arr.length; i++) {
  99. if (arr[i] == obj) return true;
  100. }
  101. return false;
  102. },
  103. aria123: function(mydocument,aA){
  104. if (mydocument == null) {
  105. return;
  106. }
  107. //create object just to check length of the properties array
  108. var jt_generic_obj = mydocument.createElement('var');
  109. var ie7 = false;
  110. if (jt_generic_obj.attributes.length > 0) {
  111. ie7 = true;
  112. }
  113.  
  114.  
  115. //changes as we add things
  116. var eLive;
  117. if (mydocument.all) {
  118. // ie
  119. eLive = mydocument.all;
  120. // .attributes does not work til 2
  121. } else {
  122. eLive = mydocument.getElementsByTagName('*');
  123. }
  124.  
  125. //static (e won't change - don't use eLive while editing page)
  126. var e = [];
  127. for (var ij=0; ij<eLive.length;ij++) {
  128. e[ij] = eLive[ij];
  129. }
  130.  
  131. for (var i = 0; i < e.length; i++) {
  132. // EACH OBJECT
  133.  
  134. //remove anything added last time favelet ran
  135.  
  136. var myExpress1 = /ariastAdded.*/;
  137. if (((ie7 && e[i].attributes && e[i].attributes.id.specified) || (!(ie7) && e[i].hasAttribute('id'))) && myExpress1.test(e[i].getAttribute('id'))) {
  138. e[i].parentNode.removeChild(e[i]);
  139. continue;
  140. }
  141.  
  142.  
  143. //original favelet code from revealARIA
  144.  
  145. var myText = 'Found: ';
  146.  
  147. /*
  148. // Check for role
  149. // ie7 cannot do this
  150. if ((!(ie7) && e[i].hasAttribute('role'))) {
  151. myRole=e[i].getAttribute('role');
  152. myText = myText + ' role="' + myRole + '" ';
  153. }
  154. */
  155.  
  156.  
  157. //Check for aria- attributes
  158. if (e[i].attributes) {
  159. for (var x = 0; x < e[i].attributes.length; x++) {
  160. var myA = e[i].attributes[x].nodeName.toLowerCase();
  161. //alert(myA + ' is ' + e[i].getAttribute(myA) );
  162. var myExpress = /ariaCheck.*/;
  163. // ie7 if below is only needed when
  164. // ie8 immitates ie7 - as then the aria attributes are in
  165. // the ie7-style list of empty attributes
  166. if ((!ie7 || (ie7 && e[i].attributes[x].specified)) && ((myExpress.test(myA) && e[i].getAttribute(myA)!=null) || (myA=='tabindex' && e[i].getAttribute(myA)=='-1') ||
  167. (myA=='role' && e[i].getAttribute(myA)!=null))) {
  168. myText = myText + ' ' + myA + '="' + e[i].getAttribute(myA) + '"';
  169.  
  170. //check for items with ids
  171. var value_is_id_attributes = ['aria-controls','aria-describedby','aria-flowto','aria-labelledby','aria-labeledby','aria-owns','aria-activedescendant'];
  172. // all can have a list of ids, except aria-activedescendant
  173.  
  174. if (ariaCheck.inArray(value_is_id_attributes,myA)) {
  175.  
  176. //report on the attribute
  177.  
  178.  
  179. //get array of ids
  180. var id_array = e[i].getAttribute(myA).split(' ');
  181. for (var mapi=0;mapi<id_array.length;mapi++) {
  182. //var myAid=e[i].getAttribute(myA);
  183. var myAid=id_array[mapi];
  184. //alert(mydocument.getElementById(myAid));
  185. if (mydocument.getElementById(myAid) != undefined && mydocument.getElementById(myAid) != null) {
  186. //get object
  187. var myIdTarget=mydocument.getElementById(myAid);
  188.  
  189. var myTextNode2 = mydocument.createTextNode('<'+myIdTarget.tagName.toLowerCase()+' id="'+myAid+'">');
  190.  
  191. //create message
  192. var mySpan2 = mydocument.createElement('h6');
  193. mySpan2.setAttribute('id', ('ariastAddedid' + i));
  194.  
  195. //style message
  196. mySpan2.style.color='navy';
  197. mySpan2.style.fontSize='small';
  198. mySpan2.style.fontWeight='bold';
  199. mySpan2.style.backgroundColor='#f5deb3';
  200. mySpan2.style.margin='0';
  201. mySpan2.style.padding='2px';
  202.  
  203. //append attribute info
  204. mySpan2.appendChild(myTextNode2);
  205.  
  206. //place message for id's object
  207. var firstthing = myIdTarget.childNodes[0];
  208. if (firstthing == undefined) {firstthing = null;}
  209. myIdTarget.insertBefore(mySpan2,firstthing);
  210. } else {
  211. myText = myText+' [NO ID MATCH] ';
  212. }
  213. }
  214.  
  215.  
  216. }
  217.  
  218.  
  219.  
  220.  
  221. }
  222. }
  223. }
  224. //Results per element
  225. if (myText != 'Found: ') {
  226. aA.foundCount++;
  227. //get color
  228. aA.cx=(aA.cx+1)%5;
  229.  
  230. //get border
  231. aA.bx=(aA.bx+1)%6;
  232.  
  233. //get width
  234. aA.wx=(aA.wx+1)%6;
  235.  
  236.  
  237. //outline
  238. e[i].style.border=aA.w[aA.wx] + 'px ' + aA.b[aA.bx] + ' ' + aA.c[aA.cx];
  239. e[i].style.marginTop='0';
  240.  
  241. //create message
  242. var mySpan = document.createElement('h6');
  243. mySpan.setAttribute('id', ('ariastAdded' + i));
  244. var myTextNode = document.createTextNode(myText);
  245. mySpan.appendChild(myTextNode);
  246.  
  247. //style message
  248. mySpan.style.color=aA.c[aA.cx];
  249. mySpan.style.fontSize='small';
  250. mySpan.style.backgroundColor='#f5deb3';
  251. mySpan.style.border=aA.w[aA.wx] + 'px ' + aA.b[aA.bx] + ' ' + aA.c[aA.cx];
  252. mySpan.style.borderBottom='0';
  253. mySpan.style.padding='2px';
  254. mySpan.style.margin='0px';
  255. mySpan.style.clear='left';
  256.  
  257. if (e[i].clientWidth && (e[i].clientWidth > 72)) {
  258. mySpan.style.width=e[i].clientWidth - 4 + 'px';
  259. }
  260.  
  261. // place message just before element it is about
  262. e[i].parentNode.insertBefore(mySpan,e[i]);
  263.  
  264. //create end message
  265. var myEnd = document.createElement('div');
  266. myEnd.setAttribute('id', ('ariastAddedend' + i));
  267. var myEndTextNode = document.createTextNode('END Element');
  268. myEnd.appendChild(myEndTextNode);
  269.  
  270. //style end message offscreen
  271. myEnd.style.position='fixed';
  272. myEnd.style.left='-199px';
  273. myEnd.style.top='auto';
  274. myEnd.width='1px';
  275. myEnd.height='1px';
  276. myEnd.overflow='hidden';
  277.  
  278. // place end message just after element it is about
  279. e[i].parentNode.insertBefore(myEnd,e[i].nextSibling);
  280.  
  281. }
  282. }
  283. // close going through each object
  284.  
  285.  
  286. //Return argument array
  287. return aA;
  288. }
  289.  
  290. };
  291.  
  292. //Feb 21, 2013
  293. //the main code from the quick and dirty favelet that used
  294. //to be revealariaCheck.js has been copied into the framework of
  295. //the Landmarks favelet, so it can go through frames & reuse other features
  296. //Marks targets of every WAI-ARIA id reference, even when they are in lists