YouTube, Captions and Control improvements

- Controls improvements (Fixes #103)
- YouTube bug fixes (Fixes #105)
- Internationalization support (Fixes #101)
- Captions legibility improvements
This commit is contained in:
Sam Potts 2015-08-08 14:37:12 +10:00
parent 12a737a49e
commit 38a206892b
14 changed files with 247 additions and 215 deletions

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
# v1.3.0
- Internationalization support (i18n) using default controls (required markup changes to controls)
- ARIA enhancements for controls (required markup changes to controls)
- Captions legibility improvements
- YouTube bug fixes
## v1.2.6 ## v1.2.6
- SASS updates and fixes (cheers @ChristianPV) - SASS updates and fixes (cheers @ChristianPV)
@ -21,7 +27,7 @@
## v1.2.1 ## v1.2.1
- Tooltip bug fix - Tooltip bug fix
## v1.2.0 # v1.2.0
- Added YouTube support - Added YouTube support
## v1.1.13 ## v1.1.13

View File

@ -1,10 +1,36 @@
# Controls HTML # Controls
This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs. This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs.
The demo Plyr setup uses a Hogan template. This purely to allow for localization at a later date. Check out `controls.html` in `/src/templates` to get an idea of how the default html is structured. ## Internationalization using default controls
## Requirements You can provide an `i18n` object as one of your options when initialising the plugin which we be used when rendering the controls.
### Example
```javascript
i18n: {
restart: "Restart",
rewind: "Rewind {seektime} secs",
play: "Play",
pause: "Pause",
forward: "Forward {seektime} secs",
played: "played",
buffered: "buffered",
currentTime: "Current time",
duration: "Duration",
volume: "Volume",
toggleMute: "Toggle Mute",
toggleCaptions: "Toggle Captions",
toggleFullscreen: "Toggle Fullscreen"
}
```
Note: `{seektime}` will be replaced with your configured seek time or the default. For example "Forward {seektime} secs" would render as "Forward 10 secs".
## Using custom HTML
The example on [plyr.io](http://plyr.io) setup uses a Hogan template. Check out `controls.html` in `/src/templates` to get an idea of how the default html is structured.
The classes and data attributes used in your template should match the `selectors` option. The classes and data attributes used in your template should match the `selectors` option.
@ -15,7 +41,7 @@ You need to add several placeholders to your html template that are replaced whe
You can include only the controls you need when specifying custom html. You can include only the controls you need when specifying custom html.
## Example ### Example
This is an example `html` option with all controls. This is an example `html` option with all controls.
@ -62,20 +88,18 @@ This is an example `html` option with all controls.
"</span>", "</span>",
"</span>", "</span>",
"<span class='player-controls-right'>", "<span class='player-controls-right'>",
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>", "<button type="button" data-player="mute">",
"<label id='mute{id}' for='mute{id}'>",
"<svg class='icon-muted'><use xlink:href='#icon-muted'></use></svg>", "<svg class='icon-muted'><use xlink:href='#icon-muted'></use></svg>",
"<svg><use xlink:href='#icon-volume'></use></svg>", "<svg><use xlink:href='#icon-volume'></use></svg>",
"<span class='sr-only'>Toggle Mute</span>", "<span class='sr-only'>Toggle Mute</span>",
"</label>", "</button>",
"<label for='volume{id}' class='sr-only'>Volume</label>", "<label for='volume{id}' class='sr-only'>Volume</label>",
"<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>", "<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>",
"<input class='sr-only' id='captions{id}' type='checkbox' data-player='captions'>", "<button type="button" data-player="captions">",
"<label for='captions{id}'>",
"<svg class='icon-captions-on'><use xlink:href='#icon-captions-on'></use></svg>", "<svg class='icon-captions-on'><use xlink:href='#icon-captions-on'></use></svg>",
"<svg><use xlink:href='#icon-captions-off'></use></svg>", "<svg><use xlink:href='#icon-captions-off'></use></svg>",
"<span class='sr-only'>Toggle Captions</span>", "<span class='sr-only'>Toggle Captions</span>",
"</label>", "</button>",
"<button type='button' data-player='fullscreen'>", "<button type='button' data-player='fullscreen'>",
"<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>", "<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
"<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>", "<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>",

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

2
docs/dist/docs.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
var templates = {}; var templates = {};
templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <div class=\"player-progress\">");t.b("\n" + i);t.b(" <label for=\"seek{id}\" class=\"sr-only\">Seek</label>");t.b("\n" + i);t.b(" <input id=\"seek{id}\" class=\"player-progress-seek\" type=\"range\" min=\"0\" max=\"100\" step=\"0.5\" value=\"0\" data-player=\"seek\">");t.b("\n" + i);t.b(" <progress class=\"player-progress-played\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <progress class=\"player-progress-buffer\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% buffered");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <span class=\"player-controls-left\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-restart\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Forward {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Current time</span>");t.b("\n" + i);t.b(" <span class=\"player-current-time\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Duration</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-right\">");t.b("\n" + i);t.b(" <input class=\"inverted sr-only\" id=\"mute{id}\" type=\"checkbox\" data-player=\"mute\">");t.b("\n" + i);t.b(" <label id=\"mute{id}\" for=\"mute{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-volume\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Mute</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" step=\"0.5\" value=\"0\" data-player=\"volume\">");t.b("\n");t.b("\n" + i);t.b(" <input class=\"sr-only\" id=\"captions{id}\" type=\"checkbox\" data-player=\"captions\">");t.b("\n" + i);t.b(" <label for=\"captions{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-captions-on\"><use xlink:href=\"#icon-captions-on\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-captions-off\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Captions</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-exit-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-enter-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }}); templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <div class=\"player-progress\">");t.b("\n" + i);t.b(" <label for=\"seek{id}\" class=\"sr-only\">Seek</label>");t.b("\n" + i);t.b(" <input id=\"seek{id}\" class=\"player-progress-seek\" type=\"range\" min=\"0\" max=\"100\" step=\"0.5\" value=\"0\" data-player=\"seek\">");t.b("\n" + i);t.b(" <progress class=\"player-progress-played\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <progress class=\"player-progress-buffer\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% buffered");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <span class=\"player-controls-left\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-restart\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Forward {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Current time</span>");t.b("\n" + i);t.b(" <span class=\"player-current-time\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Duration</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-right\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"mute\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-volume\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Mute</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" step=\"0.5\" value=\"0\" data-player=\"volume\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"captions\">");t.b("\n" + i);t.b(" <svg class=\"icon-captions-on\"><use xlink:href=\"#icon-captions-on\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-captions-off\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Captions</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-exit-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-enter-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Docs styles --> <!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.2.6/docs.css"> <link rel="stylesheet" href="//cdn.plyr.io/1.3.0/docs.css">
</head> </head>
<body> <body>
<main> <main>

View File

@ -8,10 +8,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Styles --> <!-- Styles -->
<link rel="stylesheet" href="https://cdn.plyr.io/1.2.6/plyr.css?3"> <link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/plyr.css?3">
<!-- Docs styles --> <!-- Docs styles -->
<link rel="stylesheet" href="https://cdn.plyr.io/1.2.6/docs.css?1"> <link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/docs.css?1">
</head> </head>
<body> <body>
<header> <header>
@ -97,13 +97,13 @@
b.insertBefore(c, b.childNodes[0]); b.insertBefore(c, b.childNodes[0]);
} }
} }
})(document, "https://cdn.plyr.io/1.2.6/sprite.svg"); })(document, "https://cdn.plyr.io/1.3.0/sprite.svg");
</script> </script>
<!-- Plyr core script --> <!-- Plyr core script -->
<script src="https://cdn.plyr.io/1.2.6/plyr.js?1"></script> <script src="https://cdn.plyr.io/1.3.0/plyr.js?1"></script>
<!-- Docs script --> <!-- Docs script -->
<script src="https://cdn.plyr.io/1.2.6/docs.js?1"></script> <script src="https://cdn.plyr.io/1.3.0/docs.js?1"></script>
</body> </body>
</html> </html>

