Merge branch 'master' into develop

This commit is contained in:
Sam Potts 2018-05-19 11:26:05 +10:00
commit 1bab0d07b5
27 changed files with 1349 additions and 1295 deletions

View File

@ -1,3 +1,8 @@
# v3.3.7
* Poster fixes (thanks @friday)
* Grid tweak
# v3.3.6
* Vimeo fixes for mute state

2
demo/dist/demo.css vendored

File diff suppressed because one or more lines are too long

View File

@ -2,4 +2,4 @@
// Layout
// ==========================================================================
$container-max-width: 1280px;
$container-max-width: 1260px;

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

1096
dist/plyr.js vendored

File diff suppressed because it is too large Load Diff

2
dist/plyr.js.map vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1096
dist/plyr.polyfilled.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@ const filter = require('gulp-filter');
const sass = require('gulp-sass');
const cleancss = require('gulp-clean-css');
const run = require('run-sequence');
const header = require('gulp-header');
const prefix = require('gulp-autoprefixer');
const gitbranch = require('git-branch');
const svgstore = require('gulp-svgstore');
@ -146,6 +147,7 @@ const build = {
options,
),
)
.pipe(header('typeof navigator === "object" && ')) // "Support" SSR (#935)
.pipe(sourcemaps.write(''))
.pipe(gulp.dest(output))
.pipe(filter('**/*.js'))

View File

