Skip to content

Commit 51fdbd8

Browse files
author
terrill
committed
Change buttons to divs with role="button" to fix rendering issues in high contrast mode
1 parent 372273d commit 51fdbd8

10 files changed

Lines changed: 167 additions & 72 deletions

File tree

‎build/ableplayer.dist.js‎

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,6 @@ var AblePlayerInstances = [];
630630
}
631631
$('body').append($el);
632632
bgColor = $el.css('background-color');
633-
634633
// bgColor is a string in the form 'rgb(R, G, B)', perhaps with a 4th item for alpha;
635634
// split the 3 or 4 channels into an array
636635
rgb = bgColor.replace(/[^\d,]/g, '').split(',');
@@ -645,7 +644,6 @@ var AblePlayerInstances = [];
645644
else { // background is light
646645
iconColor = 'black';
647646
}
648-
649647
if ($elements[i] === 'controller') {
650648
this.iconColor = iconColor;
651649
}
@@ -4136,12 +4134,17 @@ var AblePlayerInstances = [];
41364134
// And if iconType === 'image', we are replacing #2 with an image (with alt="" and role="presentation")
41374135
// This has been thoroughly tested and works well in all screen reader/browser combinations
41384136
// See https://github.com/ableplayer/ableplayer/issues/81
4139-
$newButton = $('<button>',{
4140-
'type': 'button',
4137+
4138+
// NOTE: Changed from <button> to <div role="button" as of 4.2.18
4139+
// because <button> elements are rendered poorly in high contrast mode
4140+
// in some OS/browser/plugin combinations
4141+
$newButton = $('<div>',{
4142+
'role': 'button',
41414143
'tabindex': '0',
41424144
'aria-label': buttonTitle,
41434145
'class': 'able-button-handler-' + control
41444146
});
4147+
41454148
if (control === 'volume' || control === 'preferences') {
41464149
if (control == 'preferences') {
41474150
this.prefCats = this.getPreferencesGroups();
@@ -8357,12 +8360,12 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
83578360
leftControls = this.seekBar.wrapperDiv.parent().prev('div.able-left-controls');
83588361
rightControls = leftControls.next('div.able-right-controls');
83598362
leftControls.children().each(function () {
8360-
if ($(this).prop('tagName')=='BUTTON') {
8363+
if ($(this).attr('role')=='button') {
83618364
widthUsed += $(this).outerWidth(true); // true = include margin
83628365
}
83638366
});
83648367
rightControls.children().each(function () {
8365-
if ($(this).prop('tagName')=='BUTTON') {
8368+
if ($(this).attr('role')=='button') {
83668369
widthUsed += $(this).outerWidth(true);
83678370
}
83688371
});
@@ -9046,12 +9049,20 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
90469049
};
90479050

90489051
AblePlayer.prototype.handleTranscriptToggle = function () {
9052+
9053+
var thisObj = this;
9054+
90499055
if (this.$transcriptDiv.is(':visible')) {
90509056
this.$transcriptArea.hide();
90519057
this.$transcriptButton.addClass('buttonOff').attr('aria-label',this.tt.showTranscript);
90529058
this.$transcriptButton.find('span.able-clipped').text(this.tt.showTranscript);
90539059
this.prefTranscript = 0;
90549060
this.$transcriptButton.focus().addClass('able-focus');
9061+
// wait a second before resetting stopgap var
9062+
// otherwise the keypress used to select 'Close' will trigger the transcript button
9063+
setTimeout(function() {
9064+
thisObj.closingTranscript = false;
9065+
}, 1000);
90559066
}
90569067
else {
90579068
this.positionDraggableWindow('transcript');
@@ -9064,12 +9075,20 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
90649075
};
90659076

90669077
AblePlayer.prototype.handleSignToggle = function () {
9078+
9079+
var thisObj = this;
9080+
90679081
if (this.$signWindow.is(':visible')) {
90689082
this.$signWindow.hide();
90699083
this.$signButton.addClass('buttonOff').attr('aria-label',this.tt.showSign);
90709084
this.$signButton.find('span.able-clipped').text(this.tt.showSign);
90719085
this.prefSign = 0;
90729086
this.$signButton.focus().addClass('able-focus');
9087+
// wait a second before resetting stopgap var
9088+
// otherwise the keypress used to select 'Close' will trigger the transcript button
9089+
setTimeout(function() {
9090+
thisObj.closingSign = false;
9091+
}, 1000);
90739092
}
90749093
else {
90759094
this.positionDraggableWindow('sign');
@@ -11642,7 +11661,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1164211661
this.handleDescriptionToggle();
1164311662
}
1164411663
else if (whichButton === 'sign') {
11645-
this.handleSignToggle();
11664+
if (!this.closingSign) {
11665+
this.handleSignToggle();
11666+
}
1164611667
}
1164711668
else if (whichButton === 'preferences') {
1164811669
if ($(el).attr('data-prefs-popup') === 'menu') {
@@ -11669,7 +11690,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1166911690
this.handleHelpClick();
1167011691
}
1167111692
else if (whichButton === 'transcript') {
11672-
this.handleTranscriptToggle();
11693+
if (!this.closingTranscript) {
11694+
this.handleTranscriptToggle();
11695+
}
1167311696
}
1167411697
else if (whichButton === 'fullscreen') {
1167511698
this.clickedFullscreenButton = true;
@@ -11705,11 +11728,13 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1170511728
// including removal of the "media player" design pattern. There's an issue about that:
1170611729
// https://github.com/w3c/aria-practices/issues/27
1170711730

11731+
var which, $thisElement;
11732+
1170811733
if (!this.okToHandleKeyPress()) {
1170911734
return false;
1171011735
}
1171111736
// Convert to lower case.
11712-
var which = e.which;
11737+
which = e.which;
1171311738
if (which >= 65 && which <= 90) {
1171411739
which += 32;
1171511740
}
@@ -11725,13 +11750,19 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1172511750
(e.target.tagName === 'TEXTAREA' && !this.stenoMode) ||
1172611751
e.target.tagName === 'SELECT'
1172711752
)){
11753+
$thisElement = $(document.activeElement);
1172811754
if (which === 27) { // escape
1172911755
this.closePopups();
1173011756
}
1173111757
else if (which === 32) { // spacebar = play/pause
1173211758
// disable spacebar support for play/pause toggle as of 4.2.10
1173311759
// spacebar should not be handled everywhere on the page, since users use that to scroll the page
1173411760
// when the player has focus, most controls are buttons so spacebar should be used to trigger the buttons
11761+
if ($thisElement.attr('role') === 'button') {
11762+
// register a click on this element
11763+
e.preventDefault();
11764+
$thisElement.click();
11765+
}
1173511766
}
1173611767
else if (which === 112) { // p = play/pause
1173711768
if (this.usingModifierKeys(e)) {
@@ -11806,14 +11837,13 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1180611837
}
1180711838
}
1180811839
else if (which === 13) { // Enter
11809-
var thisElement = $(document.activeElement);
11810-
if (thisElement.prop('tagName') === 'SPAN') {
11811-
// register a click on this SPAN
11840+
if ($thisElement.attr('role') === 'button' || $thisElement.prop('tagName') === 'SPAN') {
11841+
// register a click on this element
1181211842
// if it's a transcript span the transcript span click handler will take over
11813-
thisElement.click();
11843+
$thisElement.click();
1181411844
}
11815-
else if (thisElement.prop('tagName') === 'LI') {
11816-
thisElement.click();
11845+
else if ($thisElement.prop('tagName') === 'LI') {
11846+
$thisElement.click();
1181711847
}
1181811848
}
1181911849
}
@@ -12213,7 +12243,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1221312243
}
1221412244

1221512245
// handle clicks on player buttons
12216-
this.$controllerDiv.find('button').on('click',function(e){
12246+
this.$controllerDiv.find('div[role="button"]').on('click',function(e){
1221712247
e.stopPropagation();
1221812248
thisObj.onClickPlayerButton(this);
1221912249
});
@@ -12769,7 +12799,6 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1276912799
if (choice !== 'close') {
1277012800
$windowButton.focus();
1277112801
}
12772-
1277312802
if (choice === 'move') {
1277412803
if (!this.showedAlert(which)) {
1277512804
this.showAlert(this.tt.windowMoveAlert,which);
@@ -12796,9 +12825,11 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1279612825
else if (choice == 'close') {
1279712826
// close window, place focus on corresponding button on controller bar
1279812827
if (which === 'transcript') {
12828+
this.closingTranscript = true; // stopgrap to prevent double-firing of keypress
1279912829
this.handleTranscriptToggle();
1280012830
}
1280112831
else if (which === 'sign') {
12832+
this.closingSign = true; // stopgrap to prevent double-firing of keypress
1280212833
this.handleSignToggle();
1280312834
}
1280412835
}

‎build/ableplayer.js‎

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,6 @@ var AblePlayerInstances = [];
630630
}
631631
$('body').append($el);
632632
bgColor = $el.css('background-color');
633-
console.log('bgColor is ' + bgColor);
634633
// bgColor is a string in the form 'rgb(R, G, B)', perhaps with a 4th item for alpha;
635634
// split the 3 or 4 channels into an array
636635
rgb = bgColor.replace(/[^\d,]/g, '').split(',');
@@ -645,7 +644,6 @@ console.log('bgColor is ' + bgColor);
645644
else { // background is light
646645
iconColor = 'black';
647646
}
648-
console.log('iconColor: ' + iconColor);
649647
if ($elements[i] === 'controller') {
650648
this.iconColor = iconColor;
651649
}
@@ -4136,12 +4134,17 @@ console.log('iconColor: ' + iconColor);
41364134
// And if iconType === 'image', we are replacing #2 with an image (with alt="" and role="presentation")
41374135
// This has been thoroughly tested and works well in all screen reader/browser combinations
41384136
// See https://github.com/ableplayer/ableplayer/issues/81
4139-
$newButton = $('<button>',{
4140-
'type': 'button',
4137+
4138+
// NOTE: Changed from <button> to <div role="button" as of 4.2.18
4139+
// because <button> elements are rendered poorly in high contrast mode
4140+
// in some OS/browser/plugin combinations
4141+
$newButton = $('<div>',{
4142+
'role': 'button',
41414143
'tabindex': '0',
41424144
'aria-label': buttonTitle,
41434145
'class': 'able-button-handler-' + control
41444146
});
4147+
41454148
if (control === 'volume' || control === 'preferences') {
41464149
if (control == 'preferences') {
41474150
this.prefCats = this.getPreferencesGroups();
@@ -8357,12 +8360,12 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
83578360
leftControls = this.seekBar.wrapperDiv.parent().prev('div.able-left-controls');
83588361
rightControls = leftControls.next('div.able-right-controls');
83598362
leftControls.children().each(function () {
8360-
if ($(this).prop('tagName')=='BUTTON') {
8363+
if ($(this).attr('role')=='button') {
83618364
widthUsed += $(this).outerWidth(true); // true = include margin
83628365
}
83638366
});
83648367
rightControls.children().each(function () {
8365-
if ($(this).prop('tagName')=='BUTTON') {
8368+
if ($(this).attr('role')=='button') {
83668369
widthUsed += $(this).outerWidth(true);
83678370
}
83688371
});
@@ -9046,12 +9049,20 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
90469049
};
90479050

90489051
AblePlayer.prototype.handleTranscriptToggle = function () {
9052+
9053+
var thisObj = this;
9054+
90499055
if (this.$transcriptDiv.is(':visible')) {
90509056
this.$transcriptArea.hide();
90519057
this.$transcriptButton.addClass('buttonOff').attr('aria-label',this.tt.showTranscript);
90529058
this.$transcriptButton.find('span.able-clipped').text(this.tt.showTranscript);
90539059
this.prefTranscript = 0;
90549060
this.$transcriptButton.focus().addClass('able-focus');
9061+
// wait a second before resetting stopgap var
9062+
// otherwise the keypress used to select 'Close' will trigger the transcript button
9063+
setTimeout(function() {
9064+
thisObj.closingTranscript = false;
9065+
}, 1000);
90559066
}
90569067
else {
90579068
this.positionDraggableWindow('transcript');
@@ -9064,12 +9075,20 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
90649075
};
90659076

90669077
AblePlayer.prototype.handleSignToggle = function () {
9078+
9079+
var thisObj = this;
9080+
90679081
if (this.$signWindow.is(':visible')) {
90689082
this.$signWindow.hide();
90699083
this.$signButton.addClass('buttonOff').attr('aria-label',this.tt.showSign);
90709084
this.$signButton.find('span.able-clipped').text(this.tt.showSign);
90719085
this.prefSign = 0;
90729086
this.$signButton.focus().addClass('able-focus');
9087+
// wait a second before resetting stopgap var
9088+
// otherwise the keypress used to select 'Close' will trigger the transcript button
9089+
setTimeout(function() {
9090+
thisObj.closingSign = false;
9091+
}, 1000);
90739092
}
90749093
else {
90759094
this.positionDraggableWindow('sign');
@@ -11642,7 +11661,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1164211661
this.handleDescriptionToggle();
1164311662
}
1164411663
else if (whichButton === 'sign') {
11645-
this.handleSignToggle();
11664+
if (!this.closingSign) {
11665+
this.handleSignToggle();
11666+
}
1164611667
}
1164711668
else if (whichButton === 'preferences') {
1164811669
if ($(el).attr('data-prefs-popup') === 'menu') {
@@ -11669,7 +11690,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1166911690
this.handleHelpClick();
1167011691
}
1167111692
else if (whichButton === 'transcript') {
11672-
this.handleTranscriptToggle();
11693+
if (!this.closingTranscript) {
11694+
this.handleTranscriptToggle();
11695+
}
1167311696
}
1167411697
else if (whichButton === 'fullscreen') {
1167511698
this.clickedFullscreenButton = true;
@@ -11705,11 +11728,13 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1170511728
// including removal of the "media player" design pattern. There's an issue about that:
1170611729
// https://github.com/w3c/aria-practices/issues/27
1170711730

11731+
var which, $thisElement;
11732+
1170811733
if (!this.okToHandleKeyPress()) {
1170911734
return false;
1171011735
}
1171111736
// Convert to lower case.
11712-
var which = e.which;
11737+
which = e.which;
1171311738
if (which >= 65 && which <= 90) {
1171411739
which += 32;
1171511740
}
@@ -11725,13 +11750,19 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1172511750
(e.target.tagName === 'TEXTAREA' && !this.stenoMode) ||
1172611751
e.target.tagName === 'SELECT'
1172711752
)){
11753+
$thisElement = $(document.activeElement);
1172811754
if (which === 27) { // escape
1172911755
this.closePopups();
1173011756
}
1173111757
else if (which === 32) { // spacebar = play/pause
1173211758
// disable spacebar support for play/pause toggle as of 4.2.10
1173311759
// spacebar should not be handled everywhere on the page, since users use that to scroll the page
1173411760
// when the player has focus, most controls are buttons so spacebar should be used to trigger the buttons
11761+
if ($thisElement.attr('role') === 'button') {
11762+
// register a click on this element
11763+
e.preventDefault();
11764+
$thisElement.click();
11765+
}
1173511766
}
1173611767
else if (which === 112) { // p = play/pause
1173711768
if (this.usingModifierKeys(e)) {
@@ -11806,14 +11837,13 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1180611837
}
1180711838
}
1180811839
else if (which === 13) { // Enter
11809-
var thisElement = $(document.activeElement);
11810-
if (thisElement.prop('tagName') === 'SPAN') {
11811-
// register a click on this SPAN
11840+
if ($thisElement.attr('role') === 'button' || $thisElement.prop('tagName') === 'SPAN') {
11841+
// register a click on this element
1181211842
// if it's a transcript span the transcript span click handler will take over
11813-
thisElement.click();
11843+
$thisElement.click();
1181411844
}
11815-
else if (thisElement.prop('tagName') === 'LI') {
11816-
thisElement.click();
11845+
else if ($thisElement.prop('tagName') === 'LI') {
11846+
$thisElement.click();
1181711847
}
1181811848
}
1181911849
}
@@ -12213,7 +12243,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1221312243
}
1221412244

1221512245
// handle clicks on player buttons
12216-
this.$controllerDiv.find('button').on('click',function(e){
12246+
this.$controllerDiv.find('div[role="button"]').on('click',function(e){
1221712247
e.stopPropagation();
1221812248
thisObj.onClickPlayerButton(this);
1221912249
});
@@ -12769,7 +12799,6 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1276912799
if (choice !== 'close') {
1277012800
$windowButton.focus();
1277112801
}
12772-
1277312802
if (choice === 'move') {
1277412803
if (!this.showedAlert(which)) {
1277512804
this.showAlert(this.tt.windowMoveAlert,which);
@@ -12796,9 +12825,11 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
1279612825
else if (choice == 'close') {
1279712826
// close window, place focus on corresponding button on controller bar
1279812827
if (which === 'transcript') {
12828+
this.closingTranscript = true; // stopgrap to prevent double-firing of keypress
1279912829
this.handleTranscriptToggle();
1280012830
}
1280112831
else if (which === 'sign') {
12832+
this.closingSign = true; // stopgrap to prevent double-firing of keypress
1280212833
this.handleSignToggle();
1280312834
}
1280412835
}

‎build/ableplayer.min.css‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)