View File

@ -40,23 +40,18 @@
</span> </span>
</span> </span>
<span class="player-controls-right"> <span class="player-controls-right">
<input class="inverted sr-only" id="mute{id}" type="checkbox" data-player="mute"> <button type="button" data-player="mute">
<label id="mute{id}" for="mute{id}">
<svg class="icon-muted"><use xlink:href="#icon-muted"></use></svg> <svg class="icon-muted"><use xlink:href="#icon-muted"></use></svg>
<svg><use xlink:href="#icon-volume"></use></svg> <svg><use xlink:href="#icon-volume"></use></svg>
<span class="sr-only">Toggle Mute</span> <span class="sr-only">Toggle Mute</span>
</label> </button>
<label for="volume{id}" class="sr-only">Volume</label> <label for="volume{id}" class="sr-only">Volume</label>
<input id="volume{id}" class="player-volume" type="range" min="0" max="10" step="0.5" value="0" data-player="volume"> <input id="volume{id}" class="player-volume" type="range" min="0" max="10" step="0.5" value="0" data-player="volume">
<button type="button" data-player="captions">
<input class="sr-only" id="captions{id}" type="checkbox" data-player="captions">
<label for="captions{id}">
<svg class="icon-captions-on"><use xlink:href="#icon-captions-on"></use></svg> <svg class="icon-captions-on"><use xlink:href="#icon-captions-on"></use></svg>
<svg><use xlink:href="#icon-captions-off"></use></svg> <svg><use xlink:href="#icon-captions-off"></use></svg>
<span class="sr-only">Toggle Captions</span> <span class="sr-only">Toggle Captions</span>
</label> </button>
<button type="button" data-player="fullscreen"> <button type="button" data-player="fullscreen">
<svg class="icon-exit-fullscreen"><use xlink:href="#icon-exit-fullscreen"></use></svg> <svg class="icon-exit-fullscreen"><use xlink:href="#icon-exit-fullscreen"></use></svg>
<svg><use xlink:href="#icon-enter-fullscreen"></use></svg> <svg><use xlink:href="#icon-enter-fullscreen"></use></svg>

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "1.2.6", "version": "1.3.0",
"description": "A simple HTML5 media player using custom controls", "description": "A simple HTML5 media player using custom controls",
"homepage": "http://plyr.io", "homepage": "http://plyr.io",
"main": "gulpfile.js", "main": "gulpfile.js",

View File

