capybara-accessible 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|