upgrade mediaelement.js to instructure/mediaelement#1a177ed2cc
fixes: CNVS-34022 test plan: should include general improvements and bugfixes from upgrade, but no core functionality should change. - video and audio player - speed controls - quality controls - caption track controls (including upload and delete) - note: this does not yet fix all a11y issues Change-Id: Ifc0afbece6044cd04087f474c9e9c6a30caca74d Reviewed-on: https://gerrit.instructure.com/111518 Tested-by: Jenkins Reviewed-by: Ryan Shaw <ryan@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Product-Review: Simon Williams <simon@instructure.com>
This commit is contained in:
parent
b91fed2744
commit
13e71ca726
|
@ -33,6 +33,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subtitile upload link */
|
||||||
|
.mejs-captions-selector .upload-track {
|
||||||
|
color: white;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mejs-captions-selector .upload-track:focus {
|
||||||
|
color: rgba(33, 248, 248, 1);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Playback speed control is based on code from an as-yet-unmerged pull request to mediaelement.js
|
// Playback speed control is based on code from an as-yet-unmerged pull request to mediaelement.js
|
||||||
// See: https://github.com/matthillman/mediaelement/commit/e9efc9473ca38c240b712a11ba4c035651c204d4
|
// See: https://github.com/matthillman/mediaelement/commit/e9efc9473ca38c240b712a11ba4c035651c204d4
|
||||||
|
@ -118,4 +128,13 @@ div.mejs-speed-button {
|
||||||
background-color: rgb(200, 200, 200) !important;
|
background-color: rgb(200, 200, 200) !important;
|
||||||
background-color: rgba(255,255,255,.4) !important;
|
background-color: rgba(255,255,255,.4) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mejs-controls .mejs-speed-button .mejs-speed-selector a:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mejs-controls .mejs-speed-button .mejs-speed-selector .focus {
|
||||||
|
background-color: rgb(200, 200, 200) !important;
|
||||||
|
background-color: rgba(255,255,255,.4) !important;
|
||||||
|
}
|
||||||
/* End: Speed */
|
/* End: Speed */
|
||||||
|
|
|
@ -1,29 +1,43 @@
|
||||||
/*
|
/*
|
||||||
Built by: build_media_element_js.rake
|
Built by: build_media_element_js.rake
|
||||||
from https://github.com/johndyer/mediaelement.git
|
from https://github.com/instructure/mediaelement.git
|
||||||
revision: ceeb1a7f41b2557c4f6a865cee5564c82039201d
|
revision: a84fd12157c225714283bffc053ba17e1eea6c0c
|
||||||
|
|
||||||
YOU SHOULDN'T EDIT ME DIRECTLY
|
YOU SHOULDN'T EDIT ME DIRECTLY
|
||||||
*/
|
*/
|
||||||
.mejs-offscreen{
|
.mejs-offscreen{
|
||||||
/* Accessibility: hide screen reader texts (and prefer "top" for RTL languages). */
|
/* Accessibility: hide screen reader texts (and prefer "top" for RTL languages). Reference: http://blog.rrwd.nl/2015/04/04/the-screen-reader-text-class-why-and-how/ */
|
||||||
|
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - no likey commas */
|
||||||
|
clip: rect(1px, 1px, 1px, 1px); /* IE8-IE11 - we likey commas, no support for clip-path */
|
||||||
|
clip-path: polygon(0px 0px, 0px 0px,0px 0px, 0px 0px);
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
top: -10000px;
|
|
||||||
left: -10000px;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-container {
|
.mejs-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #000;
|
background: #000;
|
||||||
font-family: Helvetica, Arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-indent: 0;
|
text-indent: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mejs-fill-container,.mejs-fill-container .mejs-container{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mejs-fill-container{
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mejs-container:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.me-plugin {
|
.me-plugin {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +105,6 @@
|
||||||
.mejs-poster img {
|
.mejs-poster img {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-overlay {
|
.mejs-overlay {
|
||||||
|
@ -111,11 +124,11 @@
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
margin: -50px 0 0 -50px;
|
margin: -50px 0 0 -50px;
|
||||||
background: url(/images/mediaelement/bigplay.svg) no-repeat;
|
background: url("/images/mediaelement/bigplay.svg") no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-svg .mejs-overlay-button {
|
.no-svg .mejs-overlay-button {
|
||||||
background-image: url(/images/mediaelement/bigplay.png);
|
background-image: url("/images/mediaelement/bigplay.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-overlay:hover .mejs-overlay-button {
|
.mejs-overlay:hover .mejs-overlay-button {
|
||||||
|
@ -130,7 +143,7 @@
|
||||||
height: 80px;
|
height: 80px;
|
||||||
margin: -40px 0 0 -40px;
|
margin: -40px 0 0 -40px;
|
||||||
background: #333;
|
background: #333;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(0, 0, 0, 0.9);
|
background: rgba(0, 0, 0, 0.9);
|
||||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.9)), to(rgba(0,0,0,0.9)));
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.9)), to(rgba(0,0,0,0.9)));
|
||||||
background: -webkit-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
|
background: -webkit-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
|
||||||
|
@ -144,7 +157,7 @@
|
||||||
display: block;
|
display: block;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
background: transparent url(/images/mediaelement/loading.gif) 50% 50% no-repeat;
|
background: transparent url("/images/mediaelement/loading.gif") 50% 50% no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End: LAYERS */
|
/* End: LAYERS */
|
||||||
|
@ -157,7 +170,7 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.7)), to(rgba(0,0,0,0.7)));
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.7)), to(rgba(0,0,0,0.7)));
|
||||||
background: -webkit-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
|
background: -webkit-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
|
||||||
|
@ -179,7 +192,7 @@
|
||||||
height: 26px;
|
height: 26px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 11px;
|
line-height: 11px;
|
||||||
font-family: Helvetica, Arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,11 +208,11 @@
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: transparent url(/images/mediaelement/controls.svg) no-repeat;
|
background: transparent url("/images/mediaelement/controls.svg") no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-svg .mejs-controls .mejs-button button {
|
.no-svg .mejs-controls .mejs-button button {
|
||||||
background-image: url(/images/mediaelement/controls.png);
|
background-image: url("/images/mediaelement/controls.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :focus for accessibility */
|
/* :focus for accessibility */
|
||||||
|
@ -428,7 +441,7 @@
|
||||||
display: none;
|
display: none;
|
||||||
height: 115px;
|
height: 115px;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50, 50, 50, 0.7);
|
background: rgba(50, 50, 50, 0.7);
|
||||||
-webkit-border-radius: 0;
|
-webkit-border-radius: 0;
|
||||||
-moz-border-radius: 0;
|
-moz-border-radius: 0;
|
||||||
|
@ -564,7 +577,7 @@
|
||||||
right: -51px;
|
right: -51px;
|
||||||
width: 85px;
|
width: 85px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50,50,50,0.7);
|
background: rgba(50,50,50,0.7);
|
||||||
border: solid 1px transparent;
|
border: solid 1px transparent;
|
||||||
padding: 10px 10px 0 10px;
|
padding: 10px 10px 0 10px;
|
||||||
|
@ -574,11 +587,9 @@
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
.mejs-controls .mejs-captions-button:hover .mejs-captions-selector {
|
.mejs-controls .mejs-captions-button:hover .mejs-captions-selector {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
.mejs-controls .mejs-captions-button .mejs-captions-selector ul {
|
.mejs-controls .mejs-captions-button .mejs-captions-selector ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -608,7 +619,7 @@
|
||||||
float: left;
|
float: left;
|
||||||
padding: 4px 0 0 0;
|
padding: 4px 0 0 0;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
font-family: helvetica, arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +632,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
-xborder-right: solid 1px #fff;
|
border-right: solid 1px #fff;
|
||||||
width: 10000px;
|
width: 10000px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
@ -719,10 +730,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-captions-text {
|
.mejs-captions-text {
|
||||||
padding: 3px 5px;
|
padding: 0;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(20, 20, 20, 0.5);
|
background: rgba(20, 20, 20, 0.5);
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
-webkit-box-shadow: 5px 0 0 rgba(20, 20, 20, 0.5), -5px 0 0 rgba(20, 20, 20, 0.5);
|
||||||
|
box-shadow: 5px 0 0 rgba(20, 20, 20, 0.5), -5px 0 0 rgba(20, 20, 20, 0.5);
|
||||||
}
|
}
|
||||||
/* End: Track (Captions and Chapters) */
|
/* End: Track (Captions and Chapters) */
|
||||||
|
|
||||||
|
@ -790,7 +803,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-contextmenu .mejs-contextmenu-item {
|
.mejs-contextmenu .mejs-contextmenu-item {
|
||||||
font-family: Helvetica, Arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -811,13 +824,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector {
|
.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector {
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 26px;
|
bottom: 26px;
|
||||||
right: -10px;
|
right: -10px;
|
||||||
width: 130px;
|
width: 130px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50,50,50,0.7);
|
background: rgba(50,50,50,0.7);
|
||||||
border: solid 1px transparent;
|
border: solid 1px transparent;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -855,7 +867,7 @@
|
||||||
float: left;
|
float: left;
|
||||||
padding: 4px 0 0 0;
|
padding: 4px 0 0 0;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
font-family: helvetica, arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
/* End: Source Chooser */
|
/* End: Source Chooser */
|
||||||
|
@ -867,7 +879,7 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50,50,50,0.7);
|
background: rgba(50,50,50,0.7);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -880,7 +892,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50,50,50,0.7);
|
background: rgba(50,50,50,0.7);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
@ -905,13 +917,12 @@ div.mejs-speed-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-controls .mejs-speed-button .mejs-speed-selector {
|
.mejs-controls .mejs-speed-button .mejs-speed-selector {
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -100px;
|
top: -100px;
|
||||||
left: -10px;
|
left: -10px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
background: url(/images/mediaelement/background.png);
|
background: url("/images/mediaelement/background.png");
|
||||||
background: rgba(50, 50, 50, 0.7);
|
background: rgba(50, 50, 50, 0.7);
|
||||||
border: solid 1px transparent;
|
border: solid 1px transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -921,9 +932,6 @@ div.mejs-speed-button {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-controls .mejs-speed-button:hover > .mejs-speed-selector {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li label.mejs-speed-selected {
|
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li label.mejs-speed-selected {
|
||||||
color: rgba(33, 248, 248, 1);
|
color: rgba(33, 248, 248, 1);
|
||||||
|
@ -939,7 +947,6 @@ div.mejs-speed-button {
|
||||||
|
|
||||||
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li {
|
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li {
|
||||||
margin: 0 0 6px 0;
|
margin: 0 0 6px 0;
|
||||||
padding: 0 10px;
|
|
||||||
list-style-type: none !important;
|
list-style-type: none !important;
|
||||||
display: block;
|
display: block;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -950,16 +957,14 @@ div.mejs-speed-button {
|
||||||
clear: both;
|
clear: both;
|
||||||
float: left;
|
float: left;
|
||||||
margin: 3px 3px 0 5px;
|
margin: 3px 3px 0 5px;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li label {
|
.mejs-controls .mejs-speed-button .mejs-speed-selector ul li label {
|
||||||
width: 60px;
|
|
||||||
float: left;
|
float: left;
|
||||||
padding: 4px 0 0 0;
|
padding: 4px 0 0 0;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
font-family: helvetica, arial;
|
font-family: "Helvetica", Arial, serif;
|
||||||
font-size: 11.5px;
|
font-size: 11px;
|
||||||
color: white;
|
color: white;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -971,11 +976,24 @@ div.mejs-speed-button {
|
||||||
}
|
}
|
||||||
/* End: Speed */
|
/* End: Speed */
|
||||||
|
|
||||||
|
/* Start: Jump Forward */
|
||||||
|
|
||||||
|
.mejs-controls .mejs-button.mejs-jump-forward-button {
|
||||||
|
background: transparent url("/images/mediaelement/jumpforward.png") no-repeat 3px 3px;
|
||||||
|
}
|
||||||
|
.mejs-controls .mejs-button.mejs-jump-forward-button button {
|
||||||
|
background: transparent;
|
||||||
|
font-size: 9px;
|
||||||
|
line-height: normal;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End: Jump Forward */
|
||||||
|
|
||||||
/* Start: Skip Back */
|
/* Start: Skip Back */
|
||||||
|
|
||||||
.mejs-controls .mejs-button.mejs-skip-back-button {
|
.mejs-controls .mejs-button.mejs-skip-back-button {
|
||||||
background: transparent url(/images/mediaelement/skipback.png) no-repeat;
|
background: transparent url("/images/mediaelement/skipback.png") no-repeat 3px 3px;
|
||||||
background-position: 3px 3px;
|
|
||||||
}
|
}
|
||||||
.mejs-controls .mejs-button.mejs-skip-back-button button {
|
.mejs-controls .mejs-button.mejs-skip-back-button button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
|
@ -9,7 +9,7 @@ task :build_media_element_js do
|
||||||
|
|
||||||
repo_path = '../mediaelement'
|
repo_path = '../mediaelement'
|
||||||
public_path = 'public'
|
public_path = 'public'
|
||||||
repo_location = "https://github.com/johndyer/mediaelement.git"
|
repo_location = "https://github.com/instructure/mediaelement.git"
|
||||||
|
|
||||||
unless File.exists? repo_path
|
unless File.exists? repo_path
|
||||||
puts "cloning repo"
|
puts "cloning repo"
|
||||||
|
@ -70,7 +70,7 @@ task :build_media_element_js do
|
||||||
puts "Copying CSS"
|
puts "Copying CSS"
|
||||||
css = File.read "#{repo_path}/src/css/mediaelementplayer.css"
|
css = File.read "#{repo_path}/src/css/mediaelementplayer.css"
|
||||||
# fix urls to background images
|
# fix urls to background images
|
||||||
css = css.gsub('url(', 'url(/images/mediaelement/')
|
css = css.gsub('url("', 'url("/images/mediaelement/')
|
||||||
File.open("app/stylesheets/vendor/_mediaelementplayer.scss", 'w') {|f| f.write(rev_msg + css) }
|
File.open("app/stylesheets/vendor/_mediaelementplayer.scss", 'w') {|f| f.write(rev_msg + css) }
|
||||||
|
|
||||||
puts 'Copying Skin Files'
|
puts 'Copying Skin Files'
|
||||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
|
@ -1,89 +1,210 @@
|
||||||
|
//
|
||||||
|
// mep-feature-tracks.js with additional customizations
|
||||||
|
//
|
||||||
|
// to see the diff, run:
|
||||||
|
//
|
||||||
|
// upstream_url='https://raw.githubusercontent.com/instructure/mediaelement/1a177ed2cc3d51689a210d5c034c88112d5a2e42/src/js/mep-feature-sourcechooser.js'
|
||||||
|
// diff -bu \
|
||||||
|
// <(curl -s "${upstream_url}") \
|
||||||
|
// public/javascripts/mediaelement/mep-feature-sourcechooser-instructure.js
|
||||||
|
//
|
||||||
// Source Chooser Plugin
|
// Source Chooser Plugin
|
||||||
(function($) {
|
(function($) {
|
||||||
|
|
||||||
$.extend(mejs.MepDefaults, {
|
$.extend(mejs.MepDefaults, {
|
||||||
sourcechooserText: 'Source Chooser'
|
sourcechooserText: 'Source Chooser'
|
||||||
});
|
});
|
||||||
|
|
||||||
$.extend(MediaElementPlayer.prototype, {
|
$.extend(MediaElementPlayer.prototype, {
|
||||||
buildsourcechooser: function(player, controls, layers, media) {
|
sources: [],
|
||||||
if (!player.isVideo) { return; }
|
|
||||||
|
|
||||||
var t = this;
|
buildsourcechooser: function(player, controls, layers, media) {
|
||||||
|
// INSTRUCTURE ADDED
|
||||||
|
if (!player.isVideo) { return; }
|
||||||
|
|
||||||
player.sourcechooserButton =
|
var t = this;
|
||||||
$('<div class="mejs-button mejs-sourcechooser-button">'+
|
var hoverTimeout;
|
||||||
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.sourcechooserText + '" aria-label="' + t.options.sourcechooserText + '"></button>'+
|
|
||||||
'<div class="mejs-sourcechooser-selector">'+
|
|
||||||
'<ul>'+
|
|
||||||
'</ul>'+
|
|
||||||
'</div>'+
|
|
||||||
'</div>')
|
|
||||||
.appendTo(controls)
|
|
||||||
|
|
||||||
// hover
|
player.sourcechooserButton =
|
||||||
.hover(function() {
|
$('<div class="mejs-button mejs-sourcechooser-button">'+
|
||||||
$(this).find('.mejs-sourcechooser-selector').css('visibility','visible');
|
'<button type="button" role="button" aria-haspopup="true" aria-controls="' + t.id + '" title="' + t.options.sourcechooserText + '" aria-label="' + t.options.sourcechooserText + '" aria-live="assertive"></button>'+
|
||||||
}, function() {
|
'<div class="mejs-sourcechooser-selector mejs-offscreen" role="menu" aria-expanded="false" aria-hidden="true">'+
|
||||||
$(this).find('.mejs-sourcechooser-selector').css('visibility','hidden');
|
'<ul>'+
|
||||||
})
|
'</ul>'+
|
||||||
|
'</div>'+
|
||||||
|
'</div>')
|
||||||
|
.appendTo(controls)
|
||||||
|
|
||||||
// handle clicks to the language radio buttons
|
// hover
|
||||||
.on('click', 'input[type=radio]', function() {
|
.hover(function() {
|
||||||
if (media.currentSrc === this.value) { return; }
|
clearTimeout(hoverTimeout);
|
||||||
|
player.showSourcechooserSelector();
|
||||||
|
}, function() {
|
||||||
|
hoverTimeout = setTimeout(function () {
|
||||||
|
player.hideSourcechooserSelector();
|
||||||
|
}, t.options.menuTimeoutMouseLeave);
|
||||||
|
})
|
||||||
|
|
||||||
var src = this.value;
|
// keyboard menu activation
|
||||||
var currentTime = media.currentTime;
|
.on('keydown', function (e) {
|
||||||
var wasPlaying = !media.paused;
|
var keyCode = e.keyCode;
|
||||||
|
|
||||||
$(media).one('loadedmetadata', function() {
|
switch (keyCode) {
|
||||||
media.setCurrentTime(currentTime);
|
case 32: // space
|
||||||
});
|
if (!mejs.MediaFeatures.isFirefox) { // space sends the click event in Firefox
|
||||||
|
player.showSourcechooserSelector();
|
||||||
|
}
|
||||||
|
$(this).find('.mejs-sourcechooser-selector')
|
||||||
|
.find('input[type=radio]:checked').first().focus();
|
||||||
|
break;
|
||||||
|
case 13: // enter
|
||||||
|
player.showSourcechooserSelector();
|
||||||
|
$(this).find('.mejs-sourcechooser-selector')
|
||||||
|
.find('input[type=radio]:checked').first().focus();
|
||||||
|
break;
|
||||||
|
case 27: // esc
|
||||||
|
player.hideSourcechooserSelector();
|
||||||
|
$(this).find('button').focus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
$(media).one('canplay', function() {
|
// close menu when tabbing away
|
||||||
if (wasPlaying) {
|
.on('focusout', mejs.Utility.debounce(function (e) { // Safari triggers focusout multiple times
|
||||||
media.play();
|
// Firefox does NOT support e.relatedTarget to see which element
|
||||||
}
|
// just lost focus, so wait to find the next focused element
|
||||||
});
|
setTimeout(function () {
|
||||||
|
var parent = $(document.activeElement).closest('.mejs-sourcechooser-selector');
|
||||||
|
if (!parent.length) {
|
||||||
|
// focus is outside the control; close menu
|
||||||
|
player.hideSourcechooserSelector();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}, 100))
|
||||||
|
|
||||||
media.setSrc(src);
|
// handle clicks to the source radio buttons
|
||||||
media.load();
|
.delegate('input[type=radio]', 'click', function() {
|
||||||
});
|
// set aria states
|
||||||
|
$(this).attr('aria-selected', true).attr('checked', 'checked');
|
||||||
|
$(this).closest('.mejs-sourcechooser-selector').find('input[type=radio]').not(this).attr('aria-selected', 'false').removeAttr('checked');
|
||||||
|
|
||||||
// add to list
|
var src = this.value;
|
||||||
for (var i in this.node.children) {
|
|
||||||
var src = this.node.children[i];
|
|
||||||
if (src.nodeName === 'SOURCE' && (media.canPlayType(src.type) === 'probably' || media.canPlayType(src.type) === 'maybe')) {
|
|
||||||
player.addSourceButton(src.src, src.title, src.type, media.src === src.src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addSourceButton: function(src, label, type, isCurrent) {
|
if (media.currentSrc != src) {
|
||||||
var t = this;
|
var currentTime = media.currentTime;
|
||||||
if (label === '' || label === undefined) {
|
var paused = media.paused;
|
||||||
label = src;
|
media.pause();
|
||||||
}
|
media.setSrc(src);
|
||||||
type = type.split('/')[1];
|
|
||||||
|
|
||||||
t.sourcechooserButton.find('ul').append(
|
media.addEventListener('loadedmetadata', function(e) {
|
||||||
$('<li>'+
|
media.currentTime = currentTime;
|
||||||
'<label>' +
|
}, true);
|
||||||
'<input type="radio" name="' + t.id + '_sourcechooser" value="' + src + '" ' + (isCurrent ? 'checked="checked"' : '') + ' />' +
|
|
||||||
label + ' (' + type + ')</label>' +
|
|
||||||
'</li>')
|
|
||||||
);
|
|
||||||
|
|
||||||
t.adjustSourcechooserBox();
|
var canPlayAfterSourceSwitchHandler = function(e) {
|
||||||
},
|
if (!paused) {
|
||||||
|
media.play();
|
||||||
|
}
|
||||||
|
media.removeEventListener("canplay", canPlayAfterSourceSwitchHandler, true);
|
||||||
|
};
|
||||||
|
media.addEventListener('canplay', canPlayAfterSourceSwitchHandler, true);
|
||||||
|
media.load();
|
||||||
|
}
|
||||||
|
|
||||||
adjustSourcechooserBox: function() {
|
t.setAriaLabel(media);
|
||||||
var t = this;
|
})
|
||||||
// adjust the size of the outer box
|
|
||||||
t.sourcechooserButton.find('.mejs-sourcechooser-selector').height(
|
// Handle click so that screen readers can toggle the menu
|
||||||
t.sourcechooserButton.find('.mejs-sourcechooser-selector ul').outerHeight(true)
|
.delegate('button', 'click', function (e) {
|
||||||
);
|
if ($(this).siblings('.mejs-sourcechooser-selector').hasClass('mejs-offscreen')) {
|
||||||
}
|
player.showSourcechooserSelector();
|
||||||
});
|
$(this).siblings('.mejs-sourcechooser-selector').find('input[type=radio]:checked').first().focus();
|
||||||
|
} else {
|
||||||
|
player.hideSourcechooserSelector();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
for (var i in this.node.children) {
|
||||||
|
var src = this.node.children[i];
|
||||||
|
if (src.nodeName === 'SOURCE' && (media.canPlayType(src.type) == 'probably' || media.canPlayType(src.type) == 'maybe')) {
|
||||||
|
t.sources.push(src);
|
||||||
|
player.addSourceButton(src.src, src.title, src.type, media.src == src.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.setAriaLabel(media);
|
||||||
|
},
|
||||||
|
|
||||||
|
setAriaLabel: function(media) {
|
||||||
|
var label = mejs.i18n.t(this.options.sourcechooserText)
|
||||||
|
var current = this.currentSource(media);
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
label += ': ' + mejs.i18n.t(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sourcechooserButton.find('button')
|
||||||
|
.attr('aria-label', label)
|
||||||
|
.attr('title', label);
|
||||||
|
},
|
||||||
|
|
||||||
|
addSourceButton: function(src, label, type, isCurrent) {
|
||||||
|
var t = this;
|
||||||
|
if (label === '' || label == undefined) {
|
||||||
|
label = src;
|
||||||
|
}
|
||||||
|
type = type.split('/')[1];
|
||||||
|
|
||||||
|
t.sourcechooserButton.find('ul').append(
|
||||||
|
$('<li>'+
|
||||||
|
'<input type="radio" name="' + t.id + '_sourcechooser" id="' + t.id + '_sourcechooser_' + label + type + '" role="menuitemradio" value="' + src + '" ' + (isCurrent ? 'checked="checked"' : '') + 'aria-selected="' + isCurrent + '" aria-label="' + label + '"' + ' />'+
|
||||||
|
'<label for="' + t.id + '_sourcechooser_' + label + type + '" aria-hidden="true">' + label + ' (' + type + ')</label>'+
|
||||||
|
'</li>')
|
||||||
|
);
|
||||||
|
|
||||||
|
t.adjustSourcechooserBox();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
currentSource: function(media) {
|
||||||
|
var current = this.sources.filter(function(src) {
|
||||||
|
return src.src == media.src;
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
return current.title || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
adjustSourcechooserBox: function() {
|
||||||
|
var t = this;
|
||||||
|
// adjust the size of the outer box
|
||||||
|
t.sourcechooserButton.find('.mejs-sourcechooser-selector').height(
|
||||||
|
t.sourcechooserButton.find('.mejs-sourcechooser-selector ul').outerHeight(true)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
hideSourcechooserSelector: function () {
|
||||||
|
this.sourcechooserButton.find('.mejs-sourcechooser-selector')
|
||||||
|
.addClass('mejs-offscreen')
|
||||||
|
.attr('aria-expanded', 'false')
|
||||||
|
.attr('aria-hidden', 'true')
|
||||||
|
.find('input[type=radio]') // make radios not focusable
|
||||||
|
.attr('tabindex', '-1');
|
||||||
|
},
|
||||||
|
|
||||||
|
showSourcechooserSelector: function () {
|
||||||
|
this.sourcechooserButton.find('.mejs-sourcechooser-selector')
|
||||||
|
.removeClass('mejs-offscreen')
|
||||||
|
.attr('aria-expanded', 'true')
|
||||||
|
.attr('aria-hidden', 'false')
|
||||||
|
.find('input[type=radio]')
|
||||||
|
.attr('tabindex', '0');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
})(mejs.$);
|
})(mejs.$);
|
||||||
|
|
|
@ -1,104 +1,225 @@
|
||||||
//
|
//
|
||||||
// Playback speed control is based on code from an as-yet-unmerged pull request to mediaelement.js
|
// mep-feature-speed.js with additional customizations
|
||||||
// See: https://github.com/matthillman/mediaelement/commit/e9efc9473ca38c240b712a11ba4c035651c204d4
|
//
|
||||||
// And: https://github.com/johndyer/mediaelement/pull/1249
|
// to see the diff, run:
|
||||||
|
//
|
||||||
|
// upstream_url='https://raw.githubusercontent.com/instructure/mediaelement/1a177ed2cc3d51689a210d5c034c88112d5a2e42/src/js/mep-feature-speed.js'
|
||||||
|
// diff -bu \
|
||||||
|
// <(curl -s "${upstream_url}") \
|
||||||
|
// public/javascripts/mediaelement/mep-feature-speed-instructure.js
|
||||||
//
|
//
|
||||||
(function($) {
|
(function($) {
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
$.extend(mejs.MepDefaults, {
|
$.extend(mejs.MepDefaults, {
|
||||||
|
|
||||||
// INSTRUCTURE CUSTOMIZATION: adjust default available speeds
|
// We also support to pass object like this:
|
||||||
|
// [{name: 'Slow', value: '0.75'}, {name: 'Normal', value: '1.00'}, ...]
|
||||||
|
|
||||||
|
// INSTRUCTURE CUSTOMIZATION: remove 1.25 speed and add 0.50
|
||||||
speeds: ['2.00', '1.50', '1.00', '0.75', '0.50'],
|
speeds: ['2.00', '1.50', '1.00', '0.75', '0.50'],
|
||||||
|
|
||||||
defaultSpeed: '1.00'
|
defaultSpeed: '1.00',
|
||||||
|
|
||||||
|
speedChar: 'x',
|
||||||
|
|
||||||
|
speedLabel: 'Change playback speed'
|
||||||
});
|
});
|
||||||
|
|
||||||
$.extend(MediaElementPlayer.prototype, {
|
$.extend(MediaElementPlayer.prototype, {
|
||||||
|
|
||||||
// INSTRUCTURE CUSTOMIZATION - pulling latest definition of isIE from ME.js master with IE11 fixes
|
|
||||||
isIE: function() {
|
|
||||||
return (window.navigator.appName.match(/microsoft/gi) !== null) || (window.navigator.userAgent.match(/trident/gi) !== null);
|
|
||||||
},
|
|
||||||
|
|
||||||
buildspeed: function(player, controls, layers, media) {
|
buildspeed: function(player, controls, layers, media) {
|
||||||
// INSTRUCTURE CUSTOMIZATION: enable playback speed controls for both audio and video
|
|
||||||
// if (!player.isVideo)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
var t = this;
|
var t = this;
|
||||||
|
var hoverTimeout;
|
||||||
|
|
||||||
if (t.media.pluginType !== 'native') { return; }
|
if (t.media.pluginType == 'native') {
|
||||||
|
var
|
||||||
|
speedButton = null,
|
||||||
|
speedSelector = null,
|
||||||
|
playbackSpeed = null,
|
||||||
|
inputId = null,
|
||||||
|
isCurrent = null;
|
||||||
|
|
||||||
var s = '<div class="mejs-button mejs-speed-button"><button type="button">'+t.options.defaultSpeed+'x</button><div class="mejs-speed-selector"><ul>';
|
var speeds = [];
|
||||||
var i, ss;
|
var defaultInArray = false;
|
||||||
|
for (var i=0, len=t.options.speeds.length; i < len; i++) {
|
||||||
if ($.inArray(t.options.defaultSpeed, t.options.speeds) === -1) {
|
var s = t.options.speeds[i];
|
||||||
t.options.speeds.push(t.options.defaultSpeed);
|
if (typeof(s) === 'string'){
|
||||||
}
|
speeds.push({
|
||||||
|
name: s + t.options.speedChar,
|
||||||
t.options.speeds.sort(function(a, b) {
|
value: s
|
||||||
return parseFloat(b) - parseFloat(a);
|
});
|
||||||
});
|
if(s === t.options.defaultSpeed) {
|
||||||
|
defaultInArray = true;
|
||||||
for (i = 0; i < t.options.speeds.length; i++) {
|
}
|
||||||
s += '<li>';
|
}
|
||||||
if (t.options.speeds[i] === t.options.defaultSpeed) {
|
else {
|
||||||
s += '<label class="mejs-speed-selected">'+ t.options.speeds[i] + 'x';
|
speeds.push(s);
|
||||||
s += '<input type="radio" name="speed" value="' + t.options.speeds[i] + '" checked=true />';
|
if(s.value === t.options.defaultSpeed) {
|
||||||
} else {
|
defaultInArray = true;
|
||||||
s += '<label>'+ t.options.speeds[i] + 'x';
|
}
|
||||||
s += '<input type="radio" name="speed" value="' + t.options.speeds[i] + '" />';
|
}
|
||||||
}
|
}
|
||||||
s += '</label></li>';
|
|
||||||
}
|
|
||||||
s += '</ul></div></div>';
|
|
||||||
|
|
||||||
player.speedButton = $(s).appendTo(controls);
|
if (!defaultInArray) {
|
||||||
|
speeds.push({
|
||||||
player.playbackspeed = t.options.defaultSpeed;
|
name: t.options.defaultSpeed + t.options.speedChar,
|
||||||
|
value: t.options.defaultSpeed
|
||||||
player.$media.on('loadedmetadata', function() {
|
|
||||||
media.playbackRate = parseFloat(player.playbackspeed);
|
|
||||||
});
|
|
||||||
|
|
||||||
player.speedButton.on('click', 'input[type=radio]', function() {
|
|
||||||
player.playbackspeed = $(this).attr('value');
|
|
||||||
media.playbackRate = parseFloat(player.playbackspeed);
|
|
||||||
player.speedButton.find('button').text(player.playbackspeed + 'x');
|
|
||||||
player.speedButton.find('.mejs-speed-selected').removeClass('mejs-speed-selected');
|
|
||||||
player.speedButton.find('input[type=radio]:checked').parent().addClass('mejs-speed-selected');
|
|
||||||
|
|
||||||
//
|
|
||||||
// INSTRUCTURE CUSTOMIZATION - IE fixes
|
|
||||||
//
|
|
||||||
if (t.isIE()) {
|
|
||||||
// After playback completes, IE will reset the rate to the
|
|
||||||
// defaultPlaybackRate of 1.00 (with the UI still reflecting the
|
|
||||||
// selected value) unless we set defaultPlaybackRate as well.
|
|
||||||
media.defaultPlaybackRate = media.playbackRate;
|
|
||||||
|
|
||||||
// Internet Explorer fires a 'waiting' event in addition to the
|
|
||||||
// 'ratechange' event when the playback speed is changed, even though
|
|
||||||
// the HTML5 standard says not to. >_<
|
|
||||||
//
|
|
||||||
// Even worse, the 'waiting' state does not resolve with any other
|
|
||||||
// event that would indicate that we are done waiting, like 'playing'
|
|
||||||
// or 'seeked', so we are left with nothing to hook on but ye olde
|
|
||||||
// arbitrary point in the future.
|
|
||||||
$(media).one('waiting', function() {
|
|
||||||
setTimeout(function() {
|
|
||||||
layers.find('.mejs-overlay-loading').parent().hide();
|
|
||||||
controls.find('.mejs-time-buffering').hide();
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
ss = player.speedButton.find('.mejs-speed-selector');
|
speeds.sort(function(a, b) {
|
||||||
ss.height(this.speedButton.find('.mejs-speed-selector ul').outerHeight(true) + player.speedButton.find('.mejs-speed-translations').outerHeight(true));
|
return parseFloat(b.value) - parseFloat(a.value);
|
||||||
ss.css('top', (-1 * ss.height()) + 'px');
|
});
|
||||||
|
|
||||||
|
var getSpeedNameFromValue = function(value) {
|
||||||
|
for(i=0,len=speeds.length; i <len; i++) {
|
||||||
|
if (speeds[i].value === value) {
|
||||||
|
return speeds[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var speedLabel = function(speed) {
|
||||||
|
return mejs.i18n.t(t.options.speedLabel + ': Current speed ' + getSpeedNameFromValue(speed));
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = '<div class="mejs-button mejs-speed-button">' +
|
||||||
|
'<button role="button" aria-haspopup="true" aria-controls="' + t.id + '" type="button" aria-label="' + speedLabel(t.options.defaultSpeed) + '" aria-live="assertive">' + getSpeedNameFromValue(t.options.defaultSpeed) + '</button>' +
|
||||||
|
'<div class="mejs-speed-selector mejs-offscreen" role="menu" aria-expanded="false" aria-hidden="true">' +
|
||||||
|
'<ul>';
|
||||||
|
|
||||||
|
for (i = 0, il = speeds.length; i<il; i++) {
|
||||||
|
inputId = t.id + '-speed-' + speeds[i].value;
|
||||||
|
isCurrent = (speeds[i].value === t.options.defaultSpeed);
|
||||||
|
html += '<li>' +
|
||||||
|
'<input type="radio" name="speed" role="menuitemradio"' +
|
||||||
|
'value="' + speeds[i].value + '" ' +
|
||||||
|
'id="' + inputId + '" ' +
|
||||||
|
(isCurrent ? ' checked="checked"' : '') +
|
||||||
|
' aria-selected="' + isCurrent + '"' +
|
||||||
|
' aria-label="' + getSpeedNameFromValue(speeds[i].value) + '"' +
|
||||||
|
' />' +
|
||||||
|
'<label for="' + inputId + '" ' + 'aria-hidden="true"' +
|
||||||
|
(isCurrent ? ' class="mejs-speed-selected"' : '') +
|
||||||
|
'>' + speeds[i].name + '</label>' +
|
||||||
|
'</li>';
|
||||||
|
}
|
||||||
|
html += '</ul></div></div>';
|
||||||
|
|
||||||
|
player.speedButton = speedButton = $(html).appendTo(controls);
|
||||||
|
speedSelector = speedButton.find('.mejs-speed-selector');
|
||||||
|
|
||||||
|
playbackSpeed = t.options.defaultSpeed;
|
||||||
|
|
||||||
|
media.addEventListener('loadedmetadata', function(e) {
|
||||||
|
if (playbackSpeed) {
|
||||||
|
media.playbackRate = parseFloat(playbackSpeed);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
speedSelector
|
||||||
|
.on('click', 'input[type="radio"]', function() {
|
||||||
|
// set aria states
|
||||||
|
$(this).attr('aria-selected', true).attr('checked', 'checked');
|
||||||
|
$(this).closest('.mejs-speed-selector').find('input[type=radio]').not(this).attr('aria-selected', 'false').removeAttr('checked');
|
||||||
|
|
||||||
|
var newSpeed = $(this).attr('value');
|
||||||
|
playbackSpeed = newSpeed;
|
||||||
|
media.playbackRate = parseFloat(newSpeed);
|
||||||
|
speedButton.find('button')
|
||||||
|
.html(getSpeedNameFromValue(newSpeed))
|
||||||
|
.attr('aria-label', speedLabel(newSpeed));
|
||||||
|
speedButton.find('.mejs-speed-selected').removeClass('mejs-speed-selected');
|
||||||
|
speedButton.find('input[type="radio"]:checked').next().addClass('mejs-speed-selected');
|
||||||
|
});
|
||||||
|
speedButton
|
||||||
|
// set size on demand
|
||||||
|
.one( 'mouseenter focusin', function() {
|
||||||
|
speedSelector
|
||||||
|
.height(
|
||||||
|
speedButton.find('.mejs-speed-selector ul').outerHeight(true) +
|
||||||
|
speedButton.find('.mejs-speed-translations').outerHeight(true))
|
||||||
|
.css('top', (-1 * speedSelector.height()) + 'px');
|
||||||
|
})
|
||||||
|
|
||||||
|
// hover
|
||||||
|
.hover(function() {
|
||||||
|
clearTimeout(hoverTimeout);
|
||||||
|
player.showSpeedSelector();
|
||||||
|
}, function() {
|
||||||
|
hoverTimeout = setTimeout(function () {
|
||||||
|
player.hideSpeedSelector();
|
||||||
|
}, t.options.menuTimeoutMouseLeave);
|
||||||
|
})
|
||||||
|
|
||||||
|
// keyboard menu activation
|
||||||
|
.on('keydown', function (e) {
|
||||||
|
var keyCode = e.keyCode;
|
||||||
|
|
||||||
|
switch (keyCode) {
|
||||||
|
case 32: // space
|
||||||
|
if (!mejs.MediaFeatures.isFirefox) { // space sends the click event in Firefox
|
||||||
|
player.showSpeedSelector();
|
||||||
|
}
|
||||||
|
$(this).find('.mejs-speed-selector')
|
||||||
|
.find('input[type=radio]:checked').first().focus();
|
||||||
|
break;
|
||||||
|
case 13: // enter
|
||||||
|
player.showSpeedSelector();
|
||||||
|
$(this).find('.mejs-speed-selector')
|
||||||
|
.find('input[type=radio]:checked').first().focus();
|
||||||
|
break;
|
||||||
|
case 27: // esc
|
||||||
|
player.hideSpeedSelector();
|
||||||
|
$(this).find('button').focus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// close menu when tabbing away
|
||||||
|
.on('focusout', mejs.Utility.debounce(function (e) { // Safari triggers focusout multiple times
|
||||||
|
// Firefox does NOT support e.relatedTarget to see which element
|
||||||
|
// just lost focus, so wait to find the next focused element
|
||||||
|
setTimeout(function () {
|
||||||
|
var parent = $(document.activeElement).closest('.mejs-speed-selector');
|
||||||
|
if (!parent.length) {
|
||||||
|
// focus is outside the control; close menu
|
||||||
|
player.hideSpeedSelector();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}, 100))
|
||||||
|
|
||||||
|
// Handle click so that screen readers can toggle the menu
|
||||||
|
.on('click', 'button', function (e) {
|
||||||
|
if ($(this).siblings('.mejs-speed-selector').hasClass('mejs-offscreen')) {
|
||||||
|
player.showSpeedSelector();
|
||||||
|
$(this).siblings('.mejs-speed-selector').find('input[type=radio]:checked').first().focus();
|
||||||
|
} else {
|
||||||
|
player.hideSpeedSelector();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hideSpeedSelector: function () {
|
||||||
|
this.speedButton.find('.mejs-speed-selector')
|
||||||
|
.addClass('mejs-offscreen')
|
||||||
|
.attr('aria-expanded', 'false')
|
||||||
|
.attr('aria-hidden', 'true')
|
||||||
|
.find('input[type=radio]') // make radios not focusable
|
||||||
|
.attr('tabindex', '-1');
|
||||||
|
},
|
||||||
|
|
||||||
|
showSpeedSelector: function () {
|
||||||
|
this.speedButton.find('.mejs-speed-selector')
|
||||||
|
.removeClass('mejs-offscreen')
|
||||||
|
.attr('aria-expanded', 'true')
|
||||||
|
.attr('aria-hidden', 'false')
|
||||||
|
.find('input[type=radio]')
|
||||||
|
.attr('tabindex', '0');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue