capybara-accessible 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +8 -0
- data/Rakefile +0 -1
- data/lib/capybara/accessible.rb +1 -0
- data/lib/capybara/accessible/auditor.rb +25 -3
- data/lib/capybara/accessible/railtie.rb +11 -0
- data/lib/capybara/accessible/tasks.rb +35 -0
- data/lib/capybara/accessible/version.rb +1 -1
- data/lib/vendor/google/accessibility-developer-tools/axs_testing.js +654 -165
- data/spec/accessible_app.rb +4 -0
- data/spec/driver_spec.rb +18 -0
- metadata +22 -22
- data/.rspec +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ff9e45488ea2958d4b85cd7d49dd4cdaa5dafd3
|
4
|
+
data.tar.gz: ca5d1c374682e24af3fd5762fd9af8486420d163
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bdc8ffa7b1d86ce045f804938b804b579e404b662a812e33e06d7064c3664215fd1d2fb98b326c9eca2d3a7bbc09c9e2830cf9b8bdd81b3f2f5c6feb366180a
|
7
|
+
data.tar.gz: 9350403adcb506559e44ab58d716b526ed3607ce90c128cc466787454f649b9f792728566e8df290812afe9cfb345cb58c698aa9a072a726a16c585b02e62895
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -87,6 +87,14 @@ You can disable audits on individual tests by tagging the example or group with
|
|
87
87
|
Then I should see the inaccessible image # this assertion will still be executed
|
88
88
|
|
89
89
|
|
90
|
+
### Changing the severity of audit rules
|
91
|
+
|
92
|
+
If you'd like to enforce certain rules and raise errors instead of showing them as warnings,
|
93
|
+
for example images should never have alt attributes, you can configure it as follows:
|
94
|
+
|
95
|
+
Capybara::Accessible::Auditor.severe_rules = ['AX_TEXT_02']
|
96
|
+
|
97
|
+
|
90
98
|
## Support
|
91
99
|
|
92
100
|
If you think you've found a bug, or have installation questions or feature requests, please send a message
|
data/Rakefile
CHANGED
data/lib/capybara/accessible.rb
CHANGED
@@ -27,6 +27,14 @@ module Capybara::Accessible
|
|
27
27
|
@@log_level ||= :error
|
28
28
|
end
|
29
29
|
|
30
|
+
def self.severe_rules=(rules)
|
31
|
+
@@severe_rules = rules
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.severe_rules
|
35
|
+
@@severe_rules ||= []
|
36
|
+
end
|
37
|
+
|
30
38
|
def audit_rules
|
31
39
|
File.read(File.expand_path("../../../vendor/google/accessibility-developer-tools/axs_testing.js", __FILE__))
|
32
40
|
end
|
@@ -49,14 +57,30 @@ module Capybara::Accessible
|
|
49
57
|
<<-JAVASCRIPT
|
50
58
|
#{audit_rules}
|
51
59
|
var config = new axs.AuditConfiguration();
|
60
|
+
var severe_rules = #{severe_rules.to_json};
|
61
|
+
var rule;
|
62
|
+
|
63
|
+
for(rule in severe_rules) {
|
64
|
+
config.setSeverity(severe_rules[rule], axs.constants.Severity.SEVERE);
|
65
|
+
}
|
52
66
|
config.auditRulesToIgnore = #{excluded_rules.to_json};
|
67
|
+
|
53
68
|
var results = axs.Audit.run(config);
|
54
69
|
JAVASCRIPT
|
55
70
|
end
|
56
71
|
|
57
72
|
def excluded_rules
|
58
73
|
codes = Capybara::Accessible::Auditor.exclusions
|
59
|
-
|
74
|
+
codes.map { |code| mapping[code]}
|
75
|
+
end
|
76
|
+
|
77
|
+
def severe_rules
|
78
|
+
codes = Capybara::Accessible::Auditor.severe_rules
|
79
|
+
codes.map { |code| mapping[code]}
|
80
|
+
end
|
81
|
+
|
82
|
+
def mapping
|
83
|
+
@mapping ||= {
|
60
84
|
'AX_ARIA_01' => 'badAriaRole',
|
61
85
|
'AX_ARIA_02' => 'nonExistentAriaLabelledbyElement',
|
62
86
|
'AX_ARIA_03' => 'requiredAriaAttributeMissing',
|
@@ -73,8 +97,6 @@ module Capybara::Accessible
|
|
73
97
|
# 'AX_TITLE_01' => 'linkWithUnclearPurpose', # This has a duplicate name
|
74
98
|
# 'AX_ARIA_05' => '', # This has no rule associated with it
|
75
99
|
}
|
76
|
-
|
77
|
-
codes.map { |code| mapping[code]}
|
78
100
|
end
|
79
101
|
|
80
102
|
def page_url
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'rake'
|
3
|
+
require 'capybara/accessible'
|
4
|
+
|
5
|
+
namespace :capybara_accessible do
|
6
|
+
|
7
|
+
desc 'Report total number of integration tests that are accessible/inaccessible'
|
8
|
+
task :report_inaccessible_tests do
|
9
|
+
directories_to_exclude = ['features/support']
|
10
|
+
directories = Dir['features/**'].concat(Dir['spec/features/**']) - directories_to_exclude
|
11
|
+
directories.map! { |d| [d.split('/').last, d]}
|
12
|
+
directories.sort!
|
13
|
+
|
14
|
+
total_inaccessible_tests = 0
|
15
|
+
total_tests = 0
|
16
|
+
CSV.open("output_#{DateTime.now.strftime("%Y%m%dT%H%M")}.csv", 'w') do |csv|
|
17
|
+
csv<<['Module', 'Test Folder Path', 'Inaccessible Tests', 'Accessible Tests', 'Total Tests']
|
18
|
+
|
19
|
+
directories.each do |key, directory|
|
20
|
+
if directory.split('/').first == 'features'
|
21
|
+
inaccessible_count = `git grep "@inaccessible" #{directory} | wc -l`
|
22
|
+
total_count = `git grep "Scenario" #{directory} | wc -l`
|
23
|
+
else
|
24
|
+
inaccessible_count = `git grep "inaccessible.*true" #{directory} | wc -l`
|
25
|
+
total_count = `git grep "scenario.*do" #{directory} | wc -l`
|
26
|
+
end
|
27
|
+
total_inaccessible_tests += inaccessible_count.to_i
|
28
|
+
total_tests += total_count.to_i
|
29
|
+
|
30
|
+
csv << ["#{key.upcase}", "#{directory}", inaccessible_count.to_i, (total_count.to_i - inaccessible_count.to_i), total_count.to_i]
|
31
|
+
end
|
32
|
+
csv << ['TOTALS', '', total_inaccessible_tests, total_tests - total_inaccessible_tests, total_tests]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,3 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2013 Google Inc.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*
|
16
|
+
* Generated from http://github.com/GoogleChrome/accessibility-developer-tools/tree/6e426d3e4e38b611bc013c14c2ade77674397627
|
17
|
+
*
|
18
|
+
* See project README for build steps.
|
19
|
+
*/
|
20
|
+
|
21
|
+
// AUTO-GENERATED CONTENT BELOW: DO NOT EDIT! See above for details.
|
22
|
+
|
1
23
|
var COMPILED = !0, goog = goog || {};
|
2
24
|
goog.global = this;
|
3
25
|
goog.exportPath_ = function(a, b, c) {
|
@@ -387,6 +409,10 @@ goog.scope = function(a) {
|
|
387
409
|
a.call(goog.global)
|
388
410
|
};
|
389
411
|
var axs = {};
|
412
|
+
axs.browserUtils = {};
|
413
|
+
axs.browserUtils.matchSelector = function(a, b) {
|
414
|
+
return a.webkitMatchesSelector ? a.webkitMatchesSelector(b) : a.mozMatchesSelector ? a.mozMatchesSelector(b) : !1
|
415
|
+
};
|
390
416
|
axs.constants = {};
|
391
417
|
axs.constants.ARIA_ROLES = {alert:{namefrom:["author"], parent:["region"]}, alertdialog:{namefrom:["author"], namerequired:!0, parent:["alert", "dialog"]}, application:{namefrom:["author"], namerequired:!0, parent:["landmark"]}, article:{namefrom:["author"], parent:["document", "region"]}, banner:{namefrom:["author"], parent:["landmark"]}, button:{childpresentational:!0, namefrom:["contents", "author"], namerequired:!0, parent:["command"], properties:["aria-expanded", "aria-pressed"]}, checkbox:{namefrom:["contents",
|
392
418
|
"author"], namerequired:!0, parent:["input"], requiredProperties:["aria-checked"], properties:["aria-checked"]}, columnheader:{namefrom:["contents", "author"], namerequired:!0, parent:["gridcell", "sectionhead", "widget"], properties:["aria-sort"]}, combobox:{mustcontain:["listbox", "textbox"], namefrom:["author"], namerequired:!0, parent:["select"], requiredProperties:["aria-expanded"], properties:["aria-expanded", "aria-autocomplete", "aria-required"]}, command:{"abstract":!0, namefrom:["author"],
|
@@ -458,17 +484,20 @@ submit:"input_type_submit", tel:"input_type_tel", text:"input_type_text", url:"i
|
|
458
484
|
axs.constants.TAG_TO_INFORMATION_TABLE_VERBOSE_MSG = {A:"tag_link", BUTTON:"tag_button", H1:"tag_h1", H2:"tag_h2", H3:"tag_h3", H4:"tag_h4", H5:"tag_h5", H6:"tag_h6", LI:"tag_li", OL:"tag_ol", SELECT:"tag_select", TEXTAREA:"tag_textarea", UL:"tag_ul", SECTION:"tag_section", NAV:"tag_nav", ARTICLE:"tag_article", ASIDE:"tag_aside", HGROUP:"tag_hgroup", HEADER:"tag_header", FOOTER:"tag_footer", TIME:"tag_time", MARK:"tag_mark"};
|
459
485
|
axs.constants.TAG_TO_INFORMATION_TABLE_BRIEF_MSG = {BUTTON:"tag_button", SELECT:"tag_select", TEXTAREA:"tag_textarea"};
|
460
486
|
axs.constants.MIXED_VALUES = {"true":!0, "false":!0, mixed:!0};
|
461
|
-
|
462
|
-
var
|
463
|
-
|
464
|
-
|
465
|
-
|
487
|
+
(function() {
|
488
|
+
for(var a in axs.constants.ARIA_PROPERTIES) {
|
489
|
+
var b = axs.constants.ARIA_PROPERTIES[a];
|
490
|
+
if(b.values) {
|
491
|
+
for(var c = {}, d = 0;d < b.values.length;d++) {
|
492
|
+
c[b.values[d]] = !0
|
493
|
+
}
|
494
|
+
b.valuesSet = c
|
466
495
|
}
|
467
|
-
propertyDetails.valuesSet = valuesSet
|
468
496
|
}
|
469
|
-
}
|
497
|
+
})();
|
470
498
|
axs.constants.Severity = {INFO:"Info", WARNING:"Warning", SEVERE:"Severe"};
|
471
499
|
axs.constants.AuditResult = {PASS:"PASS", FAIL:"FAIL", NA:"NA"};
|
500
|
+
axs.constants.InlineElements = {TT:!0, I:!0, B:!0, BIG:!0, SMALL:!0, EM:!0, STRONG:!0, DFN:!0, CODE:!0, SAMP:!0, KBD:!0, VAR:!0, CITE:!0, ABBR:!0, ACRONYM:!0, A:!0, IMG:!0, OBJECT:!0, BR:!0, SCRIPT:!0, MAP:!0, Q:!0, SUB:!0, SUP:!0, SPAN:!0, BDO:!0, INPUT:!0, SELECT:!0, TEXTAREA:!0, LABEL:!0, BUTTON:!0};
|
472
501
|
axs.utils = {};
|
473
502
|
axs.utils.FOCUSABLE_ELEMENTS_SELECTOR = "input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),a[href],iframe,[tabindex]";
|
474
503
|
axs.utils.Color = function(a, b, c, d) {
|
@@ -485,6 +514,26 @@ axs.utils.calculateContrastRatio = function(a, b) {
|
|
485
514
|
var c = axs.utils.calculateLuminance(a), d = axs.utils.calculateLuminance(b);
|
486
515
|
return(Math.max(c, d) + 0.05) / (Math.min(c, d) + 0.05)
|
487
516
|
};
|
517
|
+
axs.utils.luminanceRatio = function(a, b) {
|
518
|
+
return(Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05)
|
519
|
+
};
|
520
|
+
axs.utils.asElement = function(a) {
|
521
|
+
switch(a.nodeType) {
|
522
|
+
case Node.COMMENT_NODE:
|
523
|
+
return null;
|
524
|
+
case Node.ELEMENT_NODE:
|
525
|
+
if("script" == a.tagName.toLowerCase()) {
|
526
|
+
return null
|
527
|
+
}
|
528
|
+
break;
|
529
|
+
case Node.TEXT_NODE:
|
530
|
+
a = a.parentElement;
|
531
|
+
break;
|
532
|
+
default:
|
533
|
+
return console.warn("Unhandled node type: ", a.nodeType), null
|
534
|
+
}
|
535
|
+
return a
|
536
|
+
};
|
488
537
|
axs.utils.elementIsTransparent = function(a) {
|
489
538
|
return"0" == a.style.opacity
|
490
539
|
};
|
@@ -498,15 +547,21 @@ axs.utils.elementIsOutsideScrollArea = function(a) {
|
|
498
547
|
var b = document.body.scrollWidth, c = document.body.scrollTop, d = document.body.scrollLeft;
|
499
548
|
return a.top >= document.body.scrollHeight || a.bottom <= -c || a.left >= b || a.right <= -d ? !0 : !1
|
500
549
|
};
|
501
|
-
axs.utils.
|
502
|
-
|
503
|
-
|
504
|
-
|
550
|
+
axs.utils.isAncestor = function(a, b) {
|
551
|
+
return null == b ? !1 : b === a ? !0 : axs.utils.isAncestor(a, b.parentNode)
|
552
|
+
};
|
553
|
+
axs.utils.overlappingElements = function(a) {
|
505
554
|
if(axs.utils.elementHasZeroArea(a)) {
|
506
555
|
return null
|
507
556
|
}
|
508
|
-
var
|
509
|
-
|
557
|
+
for(var b = [], c = a.getClientRects(), d = 0;d < c.length;d++) {
|
558
|
+
var e = c[d], e = document.elementFromPoint((e.left + e.right) / 2, (e.top + e.bottom) / 2);
|
559
|
+
if(null != e && e != a && !axs.utils.isAncestor(e, a) && !axs.utils.isAncestor(a, e)) {
|
560
|
+
var f = window.getComputedStyle(e, null);
|
561
|
+
f && (f = axs.utils.getBgColor(f, e)) && 0 < f.alpha && 0 > b.indexOf(e) && b.push(e)
|
562
|
+
}
|
563
|
+
}
|
564
|
+
return b
|
510
565
|
};
|
511
566
|
axs.utils.elementIsHtmlControl = function(a) {
|
512
567
|
var b = a.ownerDocument.defaultView;
|
@@ -516,23 +571,20 @@ axs.utils.elementIsAriaWidget = function(a) {
|
|
516
571
|
return a.hasAttribute("role") && (a = a.getAttribute("role")) && (a = axs.constants.ARIA_ROLES[a]) && "widget" in a.allParentRolesSet ? !0 : !1
|
517
572
|
};
|
518
573
|
axs.utils.elementIsVisible = function(a) {
|
519
|
-
|
520
|
-
return!1
|
521
|
-
}
|
522
|
-
if(a = axs.utils.overlappingElement(a)) {
|
523
|
-
var b = window.getComputedStyle(a, null);
|
524
|
-
if(b && (a = axs.utils.getBgColor(b, a)) && 0 < a.alpha) {
|
525
|
-
return!1
|
526
|
-
}
|
527
|
-
}
|
528
|
-
return!0
|
574
|
+
return axs.utils.elementIsTransparent(a) || axs.utils.elementHasZeroArea(a) || axs.utils.elementIsOutsideScrollArea(a) || axs.utils.overlappingElements(a).length ? !1 : !0
|
529
575
|
};
|
530
576
|
axs.utils.isLargeFont = function(a) {
|
531
577
|
var b = a.fontSize;
|
532
578
|
a = "bold" == a.fontWeight;
|
533
579
|
var c = b.match(/(\d+)px/);
|
534
580
|
if(c) {
|
535
|
-
|
581
|
+
b = parseInt(c[1], 10);
|
582
|
+
if(c = window.getComputedStyle(document.body, null).fontSize.match(/(\d+)px/)) {
|
583
|
+
var d = parseInt(c[1], 10), c = 1.2 * d, d = 1.5 * d
|
584
|
+
}else {
|
585
|
+
c = 19.2, d = 24
|
586
|
+
}
|
587
|
+
return a && b >= c || b >= d
|
536
588
|
}
|
537
589
|
if(c = b.match(/(\d+)em/)) {
|
538
590
|
return b = parseInt(c[1], 10), a && 1.2 <= b || 1.5 <= b ? !0 : !1
|
@@ -541,7 +593,7 @@ axs.utils.isLargeFont = function(a) {
|
|
541
593
|
return b = parseInt(c[1], 10), a && 120 <= b || 150 <= b ? !0 : !1
|
542
594
|
}
|
543
595
|
if(c = b.match(/(\d+)pt/)) {
|
544
|
-
if(b = parseInt(c[1], 10), a && 14 <= b ||
|
596
|
+
if(b = parseInt(c[1], 10), a && 14 <= b || 18 <= b) {
|
545
597
|
return!0
|
546
598
|
}
|
547
599
|
}
|
@@ -549,39 +601,46 @@ axs.utils.isLargeFont = function(a) {
|
|
549
601
|
};
|
550
602
|
axs.utils.getBgColor = function(a, b) {
|
551
603
|
var c = axs.utils.parseColor(a.backgroundColor);
|
552
|
-
if(!c
|
604
|
+
if(!c) {
|
553
605
|
return null
|
554
606
|
}
|
607
|
+
1 > a.opacity && (c.alpha *= a.opacity);
|
555
608
|
if(1 > c.alpha) {
|
556
|
-
var d = b
|
557
|
-
|
558
|
-
|
559
|
-
var f = window.getComputedStyle(d, null);
|
560
|
-
if(f) {
|
561
|
-
if(f.backgroundImage && "none" != f.backgroundImage) {
|
562
|
-
return null
|
563
|
-
}
|
564
|
-
if((f = axs.utils.parseColor(f.backgroundColor)) && 0 != f.alpha && (e.push(f), 1 == f.alpha)) {
|
565
|
-
c = null;
|
566
|
-
break
|
567
|
-
}
|
568
|
-
}
|
569
|
-
}
|
570
|
-
c || e.push(new axs.utils.Color(255, 255, 255, 1));
|
571
|
-
for(d = e.pop();e.length;) {
|
572
|
-
c = e.pop(), d = axs.utils.flattenColors(c, d)
|
609
|
+
var d = axs.utils.getParentBgColor(b);
|
610
|
+
if(null == d) {
|
611
|
+
return null
|
573
612
|
}
|
574
|
-
c = d
|
613
|
+
c = axs.utils.flattenColors(c, d)
|
575
614
|
}
|
576
615
|
return c
|
577
616
|
};
|
578
|
-
axs.utils.
|
579
|
-
var
|
580
|
-
|
617
|
+
axs.utils.getParentBgColor = function(a) {
|
618
|
+
var b = a;
|
619
|
+
a = [];
|
620
|
+
for(var c = null;b = b.parentElement;) {
|
621
|
+
var d = window.getComputedStyle(b, null);
|
622
|
+
if(d) {
|
623
|
+
var e = axs.utils.parseColor(d.backgroundColor);
|
624
|
+
if(e && (1 > d.opacity && (e.alpha *= d.opacity), 0 != e.alpha && (a.push(e), 1 == e.alpha))) {
|
625
|
+
c = !0;
|
626
|
+
break
|
627
|
+
}
|
628
|
+
}
|
629
|
+
}
|
630
|
+
c || a.push(new axs.utils.Color(255, 255, 255, 1));
|
631
|
+
for(b = a.pop();a.length;) {
|
632
|
+
c = a.pop(), b = axs.utils.flattenColors(c, b)
|
633
|
+
}
|
634
|
+
return b
|
635
|
+
};
|
636
|
+
axs.utils.getFgColor = function(a, b, c) {
|
637
|
+
var d = axs.utils.parseColor(a.color);
|
638
|
+
if(!d) {
|
581
639
|
return null
|
582
640
|
}
|
583
|
-
1 >
|
584
|
-
|
641
|
+
1 > d.alpha && (d = axs.utils.flattenColors(d, c));
|
642
|
+
1 > a.opacity && (b = axs.utils.getParentBgColor(b), d.alpha *= a.opacity, d = axs.utils.flattenColors(d, b));
|
643
|
+
return d
|
585
644
|
};
|
586
645
|
axs.utils.parseColor = function(a) {
|
587
646
|
var b = a.match(/^rgb\((\d+), (\d+), (\d+)\)$/);
|
@@ -592,34 +651,130 @@ axs.utils.parseColor = function(a) {
|
|
592
651
|
}
|
593
652
|
return(b = a.match(/^rgba\((\d+), (\d+), (\d+), (\d+(\.\d+)?)\)/)) ? (d = parseInt(b[4], 10), a = parseInt(b[1], 10), c = parseInt(b[2], 10), b = parseInt(b[3], 10), new axs.utils.Color(a, c, b, d)) : null
|
594
653
|
};
|
654
|
+
axs.utils.colorChannelToString = function(a) {
|
655
|
+
a = Math.round(a);
|
656
|
+
return 15 >= a ? "0" + a.toString(16) : a.toString(16)
|
657
|
+
};
|
595
658
|
axs.utils.colorToString = function(a) {
|
596
|
-
return"rgba(" + [a.red, a.green, a.blue, a.alpha].join() + ")"
|
659
|
+
return 1 == a.alpha ? "#" + axs.utils.colorChannelToString(a.red) + axs.utils.colorChannelToString(a.green) + axs.utils.colorChannelToString(a.blue) : "rgba(" + [a.red, a.green, a.blue, a.alpha].join() + ")"
|
660
|
+
};
|
661
|
+
axs.utils.luminanceFromContrastRatio = function(a, b, c) {
|
662
|
+
return c ? (a + 0.05) * b - 0.05 : (a + 0.05) / b - 0.05
|
663
|
+
};
|
664
|
+
axs.utils.translateColor = function(a, b) {
|
665
|
+
var c = a[0], c = (b - c) / ((c > b ? 0 : 1) - c);
|
666
|
+
return axs.utils.fromYCC([b, a[1] - a[1] * c, a[2] - a[2] * c])
|
667
|
+
};
|
668
|
+
axs.utils.suggestColors = function(a, b, c, d) {
|
669
|
+
if(!axs.utils.isLowContrast(c, d, !0)) {
|
670
|
+
return null
|
671
|
+
}
|
672
|
+
var e = {}, f = axs.utils.calculateLuminance(a), g = axs.utils.calculateLuminance(b), h = axs.utils.isLargeFont(d) ? 3 : 4.5, k = axs.utils.isLargeFont(d) ? 4.5 : 7, m = g > f, l = axs.utils.luminanceFromContrastRatio(f, h + 0.02, m), n = axs.utils.luminanceFromContrastRatio(f, k + 0.02, m), q = axs.utils.toYCC(b);
|
673
|
+
if(axs.utils.isLowContrast(c, d, !1) && 1 >= l && 0 <= l) {
|
674
|
+
var p = axs.utils.translateColor(q, l), l = axs.utils.calculateContrastRatio(p, a);
|
675
|
+
axs.utils.calculateLuminance(p);
|
676
|
+
f = {};
|
677
|
+
f.fg = axs.utils.colorToString(p);
|
678
|
+
f.bg = axs.utils.colorToString(a);
|
679
|
+
f.contrast = l.toFixed(2);
|
680
|
+
e.AA = f
|
681
|
+
}
|
682
|
+
axs.utils.isLowContrast(c, d, !0) && 1 >= n && 0 <= n && (n = axs.utils.translateColor(q, n), l = axs.utils.calculateContrastRatio(n, a), f = {}, f.fg = axs.utils.colorToString(n), f.bg = axs.utils.colorToString(a), f.contrast = l.toFixed(2), e.AAA = f);
|
683
|
+
h = axs.utils.luminanceFromContrastRatio(g, h + 0.02, !m);
|
684
|
+
g = axs.utils.luminanceFromContrastRatio(g, k + 0.02, !m);
|
685
|
+
a = axs.utils.toYCC(a);
|
686
|
+
!("AA" in e) && axs.utils.isLowContrast(c, d, !1) && 1 >= h && 0 <= h && (k = axs.utils.translateColor(a, h), l = axs.utils.calculateContrastRatio(b, k), f = {}, f.bg = axs.utils.colorToString(k), f.fg = axs.utils.colorToString(b), f.contrast = l.toFixed(2), e.AA = f);
|
687
|
+
!("AAA" in e) && axs.utils.isLowContrast(c, d, !0) && 1 >= g && 0 <= g && (c = axs.utils.translateColor(a, g), l = axs.utils.calculateContrastRatio(b, c), f = {}, f.bg = axs.utils.colorToString(c), f.fg = axs.utils.colorToString(b), f.contrast = l.toFixed(2), e.AAA = f);
|
688
|
+
return e
|
597
689
|
};
|
598
690
|
axs.utils.flattenColors = function(a, b) {
|
599
691
|
var c = a.alpha;
|
600
|
-
return new axs.utils.Color((1 - c) * b.red + c * a.red, (1 - c) * b.green + c * a.green, (1 - c) * b.blue + c * a.blue, 1)
|
692
|
+
return new axs.utils.Color((1 - c) * b.red + c * a.red, (1 - c) * b.green + c * a.green, (1 - c) * b.blue + c * a.blue, a.alpha + b.alpha * (1 - a.alpha))
|
601
693
|
};
|
602
694
|
axs.utils.calculateLuminance = function(a) {
|
695
|
+
return axs.utils.toYCC(a)[0]
|
696
|
+
};
|
697
|
+
axs.utils.RGBToYCCMatrix = function(a, b) {
|
698
|
+
return[[a, 1 - a - b, b], [-a / (2 - 2 * b), (a + b - 1) / (2 - 2 * b), (1 - b) / (2 - 2 * b)], [(1 - a) / (2 - 2 * a), (a + b - 1) / (2 - 2 * a), -b / (2 - 2 * a)]]
|
699
|
+
};
|
700
|
+
axs.utils.invert3x3Matrix = function(a) {
|
701
|
+
var b = a[0][0], c = a[0][1], d = a[0][2], e = a[1][0], f = a[1][1], g = a[1][2], h = a[2][0], k = a[2][1];
|
702
|
+
a = a[2][2];
|
703
|
+
return axs.utils.scalarMultiplyMatrix([[f * a - g * k, d * k - c * a, c * g - d * f], [g * h - e * a, b * a - d * h, d * e - b * g], [e * k - f * h, h * c - b * k, b * f - c * e]], 1 / (b * (f * a - g * k) - c * (a * e - g * h) + d * (e * k - f * h)))
|
704
|
+
};
|
705
|
+
axs.utils.scalarMultiplyMatrix = function(a, b) {
|
706
|
+
for(var c = [[], [], []], d = 0;3 > d;d++) {
|
707
|
+
for(var e = 0;3 > e;e++) {
|
708
|
+
c[d][e] = a[d][e] * b
|
709
|
+
}
|
710
|
+
}
|
711
|
+
return c
|
712
|
+
};
|
713
|
+
axs.utils.kR = 0.2126;
|
714
|
+
axs.utils.kB = 0.0722;
|
715
|
+
axs.utils.YCC_MATRIX = axs.utils.RGBToYCCMatrix(axs.utils.kR, axs.utils.kB);
|
716
|
+
axs.utils.INVERTED_YCC_MATRIX = axs.utils.invert3x3Matrix(axs.utils.YCC_MATRIX);
|
717
|
+
axs.utils.convertColor = function(a, b) {
|
718
|
+
var c = b[0], d = b[1], e = b[2];
|
719
|
+
return[a[0][0] * c + a[0][1] * d + a[0][2] * e, a[1][0] * c + a[1][1] * d + a[1][2] * e, a[2][0] * c + a[2][1] * d + a[2][2] * e]
|
720
|
+
};
|
721
|
+
axs.utils.multiplyMatrices = function(a, b) {
|
722
|
+
for(var c = [[], [], []], d = 0;3 > d;d++) {
|
723
|
+
for(var e = 0;3 > e;e++) {
|
724
|
+
c[d][e] = a[d][0] * b[0][e] + a[d][1] * b[1][e] + a[d][2] * b[2][e]
|
725
|
+
}
|
726
|
+
}
|
727
|
+
return c
|
728
|
+
};
|
729
|
+
axs.utils.toYCC = function(a) {
|
603
730
|
var b = a.red / 255, c = a.green / 255;
|
604
731
|
a = a.blue / 255;
|
605
732
|
b = 0.03928 >= b ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
|
606
733
|
c = 0.03928 >= c ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
607
734
|
a = 0.03928 >= a ? a / 12.92 : Math.pow((a + 0.055) / 1.055, 2.4);
|
608
|
-
return
|
735
|
+
return axs.utils.convertColor(axs.utils.YCC_MATRIX, [b, c, a])
|
736
|
+
};
|
737
|
+
axs.utils.fromYCC = function(a) {
|
738
|
+
var b = axs.utils.convertColor(axs.utils.INVERTED_YCC_MATRIX, a), c = b[0];
|
739
|
+
a = b[1];
|
740
|
+
b = b[2];
|
741
|
+
c = 0.00303949 >= c ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
742
|
+
a = 0.00303949 >= a ? 12.92 * a : 1.055 * Math.pow(a, 1 / 2.4) - 0.055;
|
743
|
+
b = 0.00303949 >= b ? 12.92 * b : 1.055 * Math.pow(b, 1 / 2.4) - 0.055;
|
744
|
+
c = Math.min(Math.max(Math.round(255 * c), 0), 255);
|
745
|
+
a = Math.min(Math.max(Math.round(255 * a), 0), 255);
|
746
|
+
b = Math.min(Math.max(Math.round(255 * b), 0), 255);
|
747
|
+
return new axs.utils.Color(c, a, b, 1)
|
748
|
+
};
|
749
|
+
axs.utils.scalarMultiplyMatrix = function(a, b) {
|
750
|
+
for(var c = [[], [], []], d = 0;3 > d;d++) {
|
751
|
+
for(var e = 0;3 > e;e++) {
|
752
|
+
c[d][e] = a[d][e] * b
|
753
|
+
}
|
754
|
+
}
|
755
|
+
return c
|
756
|
+
};
|
757
|
+
axs.utils.multiplyMatrices = function(a, b) {
|
758
|
+
for(var c = [[], [], []], d = 0;3 > d;d++) {
|
759
|
+
for(var e = 0;3 > e;e++) {
|
760
|
+
c[d][e] = a[d][0] * b[0][e] + a[d][1] * b[1][e] + a[d][2] * b[2][e]
|
761
|
+
}
|
762
|
+
}
|
763
|
+
return c
|
609
764
|
};
|
610
765
|
axs.utils.getContrastRatioForElement = function(a) {
|
611
766
|
var b = window.getComputedStyle(a, null);
|
612
767
|
return axs.utils.getContrastRatioForElementWithComputedStyle(b, a)
|
613
768
|
};
|
614
769
|
axs.utils.getContrastRatioForElementWithComputedStyle = function(a, b) {
|
615
|
-
if(
|
770
|
+
if(axs.utils.isElementHidden(b)) {
|
616
771
|
return null
|
617
772
|
}
|
618
773
|
var c = axs.utils.getBgColor(a, b);
|
619
774
|
if(!c) {
|
620
775
|
return null
|
621
776
|
}
|
622
|
-
var d = axs.utils.getFgColor(a, c);
|
777
|
+
var d = axs.utils.getFgColor(a, b, c);
|
623
778
|
return d ? axs.utils.calculateContrastRatio(d, c) : null
|
624
779
|
};
|
625
780
|
axs.utils.isNativeTextElement = function(a) {
|
@@ -652,12 +807,13 @@ axs.utils.isNativeTextElement = function(a) {
|
|
652
807
|
return!1
|
653
808
|
}
|
654
809
|
};
|
655
|
-
axs.utils.isLowContrast = function(a, b) {
|
656
|
-
|
810
|
+
axs.utils.isLowContrast = function(a, b, c) {
|
811
|
+
a = Math.round(10 * a) / 10;
|
812
|
+
return c ? 4.5 > a || !axs.utils.isLargeFont(b) && 7 > a : 3 > a || !axs.utils.isLargeFont(b) && 4.5 > a
|
657
813
|
};
|
658
814
|
axs.utils.hasLabel = function(a) {
|
659
815
|
var b = a.tagName.toLowerCase(), c = a.type ? a.type.toLowerCase() : "";
|
660
|
-
if(a.hasAttribute("aria-label") || a.hasAttribute("title") || "img" == b && a.hasAttribute("alt") || "input" == b && "image" == c && a.hasAttribute("alt") || "input" == b && ("submit" == c || "reset" == c) || a.hasAttribute("aria-labelledby") || axs.utils.isNativeTextElement(a) && a.hasAttribute("placeholder") || a.hasAttribute("id") && 0 < document.querySelectorAll(
|
816
|
+
if(a.hasAttribute("aria-label") || a.hasAttribute("title") || "img" == b && a.hasAttribute("alt") || "input" == b && "image" == c && a.hasAttribute("alt") || "input" == b && ("submit" == c || "reset" == c) || a.hasAttribute("aria-labelledby") || axs.utils.isNativeTextElement(a) && a.hasAttribute("placeholder") || a.hasAttribute("id") && 0 < document.querySelectorAll('label[for="' + a.id + '"]').length) {
|
661
817
|
return!0
|
662
818
|
}
|
663
819
|
for(b = a.parentElement;b;) {
|
@@ -681,12 +837,20 @@ axs.utils.isElementHidden = function(a) {
|
|
681
837
|
axs.utils.isElementOrAncestorHidden = function(a) {
|
682
838
|
return axs.utils.isElementHidden(a) ? !0 : a.parentElement ? axs.utils.isElementOrAncestorHidden(a.parentElement) : !1
|
683
839
|
};
|
684
|
-
axs.utils.
|
840
|
+
axs.utils.isInlineElement = function(a) {
|
841
|
+
a = a.tagName.toUpperCase();
|
842
|
+
return axs.constants.InlineElements[a]
|
843
|
+
};
|
844
|
+
axs.utils.getRoles = function(a) {
|
685
845
|
if(!a.hasAttribute("role")) {
|
686
846
|
return!1
|
687
847
|
}
|
688
|
-
a = a.getAttribute("role");
|
689
|
-
|
848
|
+
a = a.getAttribute("role").split(" ");
|
849
|
+
for(var b = [], c = !0, d = 0;d < a.length;d++) {
|
850
|
+
var e = a[d];
|
851
|
+
axs.constants.ARIA_ROLES[e] ? b.push({name:e, details:axs.constants.ARIA_ROLES[e], valid:!0}) : (b.push({name:e, valid:!1}), c = !1)
|
852
|
+
}
|
853
|
+
return{roles:b, valid:c}
|
690
854
|
};
|
691
855
|
axs.utils.getAriaPropertyValue = function(a, b, c) {
|
692
856
|
var d = a.replace(/^aria-/, ""), e = axs.constants.ARIA_PROPERTIES[d], d = {name:a, rawValue:b};
|
@@ -708,6 +872,8 @@ axs.utils.getAriaPropertyValue = function(a, b, c) {
|
|
708
872
|
}
|
709
873
|
return d;
|
710
874
|
case "integer":
|
875
|
+
;
|
876
|
+
case "decimal":
|
711
877
|
c = axs.utils.isValidNumber(b);
|
712
878
|
if(!c.valid) {
|
713
879
|
return d.valid = !1, d.reason = c.reason, d
|
@@ -752,10 +918,14 @@ axs.utils.isValidBoolean = function(a) {
|
|
752
918
|
return"boolean" != typeof b ? {valid:!1, value:a, reason:'"' + a + '" is not a true/false value'} : {valid:!0, value:b}
|
753
919
|
};
|
754
920
|
axs.utils.isValidIDRefValue = function(a, b) {
|
755
|
-
return b.ownerDocument.getElementById(a) ? {valid:!0, idref:a} : {valid:!1, idref:a, reason:'No element with ID "' + a + '"'}
|
921
|
+
return 0 == a.length ? {valid:!0, idref:a} : b.ownerDocument.getElementById(a) ? {valid:!0, idref:a} : {valid:!1, idref:a, reason:'No element with ID "' + a + '"'}
|
756
922
|
};
|
757
923
|
axs.utils.isValidNumber = function(a) {
|
758
|
-
|
924
|
+
try {
|
925
|
+
var b = JSON.parse(a)
|
926
|
+
}catch(c) {
|
927
|
+
return{valid:!1, value:a, reason:'"' + a + '" is not a number'}
|
928
|
+
}
|
759
929
|
return"number" != typeof b ? {valid:!1, value:a, reason:'"' + a + '" is not a number'} : {valid:!0, value:b}
|
760
930
|
};
|
761
931
|
axs.utils.isElementImplicitlyFocusable = function(a) {
|
@@ -822,6 +992,304 @@ axs.utils.getQuerySelectorText = function(a) {
|
|
822
992
|
}
|
823
993
|
return""
|
824
994
|
};
|
995
|
+
axs.properties = {};
|
996
|
+
axs.properties.TEXT_CONTENT_XPATH = './/text()[normalize-space(.)!=""]/parent::*[name()!="script"]';
|
997
|
+
axs.properties.getFocusProperties = function(a) {
|
998
|
+
var b = {}, c = a.getAttribute("tabindex");
|
999
|
+
void 0 != c ? b.tabindex = {value:c, valid:!0} : axs.utils.isElementImplicitlyFocusable(a) && (b.implicitlyFocusable = {value:!0, valid:!0});
|
1000
|
+
if(0 == Object.keys(b).length) {
|
1001
|
+
return null
|
1002
|
+
}
|
1003
|
+
var d = axs.utils.elementIsTransparent(a), e = axs.utils.elementHasZeroArea(a), f = axs.utils.elementIsOutsideScrollArea(a), g = axs.utils.overlappingElements(a);
|
1004
|
+
if(d || e || f || 0 < g.length) {
|
1005
|
+
var c = axs.utils.isElementOrAncestorHidden(a), h = {value:!1, valid:c};
|
1006
|
+
d && (h.transparent = !0);
|
1007
|
+
e && (h.zeroArea = !0);
|
1008
|
+
f && (h.outsideScrollArea = !0);
|
1009
|
+
0 < g.length && (h.overlappingElements = g);
|
1010
|
+
d = {value:c, valid:c};
|
1011
|
+
c && (d.reason = axs.properties.getHiddenReason(a));
|
1012
|
+
h.hidden = d;
|
1013
|
+
b.visible = h
|
1014
|
+
}else {
|
1015
|
+
b.visible = {value:!0, valid:!0}
|
1016
|
+
}
|
1017
|
+
return b
|
1018
|
+
};
|
1019
|
+
axs.properties.getHiddenReason = function(a) {
|
1020
|
+
if(!(a && a instanceof a.ownerDocument.defaultView.HTMLElement)) {
|
1021
|
+
return null
|
1022
|
+
}
|
1023
|
+
if(a.hasAttribute("chromevoxignoreariahidden")) {
|
1024
|
+
var b = !0
|
1025
|
+
}
|
1026
|
+
var c = window.getComputedStyle(a, null);
|
1027
|
+
return"none" == c.display ? {property:"display: none", on:a} : "hidden" == c.visibility ? {property:"visibility: hidden", on:a} : a.hasAttribute("aria-hidden") && "true" == a.getAttribute("aria-hidden").toLowerCase() && !b ? {property:"aria-hidden", on:a} : axs.properties.getHiddenReason(a.parentElement)
|
1028
|
+
};
|
1029
|
+
axs.properties.getColorProperties = function(a) {
|
1030
|
+
var b = {};
|
1031
|
+
(a = axs.properties.getContrastRatioProperties(a)) && (b.contrastRatio = a);
|
1032
|
+
return 0 == Object.keys(b).length ? null : b
|
1033
|
+
};
|
1034
|
+
axs.properties.hasDirectTextDescendant = function(a) {
|
1035
|
+
for(var b = (a.nodeType == Node.DOCUMENT_NODE ? a : a.ownerDocument).evaluate(axs.properties.TEXT_CONTENT_XPATH, a, null, XPathResult.ANY_TYPE, null), c = !1, d = b.iterateNext();null != d;d = b.iterateNext()) {
|
1036
|
+
if(d === a) {
|
1037
|
+
c = !0;
|
1038
|
+
break
|
1039
|
+
}
|
1040
|
+
}
|
1041
|
+
return c
|
1042
|
+
};
|
1043
|
+
axs.properties.getContrastRatioProperties = function(a) {
|
1044
|
+
if(!axs.properties.hasDirectTextDescendant(a)) {
|
1045
|
+
return null
|
1046
|
+
}
|
1047
|
+
var b = {}, c = window.getComputedStyle(a, null), d = axs.utils.getBgColor(c, a);
|
1048
|
+
if(!d) {
|
1049
|
+
return null
|
1050
|
+
}
|
1051
|
+
b.backgroundColor = axs.utils.colorToString(d);
|
1052
|
+
var e = axs.utils.getFgColor(c, a, d);
|
1053
|
+
b.foregroundColor = axs.utils.colorToString(e);
|
1054
|
+
a = axs.utils.getContrastRatioForElementWithComputedStyle(c, a);
|
1055
|
+
if(!a) {
|
1056
|
+
return null
|
1057
|
+
}
|
1058
|
+
b.value = a.toFixed(2);
|
1059
|
+
axs.utils.isLowContrast(a, c) && (b.alert = !0);
|
1060
|
+
(c = axs.utils.suggestColors(d, e, a, c)) && Object.keys(c).length && (b.suggestedColors = c);
|
1061
|
+
return b
|
1062
|
+
};
|
1063
|
+
axs.properties.findTextAlternatives = function(a, b, c) {
|
1064
|
+
var d = c || !1;
|
1065
|
+
c = axs.utils.asElement(a);
|
1066
|
+
if(!c || !d && axs.utils.isElementOrAncestorHidden(c)) {
|
1067
|
+
return null
|
1068
|
+
}
|
1069
|
+
if(a.nodeType == Node.TEXT_NODE) {
|
1070
|
+
return c = {type:"text"}, c.text = a.textContent, c.lastWord = axs.properties.getLastWord(c.text), b.content = c, a.textContent
|
1071
|
+
}
|
1072
|
+
a = null;
|
1073
|
+
d || (a = axs.properties.getTextFromAriaLabelledby(c, b));
|
1074
|
+
if(c.hasAttribute("aria-label")) {
|
1075
|
+
var e = {type:"text"};
|
1076
|
+
e.text = c.getAttribute("aria-label");
|
1077
|
+
e.lastWord = axs.properties.getLastWord(e.text);
|
1078
|
+
a ? e.unused = !0 : d && axs.utils.elementIsHtmlControl(c) || (a = e.text);
|
1079
|
+
b.ariaLabel = e
|
1080
|
+
}
|
1081
|
+
c.hasAttribute("role") && "presentation" == c.getAttribute("role") || (a = axs.properties.getTextFromHostLanguageAttributes(c, b, a, d));
|
1082
|
+
if(d && axs.utils.elementIsHtmlControl(c)) {
|
1083
|
+
e = c.ownerDocument.defaultView;
|
1084
|
+
if(c instanceof e.HTMLInputElement) {
|
1085
|
+
var f = c;
|
1086
|
+
"text" == f.type && f.value && 0 < f.value.length && (b.controlValue = {text:f.value});
|
1087
|
+
"range" == f.type && (b.controlValue = {text:f.value})
|
1088
|
+
}
|
1089
|
+
c instanceof e.HTMLSelectElement && (b.controlValue = {text:c.value});
|
1090
|
+
b.controlValue && (e = b.controlValue, a ? e.unused = !0 : a = e.text)
|
1091
|
+
}
|
1092
|
+
if(d && axs.utils.elementIsAriaWidget(c)) {
|
1093
|
+
d = c.getAttribute("role");
|
1094
|
+
"textbox" == d && c.textContent && 0 < c.textContent.length && (b.controlValue = {text:c.textContent});
|
1095
|
+
if("slider" == d || "spinbutton" == d) {
|
1096
|
+
c.hasAttribute("aria-valuetext") ? b.controlValue = {text:c.getAttribute("aria-valuetext")} : c.hasAttribute("aria-valuenow") && (b.controlValue = {value:c.getAttribute("aria-valuenow"), text:"" + c.getAttribute("aria-valuenow")})
|
1097
|
+
}
|
1098
|
+
if("menu" == d) {
|
1099
|
+
for(var g = c.querySelectorAll("[role=menuitemcheckbox], [role=menuitemradio]"), e = [], f = 0;f < g.length;f++) {
|
1100
|
+
"true" == g[f].getAttribute("aria-checked") && e.push(g[f])
|
1101
|
+
}
|
1102
|
+
if(0 < e.length) {
|
1103
|
+
g = "";
|
1104
|
+
for(f = 0;f < e.length;f++) {
|
1105
|
+
g += axs.properties.findTextAlternatives(e[f], {}, !0), f < e.length - 1 && (g += ", ")
|
1106
|
+
}
|
1107
|
+
b.controlValue = {text:g}
|
1108
|
+
}
|
1109
|
+
}
|
1110
|
+
if("combobox" == d || "select" == d) {
|
1111
|
+
b.controlValue = {text:"TODO"}
|
1112
|
+
}
|
1113
|
+
b.controlValue && (e = b.controlValue, a ? e.unused = !0 : a = e.text)
|
1114
|
+
}
|
1115
|
+
e = !0;
|
1116
|
+
c.hasAttribute("role") && (d = c.getAttribute("role"), (d = axs.constants.ARIA_ROLES[d]) && (!d.namefrom || 0 > d.namefrom.indexOf("contents")) && (e = !1));
|
1117
|
+
(d = axs.properties.getTextFromDescendantContent(c)) && e && (e = {type:"text"}, e.text = d, e.lastWord = axs.properties.getLastWord(e.text), a ? e.unused = !0 : a = d, b.content = e);
|
1118
|
+
c.hasAttribute("title") && (d = {type:"string", valid:!0}, d.text = c.getAttribute("title"), d.lastWord = axs.properties.getLastWord(d.lastWord), a ? d.unused = !0 : a = d.text, b.title = d);
|
1119
|
+
return 0 == Object.keys(b).length && null == a ? null : a
|
1120
|
+
};
|
1121
|
+
axs.properties.getTextFromDescendantContent = function(a) {
|
1122
|
+
var b = a.childNodes;
|
1123
|
+
a = [];
|
1124
|
+
for(var c = 0;c < b.length;c++) {
|
1125
|
+
var d = axs.properties.findTextAlternatives(b[c], {}, !0);
|
1126
|
+
d && a.push(d.trim())
|
1127
|
+
}
|
1128
|
+
if(a.length) {
|
1129
|
+
b = "";
|
1130
|
+
for(c = 0;c < a.length;c++) {
|
1131
|
+
b = [b, a[c]].join(" ").trim()
|
1132
|
+
}
|
1133
|
+
return b
|
1134
|
+
}
|
1135
|
+
return null
|
1136
|
+
};
|
1137
|
+
axs.properties.getTextFromAriaLabelledby = function(a, b) {
|
1138
|
+
var c = null;
|
1139
|
+
if(!a.hasAttribute("aria-labelledby")) {
|
1140
|
+
return c
|
1141
|
+
}
|
1142
|
+
for(var d = a.getAttribute("aria-labelledby").split(/\s+/), e = {valid:!0}, f = [], g = [], h = 0;h < d.length;h++) {
|
1143
|
+
var k = {type:"element"}, m = d[h];
|
1144
|
+
k.value = m;
|
1145
|
+
var l = document.getElementById(m);
|
1146
|
+
l ? (k.valid = !0, k.text = axs.properties.findTextAlternatives(l, {}, !0), k.lastWord = axs.properties.getLastWord(k.text), f.push(l.textContent.trim()), k.element = l) : (k.valid = !1, e.valid = !1, k.errorMessage = {messageKey:"noElementWithId", args:[m]});
|
1147
|
+
g.push(k)
|
1148
|
+
}
|
1149
|
+
0 < g.length && (g[g.length - 1].last = !0, e.values = g, e.text = f.join(" "), e.lastWord = axs.properties.getLastWord(e.text), c = e.text, b.ariaLabelledby = e);
|
1150
|
+
return c
|
1151
|
+
};
|
1152
|
+
axs.properties.getTextFromHostLanguageAttributes = function(a, b, c, d) {
|
1153
|
+
if(axs.browserUtils.matchSelector(a, "img")) {
|
1154
|
+
if(a.hasAttribute("alt")) {
|
1155
|
+
var e = {type:"string", valid:!0};
|
1156
|
+
e.text = a.getAttribute("alt");
|
1157
|
+
c ? e.unused = !0 : c = e.text;
|
1158
|
+
b.alt = e
|
1159
|
+
}else {
|
1160
|
+
e = {valid:!1, errorMessage:"No alt value provided"}, b.alt = e, e = a.src, "string" == typeof e && (c = e.split("/").pop(), b.filename = {text:c})
|
1161
|
+
}
|
1162
|
+
}
|
1163
|
+
if(axs.browserUtils.matchSelector(a, 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), video:not([disabled])') && !d) {
|
1164
|
+
if(a.hasAttribute("id")) {
|
1165
|
+
d = document.querySelectorAll('label[for="' + a.id + '"]');
|
1166
|
+
for(var e = {}, f = [], g = [], h = 0;h < d.length;h++) {
|
1167
|
+
var k = {type:"element"}, m = d[h], l = axs.properties.findTextAlternatives(m, {}, !0);
|
1168
|
+
l && 0 < l.trim().length && (k.text = l.trim(), g.push(l.trim()));
|
1169
|
+
k.element = m;
|
1170
|
+
f.push(k)
|
1171
|
+
}
|
1172
|
+
0 < f.length && (f[f.length - 1].last = !0, e.values = f, e.text = g.join(" "), e.lastWord = axs.properties.getLastWord(e.text), c ? e.unused = !0 : c = e.text, b.labelFor = e)
|
1173
|
+
}
|
1174
|
+
d = a.parentElement;
|
1175
|
+
for(e = {};d;) {
|
1176
|
+
if("label" == d.tagName.toLowerCase() && (f = d, f.control == a)) {
|
1177
|
+
e.type = "element";
|
1178
|
+
e.text = axs.properties.findTextAlternatives(f, {}, !0);
|
1179
|
+
e.lastWord = axs.properties.getLastWord(e.text);
|
1180
|
+
e.element = f;
|
1181
|
+
break
|
1182
|
+
}
|
1183
|
+
d = d.parentElement
|
1184
|
+
}
|
1185
|
+
e.text && (c ? e.unused = !0 : c = e.text, b.labelWrapped = e);
|
1186
|
+
Object.keys(b).length || (b.noLabel = !0)
|
1187
|
+
}
|
1188
|
+
return c
|
1189
|
+
};
|
1190
|
+
axs.properties.getLastWord = function(a) {
|
1191
|
+
if(!a) {
|
1192
|
+
return null
|
1193
|
+
}
|
1194
|
+
var b = a.lastIndexOf(" ") + 1, c = a.length - 10;
|
1195
|
+
return a.substring(b > c ? b : c)
|
1196
|
+
};
|
1197
|
+
axs.properties.getTextProperties = function(a) {
|
1198
|
+
var b = {};
|
1199
|
+
a = axs.properties.findTextAlternatives(a, b);
|
1200
|
+
if(0 == Object.keys(b).length) {
|
1201
|
+
if(!a) {
|
1202
|
+
return null
|
1203
|
+
}
|
1204
|
+
b.hasProperties = !1
|
1205
|
+
}else {
|
1206
|
+
b.hasProperties = !0
|
1207
|
+
}
|
1208
|
+
b.computedText = a;
|
1209
|
+
b.lastWord = axs.properties.getLastWord(a);
|
1210
|
+
return b
|
1211
|
+
};
|
1212
|
+
axs.properties.getAriaProperties = function(a) {
|
1213
|
+
var b = {}, c = axs.properties.getGlobalAriaProperties(a), d;
|
1214
|
+
for(d in axs.constants.ARIA_PROPERTIES) {
|
1215
|
+
var e = "aria-" + d;
|
1216
|
+
if(a.hasAttribute(e)) {
|
1217
|
+
var f = a.getAttribute(e);
|
1218
|
+
c[e] = axs.utils.getAriaPropertyValue(e, f, a)
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
0 < Object.keys(c).length && (b.properties = axs.utils.values(c));
|
1222
|
+
f = axs.utils.getRoles(a);
|
1223
|
+
if(!f) {
|
1224
|
+
return Object.keys(b).length ? b : null
|
1225
|
+
}
|
1226
|
+
b.roles = f;
|
1227
|
+
if(!f.valid || !f.roles) {
|
1228
|
+
return b
|
1229
|
+
}
|
1230
|
+
for(var e = f.roles, g = 0;g < e.length;g++) {
|
1231
|
+
var h = e[g];
|
1232
|
+
if(h.details && h.details.propertiesSet) {
|
1233
|
+
for(d in h.details.propertiesSet) {
|
1234
|
+
d in c || (a.hasAttribute(d) ? (f = a.getAttribute(d), c[d] = axs.utils.getAriaPropertyValue(d, f, a), "values" in c[d] && (f = c[d].values, f[f.length - 1].isLast = !0)) : h.details.requiredPropertiesSet[d] && (c[d] = {name:d, valid:!1, reason:"Required property not set"}))
|
1235
|
+
}
|
1236
|
+
}
|
1237
|
+
}
|
1238
|
+
0 < Object.keys(c).length && (b.properties = axs.utils.values(c));
|
1239
|
+
return 0 < Object.keys(b).length ? b : null
|
1240
|
+
};
|
1241
|
+
axs.properties.getGlobalAriaProperties = function(a) {
|
1242
|
+
for(var b = {}, c = 0;c < axs.constants.GLOBAL_PROPERTIES.length;c++) {
|
1243
|
+
var d = axs.constants.GLOBAL_PROPERTIES[c];
|
1244
|
+
if(a.hasAttribute(d)) {
|
1245
|
+
var e = a.getAttribute(d);
|
1246
|
+
b[d] = axs.utils.getAriaPropertyValue(d, e, a)
|
1247
|
+
}
|
1248
|
+
}
|
1249
|
+
return b
|
1250
|
+
};
|
1251
|
+
axs.properties.getVideoProperties = function(a) {
|
1252
|
+
if(!axs.browserUtils.matchSelector(a, "video")) {
|
1253
|
+
return null
|
1254
|
+
}
|
1255
|
+
var b = {};
|
1256
|
+
b.captionTracks = axs.properties.getTrackElements(a, "captions");
|
1257
|
+
b.descriptionTracks = axs.properties.getTrackElements(a, "descriptions");
|
1258
|
+
b.chapterTracks = axs.properties.getTrackElements(a, "chapters");
|
1259
|
+
return b
|
1260
|
+
};
|
1261
|
+
axs.properties.getTrackElements = function(a, b) {
|
1262
|
+
var c = a.querySelectorAll("track[kind=" + b + "]"), d = {};
|
1263
|
+
if(!c.length) {
|
1264
|
+
return d.valid = !1, d.reason = {messageKey:"noTracksProvided", args:[[b]]}, d
|
1265
|
+
}
|
1266
|
+
d.valid = !0;
|
1267
|
+
for(var e = [], f = 0;f < c.length;f++) {
|
1268
|
+
var g = {}, h = c[f].getAttribute("src"), k = c[f].getAttribute("srcLang"), m = c[f].getAttribute("label");
|
1269
|
+
h ? (g.valid = !0, g.src = h) : (g.valid = !1, g.reason = {messageKey:"noSrcProvided"});
|
1270
|
+
h = "";
|
1271
|
+
m && (h += m, k && (h += " "));
|
1272
|
+
k && (h += "(" + k + ")");
|
1273
|
+
"" == h && (h = "[[object Object]]");
|
1274
|
+
g.name = h;
|
1275
|
+
e.push(g)
|
1276
|
+
}
|
1277
|
+
d.values = e;
|
1278
|
+
return d
|
1279
|
+
};
|
1280
|
+
axs.properties.getAllProperties = function(a) {
|
1281
|
+
var b = axs.utils.asElement(a);
|
1282
|
+
if(!b) {
|
1283
|
+
return{}
|
1284
|
+
}
|
1285
|
+
var c = {};
|
1286
|
+
c.ariaProperties = axs.properties.getAriaProperties(b);
|
1287
|
+
c.colorProperties = axs.properties.getColorProperties(b);
|
1288
|
+
c.focusProperties = axs.properties.getFocusProperties(b);
|
1289
|
+
c.textProperties = axs.properties.getTextProperties(a);
|
1290
|
+
c.videoProperties = axs.properties.getVideoProperties(b);
|
1291
|
+
return c
|
1292
|
+
};
|
825
1293
|
axs.AuditRule = function(a) {
|
826
1294
|
for(var b = !0, c = [], d = 0;d < axs.AuditRule.requiredFields.length;d++) {
|
827
1295
|
var e = axs.AuditRule.requiredFields[d];
|
@@ -832,49 +1300,52 @@ axs.AuditRule = function(a) {
|
|
832
1300
|
}
|
833
1301
|
this.name = a.name;
|
834
1302
|
this.severity = a.severity;
|
835
|
-
this.
|
1303
|
+
this.relevantElementMatcher_ = a.relevantElementMatcher;
|
836
1304
|
this.test_ = a.test;
|
837
1305
|
this.code = a.code;
|
838
1306
|
this.heading = a.heading || "";
|
839
1307
|
this.url = a.url || "";
|
840
1308
|
this.requiresConsoleAPI = !!a.opt_requiresConsoleAPI
|
841
1309
|
};
|
842
|
-
axs.AuditRule.requiredFields =
|
1310
|
+
axs.AuditRule.requiredFields = "name severity relevantElementMatcher test code heading".split(" ");
|
843
1311
|
axs.AuditRule.NOT_APPLICABLE = {result:axs.constants.AuditResult.NA};
|
844
|
-
axs.AuditRule.prototype.
|
1312
|
+
axs.AuditRule.prototype.addElement = function(a, b) {
|
845
1313
|
a.push(b)
|
846
1314
|
};
|
847
|
-
axs.AuditRule.
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
1315
|
+
axs.AuditRule.collectMatchingElements = function(a, b, c) {
|
1316
|
+
if(a.nodeType == Node.ELEMENT_NODE) {
|
1317
|
+
var d = a
|
1318
|
+
}
|
1319
|
+
d && b.call(null, d) && c.push(d);
|
1320
|
+
for(a = a.firstChild;null != a;) {
|
1321
|
+
axs.AuditRule.collectMatchingElements(a, b, c), a = a.nextSibling
|
1322
|
+
}
|
1323
|
+
};
|
1324
|
+
axs.AuditRule.prototype.run = function(a) {
|
1325
|
+
a = a || {};
|
1326
|
+
var b = "ignoreSelectors" in a ? a.ignoreSelectors : [], c = "maxResults" in a ? a.maxResults : null, d = [];
|
1327
|
+
axs.AuditRule.collectMatchingElements("scope" in a ? a.scope : document, this.relevantElementMatcher_, d);
|
1328
|
+
var e = [];
|
1329
|
+
if(!d.length) {
|
1330
|
+
return{result:axs.constants.AuditResult.NA}
|
1331
|
+
}
|
1332
|
+
for(a = 0;a < d.length && !(null != c && e.length >= c);a++) {
|
1333
|
+
var f = d[a], g;
|
1334
|
+
a: {
|
1335
|
+
g = f;
|
1336
|
+
for(var h = 0;h < b.length;h++) {
|
1337
|
+
if(axs.browserUtils.matchSelector(g, b[h])) {
|
1338
|
+
g = !0;
|
1339
|
+
break a
|
1340
|
+
}
|
865
1341
|
}
|
866
|
-
|
867
|
-
return console.warn("Unknown XPath result type", e), null
|
868
|
-
}
|
869
|
-
}else {
|
870
|
-
if(!e.length) {
|
871
|
-
return{result:axs.constants.AuditResult.NA}
|
872
|
-
}
|
873
|
-
for(g = 0;g < e.length;g++) {
|
874
|
-
h = e[g], this.test_(h) && !c(h) && this.addNode(f, h)
|
1342
|
+
g = !1
|
875
1343
|
}
|
1344
|
+
!g && this.test_(f) && this.addElement(e, f)
|
876
1345
|
}
|
877
|
-
|
1346
|
+
b = {result:e.length ? axs.constants.AuditResult.FAIL : axs.constants.AuditResult.PASS, elements:e};
|
1347
|
+
a < d.length && (b.resultsTruncated = !0);
|
1348
|
+
return b
|
878
1349
|
};
|
879
1350
|
axs.AuditRule.specs = {};
|
880
1351
|
axs.AuditRules = {};
|
@@ -931,7 +1402,7 @@ goog.exportProperty(axs.AuditResults.prototype, "toString", axs.AuditResults.pro
|
|
931
1402
|
axs.Audit = {};
|
932
1403
|
axs.AuditConfiguration = function() {
|
933
1404
|
this.rules_ = {};
|
934
|
-
this.auditRulesToIgnore = this.auditRulesToRun = this.scope = null;
|
1405
|
+
this.maxResults = this.auditRulesToIgnore = this.auditRulesToRun = this.scope = null;
|
935
1406
|
this.withConsoleApi = !1;
|
936
1407
|
goog.exportProperty(this, "scope", this.scope);
|
937
1408
|
goog.exportProperty(this, "auditRulesToRun", this.auditRulesToRun);
|
@@ -945,6 +1416,11 @@ axs.AuditConfiguration.prototype = {ignoreSelectors:function(a, b) {
|
|
945
1416
|
Array.prototype.push.call(this.rules_[a].ignore, b)
|
946
1417
|
}, getIgnoreSelectors:function(a) {
|
947
1418
|
return a in this.rules_ && "ignore" in this.rules_[a] ? this.rules_[a].ignore : []
|
1419
|
+
}, setSeverity:function(a, b) {
|
1420
|
+
a in this.rules_ || (this.rules_[a] = {});
|
1421
|
+
this.rules_[a].severity = b
|
1422
|
+
}, getSeverity:function(a) {
|
1423
|
+
return a in this.rules_ && "severity" in this.rules_[a] ? this.rules_[a].severity : null
|
948
1424
|
}};
|
949
1425
|
goog.exportProperty(axs.AuditConfiguration.prototype, "ignoreSelectors", axs.AuditConfiguration.prototype.ignoreSelectors);
|
950
1426
|
goog.exportProperty(axs.AuditConfiguration.prototype, "getIgnoreSelectors", axs.AuditConfiguration.prototype.getIgnoreSelectors);
|
@@ -959,13 +1435,19 @@ axs.Audit.run = function(a) {
|
|
959
1435
|
}
|
960
1436
|
}
|
961
1437
|
for(e = 0;e < d.length;e++) {
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
1438
|
+
var f = d[e], g = axs.AuditRules.getRule(f);
|
1439
|
+
if(g && !g.disabled && (b || !g.requiresConsoleAPI)) {
|
1440
|
+
var h = {}, k = a.getIgnoreSelectors(g.name);
|
1441
|
+
if(0 < k.length || a.scope) {
|
1442
|
+
h.ignoreSelectors = k
|
1443
|
+
}
|
1444
|
+
a.scope && (h.scope = a.scope);
|
1445
|
+
a.maxResults && (h.maxResults = a.maxResults);
|
1446
|
+
h = g.run.call(g, h);
|
1447
|
+
g = axs.utils.namedValues(g);
|
1448
|
+
g.severity = a.getSeverity(f) || g.severity;
|
1449
|
+
h.rule = g;
|
1450
|
+
c.push(h)
|
969
1451
|
}
|
970
1452
|
}
|
971
1453
|
return c
|
@@ -999,22 +1481,18 @@ axs.Audit.accessibilityErrorMessage = function(a) {
|
|
999
1481
|
return b
|
1000
1482
|
};
|
1001
1483
|
goog.exportSymbol("axs.Audit.accessibilityErrorMessage", axs.Audit.accessibilityErrorMessage);
|
1002
|
-
axs.
|
1003
|
-
axs.browserUtils.matchSelector
|
1004
|
-
return a.webkitMatchesSelector ? a.webkitMatchesSelector(b) : a.mozMatchesSelector(b)
|
1005
|
-
};
|
1006
|
-
axs.AuditRule.specs.audioWithoutControls = {name:"audioWithoutControls", heading:"Audio elements should have controls", url:"", severity:axs.constants.Severity.WARNING, relevantNodesSelector:function(a) {
|
1007
|
-
return a.querySelectorAll("audio[autoplay]")
|
1484
|
+
axs.AuditRule.specs.audioWithoutControls = {name:"audioWithoutControls", heading:"Audio elements should have controls", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1485
|
+
return axs.browserUtils.matchSelector(a, "audio[autoplay]")
|
1008
1486
|
}, test:function(a) {
|
1009
1487
|
return!a.querySelectorAll("[controls]").length && 3 < a.duration
|
1010
1488
|
}, code:"AX_AUDIO_01"};
|
1011
|
-
axs.AuditRule.specs.badAriaAttributeValue = {name:"badAriaAttributeValue", heading:"ARIA state and property values must be valid", url:"", severity:axs.constants.Severity.SEVERE,
|
1489
|
+
axs.AuditRule.specs.badAriaAttributeValue = {name:"badAriaAttributeValue", heading:"ARIA state and property values must be valid", url:"", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) {
|
1012
1490
|
var b = "", c;
|
1013
1491
|
for(c in axs.constants.ARIA_PROPERTIES) {
|
1014
1492
|
b += "[aria-" + c + "],"
|
1015
1493
|
}
|
1016
1494
|
b = b.substring(0, b.length - 1);
|
1017
|
-
return
|
1495
|
+
return axs.browserUtils.matchSelector(a, b)
|
1018
1496
|
}, test:function(a) {
|
1019
1497
|
for(var b in axs.constants.ARIA_PROPERTIES) {
|
1020
1498
|
var c = "aria-" + b;
|
@@ -1027,64 +1505,85 @@ axs.AuditRule.specs.badAriaAttributeValue = {name:"badAriaAttributeValue", headi
|
|
1027
1505
|
}
|
1028
1506
|
return!1
|
1029
1507
|
}, code:"AX_ARIA_04"};
|
1030
|
-
axs.AuditRule.specs.badAriaRole = {name:"badAriaRole", heading:"Elements with ARIA roles must use a valid, non-abstract ARIA role", url:"https://
|
1031
|
-
return
|
1508
|
+
axs.AuditRule.specs.badAriaRole = {name:"badAriaRole", heading:"Elements with ARIA roles must use a valid, non-abstract ARIA role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_01--elements-with-aria-roles-must-use-a-valid-non-abstract-aria-role", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) {
|
1509
|
+
return axs.browserUtils.matchSelector(a, "[role]")
|
1032
1510
|
}, test:function(a) {
|
1033
|
-
return!axs.utils.
|
1511
|
+
return!axs.utils.getRoles(a).valid
|
1034
1512
|
}, code:"AX_ARIA_01"};
|
1035
|
-
axs.AuditRule.specs.controlsWithoutLabel = {name:"controlsWithoutLabel", heading:"Controls and media elements should have labels", url:"https://
|
1036
|
-
|
1513
|
+
axs.AuditRule.specs.controlsWithoutLabel = {name:"controlsWithoutLabel", heading:"Controls and media elements should have labels", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_text_01--controls-and-media-elements-should-have-labels", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) {
|
1514
|
+
if(!axs.browserUtils.matchSelector(a, 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), video:not([disabled])')) {
|
1515
|
+
return!1
|
1516
|
+
}
|
1517
|
+
if(0 <= a.tabIndex) {
|
1518
|
+
return!0
|
1519
|
+
}
|
1520
|
+
for(a = a.parentElement;null != a;a = a.parentElement) {
|
1521
|
+
if(axs.utils.elementIsAriaWidget(a)) {
|
1522
|
+
return!1
|
1523
|
+
}
|
1524
|
+
}
|
1525
|
+
return!0
|
1037
1526
|
}, test:function(a) {
|
1038
|
-
return axs.utils.isElementOrAncestorHidden(a) || "button" == a.tagName.toLowerCase() && a.textContent.replace(/^\s+|\s+$/g, "").length ? !1 : axs.utils.hasLabel(a) ? !1 : !0
|
1527
|
+
return axs.utils.isElementOrAncestorHidden(a) || "input" == a.tagName.toLowerCase() && "button" == a.type && a.value.length || "button" == a.tagName.toLowerCase() && a.textContent.replace(/^\s+|\s+$/g, "").length ? !1 : axs.utils.hasLabel(a) ? !1 : !0
|
1039
1528
|
}, code:"AX_TEXT_01", ruleName:"Controls and media elements should have labels"};
|
1040
|
-
axs.AuditRule.specs.focusableElementNotVisibleAndNotAriaHidden = {name:"focusableElementNotVisibleAndNotAriaHidden", heading:"These elements are focusable but either invisible or obscured by another element", url:"https://
|
1041
|
-
|
1529
|
+
axs.AuditRule.specs.focusableElementNotVisibleAndNotAriaHidden = {name:"focusableElementNotVisibleAndNotAriaHidden", heading:"These elements are focusable but either invisible or obscured by another element", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_focus_01--these-elements-are-focusable-but-either-invisible-or-obscured-by-another-element", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1530
|
+
if(!axs.browserUtils.matchSelector(a, axs.utils.FOCUSABLE_ELEMENTS_SELECTOR)) {
|
1531
|
+
return!1
|
1532
|
+
}
|
1533
|
+
if(0 <= a.tabIndex) {
|
1534
|
+
return!0
|
1535
|
+
}
|
1536
|
+
for(a = a.parentElement;null != a;a = a.parentElement) {
|
1537
|
+
if(axs.utils.elementIsAriaWidget(a)) {
|
1538
|
+
return!1
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
return!0
|
1042
1542
|
}, test:function(a) {
|
1043
1543
|
return axs.utils.isElementOrAncestorHidden(a) ? !1 : !axs.utils.elementIsVisible(a)
|
1044
1544
|
}, code:"AX_FOCUS_01"};
|
1045
|
-
axs.AuditRule.specs.imagesWithoutAltText = {name:"imagesWithoutAltText", heading:"Images should have an alt attribute", url:"https://
|
1046
|
-
|
1047
|
-
for(var b = [], c = 0;c < a.length;c++) {
|
1048
|
-
var d = a[c];
|
1049
|
-
axs.utils.isElementOrAncestorHidden(d) || b.push(d)
|
1050
|
-
}
|
1051
|
-
return b
|
1545
|
+
axs.AuditRule.specs.imagesWithoutAltText = {name:"imagesWithoutAltText", heading:"Images should have an alt attribute", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_text_02--images-should-have-an-alt-attribute-unless-they-have-an-aria-role-of-presentation", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1546
|
+
return axs.browserUtils.matchSelector(a, "img") && !axs.utils.isElementOrAncestorHidden(a)
|
1052
1547
|
}, test:function(a) {
|
1053
1548
|
return!a.hasAttribute("alt") && "presentation" != a.getAttribute("role")
|
1054
1549
|
}, code:"AX_TEXT_02"};
|
1055
|
-
axs.AuditRule.specs.linkWithUnclearPurpose = {name:"linkWithUnclearPurpose", heading:"The purpose of each link should be clear from the link text", url:"", severity:axs.constants.Severity.WARNING,
|
1056
|
-
return
|
1550
|
+
axs.AuditRule.specs.linkWithUnclearPurpose = {name:"linkWithUnclearPurpose", heading:"The purpose of each link should be clear from the link text", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1551
|
+
return axs.browserUtils.matchSelector(a, "a")
|
1057
1552
|
}, test:function(a) {
|
1058
1553
|
return/^\s*click\s*here\s*[^a-z]?$/i.test(a.textContent)
|
1059
1554
|
}, code:"AX_TITLE_01"};
|
1060
|
-
axs.AuditRule.specs.lowContrastElements = {name:"lowContrastElements", heading:"Text elements should have a reasonable contrast ratio", url:"https://
|
1061
|
-
return
|
1555
|
+
axs.AuditRule.specs.lowContrastElements = {name:"lowContrastElements", heading:"Text elements should have a reasonable contrast ratio", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_color_01--text-elements-should-have-a-reasonable-contrast-ratio", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1556
|
+
return axs.properties.hasDirectTextDescendant(a)
|
1062
1557
|
}, test:function(a) {
|
1063
1558
|
var b = window.getComputedStyle(a, null);
|
1064
1559
|
return(a = axs.utils.getContrastRatioForElementWithComputedStyle(b, a)) && axs.utils.isLowContrast(a, b)
|
1065
1560
|
}, code:"AX_COLOR_01"};
|
1066
|
-
axs.AuditRule.specs.
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1561
|
+
axs.AuditRule.specs.mainRoleOnInappropriateElement = {name:"mainRoleOnInappropriateElement", heading:"role=main should only appear on significant elements", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1562
|
+
return axs.browserUtils.matchSelector(a, "[role~=main]")
|
1563
|
+
}, test:function(a) {
|
1564
|
+
if(axs.utils.isInlineElement(a)) {
|
1565
|
+
return!0
|
1071
1566
|
}
|
1072
|
-
|
1073
|
-
|
1567
|
+
a = axs.properties.getTextFromDescendantContent(a);
|
1568
|
+
return!a || 50 > a.length ? !0 : !1
|
1569
|
+
}, code:"AX_ARIA_04"};
|
1570
|
+
axs.AuditRule.specs.elementsWithMeaningfulBackgroundImage = {name:"elementsWithMeaningfulBackgroundImage", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1571
|
+
return!axs.utils.isElementOrAncestorHidden(a)
|
1572
|
+
}, heading:"Meaningful images should not be used in element backgrounds", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_image_01--meaningful-images-should-not-be-used-in-element-backgrounds", test:function(a) {
|
1074
1573
|
if(a.textContent && 0 < a.textContent.length) {
|
1075
1574
|
return!1
|
1076
1575
|
}
|
1077
1576
|
a = window.getComputedStyle(a, null);
|
1078
1577
|
var b = a.backgroundImage;
|
1079
|
-
if(!b || "undefined" === b || "none" === b) {
|
1578
|
+
if(!b || "undefined" === b || "none" === b || 0 != b.indexOf("url")) {
|
1080
1579
|
return!1
|
1081
1580
|
}
|
1082
1581
|
b = parseInt(a.width, 10);
|
1083
1582
|
a = parseInt(a.height, 10);
|
1084
1583
|
return 150 > b && 150 > a
|
1085
1584
|
}, code:"AX_IMAGE_01"};
|
1086
|
-
axs.AuditRule.specs.nonExistentAriaLabelledbyElement = {name:"nonExistentAriaLabelledbyElement", heading:"aria-labelledby attributes should refer to an element which exists in the DOM", url:"https://
|
1087
|
-
return
|
1585
|
+
axs.AuditRule.specs.nonExistentAriaLabelledbyElement = {name:"nonExistentAriaLabelledbyElement", heading:"aria-labelledby attributes should refer to an element which exists in the DOM", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_02--aria-labelledby-attributes-should-refer-to-an-element-which-exists-in-the-dom", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1586
|
+
return axs.browserUtils.matchSelector(a, "[aria-labelledby]")
|
1088
1587
|
}, test:function(a) {
|
1089
1588
|
a = a.getAttribute("aria-labelledby").split(/\s+/);
|
1090
1589
|
for(var b = 0;b < a.length;b++) {
|
@@ -1094,47 +1593,37 @@ axs.AuditRule.specs.nonExistentAriaLabelledbyElement = {name:"nonExistentAriaLab
|
|
1094
1593
|
}
|
1095
1594
|
return!1
|
1096
1595
|
}, code:"AX_ARIA_02"};
|
1097
|
-
axs.AuditRule.specs.pageWithoutTitle = {name:"pageWithoutTitle", heading:"The web page should have a title that describes topic or purpose", url:"", severity:axs.constants.Severity.WARNING,
|
1098
|
-
return a
|
1596
|
+
axs.AuditRule.specs.pageWithoutTitle = {name:"pageWithoutTitle", heading:"The web page should have a title that describes topic or purpose", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1597
|
+
return"html" == a.tagName.toLowerCase()
|
1099
1598
|
}, test:function(a) {
|
1100
1599
|
a = a.querySelector("head");
|
1101
|
-
|
1102
|
-
return!0
|
1103
|
-
}
|
1104
|
-
a = a.querySelector("title");
|
1105
|
-
return!a.length || !a[0].textContent
|
1600
|
+
return a ? (a = a.querySelector("title")) ? !a.textContent : !0 : !0
|
1106
1601
|
}, code:"AX_TITLE_01"};
|
1107
|
-
axs.AuditRule.specs.requiredAriaAttributeMissing = {name:"requiredAriaAttributeMissing", heading:"Elements with ARIA roles must have all required attributes for that role", url:"", severity:axs.constants.Severity.SEVERE,
|
1108
|
-
return
|
1602
|
+
axs.AuditRule.specs.requiredAriaAttributeMissing = {name:"requiredAriaAttributeMissing", heading:"Elements with ARIA roles must have all required attributes for that role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_03--elements-with-aria-roles-must-have-all-required-attributes-for-that-role", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) {
|
1603
|
+
return axs.browserUtils.matchSelector(a, "[role]")
|
1109
1604
|
}, test:function(a) {
|
1110
|
-
var b = axs.utils.
|
1605
|
+
var b = axs.utils.getRoles(a);
|
1111
1606
|
if(!b.valid) {
|
1112
1607
|
return!1
|
1113
1608
|
}
|
1114
|
-
var
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
if(!a.hasAttribute(c)) {
|
1121
|
-
return!0
|
1609
|
+
for(var c = 0;c < b.roles.length;c++) {
|
1610
|
+
var d = b.roles[c].details.requiredPropertiesSet, e;
|
1611
|
+
for(e in d) {
|
1612
|
+
if(d = e.replace(/^aria-/, ""), !("defaultValue" in axs.constants.ARIA_PROPERTIES[d] || a.hasAttribute(e))) {
|
1613
|
+
return!0
|
1614
|
+
}
|
1122
1615
|
}
|
1123
1616
|
}
|
1124
1617
|
}, code:"AX_ARIA_03"};
|
1125
|
-
axs.AuditRule.specs.unfocusableElementsWithOnClick = {name:"unfocusableElementsWithOnClick", heading:"Elements with onclick handlers must be focusable", url:"https://
|
1126
|
-
a
|
1127
|
-
for(var b = [], c = 0;c < a.length;c++) {
|
1128
|
-
var d = a[c];
|
1129
|
-
d instanceof d.ownerDocument.defaultView.HTMLBodyElement || axs.utils.isElementOrAncestorHidden(d) || "click" in getEventListeners(d) && b.push(d)
|
1130
|
-
}
|
1131
|
-
return b
|
1618
|
+
axs.AuditRule.specs.unfocusableElementsWithOnClick = {name:"unfocusableElementsWithOnClick", heading:"Elements with onclick handlers must be focusable", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_focus_02--elements-with-onclick-handlers-must-be-focusable", severity:axs.constants.Severity.WARNING, opt_requiresConsoleAPI:!0, relevantElementMatcher:function(a) {
|
1619
|
+
return a instanceof a.ownerDocument.defaultView.HTMLBodyElement || axs.utils.isElementOrAncestorHidden(a) ? !1 : "click" in getEventListeners(a) ? !0 : !1
|
1132
1620
|
}, test:function(a) {
|
1133
1621
|
return!a.hasAttribute("tabindex") && !axs.utils.isElementImplicitlyFocusable(a)
|
1134
1622
|
}, code:"AX_FOCUS_02"};
|
1135
|
-
axs.AuditRule.specs.videoWithoutCaptions = {name:"videoWithoutCaptions", heading:"Video elements should use <track> elements to provide captions", url:"https://
|
1136
|
-
return
|
1623
|
+
axs.AuditRule.specs.videoWithoutCaptions = {name:"videoWithoutCaptions", heading:"Video elements should use <track> elements to provide captions", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_video_01--video-elements-should-use-track-elements-to-provide-captions", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) {
|
1624
|
+
return axs.browserUtils.matchSelector(a, "video")
|
1137
1625
|
}, test:function(a) {
|
1138
1626
|
return!a.querySelectorAll("track[kind=captions]").length
|
1139
1627
|
}, code:"AX_VIDEO_01"};
|
1140
1628
|
|
1629
|
+
|