@ -1,6 +1,6 @@
{
"name": "plyr",
"version": "3.3.6",
"version": "3.3.7",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io",
"main": "./dist/plyr.js",
@ -24,6 +24,7 @@
"gulp-clean-css": "^3.9.4",
"gulp-concat": "^2.6.1",
"gulp-filter": "^5.1.0",
"gulp-header": "^2.0.5",
"gulp-open": "^3.0.1",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.6.1",

View File

@ -125,13 +125,17 @@ Include the `plyr.js` script before the closing `</body>` tag and then in your J
See [initialising](#initialising) for more information on advanced setups.
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
```html
<script src="https://cdn.plyr.io/3.3.6/plyr.js"></script>
<script src="https://cdn.plyr.io/3.3.7/plyr.js"></script>
```
_Note_: Be sure to read the [polyfills](#polyfills) section below about browser compatibility
...or...
```html
<script src="https://cdn.plyr.io/3.3.7/plyr.polyfilled.js"></script>
```
### CSS
@ -144,13 +148,13 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
```html
<link rel="stylesheet" href="https://cdn.plyr.io/3.3.6/plyr.css">
<link rel="stylesheet" href="https://cdn.plyr.io/3.3.7/plyr.css">
```
### SVG Sprite
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.3.6/plyr.svg`.
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.3.7/plyr.svg`.
## Ads

View File

@ -236,7 +236,7 @@ const captions = {
// Set the span content
if (utils.is.string(caption)) {
content.textContent = caption.trim();
content.innerText = caption.trim();
} else {
content.appendChild(caption);
}

182
src/js/controls.js vendored
View File

@ -6,34 +6,13 @@ import captions from './captions';
import html5 from './html5';
import i18n from './i18n';
import support from './support';
import ui from './ui';
import utils from './utils';
// Sniff out the browser
const browser = utils.getBrowser();
const controls = {
// Webkit polyfill for lower fill range
updateRangeFill(target) {
// Get range from event if event passed
const range = utils.is.event(target) ? target.target : target;
// Needs to be a valid <input type='range'>
if (!utils.is.element(range) || range.getAttribute('type') !== 'range') {
return;
}
// Set aria value for https://github.com/sampotts/plyr/issues/905
range.setAttribute('aria-valuenow', range.value);
// WebKit only
if (!browser.isWebkit) {
return;
}
// Set CSS custom property
range.style.setProperty('--value', `${range.value / range.max * 100}%`);
},
// Get icon URL
getIconUrl() {
@ -373,7 +352,7 @@ const controls = {
break;
}
progress.textContent = `% ${suffix.toLowerCase()}`;
progress.innerText = `% ${suffix.toLowerCase()}`;
}
this.elements.display[type] = progress;
@ -429,6 +408,123 @@ const controls = {
list.appendChild(item);
},
// Update the displayed time
updateTimeDisplay(target = null, time = 0, inverted = false) {
// Bail if there's no element to display or the value isn't a number
if (!utils.is.element(target) || !utils.is.number(time)) {
return;
}
// Always display hours if duration is over an hour
const forceHours = utils.getHours(this.duration) > 0;
// eslint-disable-next-line no-param-reassign
target.innerText = utils.formatTime(time, forceHours, inverted);
},
// Update volume UI and storage
updateVolume() {
if (!this.supported.ui) {
return;
}
// Update range
if (utils.is.element(this.elements.inputs.volume)) {
controls.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);
}
// Update mute state
if (utils.is.element(this.elements.buttons.mute)) {
utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);
}
},
// Update seek value and lower fill
setRange(target, value = 0) {
if (!utils.is.element(target)) {
return;
}
// eslint-disable-next-line
target.value = value;
// Webkit range fill
controls.updateRangeFill.call(this, target);
},
// Update <progress> elements
updateProgress(event) {
if (!this.supported.ui || !utils.is.event(event)) {
return;
}
let value = 0;
const setProgress = (target, input) => {
const value = utils.is.number(input) ? input : 0;
const progress = utils.is.element(target) ? target : this.elements.display.buffer;
// Update value and label
if (utils.is.element(progress)) {
progress.value = value;
// Update text label inside
const label = progress.getElementsByTagName('span')[0];
if (utils.is.element(label)) {
label.childNodes[0].nodeValue = value;
}
}
};
if (event) {
switch (event.type) {
// Video playing
case 'timeupdate':
case 'seeking':
value = utils.getPercentage(this.currentTime, this.duration);
// Set seek range value only if it's a 'natural' time event
if (event.type === 'timeupdate') {
controls.setRange.call(this, this.elements.inputs.seek, value);
}
break;
// Check buffer status
case 'playing':
case 'progress':
setProgress(this.elements.display.buffer, this.buffered * 100);
break;
default:
break;
}
}
},
// Webkit polyfill for lower fill range
updateRangeFill(target) {
// Get range from event if event passed
const range = utils.is.event(target) ? target.target : target;
// Needs to be a valid <input type='range'>
if (!utils.is.element(range) || range.getAttribute('type') !== 'range') {
return;
}
// Set aria value for https://github.com/sampotts/plyr/issues/905
range.setAttribute('aria-valuenow', range.value);
// WebKit only
if (!browser.isWebkit) {
return;
}
// Set CSS custom property
range.style.setProperty('--value', `${range.value / range.max * 100}%`);
},
// Update hover tooltip for seeking
updateSeekTooltip(event) {
// Bail if setting not true
@ -473,7 +569,7 @@ const controls = {
}
// Display the time a click would seek to
ui.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent);
controls.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent);
// Set position
this.elements.display.seekTooltip.style.left = `${percent}%`;
@ -488,6 +584,46 @@ const controls = {
}
},
// Handle time change event
timeUpdate(event) {
// Only invert if only one time element is displayed and used for both duration and currentTime
const invert = !utils.is.element(this.elements.display.duration) && this.config.invertTime;
// Duration
controls.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert);
// Ignore updates while seeking
if (event && event.type === 'timeupdate' && this.media.seeking) {
return;
}
// Playing progress
controls.updateProgress.call(this, event);
},
// Show the duration on metadataloaded
durationUpdate() {
if (!this.supported.ui) {
return;
}
// If there's a spot to display duration
const hasDuration = utils.is.element(this.elements.display.duration);
// If there's only one time display, display duration there
if (!hasDuration && this.config.displayDuration && this.paused) {
controls.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);
}
// If there's a duration element, update content
if (hasDuration) {
controls.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);
}
// Update the tooltip (if visible)
controls.updateSeekTooltip.call(this);
},
// Hide/show a tab
toggleTab(setting, toggle) {
utils.toggleHidden(this.elements.settings.tabs[setting], !toggle);

View File

@ -56,7 +56,7 @@ const defaults = {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.3.6/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.3.7/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',

View File

@ -19,7 +19,7 @@ function onChange() {
}
// Trigger an event
utils.dispatchEvent(this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
utils.dispatchEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
// Trap focus in container
if (!browser.isIos) {

View File

@ -250,10 +250,10 @@ class Listeners {
// Listen for media events
media() {
// Time change on media
utils.on(this.player.media, 'timeupdate seeking', event => ui.timeUpdate.call(this.player, event));
utils.on(this.player.media, 'timeupdate seeking', event => controls.timeUpdate.call(this.player, event));
// Display duration
utils.on(this.player.media, 'durationchange loadeddata loadedmetadata', event => ui.durationUpdate.call(this.player, event));
utils.on(this.player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(this.player, event));
// Check for audio tracks on load
// We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point
@ -272,10 +272,10 @@ class Listeners {
});
// Check for buffer progress
utils.on(this.player.media, 'progress playing', event => ui.updateProgress.call(this.player, event));
utils.on(this.player.media, 'progress playing', event => controls.updateProgress.call(this.player, event));
// Handle volume changes
utils.on(this.player.media, 'volumechange', event => ui.updateVolume.call(this.player, event));
utils.on(this.player.media, 'volumechange', event => controls.updateVolume.call(this.player, event));
// Handle play/pause
utils.on(this.player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(this.player, event));
@ -549,7 +549,8 @@ class Listeners {
}
this.player.config.invertTime = !this.player.config.invertTime;
ui.timeUpdate.call(this.player);
controls.timeUpdate.call(this.player);
});
}

View File

@ -1,6 +1,6 @@
// ==========================================================================
// Plyr
// plyr.js v3.3.6
// plyr.js v3.3.7
// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================
@ -55,6 +55,7 @@ class Plyr {
this.config = utils.extend(
{},
defaults,
Plyr.defaults,
options || {},
(() => {
try {
@ -1269,4 +1270,6 @@ class Plyr {
}
}
Plyr.defaults = utils.cloneDeep(defaults);
export default Plyr;

View File

@ -1,6 +1,6 @@
// ==========================================================================
// Plyr Polyfilled Build
// plyr.js v3.3.6
// plyr.js v3.3.7
// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================

View File

@ -133,6 +133,7 @@ const support = {
},
});
window.addEventListener('test', null, options);
window.removeEventListener('test', null, options);
} catch (e) {
// Do nothing
}

View File

@ -74,10 +74,10 @@ const ui = {
this.quality = null;
// Reset volume display
ui.updateVolume.call(this);
controls.updateVolume.call(this);
// Reset time display
ui.timeUpdate.call(this);
controls.timeUpdate.call(this);
// Update the UI
ui.checkPlaying.call(this);
@ -218,142 +218,6 @@ const ui = {
this.toggleControls(this.loading);
}, this.loading ? 250 : 0);
},
// Update volume UI and storage
updateVolume() {
if (!this.supported.ui) {
return;
}
// Update range
if (utils.is.element(this.elements.inputs.volume)) {
ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);
}
// Update mute state
if (utils.is.element(this.elements.buttons.mute)) {
utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);
}
},
// Update seek value and lower fill
setRange(target, value = 0) {
if (!utils.is.element(target)) {
return;
}
// eslint-disable-next-line
target.value = value;
// Webkit range fill
controls.updateRangeFill.call(this, target);
},
// Set <progress> value
setProgress(target, input) {
const value = utils.is.number(input) ? input : 0;
const progress = utils.is.element(target) ? target : this.elements.display.buffer;
// Update value and label
if (utils.is.element(progress)) {
progress.value = value;
// Update text label inside
const label = progress.getElementsByTagName('span')[0];
if (utils.is.element(label)) {
label.childNodes[0].nodeValue = value;
}
}
},
// Update <progress> elements
updateProgress(event) {
if (!this.supported.ui || !utils.is.event(event)) {
return;
}
let value = 0;
if (event) {
switch (event.type) {
// Video playing
case 'timeupdate':
case 'seeking':
value = utils.getPercentage(this.currentTime, this.duration);
// Set seek range value only if it's a 'natural' time event
if (event.type === 'timeupdate') {
ui.setRange.call(this, this.elements.inputs.seek, value);
}
break;
// Check buffer status
case 'playing':
case 'progress':
ui.setProgress.call(this, this.elements.display.buffer, this.buffered * 100);
break;
default:
break;
}
}
},
// Update the displayed time
updateTimeDisplay(target = null, time = 0, inverted = false) {
// Bail if there's no element to display or the value isn't a number
if (!utils.is.element(target) || !utils.is.number(time)) {
return;
}
// Always display hours if duration is over an hour
const forceHours = utils.getHours(this.duration) > 0;
// eslint-disable-next-line no-param-reassign
target.textContent = utils.formatTime(time, forceHours, inverted);
},
// Handle time change event
timeUpdate(event) {
// Only invert if only one time element is displayed and used for both duration and currentTime
const invert = !utils.is.element(this.elements.display.duration) && this.config.invertTime;
// Duration
ui.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert);
// Ignore updates while seeking
if (event && event.type === 'timeupdate' && this.media.seeking) {
return;
}
// Playing progress
ui.updateProgress.call(this, event);
},
// Show the duration on metadataloaded
durationUpdate() {
if (!this.supported.ui) {
return;
}
// If there's a spot to display duration
const hasDuration = utils.is.element(this.elements.display.duration);
// If there's only one time display, display duration there
if (!hasDuration && this.config.displayDuration && this.paused) {
ui.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);
}
// If there's a duration element, update content
if (hasDuration) {
ui.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);
}
// Update the tooltip (if visible)
controls.updateSeekTooltip.call(this);
},
};
export default ui;

