Audio fullscreen, Tooltip tweaks, Docs

This commit is contained in:
Sam Potts 2015-10-25 11:57:52 +11:00
parent 58f8cdd8c8
commit 125a95e9e1
8 changed files with 277 additions and 95 deletions

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.css vendored

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,14 @@
// Examples
// ==========================================================================
video,
.plyr-video-embed {
border-radius: @border-radius-base;
}
.plyr-video-embed {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
// Example players
.plyr {
margin: 0 auto @padding-base;
@ -10,35 +18,11 @@
&-controls {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
.plyr-audio {
max-width: @example-width-audio;
.plyr-controls {
border-radius: @border-radius-base;
}
.plyr-progress {
border-radius: @border-radius-base @border-radius-base 0 0;
overflow: hidden;
}
}
video,
.plyr-video-embed {
border-radius: @border-radius-base;
}
.plyr-video-embed {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
// Style full supported player
.plyr-video,
.plyr-youtube,
.plyr-vimeo {
video,
.plyr-video-embed {
border-radius: @border-radius-base @border-radius-base 0 0;
}
&.plyr-fullscreen,
&-fullscreen,
&.fullscreen-active {
max-width: none;
@ -52,7 +36,19 @@ video,
}
}
}
.plyr-audio {
max-width: @example-width-audio;
.plyr-controls {
border-radius: @border-radius-base;
}
.plyr-progress {
border-radius: @border-radius-base @border-radius-base 0 0;
overflow: hidden;
}
}
// Style full supported player
.cite {
display: none;

155
readme.md
View File

@ -262,7 +262,7 @@ Options must be passed as an object to the `setup()` method as above.
<td><code>selectors</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>See <code>plyr.js</code> in <code>/src</code> for more info. The only option you might want to change is <code>container</code> which is the hook used for `setup()`, the default is <code>.plyr</code>.</td>
<td>See <code>plyr.js</code> in <code>/src</code> for more info. You probably don't need to change any of these.</td>
</tr>
<tr>
<td><code>classes</code></td>
@ -280,7 +280,7 @@ Options must be passed as an object to the `setup()` method as above.
<td><code>fullscreen</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>Three properties; <code>enabled</code> which toggles if fullscreen should be enabled (if the browser supports it). The default value is <code>true</code>. A <code>fallback</code> property which will enable a full window view for older browsers. The default value is <code>true</code>. A <code>hideControls</code> property which will hide the controls when fullscreen is active and the video is playing, after 1s. The controls reappear on hover of the progress bar (mouse), focusing a child control or pausing the video (by tap/click of video if `click` is `true`). The default value is <code>true</code>.</td>
<td>See <a href="#fullscreen-options">below</a></td>
</tr>
<tr>
<td><code>storage</code></td>
@ -297,6 +297,45 @@ Options must be passed as an object to the `setup()` method as above.
</tbody>
</table>
#### Fullscreen options
<table class="table" width="100%" id="fullscreen-options">
<thead>
<tr>
<th width="20%">Option</th>
<th width="15%">Type</th>
<th width="15%">Default</th>
<th width="50%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>enabled</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Toggles if fullscreen should be enabled (if the browser supports it).</td>
</tr>
<tr>
<td><code>fallback</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Enable a full viewport view for older browsers.</td>
</tr>
<tr>
<td><code>hideControls</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Hide the controls when fullscreen is active and the video is playing, after 1s. The controls reappear on hover of the progress bar (mouse), focusing a child control or pausing the video (by tap/click of video if `click` is `true`).</td>
</tr>
<tr>
<td><code>allowAudio</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Allow audio play to toggle fullscreen. This will be more useful later when posters are supported.</td>
</tr>
</tbody>
</table>
## API
#### Fetching the plyr instance
@ -331,8 +370,8 @@ Here's a list of the methods supported:
<th width="15%">Parameters</th>
<th width="65%">Description</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><code>play()</code></td>
<td>&mdash;</td>
@ -400,7 +439,7 @@ Here's a list of the methods supported:
</tr>
<tr>
<td><code>source(...)</code></td>
<td>String or Array</td>
<td>Array</td>
<td>
Set the media source.
<br><br>
@ -434,6 +473,112 @@ Here's a list of the methods supported:
</tbody>
</table>
#### .source() method
This allows changing the plyr source and type on the fly.
Video example:
```javascript
player.source({
type: 'video',
title: 'Bug Buck Bunny',
sources: [{
src: 'https://cdn.selz.com/plyr/1.0/movie.mp4',
type: 'video/mp4'
},
{
src: 'https://cdn.selz.com/plyr/1.0/movie.webm',
type: 'video/webm'
}],
poster: 'https://cdn.selz.com/plyr/1.0/poster.jpg',
tracks: [{
kind: 'captions',
label: 'English',
srclang:'en',
src: 'https://cdn.selz.com/plyr/1.0/example_captions_en.vtt',
default: true
}]
});
```
Audio example:
```javascript
player.source({
type: 'audio',
title: '96 by Logistics',
sources: [{
src: 'https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3',
type: 'audio/mp3'
},
{
src: 'https://cdn.selz.com/plyr/1.0/logistics-96-sample.ogg',
type: 'audio/ogg'
}]
});
```
YouTube example:
```javascript
player.source({
type: 'youtube',
title: 'Enovato interview of Dan Cederholm for Made By',
sources: 'Au87oAJ2jeE'
});
```
Vimeo example
```javascript
player.source({
type: 'vimeo',
title: 'Yosemite HD II',
sources: '87701971'
});
```
Some more details on the object parameters
<table class="table" width="100%">
<thead>
<tr>
<th width="20%">Key</th>
<th width="15%">Type</th>
<th width="65%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>type</code></td>
<td>String</td>
<td>Options are <code>video</code>, <code>audio</code>, <code>youtube</code> and <code>vimeo</code></td>
</tr>
<tr>
<td><code>title</code></td>
<td>String</td>
<td>Title of the new media. Used for the aria labelling.</td>
</tr>
<tr>
<td><code>sources</code></td>
<td>Array or String</td>
<td>This is an array of sources or optionally a string for embedded players (YouTube and Vimeo). `type` is also optional for YouTube and Vimeo when specifying an array. For YouTube and Vimeo media, only the video ID must be passed as the source as shown above. The keys of this object are mapped directly to HTML attributes so more can be added to the object if required.</td>
</tr>
<tr>
<td><code>poster</code></td>
<td>String</td>
<td>URL for the poster image (video only).</td>
</tr>
<tr>
<td><code>tracks</code></td>
<td>Array</td>
<td>An array of track objects. Each element in the array is mapped directly to a track element and any keys mapped directly to HTML attributes so as in the example above, it will render as `<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/example_captions_en.vtt" default>`. Booleans are converted to HTML5 value-less attributes.</td>
</tr>
</tbody>
</table>
## Events/Callbacks
The `plyr` object on the player element also contains a `media` property which is a reference to the `<audio>` or `<video>` element within the player which you can use to listen for events. Here's an example:

View File

@ -78,7 +78,8 @@
fullscreen: {
enabled: true,
fallback: true,
hideControls: true
hideControls: true,
allowAudio: false
},
storage: {
enabled: true,
@ -664,7 +665,7 @@
time = typeof time === 'number' ? time : plyr.media.currentTime;
// If there's no subs available, bail
if(!plyr.captions[plyr.subcount]) {
if (!plyr.captions[plyr.subcount]) {
return;
}
@ -930,9 +931,6 @@
_remove(containers[i]);
}
// Set ID
container.setAttribute('id', id);
// Add embed class for responsive
_toggleClass(plyr.media, config.classes.videoWrapper, true);
_toggleClass(plyr.media, config.classes.embedWrapper, true);
@ -942,6 +940,9 @@
// Create the YouTube container
plyr.media.appendChild(container);
// Set ID
container.setAttribute('id', id);
// Setup API
if (typeof YT === 'object') {
_youTubeReady(videoId, container);
@ -984,7 +985,7 @@
// Wait for fragaloop load
var timer = window.setInterval(function() {
if('$f' in window && iframe.loaded) {
if ('$f' in window && iframe.loaded) {
window.clearInterval(timer);
_vimeoReady.call(iframe);
@ -1122,11 +1123,11 @@
// Vimeo ready
function _vimeoReady() {
/* jshint validthis: true */
// Get the frame with fragaloop lib
plyr.embed = $f(this);
// Setup on ready
plyr.embed.addEvent('ready', function() {
// Create a faux HTML5 API using the Vimeo API
plyr.media.play = function() { plyr.embed.api('play'); };
plyr.media.pause = function() { plyr.embed.api('pause'); };
@ -1178,13 +1179,13 @@
_triggerEvent(plyr.media, 'ended');
});
/*// Always seek to 0
plyr.embed.api('seekTo', 0);
// Always seek to 0
//plyr.embed.api('seekTo', 0);
// Prevent autoplay if needed (seek will play)
if (!config.autoplay) {
plyr.embed.api('pause');
}*/
//if (!config.autoplay) {
// plyr.embed.api('pause');
//}
});
}
@ -1192,7 +1193,7 @@
function _setupCaptions() {
if (plyr.type === 'video') {
// Inject the container
if(!_getElement(config.selectors.captions)) {
if (!_getElement(config.selectors.captions)) {
plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"><span></span></div>');
}
@ -1340,7 +1341,7 @@
// Setup fullscreen
function _setupFullscreen() {
if (plyr.type != 'audio' && config.fullscreen.enabled) {
if ((plyr.type != 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
// Check for native support
var nativeSupport = fullscreen.supportsFullScreen;
@ -1660,18 +1661,21 @@
// If there's no full support, or there's no caption toggle
if (!plyr.supported.full || !plyr.buttons.captions) {
return;
}
}
// If the method is called without parameter, toggle based on current value
if (typeof show !== 'boolean') {
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
}
// Set global
plyr.captionsEnabled = show;
// Toggle state
_toggleState(plyr.buttons.captions, show);
_toggleState(plyr.buttons.captions, plyr.captionsEnabled);
// Add class hook
_toggleClass(plyr.container, config.classes.captions.active, show);
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
}
// Check if media is loading
@ -1753,7 +1757,7 @@
}
// Fallback to 0
if(isNaN(time)) {
if (isNaN(time)) {
time = 0;
}
@ -1798,10 +1802,10 @@
// Add elements to HTML5 media (source, tracks, etc)
function _insertChildElements(type, attributes) {
if(typeof attributes === 'string') {
if (typeof attributes === 'string') {
_insertElement(type, plyr.media, { src: attributes });
}
else if(attributes.constructor === Array) {
else if (attributes.constructor === Array) {
for (var i = attributes.length - 1; i >= 0; i--) {
_insertElement(type, plyr.media, attributes[i]);
}
@ -1811,7 +1815,7 @@
// Update source
// Sources are not checked for support so be careful
function _updateSource(source) {
if(typeof source === 'undefined') {
if (typeof source === 'undefined') {
return;
}
@ -1819,7 +1823,7 @@
_pause();
// Clean up YouTube stuff
if(plyr.type === 'youtube') {
if (plyr.type === 'youtube') {
// Destroy the embed instance
plyr.embed.destroy();
@ -1836,7 +1840,7 @@
_remove(plyr.media);
// Set the new type
if('type' in source && source.type !== plyr.type) {
if ('type' in source && source.type !== plyr.type) {
plyr.type = source.type;
}
@ -1853,7 +1857,7 @@
case 'youtube':
case 'vimeo':
plyr.media = document.createElement('div');
plyr.embedId = source.sources;
plyr.embedId = (typeof source.sources === 'string' ? source.sources : source.sources[0].src);
break;
}
@ -1861,8 +1865,8 @@
_prependChild(plyr.container, plyr.media);
// Set attributes for audio video
if(_inArray(config.types.html5, plyr.type)) {
if(config.crossorigin) {
if (_inArray(config.types.html5, plyr.type)) {
if (config.crossorigin) {
plyr.media.setAttribute('crossorigin', '');
}
if (config.autoplay) {
@ -1879,16 +1883,20 @@
// Classname reset
plyr.container.className = plyr.originalClassName;
// Restore class hooks
_toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen);
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
// Autoplay the new source?
config.autoplay = (source.autoplay || config.autoplay);
// Set media id for embeds
if(_inArray(config.types.embed, plyr.type)) {
if (_inArray(config.types.embed, plyr.type)) {
plyr.embedId = source.sources;
}
// Set new sources for html5
if(_inArray(config.types.html5, plyr.type)) {
if (_inArray(config.types.html5, plyr.type)) {
_insertChildElements('source', source.sources);
}
@ -1899,13 +1907,13 @@
_mediaUpdated();
// HTML5 stuff
if(_inArray(config.types.html5, plyr.type)) {
if (_inArray(config.types.html5, plyr.type)) {
// Set volume
_setVolume();
_updateVolume();
// UI updates
if(plyr.supported.full) {
if (plyr.supported.full) {
// Reset time display
_timeUpdate();
@ -1914,7 +1922,7 @@
}
// Setup captions
if('tracks' in source) {
if ('tracks' in source) {
_insertChildElements('track', source.tracks);
// Captions
@ -1930,7 +1938,7 @@
}
}
if('title' in source) {
if ('title' in source) {
config.title = source.title;
_setupPlayAria();
}
@ -2292,17 +2300,17 @@
// Select the elements
// Assume elements is a NodeList by default
if(typeof elements === 'string') {
if (typeof elements === 'string') {
elements = document.querySelectorAll(elements);
}
// Single HTMLElement passed
else if(elements instanceof HTMLElement) {
else if (elements instanceof HTMLElement) {
elements = [elements];
}
// No selector passed, possibly options as first argument
else if (!(elements instanceof NodeList) && typeof elements !== 'string') {
// If options are the first argument
if(typeof options === 'undefined' && typeof elements === 'object') {
if (typeof options === 'undefined' && typeof elements === 'object') {
options = elements;
}

View File

@ -32,10 +32,12 @@
// Tooltips
@tooltip-bg: @controls-bg;
@tooltip-border-color: @off-white;
@tooltip-border-color: fade(@gray-dark, 10%);
@tooltip-border-width: 1px;
@tooltip-shadow: 0 0 5px @tooltip-border-color, 0 0 0 @tooltip-border-width @tooltip-border-color;
@tooltip-color: @control-color;
@tooltip-padding: @control-spacing;
@tooltip-arrow-size: 5px;
@tooltip-arrow-size: 6px;
@tooltip-radius: 3px;
// Progress
@ -331,32 +333,45 @@
opacity: 0;
background: @tooltip-bg;
border: 1px solid @tooltip-border-color;
box-shadow: @tooltip-shadow;
border-radius: @tooltip-radius;
color: @tooltip-color;
font-size: @font-size-small;
line-height: 1.5;
font-weight: 600;
transform: translate(-50%, (@tooltip-padding * 3)) scale(0);
transform: translate(-50%, (@tooltip-padding * 3)) scale(.8);
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease;
// Arrow
&::after {
// Arrows
&::after,
&::before {
content: '';
position: absolute;
z-index: 1;
width: 0;
height: 0;
top: 100%;
left: 50%;
display: block;
width: 10px;
height: 10px;
background: @tooltip-bg;
transform: translate(-50%, -50%) rotate(45deg) translateY(1px);
border: 1px solid @tooltip-border-color;
border-width: 0 1px 1px 0;
transform: translateX(-50%);
}
// The border triangle
&::after {
@border-arrow-size: (@tooltip-arrow-size + (@tooltip-border-width * 1));
bottom: -(@border-arrow-size + @tooltip-border-width);
border-right: @border-arrow-size solid transparent;
border-top: @border-arrow-size solid @tooltip-border-color;
border-left: @border-arrow-size solid transparent;
z-index: 1;
}
// The background triangle
&::before {
bottom: -@tooltip-arrow-size;
border-right: @tooltip-arrow-size solid transparent;
border-top: @tooltip-arrow-size solid @tooltip-bg;
border-left: @tooltip-arrow-size solid transparent;
z-index: 2;
}
}
button:hover .plyr-tooltip,
button.tab-focus:focus .plyr-tooltip {

View File

@ -44,15 +44,18 @@ $control-color-hover: null !default;
// Tooltips
$tooltip-bg: $controls-bg !default;
$tooltip-border-color: transparentize(@gray-dark, .1) !default;
$tooltip-border-width: 1px;
$tooltip-shadow: 0 0 5px $tooltip-border-color, 0 0 0 $tooltip-border-width $tooltip-border-color;
$tooltip-color: $control-color !default;
$tooltip-padding: $control-spacing !default;
$tooltip-arrow-size: 5px !default;
$tooltip-arrow-size: 6px !default;
$tooltip-radius: 3px !default;
// Progress
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2) !default;
$progress-bg: transparentize($gray, .2) !default;
$progress-playing-bg: $blue !default;
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25) !default;
$progress-buffered-bg: transparentize($gray, .25) !default;
$progress-loading-size: 40px !default;
$progress-loading-bg: rgba(0,0,0, .15) !default;
@ -334,29 +337,44 @@ $bp-captions-large: 768px !default; // When captions jump to the larger
opacity: 0;
background: $tooltip-bg;
box-shadow: $tooltip-shadow;
border-radius: $tooltip-radius;
color: $tooltip-color;
font-size: $font-size-small;
line-height: 1.5;
font-weight: 600;
transform: translate(-50%, ($tooltip-padding * 3)) scale(0);
transform: translate(-50%, ($tooltip-padding * 3)) scale(.8);
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease;
&::after {
// Arrows
&::after,
&::before {
content: '';
display: block;
position: absolute;
left: 50%;
bottom: -$tooltip-arrow-size;
margin-left: -$tooltip-arrow-size;
width: 0;
height: 0;
transition: inherit;
border-style: solid;
border-width: $tooltip-arrow-size $tooltip-arrow-size 0 $tooltip-arrow-size;
border-color: $controls-bg transparent transparent;
top: 100%;
left: 50%;
transform: translateX(-50%);
}
// The border triangle
&::after {
$border-arrow-size: ($tooltip-arrow-size + ($tooltip-border-width * 1));
bottom: -($border-arrow-size + $tooltip-border-width);
border-right: $border-arrow-size solid transparent;
border-top: $border-arrow-size solid $tooltip-border-color;
border-left: $border-arrow-size solid transparent;
z-index: 1;
}
// The background triangle
&::before {
bottom: -$tooltip-arrow-size;
border-right: $tooltip-arrow-size solid transparent;
border-top: $tooltip-arrow-size solid $tooltip-bg;
border-left: $tooltip-arrow-size solid transparent;
z-index: 2;
}
}
button:hover .plyr-tooltip,