@ -39,7 +39,7 @@ If you have any cool ideas or features, please let me know by [creating an issue
Check `docs/index.html` and `docs/dist/docs.js` for an example setup. Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
**Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.2.6/plyr.js` to `https://cdn.plyr.io/1.2.6/plyr.js` **Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.3.0/plyr.js` to `https://cdn.plyr.io/1.3.0/plyr.js`
### Bower ### Bower
If bower is your thang, you can grab Plyr using: If bower is your thang, you can grab Plyr using:
@ -59,11 +59,11 @@ More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub]
If you want to use our CDN, you can use the following: If you want to use our CDN, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/1.2.6/plyr.css"> <link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/plyr.css">
<script src="https://cdn.plyr.io/1.2.6/plyr.js"></script> <script src="https://cdn.plyr.io/1.3.0/plyr.js"></script>
``` ```
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.2.6/sprite.svg`. You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.3.0/sprite.svg`.
### CSS ### CSS
If you want to use the default css, add the `plyr.css` file from /dist into your head, or even better use `plyr.less` or `plyr.sass` file included in `/src` in your build to save a request. If you want to use the default css, add the `plyr.css` file from /dist into your head, or even better use `plyr.less` or `plyr.sass` file included in `/src` in your build to save a request.
@ -182,6 +182,12 @@ You can pass the following options to the setup method using `plyr.setup({...})`
<td><code>["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"]</code></td> <td><code>["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"]</code></td>
<td>Toggle which control elements you would like to display when using the default controls html. If you specify a <code>html</code> option, this is redundant. The default value is to display everything.</td> <td>Toggle which control elements you would like to display when using the default controls html. If you specify a <code>html</code> option, this is redundant. The default value is to display everything.</td>
</tr> </tr>
<tr>
<td><code>i18n</code></td>
<td>Object</td>
<td><code><a href="controls.md">See controls.md</a></code></td>
<td>Used for internationalisation (i18n) of the tooltips/labels within the buttons.</td>
</tr>
<tr> <tr>
<td><code>iconPrefix</code></td> <td><code>iconPrefix</code></td>
<td>String</td> <td>String</td>

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v1.2.6 // plyr.js v1.3.0
// https://github.com/selz/plyr // https://github.com/selz/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -83,7 +83,21 @@
key: "plyr_volume" key: "plyr_volume"
}, },
controls: ["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"], controls: ["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"],
onSetup: function() {} i18n: {
restart: "Restart",
rewind: "Rewind {seektime} secs",
play: "Play",
pause: "Pause",
forward: "Forward {seektime} secs",
played: "played",
buffered: "buffered",
currentTime: "Current time",
duration: "Duration",
volume: "Volume",
toggleMute: "Toggle Mute",
toggleCaptions: "Toggle Captions",
toggleFullscreen: "Toggle Fullscreen"
}
}; };
// Build the default HTML // Build the default HTML
@ -95,10 +109,10 @@
"<label for='seek{id}' class='sr-only'>Seek</label>", "<label for='seek{id}' class='sr-only'>Seek</label>",
"<input id='seek{id}' class='player-progress-seek' type='range' min='0' max='100' step='0.5' value='0' data-player='seek'>", "<input id='seek{id}' class='player-progress-seek' type='range' min='0' max='100' step='0.5' value='0' data-player='seek'>",
"<progress class='player-progress-played' max='100' value='0'>", "<progress class='player-progress-played' max='100' value='0'>",
"<span>0</span>% played", "<span>0</span>% " + config.i18n.played,
"</progress>", "</progress>",
"<progress class='player-progress-buffer' max='100' value='0'>", "<progress class='player-progress-buffer' max='100' value='0'>",
"<span>0</span>% buffered", "<span>0</span>% " + config.i18n.buffered,
"</progress>", "</progress>",
"</div>", "</div>",
"<span class='player-controls-left'>"]; "<span class='player-controls-left'>"];
@ -108,7 +122,7 @@
html.push( html.push(
"<button type='button' data-player='restart'>", "<button type='button' data-player='restart'>",
"<svg><use xlink:href='#" + config.iconPrefix + "-restart'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-restart'></use></svg>",
"<span class='sr-only'>Restart</span>", "<span class='sr-only'>" + config.i18n.restart + "</span>",
"</button>" "</button>"
); );
} }
@ -118,7 +132,7 @@
html.push( html.push(
"<button type='button' data-player='rewind'>", "<button type='button' data-player='rewind'>",
"<svg><use xlink:href='#" + config.iconPrefix + "-rewind'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-rewind'></use></svg>",
"<span class='sr-only'>Rewind {seektime} secs</span>", "<span class='sr-only'>" + config.i18n.rewind + "</span>",
"</button>" "</button>"
); );
} }
@ -128,11 +142,11 @@
html.push( html.push(
"<button type='button' data-player='play'>", "<button type='button' data-player='play'>",
"<svg><use xlink:href='#" + config.iconPrefix + "-play'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-play'></use></svg>",
"<span class='sr-only'>Play</span>", "<span class='sr-only'>" + config.i18n.play + "</span>",
"</button>", "</button>",
"<button type='button' data-player='pause'>", "<button type='button' data-player='pause'>",
"<svg><use xlink:href='#" + config.iconPrefix + "-pause'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-pause'></use></svg>",
"<span class='sr-only'>Pause</span>", "<span class='sr-only'>" + config.i18n.pause + "</span>",
"</button>" "</button>"
); );
} }
@ -142,7 +156,7 @@
html.push( html.push(
"<button type='button' data-player='fast-forward'>", "<button type='button' data-player='fast-forward'>",
"<svg><use xlink:href='#" + config.iconPrefix + "-fast-forward'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-fast-forward'></use></svg>",
"<span class='sr-only'>Forward {seektime} secs</span>", "<span class='sr-only'>" + config.i18n.forward + "</span>",
"</button>" "</button>"
); );
} }
@ -151,7 +165,7 @@
if(_inArray(config.controls, "current-time")) { if(_inArray(config.controls, "current-time")) {
html.push( html.push(
"<span class='player-time'>", "<span class='player-time'>",
"<span class='sr-only'>Current time</span>", "<span class='sr-only'>" + config.i18n.currentTime + "</span>",
"<span class='player-current-time'>00:00</span>", "<span class='player-current-time'>00:00</span>",
"</span>" "</span>"
); );
@ -161,7 +175,7 @@
if(_inArray(config.controls, "duration")) { if(_inArray(config.controls, "duration")) {
html.push( html.push(
"<span class='player-time'>", "<span class='player-time'>",
"<span class='sr-only'>Duration</span>", "<span class='sr-only'>" + config.i18n.duration + "</span>",
"<span class='player-duration'>00:00</span>", "<span class='player-duration'>00:00</span>",
"</span>" "</span>"
); );
@ -176,19 +190,18 @@
// Toggle mute button // Toggle mute button
if(_inArray(config.controls, "mute")) { if(_inArray(config.controls, "mute")) {
html.push( html.push(
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>", "<button type='button' data-player='mute'>",
"<label id='mute{id}' for='mute{id}'>",
"<svg class='icon-muted'><use xlink:href='#" + config.iconPrefix + "-muted'></use></svg>", "<svg class='icon-muted'><use xlink:href='#" + config.iconPrefix + "-muted'></use></svg>",
"<svg><use xlink:href='#" + config.iconPrefix + "-volume'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-volume'></use></svg>",
"<span class='sr-only'>Toggle Mute</span>", "<span class='sr-only'>" + config.i18n.toggleMute + "</span>",
"</label>" "</button>"
); );
} }
// Volume range control // Volume range control
if(_inArray(config.controls, "volume")) { if(_inArray(config.controls, "volume")) {
html.push( html.push(
"<label for='volume{id}' class='sr-only'>Volume</label>", "<label for='volume{id}' class='sr-only'>" + config.i18n.volume + "</label>",
"<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>" "<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>"
); );
} }
@ -196,12 +209,11 @@
// Toggle captions button // Toggle captions button
if(_inArray(config.controls, "captions")) { if(_inArray(config.controls, "captions")) {
html.push( html.push(
"<input class='sr-only' id='captions{id}' type='checkbox' data-player='captions'>", "<button type='button' data-player='captions'>",
"<label for='captions{id}'>",
"<svg class='icon-captions-on'><use xlink:href='#" + config.iconPrefix + "-captions-on'></use></svg>", "<svg class='icon-captions-on'><use xlink:href='#" + config.iconPrefix + "-captions-on'></use></svg>",
"<svg><use xlink:href='#" + config.iconPrefix + "-captions-off'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-captions-off'></use></svg>",
"<span class='sr-only'>Toggle Captions</span>", "<span class='sr-only'>" + config.i18n.toggleCaptions + "</span>",
"</label>" "</button>"
); );
} }
@ -211,7 +223,7 @@
"<button type='button' data-player='fullscreen'>", "<button type='button' data-player='fullscreen'>",
"<svg class='icon-exit-fullscreen'><use xlink:href='#" + config.iconPrefix + "-exit-fullscreen'></use></svg>", "<svg class='icon-exit-fullscreen'><use xlink:href='#" + config.iconPrefix + "-exit-fullscreen'></use></svg>",
"<svg><use xlink:href='#" + config.iconPrefix + "-enter-fullscreen'></use></svg>", "<svg><use xlink:href='#" + config.iconPrefix + "-enter-fullscreen'></use></svg>",
"<span class='sr-only'>Toggle Fullscreen</span>", "<span class='sr-only'>" + config.i18n.toggleFullscreen + "</span>",
"</button>" "</button>"
); );
} }
@ -478,18 +490,15 @@
element.dispatchEvent(fauxEvent); element.dispatchEvent(fauxEvent);
} }
// Toggle checkbox // Toggle aria-pressed state on a toggle button
function _toggleCheckbox(event) { function _toggleState(target, state) {
// Only listen for return key // Get state
if(event.keyCode && event.keyCode != 13) { state = (typeof state === "boolean" ? state : !target.getAttribute("aria-pressed"));
return true;
}
// Toggle the checkbox // Set the attribute on target
event.target.checked = !event.target.checked; target.setAttribute("aria-pressed", state);
// Trigger change event return state;
_triggerEvent(event.target, "change");
} }
// Get percentage // Get percentage
@ -637,7 +646,7 @@
player.currentCaption = player.captions[player.subcount][1]; player.currentCaption = player.captions[player.subcount][1];
// Render the caption // Render the caption
player.captionsContainer.innerHTML = player.currentCaption; player.captionsContainer.innerHTML = player.currentCaption.trim();
} }
else { else {
// Clear the caption // Clear the caption
@ -656,7 +665,7 @@
if (config.captions.defaultActive) { if (config.captions.defaultActive) {
_toggleClass(player.container, config.classes.captions.active, true); _toggleClass(player.container, config.classes.captions.active, true);
player.buttons.captions.checked = true; _toggleState(player.buttons.captions, true);
} }
} }
@ -795,15 +804,15 @@
} }
} }
// Setup aria attributes // Setup aria attribute for play
function _setupAria() { function _setupPlayAria() {
// If there's no play button, bail // If there's no play button, bail
if(!player.buttons.play) { if(!player.buttons.play) {
return; return;
} }
// Find the current text // Find the current text
var label = player.buttons.play.innerText || "Play"; var label = player.buttons.play.innerText || config.i18n.play;
// If there's a media title set, use that for the label // If there's a media title set, use that for the label
if (typeof(config.title) !== "undefined" && config.title.length) { if (typeof(config.title) !== "undefined" && config.title.length) {
@ -913,10 +922,10 @@
cc_lang_pref: "en", cc_lang_pref: "en",
wmode: "transparent", wmode: "transparent",
modestbranding: 1, modestbranding: 1,
disablekb: 1 disablekb: 1
}, },
events: { events: {
'onReady': function(event) { "onReady": function(event) {
// Get the instance // Get the instance
var instance = event.target; var instance = event.target;
@ -925,7 +934,7 @@
player.media.pause = function() { instance.pauseVideo(); }; player.media.pause = function() { instance.pauseVideo(); };
player.media.stop = function() { instance.stopVideo(); }; player.media.stop = function() { instance.stopVideo(); };
player.media.duration = instance.getDuration(); player.media.duration = instance.getDuration();
player.media.paused = (instance.getPlayerState() == 2); player.media.paused = true;
player.media.currentTime = instance.getCurrentTime(); player.media.currentTime = instance.getCurrentTime();
player.media.muted = instance.isMuted(); player.media.muted = instance.isMuted();
@ -961,7 +970,7 @@
} }
} }
}, },
'onStateChange': function(event) { "onStateChange": function(event) {
// Get the instance // Get the instance
var instance = event.target; var instance = event.target;
@ -1010,10 +1019,10 @@
function _setupCaptions() { function _setupCaptions() {
if(player.type === "video") { if(player.type === "video") {
// Inject the container // Inject the container
player.videoContainer.insertAdjacentHTML("afterbegin", "<div class='" + config.selectors.captions.replace(".", "") + "'></div>"); player.videoContainer.insertAdjacentHTML("afterbegin", "<div class='" + config.selectors.captions.replace(".", "") + "' aria-live='assertive'><span></span></div>");
// Cache selector // Cache selector
player.captionsContainer = _getElement(config.selectors.captions); player.captionsContainer = _getElement(config.selectors.captions).querySelector("span");
// Determine if HTML5 textTracks is supported // Determine if HTML5 textTracks is supported
player.usingTextTracks = false; player.usingTextTracks = false;
@ -1088,7 +1097,7 @@
// Display a cue, if there is one // Display a cue, if there is one
if (this.activeCues[0] && this.activeCues[0].hasOwnProperty("text")) { if (this.activeCues[0] && this.activeCues[0].hasOwnProperty("text")) {
player.captionsContainer.appendChild(this.activeCues[0].getCueAsHTML()); player.captionsContainer.appendChild(this.activeCues[0].getCueAsHTML().trim());
} }
}); });
} }
@ -1170,6 +1179,9 @@
_log("Fullscreen not supported and fallback disabled."); _log("Fullscreen not supported and fallback disabled.");
} }
// Toggle state
_toggleState(player.buttons.fullscreen, false);
// Set control hide class hook // Set control hide class hook
if(config.fullscreen.hideControls) { if(config.fullscreen.hideControls) {
_toggleClass(player.container, config.classes.fullscreen.hideControls, true); _toggleClass(player.container, config.classes.fullscreen.hideControls, true);
@ -1224,7 +1236,8 @@
// Seek to time // Seek to time
// The input parameter can be an event or a number // The input parameter can be an event or a number
function _seek(input) { function _seek(input) {
var targetTime = 0; var targetTime = 0,
paused = player.media.paused;
// Explicit position // Explicit position
if (typeof input === "number") { if (typeof input === "number") {
@ -1256,6 +1269,10 @@
if(player.type == "youtube") { if(player.type == "youtube") {
player.embed.seekTo(targetTime); player.embed.seekTo(targetTime);
if(paused) {
_pause();
}
// Trigger timeupdate // Trigger timeupdate
_triggerEvent(player.media, "timeupdate"); _triggerEvent(player.media, "timeupdate");
} }
@ -1314,6 +1331,9 @@
// Set class hook // Set class hook
_toggleClass(player.container, config.classes.fullscreen.active, player.isFullscreen); _toggleClass(player.container, config.classes.fullscreen.active, player.isFullscreen);
// Set button state
_toggleState(player.buttons.fullscreen, player.isFullscreen);
// Toggle controls visibility based on mouse movement and location // Toggle controls visibility based on mouse movement and location
var hoverTimer, isMouseOver = false; var hoverTimer, isMouseOver = false;
@ -1399,10 +1419,13 @@
// Mute // Mute
function _toggleMute(muted) { function _toggleMute(muted) {
// If the method is called without parameter, toggle based on current value // If the method is called without parameter, toggle based on current value
if(typeof muted === "undefined") { if(typeof muted !== "boolean") {
muted = !player.media.muted; muted = !player.media.muted;
} }
// Set button state
_toggleState(player.buttons.mute, muted);
// Set mute on the player // Set mute on the player
player.media.muted = muted; player.media.muted = muted;
@ -1435,7 +1458,7 @@
// Update checkbox for mute state // Update checkbox for mute state
if(player.supported.full && player.buttons.mute) { if(player.supported.full && player.buttons.mute) {
player.buttons.mute.checked = (volume === 0); _toggleState(player.buttons.mute, (volume === 0));
} }
} }
@ -1447,11 +1470,14 @@
} }
// If the method is called without parameter, toggle based on current value // If the method is called without parameter, toggle based on current value
if(typeof show === "undefined") { if(typeof show !== "boolean") {
show = (player.container.className.indexOf(config.classes.captions.active) === -1); show = (player.container.className.indexOf(config.classes.captions.active) === -1);
player.buttons.captions.checked = show;
} }
// Toggle state
_toggleState(player.buttons.captions, show);
// Add class hook
_toggleClass(player.container, config.classes.captions.active, show); _toggleClass(player.container, config.classes.captions.active, show);
} }
@ -1731,9 +1757,7 @@
}); });
// Mute // Mute
_on(player.buttons.mute, "change", function() { _on(player.buttons.mute, "click", _toggleMute);
_toggleMute(this.checked);
});
// Fullscreen // Fullscreen
_on(player.buttons.fullscreen, "click", _toggleFullscreen); _on(player.buttons.fullscreen, "click", _toggleFullscreen);
@ -1753,9 +1777,7 @@
_on(player.media, "loadedmetadata", _displayDuration); _on(player.media, "loadedmetadata", _displayDuration);
// Captions // Captions
_on(player.buttons.captions, "change", function() { _on(player.buttons.captions, "click", _toggleCaptions);
_toggleCaptions(this.checked);
});
// Handle the media finishing // Handle the media finishing
_on(player.media, "ended", function() { _on(player.media, "ended", function() {
@ -1780,9 +1802,6 @@
// Loading // Loading
_on(player.media, "waiting canplay seeked", _checkLoading); _on(player.media, "waiting canplay seeked", _checkLoading);
// Toggle checkboxes on return key (as they look like buttons)
_on(player.checkboxes, "keyup", _toggleCheckbox);
// Click video // Click video
if(player.type === "video" && config.click) { if(player.type === "video" && config.click) {
_on(player.videoContainer, "click", function() { _on(player.videoContainer, "click", function() {
@ -1900,7 +1919,7 @@
} }
// Set up aria-label for Play button with the title option // Set up aria-label for Play button with the title option
_setupAria(); _setupPlayAria();
} }
// Successful setup // Successful setup
@ -2026,7 +2045,9 @@
element.plyr = (Object.keys(instance).length ? instance : false); element.plyr = (Object.keys(instance).length ? instance : false);
// Callback // Callback
config.onSetup.apply(element.plyr); if(typeof config.onSetup === "function") {
config.onSetup.apply(element.plyr);
}
} }
// Add to return array even if it's already setup // Add to return array even if it's already setup

View File

@ -17,7 +17,11 @@
// Font sizes // Font sizes
@font-size-small: 14px; @font-size-small: 14px;
@font-size-base: 16px; @font-size-base: 16px;
@font-size-large: ceil((@font-size-base * 1.5));
// Captions
@font-size-captions-base: ceil(@font-size-base * 1.25);
@font-size-captions-medium: ceil(@font-size-base * 1.5);
@font-size-captions-large: (@font-size-base * 2);
// Controls // Controls
@control-spacing: 10px; @control-spacing: 10px;
@ -189,26 +193,31 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
padding: 20px; padding: (@control-spacing * 2) (@control-spacing * 2) (@control-spacing * 3);
min-height: 2.5em;
color: #fff; color: #fff;
font-size: @font-size-base; font-size: @font-size-captions-base;
font-weight: 600;
text-shadow:
-1px -1px 0 @gray,
1px -1px 0 @gray,
-1px 1px 0 @gray,
1px 1px 0 @gray;
text-align: center; text-align: center;
.font-smoothing(); .font-smoothing();
span {
border-radius: 2px;
padding: 3px 10px;
background: rgba(0,0,0, .9);
}
span:empty {
display: none;
}
@media (min-width: @bp-captions-large) { @media (min-width: @bp-captions-large) {
font-size: @font-size-large; font-size: @font-size-captions-medium;
} }
} }
&.captions-active &-captions { &.captions-active &-captions {
display: block; display: block;
} }
&.fullscreen-active &-captions {
font-size: @font-size-captions-large;
}
// Player controls // Player controls
&-controls { &-controls {
@ -236,16 +245,19 @@
} }
} }
input + label, // Buttons
button { button {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
margin: 0 2px; margin: 0 2px;
padding: (@control-spacing / 2) @control-spacing; padding: (@control-spacing / 2) @control-spacing;
overflow: hidden;
transition: background .3s ease, color .3s ease, opacity .3s ease; border: 0;
background: transparent;
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;
color: @control-color;
transition: background .3s ease, color .3s ease, opacity .3s ease;
svg { svg {
width: 18px; width: 18px;
@ -254,41 +266,27 @@
fill: currentColor; fill: currentColor;
transition: fill .3s ease; transition: fill .3s ease;
} }
}
input + label, // Hover and tab focus
.inverted:checked + label { &.tab-focus,
opacity: .5; &:hover {
} background: @control-bg-hover;
button, color: @control-color-hover;
.inverted + label, }
input:checked + label { // Default focus
color: @control-color; &:focus {
opacity: 1; outline: 0;
} }
button {
border: 0;
background: transparent;
overflow: hidden;
} }
// Specificity for overriding .inverted // Hide toggle icons by default
button:focus,
button:hover,
[type="checkbox"]:focus + label,
[type="checkbox"] + label:hover {
background: @control-bg-hover;
color: @control-color-hover;
opacity: 1;
}
button:focus,
input:focus + label {
outline: 0;
}
.icon-exit-fullscreen, .icon-exit-fullscreen,
.icon-muted, .icon-muted,
.icon-captions-on { .icon-captions-on {
display: none; display: none;
} }
// Player time
.player-time { .player-time {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
@ -309,7 +307,7 @@
// Add a slash in before // Add a slash in before
&::before { &::before {
content: "\2044"; content: '\2044';
margin-right: @control-spacing; margin-right: @control-spacing;
} }
} }
@ -338,7 +336,7 @@
// Arrow // Arrow
&::after { &::after {
content: ""; content: '';
position: absolute; position: absolute;
z-index: 1; z-index: 1;
top: 100%; top: 100%;
@ -352,14 +350,11 @@
border-width: 0 1px 1px 0; border-width: 0 1px 1px 0;
} }
} }
label:hover .player-tooltip,
input.tab-focus:focus + label .player-tooltip,
button:hover .player-tooltip, button:hover .player-tooltip,
button.tab-focus:focus .player-tooltip { button.tab-focus:focus .player-tooltip {
opacity: 1; opacity: 1;
transform: translate(-50%, 0) scale(1); transform: translate(-50%, 0) scale(1);
} }
label:hover .player-tooltip,
button:hover .player-tooltip { button:hover .player-tooltip {
z-index: 3; z-index: 3;
} }
@ -377,7 +372,7 @@
&-buffer[value], &-buffer[value],
&-played[value], &-played[value],
&-seek[type=range] { &-seek[type='range'] {
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
@ -417,7 +412,7 @@
// Seek control // Seek control
// <input[type='range']> element // <input[type='range']> element
// Specificity is for bootstrap compatibility // Specificity is for bootstrap compatibility
&-seek[type=range] { &-seek[type='range'] {
z-index: 4; z-index: 4;
cursor: pointer; cursor: pointer;
outline: 0; outline: 0;
@ -492,7 +487,7 @@
// Volume control // Volume control
// <input[type='range']> element // <input[type='range']> element
// Specificity is for bootstrap compatibility // Specificity is for bootstrap compatibility
&-volume[type="range"] { &-volume[type='range'] {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
-webkit-appearance: none; -webkit-appearance: none;
@ -558,7 +553,6 @@
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
&.ios &-volume, &.ios &-volume,
&.ios [data-player='mute'], &.ios [data-player='mute'],
&.ios [data-player='mute'] + label,
&-audio.ios &-controls-right { &-audio.ios &-controls-right {
display: none; display: none;
} }
@ -645,15 +639,11 @@
// Some options are hidden by default // Some options are hidden by default
[data-player='captions'], [data-player='captions'],
[data-player='captions'] + label, [data-player='fullscreen'] {
[data-player='fullscreen'],
[data-player='fullscreen'] + label {
display: none; display: none;
} }
&.captions-enabled [data-player='captions'], &.captions-enabled [data-player='captions'],
&.captions-enabled [data-player='captions'] + label, &.fullscreen-enabled [data-player='fullscreen'] {
&.fullscreen-enabled [data-player='fullscreen'],
&.fullscreen-enabled [data-player='fullscreen'] + label {
display: inline-block; display: inline-block;
} }
} }

View File

@ -17,7 +17,11 @@ $off-white: #D6DADD !default;
// Font sizes // Font sizes
$font-size-small: 14px !default; $font-size-small: 14px !default;
$font-size-base: 16px !default; $font-size-base: 16px !default;
$font-size-large: ceil(($font-size-base * 1.5)) !default;
// Captions
$font-size-captions-base: ceil(@font-size-base * 1.25) !default;
$font-size-captions-medium: ceil(@font-size-base * 1.5) !default;
$font-size-captions-large: (@font-size-base * 2) !default;
// Controls // Controls
$control-spacing: 10px !default; $control-spacing: 10px !default;
@ -89,7 +93,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
{ {
zoom: 1; zoom: 1;
&:before, &:before,
&:after { content: ""; display: table; } &:after { content: ''; display: table; }
&:after { clear: both; } &:after { clear: both; }
} }
// Tab focus styles // Tab focus styles
@ -192,26 +196,31 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
padding: 20px; padding: ($control-spacing * 2) ($control-spacing * 2) ($control-spacing * 3);
min-height: 2.5em;
color: #fff; color: #fff;
font-size: $font-size-base; font-size: $font-size-captions-base;
font-weight: 600;
text-shadow:
-1px -1px 0 $gray,
1px -1px 0 $gray,
-1px 1px 0 $gray,
1px 1px 0 $gray;
text-align: center; text-align: center;
@include font-smoothing(); @include font-smoothing();
@media (min-width: $bp-captions-large) { span {
font-size: $font-size-large; border-radius: 2px;
padding: 3px 10px;
background: rgba(0,0,0, .9);
}
span:empty {
display: none;
}
@media (min-width: @bp-captions-large) {
font-size: $font-size-captions-medium;
} }
} }
&.captions-active &-captions { &.captions-active &-captions {
display: block; display: block;
} }
&.fullscreen-active &-captions {
font-size: $font-size-captions-large;
}
// Player controls // Player controls
&-controls { &-controls {
@ -239,16 +248,19 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
} }
} }
input + label, // Buttons
button { button {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
margin: 0 2px; margin: 0 2px;
padding: ($control-spacing / 2) $control-spacing; padding: ($control-spacing / 2) $control-spacing;
overflow: hidden;
transition: background .3s ease, color .3s ease, opacity .3s ease; border: 0;
background: transparent;
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;
color: $control-color;
transition: background .3s ease, color .3s ease, opacity .3s ease;
svg { svg {
width: 18px; width: 18px;
@ -257,41 +269,27 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
fill: currentColor; fill: currentColor;
transition: fill .3s ease; transition: fill .3s ease;
} }
}
input + label, // Hover and tab focus
.inverted:checked + label { &.tab-focus,
opacity: .5; &:hover {
} background: $control-bg-hover;
button, color: $control-color-hover;
.inverted + label, }
input:checked + label { // Default focus
color: $control-color; &:focus {
opacity: 1; outline: 0;
} }
button {
border: 0;
background: transparent;
overflow: hidden;
} }
// Specificity for overriding .inverted // Hide toggle icons by default
button:focus,
button:hover,
[type="checkbox"]:focus + label,
[type="checkbox"] + label:hover {
background: $control-bg-hover;
color: $control-color-hover;
opacity: 1;
}
button:focus,
input:focus + label {
outline: 0;
}
.icon-exit-fullscreen, .icon-exit-fullscreen,
.icon-muted, .icon-muted,
.icon-captions-on { .icon-captions-on {
display: none; display: none;
} }
// Time display
.player-time { .player-time {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
@ -312,7 +310,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
// Add a slash in before // Add a slash in before
&::before { &::before {
content: "\2044"; content: '\2044';
margin-right: $control-spacing; margin-right: $control-spacing;
} }
} }
@ -339,7 +337,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
transition: transform .2s .1s ease, opacity .2s .1s ease; transition: transform .2s .1s ease, opacity .2s .1s ease;
&::after { &::after {
content: ""; content: '';
display: block; display: block;
position: absolute; position: absolute;
left: 50%; left: 50%;
@ -353,14 +351,11 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
border-color: $controls-bg transparent transparent; border-color: $controls-bg transparent transparent;
} }
} }
label:hover .player-tooltip,
input:focus + label .player-tooltip,
button:hover .player-tooltip, button:hover .player-tooltip,
button:focus .player-tooltip { button:focus .player-tooltip {
opacity: 1; opacity: 1;
transform: translate(-50%, 0) scale(1); transform: translate(-50%, 0) scale(1);
} }
label:hover .player-tooltip,
button:hover .player-tooltip { button:hover .player-tooltip {
z-index: 3; z-index: 3;
} }
@ -378,7 +373,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
&-buffer[value], &-buffer[value],
&-played[value], &-played[value],
&-seek[type=range] { &-seek[type='range'] {
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
@ -418,7 +413,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
// Seek control // Seek control
// <input[type='range']> element // <input[type='range']> element
// Specificity is for bootstrap compatibility // Specificity is for bootstrap compatibility
&-seek[type=range] { &-seek[type='range'] {
z-index: 4; z-index: 4;
cursor: pointer; cursor: pointer;
outline: 0; outline: 0;
@ -493,7 +488,7 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
// Volume control // Volume control
// <input[type='range']> element // <input[type='range']> element
// Specificity is for bootstrap compatibility // Specificity is for bootstrap compatibility
&-volume[type=range] { &-volume[type='range'] {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
-webkit-appearance: none; -webkit-appearance: none;
@ -559,7 +554,6 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
&.ios &-volume, &.ios &-volume,
&.ios [data-player='mute'], &.ios [data-player='mute'],
&.ios [data-player='mute'] + label,
&-audio.ios &-controls-right { &-audio.ios &-controls-right {
display: none; display: none;
} }
@ -646,15 +640,11 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
// Some options are hidden by default // Some options are hidden by default
[data-player='captions'], [data-player='captions'],
[data-player='captions'] + label, [data-player='fullscreen'] {
[data-player='fullscreen'],
[data-player='fullscreen'] + label {
display: none; display: none;
} }
&.captions-enabled [data-player='captions'], &.captions-enabled [data-player='captions'],
&.captions-enabled [data-player='captions'] + label, &.fullscreen-enabled [data-player='fullscreen'] {
&.fullscreen-enabled [data-player='fullscreen'],
&.fullscreen-enabled [data-player='fullscreen'] + label {
display: inline-block; display: inline-block;
} }
} }