View File

@ -3,15 +3,13 @@
// ==========================================================================
import loadjs from 'loadjs';
import Storage from './storage';
import support from './support';
import { providers } from './types';
const utils = {
// Check variable types
is: {
plyr(input) {
return this.instanceof(input, window.Plyr);
},
object(input) {
return this.getConstructor(input) === Object;
},
@ -31,22 +29,22 @@ const utils = {
return !this.nullOrUndefined(input) && Array.isArray(input);
},
weakMap(input) {
return this.instanceof(input, window.WeakMap);
return this.instanceof(input, WeakMap);
},
nodeList(input) {
return this.instanceof(input, window.NodeList);
return this.instanceof(input, NodeList);
},
element(input) {
return this.instanceof(input, window.Element);
return this.instanceof(input, Element);
},
textNode(input) {
return this.getConstructor(input) === Text;
},
event(input) {
return this.instanceof(input, window.Event);
return this.instanceof(input, Event);
},
cue(input) {
return this.instanceof(input, window.TextTrackCue) || this.instanceof(input, window.VTTCue);
return this.instanceof(input, TextTrackCue) || this.instanceof(input, VTTCue);
},
track(input) {
return this.instanceof(input, TextTrack) || (!this.nullOrUndefined(input) && this.string(input.kind));
@ -159,6 +157,8 @@ const utils = {
// Only load once if ID set
if (!hasId || !exists()) {
const useStorage = Storage.supported;
// Create container
const container = document.createElement('div');
utils.toggleHidden(container, true);
@ -168,7 +168,7 @@ const utils = {
}
// Check in cache
if (support.storage) {
if (useStorage) {
const cached = window.localStorage.getItem(prefix + id);
isCached = cached !== null;
@ -187,7 +187,7 @@ const utils = {
return;
}
if (support.storage) {
if (useStorage) {
window.localStorage.setItem(
prefix + id,
JSON.stringify({
@ -250,7 +250,7 @@ const utils = {
// Add text node
if (utils.is.string(text)) {
element.textContent = text;
element.innerText = text;
}
// Return built element
@ -547,7 +547,7 @@ const utils = {
const event = new CustomEvent(type, {
bubbles,
detail: Object.assign({}, detail, {
plyr: utils.is.plyr(this) ? this : null,
plyr: this,
}),
});
@ -583,7 +583,7 @@ const utils = {
return input;
}
return input.toString().replace(/{(\d+)}/g, (match, i) => utils.is.string(args[i]) ? args[i] : '');
return input.toString().replace(/{(\d+)}/g, (match, i) => (utils.is.string(args[i]) ? args[i] : ''));
},
// Get percentage
@ -706,6 +706,11 @@ const utils = {
return array.filter((item, index) => array.indexOf(item) === index);
},
// Clone nested objects
cloneDeep(object) {
return JSON.parse(JSON.stringify(object));
},
// Get the closest value in an array
closest(array, value) {
if (!utils.is.array(array) || !array.length) {

View File

@ -6,7 +6,7 @@
background-color: #000;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 100% 100%;
background-size: contain;
height: 100%;
left: 0;
opacity: 0;
@ -15,6 +15,7 @@
transition: opacity 0.3s ease;
width: 100%;
z-index: 1;
pointer-events: none;
}
.plyr--stopped .plyr__poster {

View File

@ -1604,6 +1604,12 @@ concat-stream@^1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concat-with-sourcemaps@*:
version "1.1.0"
resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e"
dependencies:
source-map "^0.6.1"
concat-with-sourcemaps@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.5.tgz#8964bc2347d05819b63798104d87d6e001bed8d0"
@ -3024,6 +3030,14 @@ gulp-filter@^5.1.0:
plugin-error "^0.1.2"
streamfilter "^1.0.5"
gulp-header@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-2.0.5.tgz#16e229c73593ade301168024fea68dab75d9d38c"
dependencies:
concat-with-sourcemaps "*"
lodash.template "^4.4.0"
through2 "^2.0.0"
gulp-open@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/gulp-open/-/gulp-open-3.0.1.tgz#a2f747b4aa31abec9399b527158b0368c57e2102"
@ -4176,7 +4190,7 @@ lodash._reinterpolate@^2.4.1, lodash._reinterpolate@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz#4f1227aa5a8711fc632f5b07a1f4607aab8b3222"
lodash._reinterpolate@^3.0.0:
lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@ -4342,6 +4356,13 @@ lodash.template@^3.0.0:
lodash.restparam "^3.0.0"
lodash.templatesettings "^3.0.0"
lodash.template@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.templatesettings "^4.0.0"
lodash.templatesettings@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
@ -4349,6 +4370,12 @@ lodash.templatesettings@^3.0.0:
lodash._reinterpolate "^3.0.0"
lodash.escape "^3.0.0"
lodash.templatesettings@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.templatesettings@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz#ea76c75d11eb86d4dbe89a83893bb861929ac699"