commit
e1183d6049
20
changelog.md
20
changelog.md
@ -1,3 +1,23 @@
|
|||||||
|
## v3.2.1
|
||||||
|
|
||||||
|
* Accessibility improvements for the controls (part of #905 fixes)
|
||||||
|
* Fix for context menu showing on YouTube (thanks Anthony Recenello in Slack)
|
||||||
|
* Vimeo fix for their API not returning the right duration until playback begins (fixes #891)
|
||||||
|
|
||||||
|
## v3.2.0
|
||||||
|
|
||||||
|
* Fullscreen fixes (thanks @friday)
|
||||||
|
* Menu fix for if speed not in config
|
||||||
|
* Menu z-index fix (thanks @danielsarin)
|
||||||
|
* i18n fix for missing "Normal" string (thanks @danielsarin)
|
||||||
|
* Safer check for active caption (thanks @Antonio-Laguna)
|
||||||
|
* Add custom property fallback (thanks @friday)
|
||||||
|
* Fixed bug for captions with no srclang and labels and improved logic (fixes #875)
|
||||||
|
* Fix for `playing` false positive (fixes #898)
|
||||||
|
* Fix for IE issue with navigator.language (thanks @nicolasthy) (fixes #893)
|
||||||
|
* Fix for Vimeo controls missing on iOS (thanks @verde-io) (fixes #807)
|
||||||
|
* Fix for double vimeo caption rendering (fixes #877)
|
||||||
|
|
||||||
## v3.1.0
|
## v3.1.0
|
||||||
|
|
||||||
* Styling fixes
|
* Styling fixes
|
||||||
|
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
3
demo/dist/demo.js
vendored
3
demo/dist/demo.js
vendored
@ -3887,7 +3887,7 @@ singleton.Client = Client;
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup the player
|
// Setup the player
|
||||||
var player = new Plyr('video', {
|
var player = new Plyr('#player', {
|
||||||
debug: true,
|
debug: true,
|
||||||
title: 'View From A Blue Moon',
|
title: 'View From A Blue Moon',
|
||||||
iconUrl: '../dist/plyr.svg',
|
iconUrl: '../dist/plyr.svg',
|
||||||
@ -4011,7 +4011,6 @@ singleton.Client = Client;
|
|||||||
case types.youtube:
|
case types.youtube:
|
||||||
player.source = {
|
player.source = {
|
||||||
type: 'video',
|
type: 'video',
|
||||||
title: 'View From A Blue Moon',
|
|
||||||
sources: [{
|
sources: [{
|
||||||
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
||||||
provider: 'youtube'
|
provider: 'youtube'
|
||||||
|
2
demo/dist/demo.js.map
vendored
2
demo/dist/demo.js.map
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js
vendored
2
demo/dist/demo.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js.map
vendored
2
demo/dist/demo.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -114,7 +114,7 @@
|
|||||||
<title>HTML5</title>
|
<title>HTML5</title>
|
||||||
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> © Brainfarm
|
<a href="https://itunes.apple.com/au/movie/view-from-a-blue-moon/id1041586323" target="_blank">View From A Blue Moon</a> © Brainfarm
|
||||||
</small>
|
</small>
|
||||||
</li>
|
</li>
|
||||||
<li class="plyr__cite plyr__cite--audio" hidden>
|
<li class="plyr__cite plyr__cite--audio" hidden>
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="plyr__cite plyr__cite--vimeo" hidden>
|
<li class="plyr__cite plyr__cite--vimeo" hidden>
|
||||||
<small>
|
<small>
|
||||||
<a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on
|
<a href="https://vimeo.com/76979871" target="_blank">The New Vimeo Player</a> on
|
||||||
<span class="color--vimeo">
|
<span class="color--vimeo">
|
||||||
<svg class="icon" role="presentation">
|
<svg class="icon" role="presentation">
|
||||||
<title>Vimeo</title>
|
<title>Vimeo</title>
|
||||||
|
@ -47,7 +47,7 @@ import Raven from 'raven-js';
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup the player
|
// Setup the player
|
||||||
const player = new Plyr('video', {
|
const player = new Plyr('#player', {
|
||||||
debug: true,
|
debug: true,
|
||||||
title: 'View From A Blue Moon',
|
title: 'View From A Blue Moon',
|
||||||
iconUrl: '../dist/plyr.svg',
|
iconUrl: '../dist/plyr.svg',
|
||||||
@ -182,7 +182,6 @@ import Raven from 'raven-js';
|
|||||||
case types.youtube:
|
case types.youtube:
|
||||||
player.source = {
|
player.source = {
|
||||||
type: 'video',
|
type: 'video',
|
||||||
title: 'View From A Blue Moon',
|
|
||||||
sources: [{
|
sources: [{
|
||||||
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
||||||
provider: 'youtube',
|
provider: 'youtube',
|
||||||
|
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
325
dist/plyr.js
vendored
325
dist/plyr.js
vendored
@ -77,7 +77,7 @@ var defaults = {
|
|||||||
// Sprite (for icons)
|
// Sprite (for icons)
|
||||||
loadSprite: true,
|
loadSprite: true,
|
||||||
iconPrefix: 'plyr',
|
iconPrefix: 'plyr',
|
||||||
iconUrl: 'https://cdn.plyr.io/3.1.0/plyr.svg',
|
iconUrl: 'https://cdn.plyr.io/3.2.1/plyr.svg',
|
||||||
|
|
||||||
// Blank video (used to prevent errors on source change)
|
// Blank video (used to prevent errors on source change)
|
||||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||||
@ -116,7 +116,7 @@ var defaults = {
|
|||||||
// Captions settings
|
// Captions settings
|
||||||
captions: {
|
captions: {
|
||||||
active: false,
|
active: false,
|
||||||
language: window.navigator.language.split('-')[0]
|
language: (navigator.language || navigator.userLanguage).split('-')[0]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fullscreen settings
|
// Fullscreen settings
|
||||||
@ -164,6 +164,7 @@ var defaults = {
|
|||||||
captions: 'Captions',
|
captions: 'Captions',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
speed: 'Speed',
|
speed: 'Speed',
|
||||||
|
normal: 'Normal',
|
||||||
quality: 'Quality',
|
quality: 'Quality',
|
||||||
loop: 'Loop',
|
loop: 'Loop',
|
||||||
start: 'Start',
|
start: 'Start',
|
||||||
@ -171,6 +172,7 @@ var defaults = {
|
|||||||
all: 'All',
|
all: 'All',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
disabled: 'Disabled',
|
disabled: 'Disabled',
|
||||||
|
enabled: 'Enabled',
|
||||||
advertisement: 'Ad'
|
advertisement: 'Ad'
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1702,16 +1704,16 @@ var support = {
|
|||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
// Basic functionality vs full UI
|
// Basic functionality vs full UI
|
||||||
check: function check(type, provider, inline) {
|
check: function check(type, provider, playsinline) {
|
||||||
var api = false;
|
var api = false;
|
||||||
var ui = false;
|
var ui = false;
|
||||||
var browser = utils.getBrowser();
|
var browser = utils.getBrowser();
|
||||||
var playsInline = browser.isIPhone && inline && support.inline;
|
var canPlayInline = browser.isIPhone && playsinline && support.playsinline;
|
||||||
|
|
||||||
switch (provider + ':' + type) {
|
switch (provider + ':' + type) {
|
||||||
case 'html5:video':
|
case 'html5:video':
|
||||||
api = support.video;
|
api = support.video;
|
||||||
ui = api && support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = api && support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'html5:audio':
|
case 'html5:audio':
|
||||||
@ -1722,7 +1724,7 @@ var support = {
|
|||||||
case 'youtube:video':
|
case 'youtube:video':
|
||||||
case 'vimeo:video':
|
case 'vimeo:video':
|
||||||
api = true;
|
api = true;
|
||||||
ui = support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1750,7 +1752,7 @@ var support = {
|
|||||||
|
|
||||||
// Inline playback support
|
// Inline playback support
|
||||||
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
||||||
inline: 'playsInline' in document.createElement('video'),
|
playsinline: 'playsInline' in document.createElement('video'),
|
||||||
|
|
||||||
// Check for mime type support against a player instance
|
// Check for mime type support against a player instance
|
||||||
// Credits: http://diveintohtml5.info/everything.html
|
// Credits: http://diveintohtml5.info/everything.html
|
||||||
@ -2034,7 +2036,7 @@ var Fullscreen = function () {
|
|||||||
} else if (!Fullscreen.native) {
|
} else if (!Fullscreen.native) {
|
||||||
toggleFallback.call(this, false);
|
toggleFallback.call(this, false);
|
||||||
} else if (!this.prefix) {
|
} else if (!this.prefix) {
|
||||||
document.cancelFullScreen();
|
(document.cancelFullScreen || document.exitFullscreen).call(document);
|
||||||
} else if (!utils.is.empty(this.prefix)) {
|
} else if (!utils.is.empty(this.prefix)) {
|
||||||
var action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
var action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
||||||
document['' + this.prefix + action + this.name]();
|
document['' + this.prefix + action + this.name]();
|
||||||
@ -2100,7 +2102,7 @@ var Fullscreen = function () {
|
|||||||
get: function get$$1() {
|
get: function get$$1() {
|
||||||
// No prefix
|
// No prefix
|
||||||
if (utils.is.function(document.exitFullscreen)) {
|
if (utils.is.function(document.exitFullscreen)) {
|
||||||
return false;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for fullscreen support by vendor prefix
|
// Check for fullscreen support by vendor prefix
|
||||||
@ -2129,6 +2131,36 @@ var Fullscreen = function () {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
var i18n = {
|
||||||
|
get: function get$$1() {
|
||||||
|
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
||||||
|
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||||
|
|
||||||
|
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = config.i18n[key];
|
||||||
|
|
||||||
|
var replace = {
|
||||||
|
'{seektime}': config.seekTime,
|
||||||
|
'{title}': config.title
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(replace).forEach(function (_ref) {
|
||||||
|
var _ref2 = slicedToArray(_ref, 2),
|
||||||
|
key = _ref2[0],
|
||||||
|
value = _ref2[1];
|
||||||
|
|
||||||
|
string = utils.replaceAll(string, key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
var captions = {
|
var captions = {
|
||||||
// Setup captions
|
// Setup captions
|
||||||
setup: function setup() {
|
setup: function setup() {
|
||||||
@ -2168,6 +2200,7 @@ var captions = {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject the container
|
// Inject the container
|
||||||
if (!utils.is.element(this.elements.captions)) {
|
if (!utils.is.element(this.elements.captions)) {
|
||||||
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
||||||
@ -2272,9 +2305,54 @@ var captions = {
|
|||||||
getCurrentTrack: function getCurrentTrack() {
|
getCurrentTrack: function getCurrentTrack() {
|
||||||
var _this2 = this;
|
var _this2 = this;
|
||||||
|
|
||||||
return captions.getTracks.call(this).find(function (track) {
|
var tracks = captions.getTracks.call(this);
|
||||||
|
|
||||||
|
if (!tracks.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get track based on current language
|
||||||
|
var track = tracks.find(function (track) {
|
||||||
return track.language.toLowerCase() === _this2.language;
|
return track.language.toLowerCase() === _this2.language;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get the <track> with default attribute
|
||||||
|
if (!track) {
|
||||||
|
track = utils.getElement.call(this, 'track[default]');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the first track
|
||||||
|
if (!track) {
|
||||||
|
var _tracks = slicedToArray(tracks, 1);
|
||||||
|
|
||||||
|
track = _tracks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return track;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// Get UI label for track
|
||||||
|
getLabel: function getLabel(track) {
|
||||||
|
var currentTrack = track;
|
||||||
|
|
||||||
|
if (!utils.is.track(currentTrack) && support.textTracks && this.captions.active) {
|
||||||
|
currentTrack = captions.getCurrentTrack.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.is.track(currentTrack)) {
|
||||||
|
if (!utils.is.empty(currentTrack.label)) {
|
||||||
|
return currentTrack.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils.is.empty(currentTrack.language)) {
|
||||||
|
return track.language.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('enabled', this.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('disabled', this.config);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -2336,11 +2414,6 @@ var captions = {
|
|||||||
|
|
||||||
// Display captions container and button (for initialization)
|
// Display captions container and button (for initialization)
|
||||||
show: function show() {
|
show: function show() {
|
||||||
// If there's no caption toggle, bail
|
|
||||||
if (!utils.is.element(this.elements.buttons.captions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the value from storage
|
// Try to load the value from storage
|
||||||
var active = this.storage.get('captions');
|
var active = this.storage.get('captions');
|
||||||
|
|
||||||
@ -2360,36 +2433,6 @@ var captions = {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
var i18n = {
|
|
||||||
get: function get$$1() {
|
|
||||||
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
||||||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
||||||
|
|
||||||
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var string = config.i18n[key];
|
|
||||||
|
|
||||||
var replace = {
|
|
||||||
'{seektime}': config.seekTime,
|
|
||||||
'{title}': config.title
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.entries(replace).forEach(function (_ref) {
|
|
||||||
var _ref2 = slicedToArray(_ref, 2),
|
|
||||||
key = _ref2[0],
|
|
||||||
value = _ref2[1];
|
|
||||||
|
|
||||||
string = utils.replaceAll(string, key, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
var ui = {
|
var ui = {
|
||||||
addStyleHook: function addStyleHook() {
|
addStyleHook: function addStyleHook() {
|
||||||
utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
||||||
@ -2892,10 +2935,6 @@ var browser$1 = utils.getBrowser();
|
|||||||
var controls = {
|
var controls = {
|
||||||
// Webkit polyfill for lower fill range
|
// Webkit polyfill for lower fill range
|
||||||
updateRangeFill: function updateRangeFill(target) {
|
updateRangeFill: function updateRangeFill(target) {
|
||||||
// WebKit only
|
|
||||||
if (!browser$1.isWebkit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get range from event if event passed
|
// Get range from event if event passed
|
||||||
var range = utils.is.event(target) ? target.target : target;
|
var range = utils.is.event(target) ? target.target : target;
|
||||||
@ -2905,6 +2944,14 @@ var controls = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set aria value for https://github.com/sampotts/plyr/issues/905
|
||||||
|
range.setAttribute('aria-valuenow', range.value);
|
||||||
|
|
||||||
|
// WebKit only
|
||||||
|
if (!browser$1.isWebkit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set CSS custom property
|
// Set CSS custom property
|
||||||
range.style.setProperty('--value', range.value / range.max * 100 + '%');
|
range.style.setProperty('--value', range.value / range.max * 100 + '%');
|
||||||
},
|
},
|
||||||
@ -2928,7 +2975,8 @@ var controls = {
|
|||||||
// Create <svg>
|
// Create <svg>
|
||||||
var icon = document.createElementNS(namespace, 'svg');
|
var icon = document.createElementNS(namespace, 'svg');
|
||||||
utils.setAttributes(icon, utils.extend(attributes, {
|
utils.setAttributes(icon, utils.extend(attributes, {
|
||||||
role: 'presentation'
|
role: 'presentation',
|
||||||
|
focusable: 'false'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Create the <use> to reference sprite
|
// Create the <use> to reference sprite
|
||||||
@ -3110,6 +3158,7 @@ var controls = {
|
|||||||
// Seek label
|
// Seek label
|
||||||
var label = utils.createElement('label', {
|
var label = utils.createElement('label', {
|
||||||
for: attributes.id,
|
for: attributes.id,
|
||||||
|
id: attributes.id + '-label',
|
||||||
class: this.config.classNames.hidden
|
class: this.config.classNames.hidden
|
||||||
}, i18n.get(type, this.config));
|
}, i18n.get(type, this.config));
|
||||||
|
|
||||||
@ -3120,7 +3169,13 @@ var controls = {
|
|||||||
max: 100,
|
max: 100,
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
value: 0,
|
value: 0,
|
||||||
autocomplete: 'off'
|
autocomplete: 'off',
|
||||||
|
// A11y fixes for https://github.com/sampotts/plyr/issues/905
|
||||||
|
role: 'slider',
|
||||||
|
'aria-labelledby': attributes.id + '-label',
|
||||||
|
'aria-valuemin': 0,
|
||||||
|
'aria-valuemax': 100,
|
||||||
|
'aria-valuenow': 0
|
||||||
}, attributes));
|
}, attributes));
|
||||||
|
|
||||||
this.elements.inputs[type] = input;
|
this.elements.inputs[type] = input;
|
||||||
@ -3140,7 +3195,9 @@ var controls = {
|
|||||||
var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(this.config.selectors.display[type]), {
|
var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(this.config.selectors.display[type]), {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
value: 0
|
value: 0,
|
||||||
|
role: 'presentation',
|
||||||
|
'aria-hidden': true
|
||||||
}, attributes));
|
}, attributes));
|
||||||
|
|
||||||
// Create the label inside
|
// Create the label inside
|
||||||
@ -3310,6 +3367,9 @@ var controls = {
|
|||||||
var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
||||||
controls.toggleTab.call(this, type, toggle);
|
controls.toggleTab.call(this, type, toggle);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If we're hiding, nothing more to do
|
// If we're hiding, nothing more to do
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -3366,16 +3426,17 @@ var controls = {
|
|||||||
getLabel: function getLabel(setting, value) {
|
getLabel: function getLabel(setting, value) {
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
case 'speed':
|
case 'speed':
|
||||||
return value === 1 ? 'Normal' : value + '×';
|
return value === 1 ? i18n.get('normal', this.config) : value + '×';
|
||||||
|
|
||||||
case 'quality':
|
case 'quality':
|
||||||
if (utils.is.number(value)) {
|
if (utils.is.number(value)) {
|
||||||
return value + 'p';
|
return value + 'p';
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.toTitleCase(value);
|
return utils.toTitleCase(value);
|
||||||
|
|
||||||
case 'captions':
|
case 'captions':
|
||||||
return controls.getLanguage.call(this);
|
return captions.getLabel.call(this);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@ -3391,7 +3452,18 @@ var controls = {
|
|||||||
|
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
case 'captions':
|
case 'captions':
|
||||||
value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
|
if (this.captions.active) {
|
||||||
|
if (this.options.captions.length > 2 || !this.options.captions.some(function (lang) {
|
||||||
|
return lang === 'enabled';
|
||||||
|
})) {
|
||||||
|
value = this.captions.language;
|
||||||
|
} else {
|
||||||
|
value = 'enabled';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -3422,17 +3494,19 @@ var controls = {
|
|||||||
list = pane && pane.querySelector('ul');
|
list = pane && pane.querySelector('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the label
|
// If there's no list it means it's not been rendered...
|
||||||
if (!utils.is.empty(value)) {
|
if (!utils.is.element(list)) {
|
||||||
var label = this.elements.settings.tabs[setting].querySelector('.' + this.config.classNames.menu.value);
|
return;
|
||||||
label.innerHTML = controls.getLabel.call(this, setting, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the radio option
|
// Update the label
|
||||||
|
var label = this.elements.settings.tabs[setting].querySelector('.' + this.config.classNames.menu.value);
|
||||||
|
label.innerHTML = controls.getLabel.call(this, setting, value);
|
||||||
|
|
||||||
|
// Find the radio option and check it
|
||||||
var target = list && list.querySelector('input[value="' + value + '"]');
|
var target = list && list.querySelector('input[value="' + value + '"]');
|
||||||
|
|
||||||
if (utils.is.element(target)) {
|
if (utils.is.element(target)) {
|
||||||
// Check it
|
|
||||||
target.checked = true;
|
target.checked = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3476,21 +3550,6 @@ var controls = {
|
|||||||
|
|
||||||
// Get current selected caption language
|
// Get current selected caption language
|
||||||
// TODO: rework this to user the getter in the API?
|
// TODO: rework this to user the getter in the API?
|
||||||
getLanguage: function getLanguage() {
|
|
||||||
if (!this.supported.ui) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
|
|
||||||
var currentTrack = captions.getCurrentTrack.call(this);
|
|
||||||
|
|
||||||
if (utils.is.track(currentTrack)) {
|
|
||||||
return currentTrack.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i18n.get('disabled', this.config);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// Set a list of available captions languages
|
// Set a list of available captions languages
|
||||||
@ -3508,6 +3567,9 @@ var controls = {
|
|||||||
// Empty the menu
|
// Empty the menu
|
||||||
utils.emptyElement(list);
|
utils.emptyElement(list);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If there's no captions, bail
|
// If there's no captions, bail
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -3516,8 +3578,8 @@ var controls = {
|
|||||||
// Re-map the tracks into just the data we need
|
// Re-map the tracks into just the data we need
|
||||||
var tracks = captions.getTracks.call(this).map(function (track) {
|
var tracks = captions.getTracks.call(this).map(function (track) {
|
||||||
return {
|
return {
|
||||||
language: track.language,
|
language: !utils.is.empty(track.language) ? track.language : 'enabled',
|
||||||
label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase()
|
label: captions.getLabel.call(_this3, track)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3529,7 +3591,12 @@ var controls = {
|
|||||||
|
|
||||||
// Generate options
|
// Generate options
|
||||||
tracks.forEach(function (track) {
|
tracks.forEach(function (track) {
|
||||||
controls.createMenuItem.call(_this3, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this3, track.language.toUpperCase()), track.language.toLowerCase() === _this3.captions.language.toLowerCase());
|
controls.createMenuItem.call(_this3, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this3, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this3.captions.language.toLowerCase());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store reference
|
||||||
|
this.options.captions = tracks.map(function (track) {
|
||||||
|
return track.language;
|
||||||
});
|
});
|
||||||
|
|
||||||
controls.updateSetting.call(this, type, list);
|
controls.updateSetting.call(this, type, list);
|
||||||
@ -4048,7 +4115,7 @@ var controls = {
|
|||||||
seektime: this.config.seekTime,
|
seektime: this.config.seekTime,
|
||||||
speed: this.speed,
|
speed: this.speed,
|
||||||
quality: this.quality,
|
quality: this.quality,
|
||||||
captions: controls.getLanguage.call(this)
|
captions: captions.getLabel.call(this)
|
||||||
// TODO: Looping
|
// TODO: Looping
|
||||||
// loop: 'None',
|
// loop: 'None',
|
||||||
});
|
});
|
||||||
@ -4070,7 +4137,7 @@ var controls = {
|
|||||||
// Inject controls HTML
|
// Inject controls HTML
|
||||||
if (utils.is.element(container)) {
|
if (utils.is.element(container)) {
|
||||||
target.appendChild(container);
|
target.appendChild(container);
|
||||||
} else {
|
} else if (container) {
|
||||||
target.insertAdjacentHTML('beforeend', container);
|
target.insertAdjacentHTML('beforeend', container);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4402,6 +4469,10 @@ var Listeners = function () {
|
|||||||
// If autoplay, then load advertisement if required
|
// If autoplay, then load advertisement if required
|
||||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||||
utils.on(this.player.media, 'playing', function () {
|
utils.on(this.player.media, 'playing', function () {
|
||||||
|
if (!_this3.player.ads) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If ads are enabled, wait for them first
|
// If ads are enabled, wait for them first
|
||||||
if (_this3.player.ads.enabled && !_this3.player.ads.initialized) {
|
if (_this3.player.ads.enabled && !_this3.player.ads.initialized) {
|
||||||
// Wait for manager response
|
// Wait for manager response
|
||||||
@ -4443,7 +4514,7 @@ var Listeners = function () {
|
|||||||
|
|
||||||
// Disable right click
|
// Disable right click
|
||||||
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
||||||
utils.on(this.player.media, 'contextmenu', function (event) {
|
utils.on(this.player.elements.wrapper, 'contextmenu', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
@ -5729,7 +5800,11 @@ var youtube = {
|
|||||||
return Number(instance.getCurrentTime());
|
return Number(instance.getCurrentTime());
|
||||||
},
|
},
|
||||||
set: function set(time) {
|
set: function set(time) {
|
||||||
|
// Vimeo will automatically play on seek
|
||||||
|
var paused = player.media.paused;
|
||||||
|
|
||||||
// Set seeking flag
|
// Set seeking flag
|
||||||
|
|
||||||
player.media.seeking = true;
|
player.media.seeking = true;
|
||||||
|
|
||||||
// Trigger seeking
|
// Trigger seeking
|
||||||
@ -5737,6 +5812,11 @@ var youtube = {
|
|||||||
|
|
||||||
// Seek after events sent
|
// Seek after events sent
|
||||||
instance.seekTo(time);
|
instance.seekTo(time);
|
||||||
|
|
||||||
|
// Restore pause state
|
||||||
|
if (paused) {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -5974,10 +6054,14 @@ var vimeo = {
|
|||||||
setAspectRatio: function setAspectRatio(input) {
|
setAspectRatio: function setAspectRatio(input) {
|
||||||
var ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
var ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
||||||
var padding = 100 / ratio[0] * ratio[1];
|
var padding = 100 / ratio[0] * ratio[1];
|
||||||
|
this.elements.wrapper.style.paddingBottom = padding + '%';
|
||||||
|
|
||||||
|
if (this.supported.ui) {
|
||||||
var height = 240;
|
var height = 240;
|
||||||
var offset = (height - padding) / (height / 50);
|
var offset = (height - padding) / (height / 50);
|
||||||
this.elements.wrapper.style.paddingBottom = padding + '%';
|
|
||||||
this.media.style.transform = 'translateY(-' + offset + '%)';
|
this.media.style.transform = 'translateY(-' + offset + '%)';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -5996,7 +6080,8 @@ var vimeo = {
|
|||||||
title: false,
|
title: false,
|
||||||
speed: true,
|
speed: true,
|
||||||
transparent: 0,
|
transparent: 0,
|
||||||
gesture: 'media'
|
gesture: 'media',
|
||||||
|
playsinline: !this.config.fullscreen.iosNative
|
||||||
};
|
};
|
||||||
var params = utils.buildUrlParams(options);
|
var params = utils.buildUrlParams(options);
|
||||||
|
|
||||||
@ -6030,6 +6115,11 @@ var vimeo = {
|
|||||||
player.media.paused = true;
|
player.media.paused = true;
|
||||||
player.media.currentTime = 0;
|
player.media.currentTime = 0;
|
||||||
|
|
||||||
|
// Disable native text track rendering
|
||||||
|
if (player.supported.ui) {
|
||||||
|
player.embed.disableTextTrack();
|
||||||
|
}
|
||||||
|
|
||||||
// Create a faux HTML5 API using the Vimeo API
|
// Create a faux HTML5 API using the Vimeo API
|
||||||
player.media.play = function () {
|
player.media.play = function () {
|
||||||
player.embed.play().then(function () {
|
player.embed.play().then(function () {
|
||||||
@ -6068,7 +6158,9 @@ var vimeo = {
|
|||||||
utils.dispatchEvent.call(player, player.media, 'seeking');
|
utils.dispatchEvent.call(player, player.media, 'seeking');
|
||||||
|
|
||||||
// Seek after events
|
// Seek after events
|
||||||
player.embed.setCurrentTime(time);
|
player.embed.setCurrentTime(time).catch(function () {
|
||||||
|
// Do nothing
|
||||||
|
});
|
||||||
|
|
||||||
// Restore pause state
|
// Restore pause state
|
||||||
if (paused) {
|
if (paused) {
|
||||||
@ -6248,6 +6340,15 @@ var vimeo = {
|
|||||||
if (parseInt(data.percent, 10) === 1) {
|
if (parseInt(data.percent, 10) === 1) {
|
||||||
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get duration as if we do it before load, it gives an incorrect value
|
||||||
|
// https://github.com/sampotts/plyr/issues/891
|
||||||
|
player.embed.getDuration().then(function (value) {
|
||||||
|
if (value !== player.media.duration) {
|
||||||
|
player.media.duration = value;
|
||||||
|
utils.dispatchEvent.call(player, player.media, 'durationchange');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('seeked', function () {
|
player.embed.on('seeked', function () {
|
||||||
@ -6399,7 +6500,7 @@ var source = {
|
|||||||
_this2.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
_this2.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
_this2.supported = support.check(_this2.type, _this2.provider, _this2.config.inline);
|
_this2.supported = support.check(_this2.type, _this2.provider, _this2.config.playsinline);
|
||||||
|
|
||||||
// Create new markup
|
// Create new markup
|
||||||
switch (_this2.provider + ':' + _this2.type) {
|
switch (_this2.provider + ':' + _this2.type) {
|
||||||
@ -6447,7 +6548,7 @@ var source = {
|
|||||||
if (_this2.config.muted) {
|
if (_this2.config.muted) {
|
||||||
_this2.media.setAttribute('muted', '');
|
_this2.media.setAttribute('muted', '');
|
||||||
}
|
}
|
||||||
if (_this2.config.inline) {
|
if (_this2.config.playsinline) {
|
||||||
_this2.media.setAttribute('playsinline', '');
|
_this2.media.setAttribute('playsinline', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6528,7 +6629,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set config
|
// Set config
|
||||||
this.config = utils.extend({}, defaults, options, function () {
|
this.config = utils.extend({}, defaults, options || {}, function () {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(_this.media.getAttribute('data-plyr-config'));
|
return JSON.parse(_this.media.getAttribute('data-plyr-config'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -6565,7 +6666,8 @@ var Plyr = function () {
|
|||||||
// Options
|
// Options
|
||||||
this.options = {
|
this.options = {
|
||||||
speed: [],
|
speed: [],
|
||||||
quality: []
|
quality: [],
|
||||||
|
captions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
@ -6650,12 +6752,17 @@ var Plyr = function () {
|
|||||||
if (truthy.includes(params.autoplay)) {
|
if (truthy.includes(params.autoplay)) {
|
||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (truthy.includes(params.playsinline)) {
|
|
||||||
this.config.inline = true;
|
|
||||||
}
|
|
||||||
if (truthy.includes(params.loop)) {
|
if (truthy.includes(params.loop)) {
|
||||||
this.config.loop.active = true;
|
this.config.loop.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace fullscreen.iosNative with this playsinline config option
|
||||||
|
// YouTube requires the playsinline in the URL
|
||||||
|
if (this.isYouTube) {
|
||||||
|
this.config.playsinline = truthy.includes(params.playsinline);
|
||||||
|
} else {
|
||||||
|
this.config.playsinline = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <div> with attributes
|
// <div> with attributes
|
||||||
@ -6689,7 +6796,7 @@ var Plyr = function () {
|
|||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('playsinline')) {
|
if (this.media.hasAttribute('playsinline')) {
|
||||||
this.config.inline = true;
|
this.config.playsinline = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('muted')) {
|
if (this.media.hasAttribute('muted')) {
|
||||||
this.config.muted = true;
|
this.config.muted = true;
|
||||||
@ -6706,7 +6813,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for support again but with type
|
// Check for support again but with type
|
||||||
this.supported = support.check(this.type, this.provider, this.config.inline);
|
this.supported = support.check(this.type, this.provider, this.config.playsinline);
|
||||||
|
|
||||||
// If no support for even API, bail
|
// If no support for even API, bail
|
||||||
if (!this.supported.api) {
|
if (!this.supported.api) {
|
||||||
@ -6926,13 +7033,13 @@ var Plyr = function () {
|
|||||||
* @param {boolean} input - Whether to enable captions
|
* @param {boolean} input - Whether to enable captions
|
||||||
*/
|
*/
|
||||||
value: function toggleCaptions(input) {
|
value: function toggleCaptions(input) {
|
||||||
// If there's no full support, or there's no caption toggle
|
// If there's no full support
|
||||||
if (!this.supported.ui || !utils.is.element(this.elements.buttons.captions)) {
|
if (!this.supported.ui) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the method is called without parameter, toggle based on current value
|
// If the method is called without parameter, toggle based on current value
|
||||||
var show = utils.is.boolean(input) ? input : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;
|
var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||||
|
|
||||||
// Nothing to change...
|
// Nothing to change...
|
||||||
if (this.captions.active === show) {
|
if (this.captions.active === show) {
|
||||||
@ -7291,7 +7398,7 @@ var Plyr = function () {
|
|||||||
}, {
|
}, {
|
||||||
key: 'playing',
|
key: 'playing',
|
||||||
get: function get$$1() {
|
get: function get$$1() {
|
||||||
return Boolean(!this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
return Boolean(this.ready && !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7320,7 +7427,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
this.media.currentTime = parseFloat(targetTime.toFixed(4));
|
this.media.currentTime = targetTime;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
this.debug.log('Seeking to ' + this.currentTime + ' seconds');
|
this.debug.log('Seeking to ' + this.currentTime + ' seconds');
|
||||||
@ -7377,7 +7484,7 @@ var Plyr = function () {
|
|||||||
key: 'duration',
|
key: 'duration',
|
||||||
get: function get$$1() {
|
get: function get$$1() {
|
||||||
// Faux duration set via config
|
// Faux duration set via config
|
||||||
var fauxDuration = parseInt(this.config.duration, 10);
|
var fauxDuration = parseFloat(this.config.duration);
|
||||||
|
|
||||||
// True duration
|
// True duration
|
||||||
var realDuration = this.media ? Number(this.media.duration) : 0;
|
var realDuration = this.media ? Number(this.media.duration) : 0;
|
||||||
@ -7728,17 +7835,29 @@ var Plyr = function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions based on input
|
|
||||||
this.toggleCaptions(!utils.is.empty(input));
|
|
||||||
|
|
||||||
// If empty string is passed, assume disable captions
|
// If empty string is passed, assume disable captions
|
||||||
if (utils.is.empty(input)) {
|
if (utils.is.empty(input)) {
|
||||||
|
this.toggleCaptions(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize
|
// Normalize
|
||||||
var language = input.toLowerCase();
|
var language = input.toLowerCase();
|
||||||
|
|
||||||
|
// Check for support
|
||||||
|
if (!this.options.captions.includes(language)) {
|
||||||
|
this.debug.warn('Unsupported language option: ' + language);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure captions are enabled
|
||||||
|
this.toggleCaptions(true);
|
||||||
|
|
||||||
|
// Enabled only
|
||||||
|
if (language === 'enabled') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If nothing to change, bail
|
// If nothing to change, bail
|
||||||
if (this.language === language) {
|
if (this.language === language) {
|
||||||
return;
|
return;
|
||||||
|
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js
vendored
2
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
325
dist/plyr.polyfilled.js
vendored
325
dist/plyr.polyfilled.js
vendored
@ -5117,7 +5117,7 @@ var defaults = {
|
|||||||
// Sprite (for icons)
|
// Sprite (for icons)
|
||||||
loadSprite: true,
|
loadSprite: true,
|
||||||
iconPrefix: 'plyr',
|
iconPrefix: 'plyr',
|
||||||
iconUrl: 'https://cdn.plyr.io/3.1.0/plyr.svg',
|
iconUrl: 'https://cdn.plyr.io/3.2.1/plyr.svg',
|
||||||
|
|
||||||
// Blank video (used to prevent errors on source change)
|
// Blank video (used to prevent errors on source change)
|
||||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||||
@ -5156,7 +5156,7 @@ var defaults = {
|
|||||||
// Captions settings
|
// Captions settings
|
||||||
captions: {
|
captions: {
|
||||||
active: false,
|
active: false,
|
||||||
language: window.navigator.language.split('-')[0]
|
language: (navigator.language || navigator.userLanguage).split('-')[0]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fullscreen settings
|
// Fullscreen settings
|
||||||
@ -5204,6 +5204,7 @@ var defaults = {
|
|||||||
captions: 'Captions',
|
captions: 'Captions',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
speed: 'Speed',
|
speed: 'Speed',
|
||||||
|
normal: 'Normal',
|
||||||
quality: 'Quality',
|
quality: 'Quality',
|
||||||
loop: 'Loop',
|
loop: 'Loop',
|
||||||
start: 'Start',
|
start: 'Start',
|
||||||
@ -5211,6 +5212,7 @@ var defaults = {
|
|||||||
all: 'All',
|
all: 'All',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
disabled: 'Disabled',
|
disabled: 'Disabled',
|
||||||
|
enabled: 'Enabled',
|
||||||
advertisement: 'Ad'
|
advertisement: 'Ad'
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -6736,16 +6738,16 @@ var support = {
|
|||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
// Basic functionality vs full UI
|
// Basic functionality vs full UI
|
||||||
check: function check(type, provider, inline) {
|
check: function check(type, provider, playsinline) {
|
||||||
var api = false;
|
var api = false;
|
||||||
var ui = false;
|
var ui = false;
|
||||||
var browser = utils.getBrowser();
|
var browser = utils.getBrowser();
|
||||||
var playsInline = browser.isIPhone && inline && support.inline;
|
var canPlayInline = browser.isIPhone && playsinline && support.playsinline;
|
||||||
|
|
||||||
switch (provider + ':' + type) {
|
switch (provider + ':' + type) {
|
||||||
case 'html5:video':
|
case 'html5:video':
|
||||||
api = support.video;
|
api = support.video;
|
||||||
ui = api && support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = api && support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'html5:audio':
|
case 'html5:audio':
|
||||||
@ -6756,7 +6758,7 @@ var support = {
|
|||||||
case 'youtube:video':
|
case 'youtube:video':
|
||||||
case 'vimeo:video':
|
case 'vimeo:video':
|
||||||
api = true;
|
api = true;
|
||||||
ui = support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -6784,7 +6786,7 @@ var support = {
|
|||||||
|
|
||||||
// Inline playback support
|
// Inline playback support
|
||||||
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
||||||
inline: 'playsInline' in document.createElement('video'),
|
playsinline: 'playsInline' in document.createElement('video'),
|
||||||
|
|
||||||
// Check for mime type support against a player instance
|
// Check for mime type support against a player instance
|
||||||
// Credits: http://diveintohtml5.info/everything.html
|
// Credits: http://diveintohtml5.info/everything.html
|
||||||
@ -7068,7 +7070,7 @@ var Fullscreen = function () {
|
|||||||
} else if (!Fullscreen.native) {
|
} else if (!Fullscreen.native) {
|
||||||
toggleFallback.call(this, false);
|
toggleFallback.call(this, false);
|
||||||
} else if (!this.prefix) {
|
} else if (!this.prefix) {
|
||||||
document.cancelFullScreen();
|
(document.cancelFullScreen || document.exitFullscreen).call(document);
|
||||||
} else if (!utils.is.empty(this.prefix)) {
|
} else if (!utils.is.empty(this.prefix)) {
|
||||||
var action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
var action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
||||||
document['' + this.prefix + action + this.name]();
|
document['' + this.prefix + action + this.name]();
|
||||||
@ -7134,7 +7136,7 @@ var Fullscreen = function () {
|
|||||||
get: function get() {
|
get: function get() {
|
||||||
// No prefix
|
// No prefix
|
||||||
if (utils.is.function(document.exitFullscreen)) {
|
if (utils.is.function(document.exitFullscreen)) {
|
||||||
return false;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for fullscreen support by vendor prefix
|
// Check for fullscreen support by vendor prefix
|
||||||
@ -7163,6 +7165,36 @@ var Fullscreen = function () {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
var i18n = {
|
||||||
|
get: function get() {
|
||||||
|
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
||||||
|
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||||
|
|
||||||
|
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = config.i18n[key];
|
||||||
|
|
||||||
|
var replace = {
|
||||||
|
'{seektime}': config.seekTime,
|
||||||
|
'{title}': config.title
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(replace).forEach(function (_ref) {
|
||||||
|
var _ref2 = slicedToArray(_ref, 2),
|
||||||
|
key = _ref2[0],
|
||||||
|
value = _ref2[1];
|
||||||
|
|
||||||
|
string = utils.replaceAll(string, key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
var captions = {
|
var captions = {
|
||||||
// Setup captions
|
// Setup captions
|
||||||
setup: function setup() {
|
setup: function setup() {
|
||||||
@ -7202,6 +7234,7 @@ var captions = {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject the container
|
// Inject the container
|
||||||
if (!utils.is.element(this.elements.captions)) {
|
if (!utils.is.element(this.elements.captions)) {
|
||||||
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
||||||
@ -7306,9 +7339,54 @@ var captions = {
|
|||||||
getCurrentTrack: function getCurrentTrack() {
|
getCurrentTrack: function getCurrentTrack() {
|
||||||
var _this2 = this;
|
var _this2 = this;
|
||||||
|
|
||||||
return captions.getTracks.call(this).find(function (track) {
|
var tracks = captions.getTracks.call(this);
|
||||||
|
|
||||||
|
if (!tracks.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get track based on current language
|
||||||
|
var track = tracks.find(function (track) {
|
||||||
return track.language.toLowerCase() === _this2.language;
|
return track.language.toLowerCase() === _this2.language;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get the <track> with default attribute
|
||||||
|
if (!track) {
|
||||||
|
track = utils.getElement.call(this, 'track[default]');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the first track
|
||||||
|
if (!track) {
|
||||||
|
var _tracks = slicedToArray(tracks, 1);
|
||||||
|
|
||||||
|
track = _tracks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return track;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// Get UI label for track
|
||||||
|
getLabel: function getLabel(track) {
|
||||||
|
var currentTrack = track;
|
||||||
|
|
||||||
|
if (!utils.is.track(currentTrack) && support.textTracks && this.captions.active) {
|
||||||
|
currentTrack = captions.getCurrentTrack.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.is.track(currentTrack)) {
|
||||||
|
if (!utils.is.empty(currentTrack.label)) {
|
||||||
|
return currentTrack.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils.is.empty(currentTrack.language)) {
|
||||||
|
return track.language.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('enabled', this.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('disabled', this.config);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -7370,11 +7448,6 @@ var captions = {
|
|||||||
|
|
||||||
// Display captions container and button (for initialization)
|
// Display captions container and button (for initialization)
|
||||||
show: function show() {
|
show: function show() {
|
||||||
// If there's no caption toggle, bail
|
|
||||||
if (!utils.is.element(this.elements.buttons.captions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the value from storage
|
// Try to load the value from storage
|
||||||
var active = this.storage.get('captions');
|
var active = this.storage.get('captions');
|
||||||
|
|
||||||
@ -7394,36 +7467,6 @@ var captions = {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
var i18n = {
|
|
||||||
get: function get() {
|
|
||||||
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
||||||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
||||||
|
|
||||||
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var string = config.i18n[key];
|
|
||||||
|
|
||||||
var replace = {
|
|
||||||
'{seektime}': config.seekTime,
|
|
||||||
'{title}': config.title
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.entries(replace).forEach(function (_ref) {
|
|
||||||
var _ref2 = slicedToArray(_ref, 2),
|
|
||||||
key = _ref2[0],
|
|
||||||
value = _ref2[1];
|
|
||||||
|
|
||||||
string = utils.replaceAll(string, key, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
var ui = {
|
var ui = {
|
||||||
addStyleHook: function addStyleHook() {
|
addStyleHook: function addStyleHook() {
|
||||||
utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
||||||
@ -7926,10 +7969,6 @@ var browser$1 = utils.getBrowser();
|
|||||||
var controls = {
|
var controls = {
|
||||||
// Webkit polyfill for lower fill range
|
// Webkit polyfill for lower fill range
|
||||||
updateRangeFill: function updateRangeFill(target) {
|
updateRangeFill: function updateRangeFill(target) {
|
||||||
// WebKit only
|
|
||||||
if (!browser$1.isWebkit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get range from event if event passed
|
// Get range from event if event passed
|
||||||
var range = utils.is.event(target) ? target.target : target;
|
var range = utils.is.event(target) ? target.target : target;
|
||||||
@ -7939,6 +7978,14 @@ var controls = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set aria value for https://github.com/sampotts/plyr/issues/905
|
||||||
|
range.setAttribute('aria-valuenow', range.value);
|
||||||
|
|
||||||
|
// WebKit only
|
||||||
|
if (!browser$1.isWebkit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set CSS custom property
|
// Set CSS custom property
|
||||||
range.style.setProperty('--value', range.value / range.max * 100 + '%');
|
range.style.setProperty('--value', range.value / range.max * 100 + '%');
|
||||||
},
|
},
|
||||||
@ -7962,7 +8009,8 @@ var controls = {
|
|||||||
// Create <svg>
|
// Create <svg>
|
||||||
var icon = document.createElementNS(namespace, 'svg');
|
var icon = document.createElementNS(namespace, 'svg');
|
||||||
utils.setAttributes(icon, utils.extend(attributes, {
|
utils.setAttributes(icon, utils.extend(attributes, {
|
||||||
role: 'presentation'
|
role: 'presentation',
|
||||||
|
focusable: 'false'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Create the <use> to reference sprite
|
// Create the <use> to reference sprite
|
||||||
@ -8144,6 +8192,7 @@ var controls = {
|
|||||||
// Seek label
|
// Seek label
|
||||||
var label = utils.createElement('label', {
|
var label = utils.createElement('label', {
|
||||||
for: attributes.id,
|
for: attributes.id,
|
||||||
|
id: attributes.id + '-label',
|
||||||
class: this.config.classNames.hidden
|
class: this.config.classNames.hidden
|
||||||
}, i18n.get(type, this.config));
|
}, i18n.get(type, this.config));
|
||||||
|
|
||||||
@ -8154,7 +8203,13 @@ var controls = {
|
|||||||
max: 100,
|
max: 100,
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
value: 0,
|
value: 0,
|
||||||
autocomplete: 'off'
|
autocomplete: 'off',
|
||||||
|
// A11y fixes for https://github.com/sampotts/plyr/issues/905
|
||||||
|
role: 'slider',
|
||||||
|
'aria-labelledby': attributes.id + '-label',
|
||||||
|
'aria-valuemin': 0,
|
||||||
|
'aria-valuemax': 100,
|
||||||
|
'aria-valuenow': 0
|
||||||
}, attributes));
|
}, attributes));
|
||||||
|
|
||||||
this.elements.inputs[type] = input;
|
this.elements.inputs[type] = input;
|
||||||
@ -8174,7 +8229,9 @@ var controls = {
|
|||||||
var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(this.config.selectors.display[type]), {
|
var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(this.config.selectors.display[type]), {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
value: 0
|
value: 0,
|
||||||
|
role: 'presentation',
|
||||||
|
'aria-hidden': true
|
||||||
}, attributes));
|
}, attributes));
|
||||||
|
|
||||||
// Create the label inside
|
// Create the label inside
|
||||||
@ -8344,6 +8401,9 @@ var controls = {
|
|||||||
var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
||||||
controls.toggleTab.call(this, type, toggle);
|
controls.toggleTab.call(this, type, toggle);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If we're hiding, nothing more to do
|
// If we're hiding, nothing more to do
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -8400,16 +8460,17 @@ var controls = {
|
|||||||
getLabel: function getLabel(setting, value) {
|
getLabel: function getLabel(setting, value) {
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
case 'speed':
|
case 'speed':
|
||||||
return value === 1 ? 'Normal' : value + '×';
|
return value === 1 ? i18n.get('normal', this.config) : value + '×';
|
||||||
|
|
||||||
case 'quality':
|
case 'quality':
|
||||||
if (utils.is.number(value)) {
|
if (utils.is.number(value)) {
|
||||||
return value + 'p';
|
return value + 'p';
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.toTitleCase(value);
|
return utils.toTitleCase(value);
|
||||||
|
|
||||||
case 'captions':
|
case 'captions':
|
||||||
return controls.getLanguage.call(this);
|
return captions.getLabel.call(this);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@ -8425,7 +8486,18 @@ var controls = {
|
|||||||
|
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
case 'captions':
|
case 'captions':
|
||||||
value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
|
if (this.captions.active) {
|
||||||
|
if (this.options.captions.length > 2 || !this.options.captions.some(function (lang) {
|
||||||
|
return lang === 'enabled';
|
||||||
|
})) {
|
||||||
|
value = this.captions.language;
|
||||||
|
} else {
|
||||||
|
value = 'enabled';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -8456,17 +8528,19 @@ var controls = {
|
|||||||
list = pane && pane.querySelector('ul');
|
list = pane && pane.querySelector('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the label
|
// If there's no list it means it's not been rendered...
|
||||||
if (!utils.is.empty(value)) {
|
if (!utils.is.element(list)) {
|
||||||
var label = this.elements.settings.tabs[setting].querySelector('.' + this.config.classNames.menu.value);
|
return;
|
||||||
label.innerHTML = controls.getLabel.call(this, setting, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the radio option
|
// Update the label
|
||||||
|
var label = this.elements.settings.tabs[setting].querySelector('.' + this.config.classNames.menu.value);
|
||||||
|
label.innerHTML = controls.getLabel.call(this, setting, value);
|
||||||
|
|
||||||
|
// Find the radio option and check it
|
||||||
var target = list && list.querySelector('input[value="' + value + '"]');
|
var target = list && list.querySelector('input[value="' + value + '"]');
|
||||||
|
|
||||||
if (utils.is.element(target)) {
|
if (utils.is.element(target)) {
|
||||||
// Check it
|
|
||||||
target.checked = true;
|
target.checked = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -8510,21 +8584,6 @@ var controls = {
|
|||||||
|
|
||||||
// Get current selected caption language
|
// Get current selected caption language
|
||||||
// TODO: rework this to user the getter in the API?
|
// TODO: rework this to user the getter in the API?
|
||||||
getLanguage: function getLanguage() {
|
|
||||||
if (!this.supported.ui) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
|
|
||||||
var currentTrack = captions.getCurrentTrack.call(this);
|
|
||||||
|
|
||||||
if (utils.is.track(currentTrack)) {
|
|
||||||
return currentTrack.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i18n.get('disabled', this.config);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// Set a list of available captions languages
|
// Set a list of available captions languages
|
||||||
@ -8542,6 +8601,9 @@ var controls = {
|
|||||||
// Empty the menu
|
// Empty the menu
|
||||||
utils.emptyElement(list);
|
utils.emptyElement(list);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If there's no captions, bail
|
// If there's no captions, bail
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -8550,8 +8612,8 @@ var controls = {
|
|||||||
// Re-map the tracks into just the data we need
|
// Re-map the tracks into just the data we need
|
||||||
var tracks = captions.getTracks.call(this).map(function (track) {
|
var tracks = captions.getTracks.call(this).map(function (track) {
|
||||||
return {
|
return {
|
||||||
language: track.language,
|
language: !utils.is.empty(track.language) ? track.language : 'enabled',
|
||||||
label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase()
|
label: captions.getLabel.call(_this3, track)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -8563,7 +8625,12 @@ var controls = {
|
|||||||
|
|
||||||
// Generate options
|
// Generate options
|
||||||
tracks.forEach(function (track) {
|
tracks.forEach(function (track) {
|
||||||
controls.createMenuItem.call(_this3, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this3, track.language.toUpperCase()), track.language.toLowerCase() === _this3.captions.language.toLowerCase());
|
controls.createMenuItem.call(_this3, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this3, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this3.captions.language.toLowerCase());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store reference
|
||||||
|
this.options.captions = tracks.map(function (track) {
|
||||||
|
return track.language;
|
||||||
});
|
});
|
||||||
|
|
||||||
controls.updateSetting.call(this, type, list);
|
controls.updateSetting.call(this, type, list);
|
||||||
@ -9082,7 +9149,7 @@ var controls = {
|
|||||||
seektime: this.config.seekTime,
|
seektime: this.config.seekTime,
|
||||||
speed: this.speed,
|
speed: this.speed,
|
||||||
quality: this.quality,
|
quality: this.quality,
|
||||||
captions: controls.getLanguage.call(this)
|
captions: captions.getLabel.call(this)
|
||||||
// TODO: Looping
|
// TODO: Looping
|
||||||
// loop: 'None',
|
// loop: 'None',
|
||||||
});
|
});
|
||||||
@ -9104,7 +9171,7 @@ var controls = {
|
|||||||
// Inject controls HTML
|
// Inject controls HTML
|
||||||
if (utils.is.element(container)) {
|
if (utils.is.element(container)) {
|
||||||
target.appendChild(container);
|
target.appendChild(container);
|
||||||
} else {
|
} else if (container) {
|
||||||
target.insertAdjacentHTML('beforeend', container);
|
target.insertAdjacentHTML('beforeend', container);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9436,6 +9503,10 @@ var Listeners = function () {
|
|||||||
// If autoplay, then load advertisement if required
|
// If autoplay, then load advertisement if required
|
||||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||||
utils.on(this.player.media, 'playing', function () {
|
utils.on(this.player.media, 'playing', function () {
|
||||||
|
if (!_this3.player.ads) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If ads are enabled, wait for them first
|
// If ads are enabled, wait for them first
|
||||||
if (_this3.player.ads.enabled && !_this3.player.ads.initialized) {
|
if (_this3.player.ads.enabled && !_this3.player.ads.initialized) {
|
||||||
// Wait for manager response
|
// Wait for manager response
|
||||||
@ -9477,7 +9548,7 @@ var Listeners = function () {
|
|||||||
|
|
||||||
// Disable right click
|
// Disable right click
|
||||||
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
||||||
utils.on(this.player.media, 'contextmenu', function (event) {
|
utils.on(this.player.elements.wrapper, 'contextmenu', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
@ -10763,7 +10834,11 @@ var youtube = {
|
|||||||
return Number(instance.getCurrentTime());
|
return Number(instance.getCurrentTime());
|
||||||
},
|
},
|
||||||
set: function set(time) {
|
set: function set(time) {
|
||||||
|
// Vimeo will automatically play on seek
|
||||||
|
var paused = player.media.paused;
|
||||||
|
|
||||||
// Set seeking flag
|
// Set seeking flag
|
||||||
|
|
||||||
player.media.seeking = true;
|
player.media.seeking = true;
|
||||||
|
|
||||||
// Trigger seeking
|
// Trigger seeking
|
||||||
@ -10771,6 +10846,11 @@ var youtube = {
|
|||||||
|
|
||||||
// Seek after events sent
|
// Seek after events sent
|
||||||
instance.seekTo(time);
|
instance.seekTo(time);
|
||||||
|
|
||||||
|
// Restore pause state
|
||||||
|
if (paused) {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -11008,10 +11088,14 @@ var vimeo = {
|
|||||||
setAspectRatio: function setAspectRatio(input) {
|
setAspectRatio: function setAspectRatio(input) {
|
||||||
var ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
var ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
||||||
var padding = 100 / ratio[0] * ratio[1];
|
var padding = 100 / ratio[0] * ratio[1];
|
||||||
|
this.elements.wrapper.style.paddingBottom = padding + '%';
|
||||||
|
|
||||||
|
if (this.supported.ui) {
|
||||||
var height = 240;
|
var height = 240;
|
||||||
var offset = (height - padding) / (height / 50);
|
var offset = (height - padding) / (height / 50);
|
||||||
this.elements.wrapper.style.paddingBottom = padding + '%';
|
|
||||||
this.media.style.transform = 'translateY(-' + offset + '%)';
|
this.media.style.transform = 'translateY(-' + offset + '%)';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -11030,7 +11114,8 @@ var vimeo = {
|
|||||||
title: false,
|
title: false,
|
||||||
speed: true,
|
speed: true,
|
||||||
transparent: 0,
|
transparent: 0,
|
||||||
gesture: 'media'
|
gesture: 'media',
|
||||||
|
playsinline: !this.config.fullscreen.iosNative
|
||||||
};
|
};
|
||||||
var params = utils.buildUrlParams(options);
|
var params = utils.buildUrlParams(options);
|
||||||
|
|
||||||
@ -11064,6 +11149,11 @@ var vimeo = {
|
|||||||
player.media.paused = true;
|
player.media.paused = true;
|
||||||
player.media.currentTime = 0;
|
player.media.currentTime = 0;
|
||||||
|
|
||||||
|
// Disable native text track rendering
|
||||||
|
if (player.supported.ui) {
|
||||||
|
player.embed.disableTextTrack();
|
||||||
|
}
|
||||||
|
|
||||||
// Create a faux HTML5 API using the Vimeo API
|
// Create a faux HTML5 API using the Vimeo API
|
||||||
player.media.play = function () {
|
player.media.play = function () {
|
||||||
player.embed.play().then(function () {
|
player.embed.play().then(function () {
|
||||||
@ -11102,7 +11192,9 @@ var vimeo = {
|
|||||||
utils.dispatchEvent.call(player, player.media, 'seeking');
|
utils.dispatchEvent.call(player, player.media, 'seeking');
|
||||||
|
|
||||||
// Seek after events
|
// Seek after events
|
||||||
player.embed.setCurrentTime(time);
|
player.embed.setCurrentTime(time).catch(function () {
|
||||||
|
// Do nothing
|
||||||
|
});
|
||||||
|
|
||||||
// Restore pause state
|
// Restore pause state
|
||||||
if (paused) {
|
if (paused) {
|
||||||
@ -11282,6 +11374,15 @@ var vimeo = {
|
|||||||
if (parseInt(data.percent, 10) === 1) {
|
if (parseInt(data.percent, 10) === 1) {
|
||||||
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get duration as if we do it before load, it gives an incorrect value
|
||||||
|
// https://github.com/sampotts/plyr/issues/891
|
||||||
|
player.embed.getDuration().then(function (value) {
|
||||||
|
if (value !== player.media.duration) {
|
||||||
|
player.media.duration = value;
|
||||||
|
utils.dispatchEvent.call(player, player.media, 'durationchange');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('seeked', function () {
|
player.embed.on('seeked', function () {
|
||||||
@ -11433,7 +11534,7 @@ var source = {
|
|||||||
_this2.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
_this2.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
_this2.supported = support.check(_this2.type, _this2.provider, _this2.config.inline);
|
_this2.supported = support.check(_this2.type, _this2.provider, _this2.config.playsinline);
|
||||||
|
|
||||||
// Create new markup
|
// Create new markup
|
||||||
switch (_this2.provider + ':' + _this2.type) {
|
switch (_this2.provider + ':' + _this2.type) {
|
||||||
@ -11481,7 +11582,7 @@ var source = {
|
|||||||
if (_this2.config.muted) {
|
if (_this2.config.muted) {
|
||||||
_this2.media.setAttribute('muted', '');
|
_this2.media.setAttribute('muted', '');
|
||||||
}
|
}
|
||||||
if (_this2.config.inline) {
|
if (_this2.config.playsinline) {
|
||||||
_this2.media.setAttribute('playsinline', '');
|
_this2.media.setAttribute('playsinline', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11562,7 +11663,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set config
|
// Set config
|
||||||
this.config = utils.extend({}, defaults, options, function () {
|
this.config = utils.extend({}, defaults, options || {}, function () {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(_this.media.getAttribute('data-plyr-config'));
|
return JSON.parse(_this.media.getAttribute('data-plyr-config'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -11599,7 +11700,8 @@ var Plyr = function () {
|
|||||||
// Options
|
// Options
|
||||||
this.options = {
|
this.options = {
|
||||||
speed: [],
|
speed: [],
|
||||||
quality: []
|
quality: [],
|
||||||
|
captions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
@ -11684,12 +11786,17 @@ var Plyr = function () {
|
|||||||
if (truthy.includes(params.autoplay)) {
|
if (truthy.includes(params.autoplay)) {
|
||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (truthy.includes(params.playsinline)) {
|
|
||||||
this.config.inline = true;
|
|
||||||
}
|
|
||||||
if (truthy.includes(params.loop)) {
|
if (truthy.includes(params.loop)) {
|
||||||
this.config.loop.active = true;
|
this.config.loop.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace fullscreen.iosNative with this playsinline config option
|
||||||
|
// YouTube requires the playsinline in the URL
|
||||||
|
if (this.isYouTube) {
|
||||||
|
this.config.playsinline = truthy.includes(params.playsinline);
|
||||||
|
} else {
|
||||||
|
this.config.playsinline = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <div> with attributes
|
// <div> with attributes
|
||||||
@ -11723,7 +11830,7 @@ var Plyr = function () {
|
|||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('playsinline')) {
|
if (this.media.hasAttribute('playsinline')) {
|
||||||
this.config.inline = true;
|
this.config.playsinline = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('muted')) {
|
if (this.media.hasAttribute('muted')) {
|
||||||
this.config.muted = true;
|
this.config.muted = true;
|
||||||
@ -11740,7 +11847,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for support again but with type
|
// Check for support again but with type
|
||||||
this.supported = support.check(this.type, this.provider, this.config.inline);
|
this.supported = support.check(this.type, this.provider, this.config.playsinline);
|
||||||
|
|
||||||
// If no support for even API, bail
|
// If no support for even API, bail
|
||||||
if (!this.supported.api) {
|
if (!this.supported.api) {
|
||||||
@ -11960,13 +12067,13 @@ var Plyr = function () {
|
|||||||
* @param {boolean} input - Whether to enable captions
|
* @param {boolean} input - Whether to enable captions
|
||||||
*/
|
*/
|
||||||
value: function toggleCaptions(input) {
|
value: function toggleCaptions(input) {
|
||||||
// If there's no full support, or there's no caption toggle
|
// If there's no full support
|
||||||
if (!this.supported.ui || !utils.is.element(this.elements.buttons.captions)) {
|
if (!this.supported.ui) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the method is called without parameter, toggle based on current value
|
// If the method is called without parameter, toggle based on current value
|
||||||
var show = utils.is.boolean(input) ? input : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;
|
var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||||
|
|
||||||
// Nothing to change...
|
// Nothing to change...
|
||||||
if (this.captions.active === show) {
|
if (this.captions.active === show) {
|
||||||
@ -12325,7 +12432,7 @@ var Plyr = function () {
|
|||||||
}, {
|
}, {
|
||||||
key: 'playing',
|
key: 'playing',
|
||||||
get: function get() {
|
get: function get() {
|
||||||
return Boolean(!this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
return Boolean(this.ready && !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12354,7 +12461,7 @@ var Plyr = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
this.media.currentTime = parseFloat(targetTime.toFixed(4));
|
this.media.currentTime = targetTime;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
this.debug.log('Seeking to ' + this.currentTime + ' seconds');
|
this.debug.log('Seeking to ' + this.currentTime + ' seconds');
|
||||||
@ -12411,7 +12518,7 @@ var Plyr = function () {
|
|||||||
key: 'duration',
|
key: 'duration',
|
||||||
get: function get() {
|
get: function get() {
|
||||||
// Faux duration set via config
|
// Faux duration set via config
|
||||||
var fauxDuration = parseInt(this.config.duration, 10);
|
var fauxDuration = parseFloat(this.config.duration);
|
||||||
|
|
||||||
// True duration
|
// True duration
|
||||||
var realDuration = this.media ? Number(this.media.duration) : 0;
|
var realDuration = this.media ? Number(this.media.duration) : 0;
|
||||||
@ -12762,17 +12869,29 @@ var Plyr = function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions based on input
|
|
||||||
this.toggleCaptions(!utils.is.empty(input));
|
|
||||||
|
|
||||||
// If empty string is passed, assume disable captions
|
// If empty string is passed, assume disable captions
|
||||||
if (utils.is.empty(input)) {
|
if (utils.is.empty(input)) {
|
||||||
|
this.toggleCaptions(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize
|
// Normalize
|
||||||
var language = input.toLowerCase();
|
var language = input.toLowerCase();
|
||||||
|
|
||||||
|
// Check for support
|
||||||
|
if (!this.options.captions.includes(language)) {
|
||||||
|
this.debug.warn('Unsupported language option: ' + language);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure captions are enabled
|
||||||
|
this.toggleCaptions(true);
|
||||||
|
|
||||||
|
// Enabled only
|
||||||
|
if (language === 'enabled') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If nothing to change, bail
|
// If nothing to change, bail
|
||||||
if (this.language === language) {
|
if (this.language === language) {
|
||||||
return;
|
return;
|
||||||
|
2
dist/plyr.polyfilled.js.map
vendored
2
dist/plyr.polyfilled.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js
vendored
2
dist/plyr.polyfilled.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js.map
vendored
2
dist/plyr.polyfilled.min.js.map
vendored
File diff suppressed because one or more lines are too long
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "3.1.0",
|
"version": "3.2.1",
|
||||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||||
"homepage": "https://plyr.io",
|
"homepage": "https://plyr.io",
|
||||||
"main": "./dist/plyr.js",
|
"main": "./dist/plyr.js",
|
||||||
@ -9,14 +9,14 @@
|
|||||||
"style": "./dist/plyr.css",
|
"style": "./dist/plyr.css",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-eslint": "^8.2.2",
|
"babel-eslint": "^8.2.3",
|
||||||
"babel-plugin-external-helpers": "^6.22.0",
|
"babel-plugin-external-helpers": "^6.22.0",
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-airbnb-base": "^12.1.0",
|
"eslint-config-airbnb-base": "^12.1.0",
|
||||||
"eslint-config-prettier": "^2.9.0",
|
"eslint-config-prettier": "^2.9.0",
|
||||||
"eslint-plugin-import": "^2.10.0",
|
"eslint-plugin-import": "^2.11.0",
|
||||||
"git-branch": "^2.0.1",
|
"git-branch": "^2.0.1",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-autoprefixer": "^5.0.0",
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
"gulp-rename": "^1.2.2",
|
"gulp-rename": "^1.2.2",
|
||||||
"gulp-replace": "^0.6.1",
|
"gulp-replace": "^0.6.1",
|
||||||
"gulp-s3": "^0.11.0",
|
"gulp-s3": "^0.11.0",
|
||||||
"gulp-sass": "^3.2.1",
|
"gulp-sass": "^4.0.1",
|
||||||
"gulp-size": "^3.0.0",
|
"gulp-size": "^3.0.0",
|
||||||
"gulp-sourcemaps": "^2.6.4",
|
"gulp-sourcemaps": "^2.6.4",
|
||||||
"gulp-svgmin": "^1.2.4",
|
"gulp-svgmin": "^1.2.4",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"rollup-plugin-node-resolve": "^3.3.0",
|
"rollup-plugin-node-resolve": "^3.3.0",
|
||||||
"run-sequence": "^2.2.1",
|
"run-sequence": "^2.2.1",
|
||||||
"stylelint": "^9.2.0",
|
"stylelint": "^9.2.0",
|
||||||
"stylelint-config-prettier": "^3.0.4",
|
"stylelint-config-prettier": "^3.2.0",
|
||||||
"stylelint-config-recommended": "^2.1.0",
|
"stylelint-config-recommended": "^2.1.0",
|
||||||
"stylelint-config-sass-guidelines": "^5.0.0",
|
"stylelint-config-sass-guidelines": "^5.0.0",
|
||||||
"stylelint-order": "^0.8.1",
|
"stylelint-order": "^0.8.1",
|
||||||
|
@ -128,7 +128,7 @@ 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:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.1.0/plyr.js"></script>
|
<script src="https://cdn.plyr.io/3.2.1/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
_Note_: Be sure to read the [polyfills](#polyfills) section below about browser compatibility
|
_Note_: Be sure to read the [polyfills](#polyfills) section below about browser compatibility
|
||||||
@ -144,13 +144,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:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.1.0/plyr.css">
|
<link rel="stylesheet" href="https://cdn.plyr.io/3.2.1/plyr.css">
|
||||||
```
|
```
|
||||||
|
|
||||||
### SVG Sprite
|
### 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
|
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.1.0/plyr.svg`.
|
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.2.1/plyr.svg`.
|
||||||
|
|
||||||
## Ads
|
## Ads
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import support from './support';
|
import support from './support';
|
||||||
import utils from './utils';
|
import utils from './utils';
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
|
import i18n from './i18n';
|
||||||
|
|
||||||
const captions = {
|
const captions = {
|
||||||
// Setup captions
|
// Setup captions
|
||||||
@ -46,6 +47,7 @@ const captions = {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject the container
|
// Inject the container
|
||||||
if (!utils.is.element(this.elements.captions)) {
|
if (!utils.is.element(this.elements.captions)) {
|
||||||
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
||||||
@ -148,7 +150,49 @@ const captions = {
|
|||||||
|
|
||||||
// Get the current track for the current language
|
// Get the current track for the current language
|
||||||
getCurrentTrack() {
|
getCurrentTrack() {
|
||||||
return captions.getTracks.call(this).find(track => track.language.toLowerCase() === this.language);
|
const tracks = captions.getTracks.call(this);
|
||||||
|
|
||||||
|
if (!tracks.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get track based on current language
|
||||||
|
let track = tracks.find(track => track.language.toLowerCase() === this.language);
|
||||||
|
|
||||||
|
// Get the <track> with default attribute
|
||||||
|
if (!track) {
|
||||||
|
track = utils.getElement.call(this, 'track[default]');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the first track
|
||||||
|
if (!track) {
|
||||||
|
[track] = tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
return track;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get UI label for track
|
||||||
|
getLabel(track) {
|
||||||
|
let currentTrack = track;
|
||||||
|
|
||||||
|
if (!utils.is.track(currentTrack) && support.textTracks && this.captions.active) {
|
||||||
|
currentTrack = captions.getCurrentTrack.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.is.track(currentTrack)) {
|
||||||
|
if (!utils.is.empty(currentTrack.label)) {
|
||||||
|
return currentTrack.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils.is.empty(currentTrack.language)) {
|
||||||
|
return track.language.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('enabled', this.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.get('disabled', this.config);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Display active caption if it contains text
|
// Display active caption if it contains text
|
||||||
@ -206,11 +250,6 @@ const captions = {
|
|||||||
|
|
||||||
// Display captions container and button (for initialization)
|
// Display captions container and button (for initialization)
|
||||||
show() {
|
show() {
|
||||||
// If there's no caption toggle, bail
|
|
||||||
if (!utils.is.element(this.elements.buttons.captions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the value from storage
|
// Try to load the value from storage
|
||||||
let active = this.storage.get('captions');
|
let active = this.storage.get('captions');
|
||||||
|
|
||||||
|
90
src/js/controls.js
vendored
90
src/js/controls.js
vendored
@ -15,10 +15,7 @@ const browser = utils.getBrowser();
|
|||||||
const controls = {
|
const controls = {
|
||||||
// Webkit polyfill for lower fill range
|
// Webkit polyfill for lower fill range
|
||||||
updateRangeFill(target) {
|
updateRangeFill(target) {
|
||||||
// WebKit only
|
|
||||||
if (!browser.isWebkit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get range from event if event passed
|
// Get range from event if event passed
|
||||||
const range = utils.is.event(target) ? target.target : target;
|
const range = utils.is.event(target) ? target.target : target;
|
||||||
@ -28,6 +25,14 @@ const controls = {
|
|||||||
return;
|
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
|
// Set CSS custom property
|
||||||
range.style.setProperty('--value', `${range.value / range.max * 100}%`);
|
range.style.setProperty('--value', `${range.value / range.max * 100}%`);
|
||||||
},
|
},
|
||||||
@ -52,6 +57,7 @@ const controls = {
|
|||||||
icon,
|
icon,
|
||||||
utils.extend(attributes, {
|
utils.extend(attributes, {
|
||||||
role: 'presentation',
|
role: 'presentation',
|
||||||
|
focusable: 'false',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -238,6 +244,7 @@ const controls = {
|
|||||||
'label',
|
'label',
|
||||||
{
|
{
|
||||||
for: attributes.id,
|
for: attributes.id,
|
||||||
|
id: `${attributes.id}-label`,
|
||||||
class: this.config.classNames.hidden,
|
class: this.config.classNames.hidden,
|
||||||
},
|
},
|
||||||
i18n.get(type, this.config),
|
i18n.get(type, this.config),
|
||||||
@ -255,6 +262,12 @@ const controls = {
|
|||||||
step: 0.01,
|
step: 0.01,
|
||||||
value: 0,
|
value: 0,
|
||||||
autocomplete: 'off',
|
autocomplete: 'off',
|
||||||
|
// A11y fixes for https://github.com/sampotts/plyr/issues/905
|
||||||
|
role: 'slider',
|
||||||
|
'aria-labelledby': `${attributes.id}-label`,
|
||||||
|
'aria-valuemin': 0,
|
||||||
|
'aria-valuemax': 100,
|
||||||
|
'aria-valuenow': 0,
|
||||||
},
|
},
|
||||||
attributes,
|
attributes,
|
||||||
),
|
),
|
||||||
@ -281,6 +294,8 @@ const controls = {
|
|||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
value: 0,
|
value: 0,
|
||||||
|
role: 'presentation',
|
||||||
|
'aria-hidden': true,
|
||||||
},
|
},
|
||||||
attributes,
|
attributes,
|
||||||
),
|
),
|
||||||
@ -456,6 +471,9 @@ const controls = {
|
|||||||
const toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
const toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
|
||||||
controls.toggleTab.call(this, type, toggle);
|
controls.toggleTab.call(this, type, toggle);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If we're hiding, nothing more to do
|
// If we're hiding, nothing more to do
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -495,10 +513,12 @@ const controls = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Sort options by the config and then render options
|
// Sort options by the config and then render options
|
||||||
this.options.quality.sort((a, b) => {
|
this.options.quality
|
||||||
|
.sort((a, b) => {
|
||||||
const sorting = this.config.quality.options;
|
const sorting = this.config.quality.options;
|
||||||
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
|
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
|
||||||
}).forEach(quality => {
|
})
|
||||||
|
.forEach(quality => {
|
||||||
const label = controls.getLabel.call(this, 'quality', quality);
|
const label = controls.getLabel.call(this, 'quality', quality);
|
||||||
controls.createMenuItem.call(this, quality, list, type, label, getBadge(quality));
|
controls.createMenuItem.call(this, quality, list, type, label, getBadge(quality));
|
||||||
});
|
});
|
||||||
@ -517,10 +537,11 @@ const controls = {
|
|||||||
if (utils.is.number(value)) {
|
if (utils.is.number(value)) {
|
||||||
return `${value}p`;
|
return `${value}p`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.toTitleCase(value);
|
return utils.toTitleCase(value);
|
||||||
|
|
||||||
case 'captions':
|
case 'captions':
|
||||||
return controls.getLanguage.call(this);
|
return captions.getLabel.call(this);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@ -535,7 +556,16 @@ const controls = {
|
|||||||
|
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
case 'captions':
|
case 'captions':
|
||||||
value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
|
if (this.captions.active) {
|
||||||
|
if (this.options.captions.length > 2 || !this.options.captions.some(lang => lang === 'enabled')) {
|
||||||
|
value = this.captions.language;
|
||||||
|
} else {
|
||||||
|
value = 'enabled';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -566,17 +596,19 @@ const controls = {
|
|||||||
list = pane && pane.querySelector('ul');
|
list = pane && pane.querySelector('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the label
|
// If there's no list it means it's not been rendered...
|
||||||
if (!utils.is.empty(value)) {
|
if (!utils.is.element(list)) {
|
||||||
const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);
|
return;
|
||||||
label.innerHTML = controls.getLabel.call(this, setting, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the radio option
|
// Update the label
|
||||||
|
const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);
|
||||||
|
label.innerHTML = controls.getLabel.call(this, setting, value);
|
||||||
|
|
||||||
|
// Find the radio option and check it
|
||||||
const target = list && list.querySelector(`input[value="${value}"]`);
|
const target = list && list.querySelector(`input[value="${value}"]`);
|
||||||
|
|
||||||
if (utils.is.element(target)) {
|
if (utils.is.element(target)) {
|
||||||
// Check it
|
|
||||||
target.checked = true;
|
target.checked = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -627,21 +659,7 @@ const controls = {
|
|||||||
|
|
||||||
// Get current selected caption language
|
// Get current selected caption language
|
||||||
// TODO: rework this to user the getter in the API?
|
// TODO: rework this to user the getter in the API?
|
||||||
getLanguage() {
|
|
||||||
if (!this.supported.ui) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
|
|
||||||
const currentTrack = captions.getCurrentTrack.call(this);
|
|
||||||
|
|
||||||
if (utils.is.track(currentTrack)) {
|
|
||||||
return currentTrack.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i18n.get('disabled', this.config);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Set a list of available captions languages
|
// Set a list of available captions languages
|
||||||
setCaptionsMenu() {
|
setCaptionsMenu() {
|
||||||
@ -656,6 +674,9 @@ const controls = {
|
|||||||
// Empty the menu
|
// Empty the menu
|
||||||
utils.emptyElement(list);
|
utils.emptyElement(list);
|
||||||
|
|
||||||
|
// Check if we need to toggle the parent
|
||||||
|
controls.checkMenu.call(this);
|
||||||
|
|
||||||
// If there's no captions, bail
|
// If there's no captions, bail
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
@ -663,8 +684,8 @@ const controls = {
|
|||||||
|
|
||||||
// Re-map the tracks into just the data we need
|
// Re-map the tracks into just the data we need
|
||||||
const tracks = captions.getTracks.call(this).map(track => ({
|
const tracks = captions.getTracks.call(this).map(track => ({
|
||||||
language: track.language,
|
language: !utils.is.empty(track.language) ? track.language : 'enabled',
|
||||||
label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),
|
label: captions.getLabel.call(this, track),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Add the "Disabled" option to turn off captions
|
// Add the "Disabled" option to turn off captions
|
||||||
@ -680,12 +701,15 @@ const controls = {
|
|||||||
track.language,
|
track.language,
|
||||||
list,
|
list,
|
||||||
'language',
|
'language',
|
||||||
track.label || track.language,
|
track.label,
|
||||||
controls.createBadge.call(this, track.language.toUpperCase()),
|
track.language !== 'enabled' ? controls.createBadge.call(this, track.language.toUpperCase()) : null,
|
||||||
track.language.toLowerCase() === this.captions.language.toLowerCase(),
|
track.language.toLowerCase() === this.captions.language.toLowerCase(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Store reference
|
||||||
|
this.options.captions = tracks.map(track => track.language);
|
||||||
|
|
||||||
controls.updateSetting.call(this, type, list);
|
controls.updateSetting.call(this, type, list);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1211,7 +1235,7 @@ const controls = {
|
|||||||
seektime: this.config.seekTime,
|
seektime: this.config.seekTime,
|
||||||
speed: this.speed,
|
speed: this.speed,
|
||||||
quality: this.quality,
|
quality: this.quality,
|
||||||
captions: controls.getLanguage.call(this),
|
captions: captions.getLabel.call(this),
|
||||||
// TODO: Looping
|
// TODO: Looping
|
||||||
// loop: 'None',
|
// loop: 'None',
|
||||||
});
|
});
|
||||||
|
@ -56,7 +56,7 @@ const defaults = {
|
|||||||
// Sprite (for icons)
|
// Sprite (for icons)
|
||||||
loadSprite: true,
|
loadSprite: true,
|
||||||
iconPrefix: 'plyr',
|
iconPrefix: 'plyr',
|
||||||
iconUrl: 'https://cdn.plyr.io/3.1.0/plyr.svg',
|
iconUrl: 'https://cdn.plyr.io/3.2.1/plyr.svg',
|
||||||
|
|
||||||
// Blank video (used to prevent errors on source change)
|
// Blank video (used to prevent errors on source change)
|
||||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||||
@ -115,7 +115,7 @@ const defaults = {
|
|||||||
// Captions settings
|
// Captions settings
|
||||||
captions: {
|
captions: {
|
||||||
active: false,
|
active: false,
|
||||||
language: window.navigator.language ? window.navigator.language.split('-')[0] : 'en',
|
language: (navigator.language || navigator.userLanguage).split('-')[0],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fullscreen settings
|
// Fullscreen settings
|
||||||
@ -185,6 +185,7 @@ const defaults = {
|
|||||||
all: 'All',
|
all: 'All',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
disabled: 'Disabled',
|
disabled: 'Disabled',
|
||||||
|
enabled: 'Enabled',
|
||||||
advertisement: 'Ad',
|
advertisement: 'Ad',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class Fullscreen {
|
|||||||
static get prefix() {
|
static get prefix() {
|
||||||
// No prefix
|
// No prefix
|
||||||
if (utils.is.function(document.exitFullscreen)) {
|
if (utils.is.function(document.exitFullscreen)) {
|
||||||
return false;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for fullscreen support by vendor prefix
|
// Check for fullscreen support by vendor prefix
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// Plyr Event Listeners
|
// Plyr Event Listeners
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import support from './support';
|
|
||||||
import utils from './utils';
|
import utils from './utils';
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
import ui from './ui';
|
import ui from './ui';
|
||||||
@ -293,6 +292,10 @@ class Listeners {
|
|||||||
// If autoplay, then load advertisement if required
|
// If autoplay, then load advertisement if required
|
||||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||||
utils.on(this.player.media, 'playing', () => {
|
utils.on(this.player.media, 'playing', () => {
|
||||||
|
if (!this.player.ads) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If ads are enabled, wait for them first
|
// If ads are enabled, wait for them first
|
||||||
if (this.player.ads.enabled && !this.player.ads.initialized) {
|
if (this.player.ads.enabled && !this.player.ads.initialized) {
|
||||||
// Wait for manager response
|
// Wait for manager response
|
||||||
@ -331,7 +334,7 @@ class Listeners {
|
|||||||
// Disable right click
|
// Disable right click
|
||||||
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
||||||
utils.on(
|
utils.on(
|
||||||
this.player.media,
|
this.player.elements.wrapper,
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
event => {
|
event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -35,10 +35,14 @@ const vimeo = {
|
|||||||
setAspectRatio(input) {
|
setAspectRatio(input) {
|
||||||
const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');
|
||||||
const padding = 100 / ratio[0] * ratio[1];
|
const padding = 100 / ratio[0] * ratio[1];
|
||||||
|
this.elements.wrapper.style.paddingBottom = `${padding}%`;
|
||||||
|
|
||||||
|
if (this.supported.ui) {
|
||||||
const height = 240;
|
const height = 240;
|
||||||
const offset = (height - padding) / (height / 50);
|
const offset = (height - padding) / (height / 50);
|
||||||
this.elements.wrapper.style.paddingBottom = `${padding}%`;
|
|
||||||
this.media.style.transform = `translateY(-${offset}%)`;
|
this.media.style.transform = `translateY(-${offset}%)`;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// API Ready
|
// API Ready
|
||||||
@ -55,6 +59,7 @@ const vimeo = {
|
|||||||
speed: true,
|
speed: true,
|
||||||
transparent: 0,
|
transparent: 0,
|
||||||
gesture: 'media',
|
gesture: 'media',
|
||||||
|
playsinline: !this.config.fullscreen.iosNative,
|
||||||
};
|
};
|
||||||
const params = utils.buildUrlParams(options);
|
const params = utils.buildUrlParams(options);
|
||||||
|
|
||||||
@ -88,6 +93,11 @@ const vimeo = {
|
|||||||
player.media.paused = true;
|
player.media.paused = true;
|
||||||
player.media.currentTime = 0;
|
player.media.currentTime = 0;
|
||||||
|
|
||||||
|
// Disable native text track rendering
|
||||||
|
if (player.supported.ui) {
|
||||||
|
player.embed.disableTextTrack();
|
||||||
|
}
|
||||||
|
|
||||||
// Create a faux HTML5 API using the Vimeo API
|
// Create a faux HTML5 API using the Vimeo API
|
||||||
player.media.play = () => {
|
player.media.play = () => {
|
||||||
player.embed.play().then(() => {
|
player.embed.play().then(() => {
|
||||||
@ -124,7 +134,9 @@ const vimeo = {
|
|||||||
utils.dispatchEvent.call(player, player.media, 'seeking');
|
utils.dispatchEvent.call(player, player.media, 'seeking');
|
||||||
|
|
||||||
// Seek after events
|
// Seek after events
|
||||||
player.embed.setCurrentTime(time);
|
player.embed.setCurrentTime(time).catch(() => {
|
||||||
|
// Do nothing
|
||||||
|
});
|
||||||
|
|
||||||
// Restore pause state
|
// Restore pause state
|
||||||
if (paused) {
|
if (paused) {
|
||||||
@ -310,6 +322,15 @@ const vimeo = {
|
|||||||
if (parseInt(data.percent, 10) === 1) {
|
if (parseInt(data.percent, 10) === 1) {
|
||||||
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
utils.dispatchEvent.call(player, player.media, 'canplaythrough');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get duration as if we do it before load, it gives an incorrect value
|
||||||
|
// https://github.com/sampotts/plyr/issues/891
|
||||||
|
player.embed.getDuration().then(value => {
|
||||||
|
if (value !== player.media.duration) {
|
||||||
|
player.media.duration = value;
|
||||||
|
utils.dispatchEvent.call(player, player.media, 'durationchange');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('seeked', () => {
|
player.embed.on('seeked', () => {
|
||||||
|
@ -270,6 +270,9 @@ const youtube = {
|
|||||||
return Number(instance.getCurrentTime());
|
return Number(instance.getCurrentTime());
|
||||||
},
|
},
|
||||||
set(time) {
|
set(time) {
|
||||||
|
// Vimeo will automatically play on seek
|
||||||
|
const { paused } = player.media;
|
||||||
|
|
||||||
// Set seeking flag
|
// Set seeking flag
|
||||||
player.media.seeking = true;
|
player.media.seeking = true;
|
||||||
|
|
||||||
@ -278,6 +281,11 @@ const youtube = {
|
|||||||
|
|
||||||
// Seek after events sent
|
// Seek after events sent
|
||||||
instance.seekTo(time);
|
instance.seekTo(time);
|
||||||
|
|
||||||
|
// Restore pause state
|
||||||
|
if (paused) {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v3.1.0
|
// plyr.js v3.2.1
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@ -97,6 +97,7 @@ class Plyr {
|
|||||||
this.options = {
|
this.options = {
|
||||||
speed: [],
|
speed: [],
|
||||||
quality: [],
|
quality: [],
|
||||||
|
captions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
@ -184,12 +185,17 @@ class Plyr {
|
|||||||
if (truthy.includes(params.autoplay)) {
|
if (truthy.includes(params.autoplay)) {
|
||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (truthy.includes(params.playsinline)) {
|
|
||||||
this.config.inline = true;
|
|
||||||
}
|
|
||||||
if (truthy.includes(params.loop)) {
|
if (truthy.includes(params.loop)) {
|
||||||
this.config.loop.active = true;
|
this.config.loop.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace fullscreen.iosNative with this playsinline config option
|
||||||
|
// YouTube requires the playsinline in the URL
|
||||||
|
if (this.isYouTube) {
|
||||||
|
this.config.playsinline = truthy.includes(params.playsinline);
|
||||||
|
} else {
|
||||||
|
this.config.playsinline = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// <div> with attributes
|
// <div> with attributes
|
||||||
@ -223,7 +229,7 @@ class Plyr {
|
|||||||
this.config.autoplay = true;
|
this.config.autoplay = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('playsinline')) {
|
if (this.media.hasAttribute('playsinline')) {
|
||||||
this.config.inline = true;
|
this.config.playsinline = true;
|
||||||
}
|
}
|
||||||
if (this.media.hasAttribute('muted')) {
|
if (this.media.hasAttribute('muted')) {
|
||||||
this.config.muted = true;
|
this.config.muted = true;
|
||||||
@ -240,7 +246,7 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for support again but with type
|
// Check for support again but with type
|
||||||
this.supported = support.check(this.type, this.provider, this.config.inline);
|
this.supported = support.check(this.type, this.provider, this.config.playsinline);
|
||||||
|
|
||||||
// If no support for even API, bail
|
// If no support for even API, bail
|
||||||
if (!this.supported.api) {
|
if (!this.supported.api) {
|
||||||
@ -368,7 +374,7 @@ class Plyr {
|
|||||||
* Get playing state
|
* Get playing state
|
||||||
*/
|
*/
|
||||||
get playing() {
|
get playing() {
|
||||||
return Boolean(!this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
return Boolean(this.ready && !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -446,7 +452,7 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
this.media.currentTime = parseFloat(targetTime.toFixed(4));
|
this.media.currentTime = targetTime;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
this.debug.log(`Seeking to ${this.currentTime} seconds`);
|
this.debug.log(`Seeking to ${this.currentTime} seconds`);
|
||||||
@ -492,7 +498,7 @@ class Plyr {
|
|||||||
*/
|
*/
|
||||||
get duration() {
|
get duration() {
|
||||||
// Faux duration set via config
|
// Faux duration set via config
|
||||||
const fauxDuration = parseInt(this.config.duration, 10);
|
const fauxDuration = parseFloat(this.config.duration);
|
||||||
|
|
||||||
// True duration
|
// True duration
|
||||||
const realDuration = this.media ? Number(this.media.duration) : 0;
|
const realDuration = this.media ? Number(this.media.duration) : 0;
|
||||||
@ -839,8 +845,8 @@ class Plyr {
|
|||||||
* @param {boolean} input - Whether to enable captions
|
* @param {boolean} input - Whether to enable captions
|
||||||
*/
|
*/
|
||||||
toggleCaptions(input) {
|
toggleCaptions(input) {
|
||||||
// If there's no full support, or there's no caption toggle
|
// If there's no full support
|
||||||
if (!this.supported.ui || !utils.is.element(this.elements.buttons.captions)) {
|
if (!this.supported.ui) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,17 +881,29 @@ class Plyr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions based on input
|
|
||||||
this.toggleCaptions(!utils.is.empty(input));
|
|
||||||
|
|
||||||
// If empty string is passed, assume disable captions
|
// If empty string is passed, assume disable captions
|
||||||
if (utils.is.empty(input)) {
|
if (utils.is.empty(input)) {
|
||||||
|
this.toggleCaptions(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize
|
// Normalize
|
||||||
const language = input.toLowerCase();
|
const language = input.toLowerCase();
|
||||||
|
|
||||||
|
// Check for support
|
||||||
|
if (!this.options.captions.includes(language)) {
|
||||||
|
this.debug.warn(`Unsupported language option: ${language}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure captions are enabled
|
||||||
|
this.toggleCaptions(true);
|
||||||
|
|
||||||
|
// Enabled only
|
||||||
|
if (language === 'enabled') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If nothing to change, bail
|
// If nothing to change, bail
|
||||||
if (this.language === language) {
|
if (this.language === language) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr Polyfilled Build
|
// Plyr Polyfilled Build
|
||||||
// plyr.js v3.1.0
|
// plyr.js v3.2.1
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
@ -55,7 +55,7 @@ const source = {
|
|||||||
this.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
this.provider = !utils.is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5;
|
||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
this.supported = support.check(this.type, this.provider, this.config.inline);
|
this.supported = support.check(this.type, this.provider, this.config.playsinline);
|
||||||
|
|
||||||
// Create new markup
|
// Create new markup
|
||||||
switch (`${this.provider}:${this.type}`) {
|
switch (`${this.provider}:${this.type}`) {
|
||||||
@ -103,7 +103,7 @@ const source = {
|
|||||||
if (this.config.muted) {
|
if (this.config.muted) {
|
||||||
this.media.setAttribute('muted', '');
|
this.media.setAttribute('muted', '');
|
||||||
}
|
}
|
||||||
if (this.config.inline) {
|
if (this.config.playsinline) {
|
||||||
this.media.setAttribute('playsinline', '');
|
this.media.setAttribute('playsinline', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,16 @@ const support = {
|
|||||||
|
|
||||||
// Check for support
|
// Check for support
|
||||||
// Basic functionality vs full UI
|
// Basic functionality vs full UI
|
||||||
check(type, provider, inline) {
|
check(type, provider, playsinline) {
|
||||||
let api = false;
|
let api = false;
|
||||||
let ui = false;
|
let ui = false;
|
||||||
const browser = utils.getBrowser();
|
const browser = utils.getBrowser();
|
||||||
const playsInline = browser.isIPhone && inline && support.inline;
|
const canPlayInline = browser.isIPhone && playsinline && support.playsinline;
|
||||||
|
|
||||||
switch (`${provider}:${type}`) {
|
switch (`${provider}:${type}`) {
|
||||||
case 'html5:video':
|
case 'html5:video':
|
||||||
api = support.video;
|
api = support.video;
|
||||||
ui = api && support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = api && support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'html5:audio':
|
case 'html5:audio':
|
||||||
@ -32,7 +32,7 @@ const support = {
|
|||||||
case 'youtube:video':
|
case 'youtube:video':
|
||||||
case 'vimeo:video':
|
case 'vimeo:video':
|
||||||
api = true;
|
api = true;
|
||||||
ui = support.rangeInput && (!browser.isIPhone || playsInline);
|
ui = support.rangeInput && (!browser.isIPhone || canPlayInline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -59,7 +59,7 @@ const support = {
|
|||||||
|
|
||||||
// Inline playback support
|
// Inline playback support
|
||||||
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
||||||
inline: 'playsInline' in document.createElement('video'),
|
playsinline: 'playsInline' in document.createElement('video'),
|
||||||
|
|
||||||
// Check for mime type support against a player instance
|
// Check for mime type support against a player instance
|
||||||
// Credits: http://diveintohtml5.info/everything.html
|
// Credits: http://diveintohtml5.info/everything.html
|
||||||
|
@ -3,14 +3,12 @@
|
|||||||
// YouTube, Vimeo, etc
|
// YouTube, Vimeo, etc
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
.plyr__video-embed {
|
// Default to 16:9 ratio but this is set by JavaScript based on config
|
||||||
// Default to 16:9 ratio but this is set by JavaScript based on config
|
$embed-padding: ((100 / 16) * 9);
|
||||||
$padding: ((100 / 16) * 9);
|
|
||||||
$height: 240;
|
|
||||||
$offset: to-percentage(($height - $padding) / ($height / 50));
|
|
||||||
|
|
||||||
|
.plyr__video-embed {
|
||||||
height: 0;
|
height: 0;
|
||||||
padding-bottom: to-percentage($padding);
|
padding-bottom: to-percentage($embed-padding);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
@ -22,6 +20,17 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the full custom UI is supported
|
||||||
|
.plyr--full-ui .plyr__video-embed {
|
||||||
|
$height: 240;
|
||||||
|
$offset: to-percentage(($height - $embed-padding) / ($height / 50));
|
||||||
|
|
||||||
|
// To allow mouse events to be captured if full support
|
||||||
|
iframe {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
// Vimeo hack
|
// Vimeo hack
|
||||||
> div {
|
> div {
|
||||||
@ -30,7 +39,3 @@
|
|||||||
transform: translateY(-$offset);
|
transform: translateY(-$offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// To allow mouse events to be captured if full support
|
|
||||||
.plyr--full-ui .plyr__video-embed iframe {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user