aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSam Potts <me@sampotts.me>2016-02-21 13:17:30 +1100
committerSam Potts <me@sampotts.me>2016-02-21 13:17:30 +1100
commitb18ed0338477059b0c8bace92fc96cf5ef0bbc6f (patch)
tree8cab00060c9a22d73847d088b3e5efcebbc32cc0 /src
parente742527e653e1fd8626dcb28012fee64d58e4b3f (diff)
downloadplyr-b18ed0338477059b0c8bace92fc96cf5ef0bbc6f.tar.lz
plyr-b18ed0338477059b0c8bace92fc96cf5ef0bbc6f.tar.xz
plyr-b18ed0338477059b0c8bace92fc96cf5ef0bbc6f.zip
WIP on captions bug, manual duration option, reset media object
Diffstat (limited to 'src')
-rw-r--r--src/js/plyr.js792
-rw-r--r--src/less/plyr.less73
-rw-r--r--src/sass/plyr.scss82
3 files changed, 503 insertions, 444 deletions
diff --git a/src/js/plyr.js b/src/js/plyr.js
index fce746db..d04972a8 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -26,7 +26,7 @@
/*global YT,$f*/
// Globals
- var fullscreen, config, api = {};
+ var fullscreen, api = {};
// Default config
var defaults = {
@@ -36,13 +36,14 @@
loop: false,
seekTime: 10,
volume: 5,
+ duration: null,
+ displayDuration: true,
+ iconPrefix: 'icon',
click: true,
tooltips: {
controls: false,
seek: true
},
- displayDuration: true,
- iconPrefix: 'icon',
selectors: {
container: '.plyr',
controls: {
@@ -155,157 +156,6 @@
events: ['ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'emptied']
};
- // Build the default HTML
- function _buildControls() {
- // Open and add the progress and seek elements
- var html = [
- '<div class="plyr__controls">',
- '<div class="plyr__progress">',
- '<label for="seek{id}" class="plyr__sr-only">Seek</label>',
- '<input id="seek{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">',
- '<progress class="plyr__progress--played" max="100" value="0">',
- '<span>0</span>% ' + config.i18n.played,
- '</progress>',
- '<progress class="plyr__progress--buffer" max="100" value="0">',
- '<span>0</span>% ' + config.i18n.buffered,
- '</progress>'];
-
- // Seek tooltip
- if (config.tooltips.seek) {
- html.push('<span class="plyr__tooltip">--:--</span>');
- }
-
- // Close progress
- html.push('</div>',
- '<span class="plyr__controls--left">');
-
- // Restart button
- if (_inArray(config.controls, 'restart')) {
- html.push(
- '<button type="button" data-plyr="restart">',
- '<svg><use xlink:href="#' + config.iconPrefix + '-restart" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.restart + '</span>',
- '</button>'
- );
- }
-
- // Rewind button
- if (_inArray(config.controls, 'rewind')) {
- html.push(
- '<button type="button" data-plyr="rewind">',
- '<svg><use xlink:href="#' + config.iconPrefix + '-rewind" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.rewind + '</span>',
- '</button>'
- );
- }
-
- // Play/pause button
- if (_inArray(config.controls, 'play')) {
- html.push(
- '<button type="button" data-plyr="play">',
- '<svg><use xlink:href="#' + config.iconPrefix + '-play" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.play + '</span>',
- '</button>',
- '<button type="button" data-plyr="pause">',
- '<svg><use xlink:href="#' + config.iconPrefix + '-pause" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.pause + '</span>',
- '</button>'
- );
- }
-
- // Fast forward button
- if (_inArray(config.controls, 'fast-forward')) {
- html.push(
- '<button type="button" data-plyr="fast-forward">',
- '<svg><use xlink:href="#' + config.iconPrefix + '-fast-forward" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.forward + '</span>',
- '</button>'
- );
- }
-
- // Media current time display
- if (_inArray(config.controls, 'current-time')) {
- html.push(
- '<span class="plyr__time">',
- '<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>',
- '<span class="plyr__time--current">00:00</span>',
- '</span>'
- );
- }
-
- // Media duration display
- if (_inArray(config.controls, 'duration')) {
- html.push(
- '<span class="plyr__time">',
- '<span class="plyr__sr-only">' + config.i18n.duration + '</span>',
- '<span class="plyr__time--duration">--:--</span>',
- '</span>'
- );
- }
-
- // Close left controls
- html.push(
- '</span>',
- '<span class="plyr__controls--right">'
- );
-
- // Toggle mute button
- if (_inArray(config.controls, 'mute')) {
- html.push(
- '<button type="button" data-plyr="mute">',
- '<svg class="icon--muted"><use xlink:href="#' + config.iconPrefix + '-muted" /></svg>',
- '<svg><use xlink:href="#' + config.iconPrefix + '-volume" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>',
- '</button>'
- );
- }
-
- // Volume range control
- if (_inArray(config.controls, 'volume')) {
- html.push(
- '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
- '<input id="volume{id}" class="plyr__volume" type="range" min="0" max="10" value="5" data-plyr="volume">'
- );
- }
-
- // Toggle captions button
- if (_inArray(config.controls, 'captions')) {
- html.push(
- '<button type="button" data-plyr="captions">',
- '<svg class="icon--captions-on"><use xlink:href="#' + config.iconPrefix + '-captions-on" /></svg>',
- '<svg><use xlink:href="#' + config.iconPrefix + '-captions-off" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>',
- '</button>'
- );
- }
-
- // Toggle fullscreen button
- if (_inArray(config.controls, 'fullscreen')) {
- html.push(
- '<button type="button" data-plyr="fullscreen">',
- '<svg class="icon--exit-fullscreen"><use xlink:href="#' + config.iconPrefix + '-exit-fullscreen" /></svg>',
- '<svg><use xlink:href="#' + config.iconPrefix + '-enter-fullscreen" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>',
- '</button>'
- );
- }
-
- // Close everything
- html.push(
- '</span>',
- '</div>'
- );
-
- return html.join('');
- }
-
- // Debugging
- function _log(text, warn) {
- if (config.debug && window.console) {
- console[(warn ? 'warn' : 'log')](text);
- }
- }
-
// Credits: http://paypal.github.io/accessible-html5-video-player/
// Unfortunately, due to mixed support, UA sniffing is required
function _browserSniff() {
@@ -623,19 +473,42 @@
return ((current / max) * 100).toFixed(2);
}
- // Deep extend/merge two Objects
+ // Deep extend/merge destination object with N more objects
// http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
// Removed call to arguments.callee (used explicit function name instead)
- function _extend(destination, source) {
- for (var property in source) {
- if (source[property] && source[property].constructor && source[property].constructor === Object) {
- destination[property] = destination[property] || {};
- _extend(destination[property], source[property]);
- }
- else {
- destination[property] = source[property];
+ function _extend() {
+ // Get arguments
+ var objects = arguments;
+
+ // Bail if nothing to merge
+ if(!objects.length) {
+ return;
+ }
+
+ // Return first if specified but nothing to merge
+ if(objects.lenth == 1) {
+ return objects[0];
+ }
+
+ // First object is the destination
+ var destination = Array.prototype.shift.call(objects),
+ length = objects.length;
+
+ // Loop through all objects to merge
+ for (var i = 0; i < length; i++) {
+ var source = objects[i];
+
+ for (var property in source) {
+ if (source[property] && source[property].constructor && source[property].constructor === Object) {
+ destination[property] = destination[property] || {};
+ _extend(destination[property], source[property]);
+ }
+ else {
+ destination[property] = source[property];
+ }
}
}
+
return destination;
}
@@ -744,11 +617,360 @@
}
// Player instance
- function Plyr(container) {
+ function Plyr(container, config) {
var plyr = this;
plyr.container = container;
plyr.timers = {};
+ // Log config options
+ _log(config);
+
+ // Debugging
+ function _log(text, warn) {
+ if (config.debug && window.console) {
+ console[(warn ? 'warn' : 'log')](text);
+ }
+ }
+
+ // Build the default HTML
+ function _buildControls() {
+ // Open and add the progress and seek elements
+ var html = [
+ '<div class="plyr__controls">',
+ '<div class="plyr__progress">',
+ '<label for="seek{id}" class="plyr__sr-only">Seek</label>',
+ '<input id="seek{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">',
+ '<progress class="plyr__progress--played" max="100" value="0">',
+ '<span>0</span>% ' + config.i18n.played,
+ '</progress>',
+ '<progress class="plyr__progress--buffer" max="100" value="0">',
+ '<span>0</span>% ' + config.i18n.buffered,
+ '</progress>'];
+
+ // Seek tooltip
+ if (config.tooltips.seek) {
+ html.push('<span class="plyr__tooltip">00:00</span>');
+ }
+
+ // Close progress
+ html.push('</div>',
+ '<span class="plyr__controls--left">');
+
+ // Restart button
+ if (_inArray(config.controls, 'restart')) {
+ html.push(
+ '<button type="button" data-plyr="restart">',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-restart" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.restart + '</span>',
+ '</button>'
+ );
+ }
+
+ // Rewind button
+ if (_inArray(config.controls, 'rewind')) {
+ html.push(
+ '<button type="button" data-plyr="rewind">',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-rewind" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.rewind + '</span>',
+ '</button>'
+ );
+ }
+
+ // Play/pause button
+ if (_inArray(config.controls, 'play')) {
+ html.push(
+ '<button type="button" data-plyr="play">',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-play" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.play + '</span>',
+ '</button>',
+ '<button type="button" data-plyr="pause">',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-pause" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.pause + '</span>',
+ '</button>'
+ );
+ }
+
+ // Fast forward button
+ if (_inArray(config.controls, 'fast-forward')) {
+ html.push(
+ '<button type="button" data-plyr="fast-forward">',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-fast-forward" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.forward + '</span>',
+ '</button>'
+ );
+ }
+
+ // Media current time display
+ if (_inArray(config.controls, 'current-time')) {
+ html.push(
+ '<span class="plyr__time">',
+ '<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>',
+ '<span class="plyr__time--current">00:00</span>',
+ '</span>'
+ );
+ }
+
+ // Media duration display
+ if (_inArray(config.controls, 'duration')) {
+ html.push(
+ '<span class="plyr__time">',
+ '<span class="plyr__sr-only">' + config.i18n.duration + '</span>',
+ '<span class="plyr__time--duration">00:00</span>',
+ '</span>'
+ );
+ }
+
+ // Close left controls
+ html.push(
+ '</span>',
+ '<span class="plyr__controls--right">'
+ );
+
+ // Toggle mute button
+ if (_inArray(config.controls, 'mute')) {
+ html.push(
+ '<button type="button" data-plyr="mute">',
+ '<svg class="icon--muted"><use xlink:href="#' + config.iconPrefix + '-muted" /></svg>',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-volume" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>',
+ '</button>'
+ );
+ }
+
+ // Volume range control
+ if (_inArray(config.controls, 'volume')) {
+ html.push(
+ '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
+ '<input id="volume{id}" class="plyr__volume" type="range" min="0" max="10" value="5" data-plyr="volume">'
+ );
+ }
+
+ // Toggle captions button
+ if (_inArray(config.controls, 'captions')) {
+ html.push(
+ '<button type="button" data-plyr="captions">',
+ '<svg class="icon--captions-on"><use xlink:href="#' + config.iconPrefix + '-captions-on" /></svg>',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-captions-off" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>',
+ '</button>'
+ );
+ }
+
+ // Toggle fullscreen button
+ if (_inArray(config.controls, 'fullscreen')) {
+ html.push(
+ '<button type="button" data-plyr="fullscreen">',
+ '<svg class="icon--exit-fullscreen"><use xlink:href="#' + config.iconPrefix + '-exit-fullscreen" /></svg>',
+ '<svg><use xlink:href="#' + config.iconPrefix + '-enter-fullscreen" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>',
+ '</button>'
+ );
+ }
+
+ // Close everything
+ html.push(
+ '</span>',
+ '</div>'
+ );
+
+ return html.join('');
+ }
+
+ // Setup fullscreen
+ function _setupFullscreen() {
+ if (!plyr.supported.full) {
+ return;
+ }
+
+ if ((plyr.type != 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
+ // Check for native support
+ var nativeSupport = fullscreen.supportsFullScreen;
+
+ if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) {
+ _log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
+
+ // Add styling hook
+ _toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
+ }
+ else {
+ _log('Fullscreen not supported and fallback disabled');
+ }
+
+ // Toggle state
+ _toggleState(plyr.buttons.fullscreen, false);
+
+ // Setup focus trap
+ _focusTrap();
+
+ // Set control hide class hook
+ if (config.fullscreen.hideControls) {
+ _toggleClass(plyr.container, config.classes.fullscreen.hideControls, true);
+ }
+ }
+ }
+
+ // Setup captions
+ function _setupCaptions() {
+ if (plyr.type !== 'video') {
+ return;
+ }
+
+ // Inject the container
+ if (!_getElement(config.selectors.captions)) {
+ plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"><span></span></div>');
+ }
+
+ // Cache selector
+ plyr.captionsContainer = _getElement(config.selectors.captions).querySelector('span');
+
+ // Determine if HTML5 textTracks is supported
+ plyr.usingTextTracks = false;
+ if (plyr.media.textTracks) {
+ plyr.usingTextTracks = true;
+ }
+
+ // Get URL of caption file if exists
+ var captionSrc = '',
+ kind,
+ children = plyr.media.childNodes;
+
+ for (var i = 0; i < children.length; i++) {
+ if (children[i].nodeName.toLowerCase() === 'track') {
+ kind = children[i].kind;
+ if (kind === 'captions' || kind === 'subtitles') {
+ captionSrc = children[i].getAttribute('src');
+ }
+ }
+ }
+
+ // Record if caption file exists or not
+ plyr.captionExists = true;
+ if (captionSrc === '') {
+ plyr.captionExists = false;
+ _log('No caption track found');
+ }
+ else {
+ _log('Caption track found; URI: ' + captionSrc);
+ }
+
+ // If no caption file exists, hide container for caption text
+ if (!plyr.captionExists) {
+ _toggleClass(plyr.container, config.classes.captions.enabled);
+ }
+ // If caption file exists, process captions
+ else {
+ // Turn off native caption rendering to avoid double captions
+ // This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below
+ var tracks = plyr.media.textTracks;
+ for (var x = 0; x < tracks.length; x++) {
+ tracks[x].mode = 'hidden';
+ }
+
+ // Enable UI
+ _showCaptions(plyr);
+
+ // Disable unsupported browsers than report false positive
+ if ((plyr.browser.name === 'IE' && plyr.browser.version >= 10) ||
+ (plyr.browser.name === 'Firefox' && plyr.browser.version >= 31)) {
+ // ||
+ //(plyr.browser.name === 'Chrome' && plyr.browser.version >= 43) ||
+ //(plyr.browser.name === 'Safari' && plyr.browser.version >= 7)) {
+
+ // Debugging
+ _log('Detected unsupported browser for HTML5 captions - using fallback');
+
+ // Set to false so skips to 'manual' captioning
+ plyr.usingTextTracks = false;
+ }
+
+ // Rendering caption tracks
+ // Native support required - http://caniuse.com/webvtt
+ if (plyr.usingTextTracks) {
+ _log('TextTracks supported');
+
+ for (var y = 0; y < tracks.length; y++) {
+ var track = tracks[y];
+
+ if (track.kind === 'captions' || track.kind === 'subtitles') {
+ _on(track, 'cuechange', function() {
+ console.log('cuechange');
+ console.log(this);
+
+ // Clear container
+ plyr.captionsContainer.innerHTML = '';
+
+ // Display a cue, if there is one
+ if (this.activeCues[0] && 'text' in this.activeCues[0]) {
+ console.log(this.activeCues[0].getCueAsHTML());
+
+ plyr.captionsContainer.appendChild(this.activeCues[0].getCueAsHTML());
+
+ // Force redraw
+ var redraw = plyr.captionsContainer.offsetHeight;
+ }
+ });
+ }
+ }
+ }
+ // Caption tracks not natively supported
+ else {
+ _log('TextTracks not supported so rendering captions manually');
+
+ // Render captions from array at appropriate time
+ plyr.currentCaption = '';
+ plyr.captions = [];
+
+ if (captionSrc !== '') {
+ // Create XMLHttpRequest Object
+ var xhr = new XMLHttpRequest();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ var records = [],
+ record,
+ req = xhr.responseText;
+
+ records = req.split('\n\n');
+
+ for (var r = 0; r < records.length; r++) {
+ record = records[r];
+ plyr.captions[r] = [];
+ plyr.captions[r] = record.split('\n');
+ }
+
+ // Remove first element ('VTT')
+ plyr.captions.shift();
+
+ _log('Successfully loaded the caption file via AJAX');
+ }
+ else {
+ _log('There was a problem loading the caption file via AJAX', true);
+ }
+ }
+ };
+
+ xhr.open('get', captionSrc, true);
+
+ xhr.send();
+ }
+ }
+
+ // If Safari 7+, removing track from DOM [see 'turn off native caption rendering' above]
+ /*if (plyr.browser.name === 'Safari' && plyr.browser.version >= 7) {
+ _log('Safari 7+ detected; removing track from DOM');
+
+ // Find all <track> elements
+ tracks = plyr.media.getElementsByTagName('track');
+
+ // Loop through and remove one by one
+ for (var t = 0; t < tracks.length; t++) {
+ plyr.media.removeChild(tracks[t]);
+ }
+ }*/
+ }
+ }
+
// Captions functions
// Seek the manual caption time and update UI
function _seekManualCaptions(time) {
@@ -1402,194 +1624,6 @@
});
}
- // Setup captions
- function _setupCaptions() {
- if (plyr.type !== 'video') {
- return;
- }
-
- // Inject the container
- if (!_getElement(config.selectors.captions)) {
- plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"><span></span></div>');
- }
-
- // Cache selector
- plyr.captionsContainer = _getElement(config.selectors.captions).querySelector('span');
-
- // Determine if HTML5 textTracks is supported
- plyr.usingTextTracks = false;
- if (plyr.media.textTracks) {
- plyr.usingTextTracks = true;
- }
-
- // Get URL of caption file if exists
- var captionSrc = '',
- kind,
- children = plyr.media.childNodes;
-
- for (var i = 0; i < children.length; i++) {
- if (children[i].nodeName.toLowerCase() === 'track') {
- kind = children[i].kind;
- if (kind === 'captions' || kind === 'subtitles') {
- captionSrc = children[i].getAttribute('src');
- }
- }
- }
-
- // Record if caption file exists or not
- plyr.captionExists = true;
- if (captionSrc === '') {
- plyr.captionExists = false;
- _log('No caption track found');
- }
- else {
- _log('Caption track found; URI: ' + captionSrc);
- }
-
- // If no caption file exists, hide container for caption text
- if (!plyr.captionExists) {
- _toggleClass(plyr.container, config.classes.captions.enabled);
- }
- // If caption file exists, process captions
- else {
- // Turn off native caption rendering to avoid double captions
- // This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below
- var tracks = plyr.media.textTracks;
- for (var x = 0; x < tracks.length; x++) {
- tracks[x].mode = 'hidden';
- }
-
- // Enable UI
- _showCaptions(plyr);
-
- // Disable unsupported browsers than report false positive
- if ((plyr.browser.name === 'IE' && plyr.browser.version >= 10) ||
- (plyr.browser.name === 'Firefox' && plyr.browser.version >= 31) ||
- (plyr.browser.name === 'Chrome' && plyr.browser.version >= 43) ||
- (plyr.browser.name === 'Safari' && plyr.browser.version >= 7)) {
- // Debugging
- _log('Detected unsupported browser for HTML5 captions - using fallback');
-
- // Set to false so skips to 'manual' captioning
- plyr.usingTextTracks = false;
- }
-
- // Rendering caption tracks
- // Native support required - http://caniuse.com/webvtt
- if (plyr.usingTextTracks) {
- _log('TextTracks supported');
-
- for (var y = 0; y < tracks.length; y++) {
- var track = tracks[y];
-
- if (track.kind === 'captions' || track.kind === 'subtitles') {
- _on(track, 'cuechange', function() {
- // Clear container
- plyr.captionsContainer.innerHTML = '';
-
- // Display a cue, if there is one
- if (this.activeCues[0] && this.activeCues[0].hasOwnProperty('text')) {
- plyr.captionsContainer.appendChild(this.activeCues[0].getCueAsHTML().trim());
-
- // Force redraw
- // var redraw = plyr.captionsContainer.offsetHeight;
- }
- });
- }
- }
- }
- // Caption tracks not natively supported
- else {
- _log('TextTracks not supported so rendering captions manually');
-
- // Render captions from array at appropriate time
- plyr.currentCaption = '';
- plyr.captions = [];
-
- if (captionSrc !== '') {
- // Create XMLHttpRequest Object
- var xhr = new XMLHttpRequest();
-
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4) {
- if (xhr.status === 200) {
- var records = [],
- record,
- req = xhr.responseText;
-
- records = req.split('\n\n');
-
- for (var r = 0; r < records.length; r++) {
- record = records[r];
- plyr.captions[r] = [];
- plyr.captions[r] = record.split('\n');
- }
-
- // Remove first element ('VTT')
- plyr.captions.shift();
-
- _log('Successfully loaded the caption file via AJAX');
- }
- else {
- _log('There was a problem loading the caption file via AJAX', true);
- }
- }
- };
-
- xhr.open('get', captionSrc, true);
-
- xhr.send();
- }
- }
-
- // If Safari 7+, removing track from DOM [see 'turn off native caption rendering' above]
- if (plyr.browser.name === 'Safari' && plyr.browser.version >= 7) {
- _log('Safari 7+ detected; removing track from DOM');
-
- // Find all <track> elements
- tracks = plyr.media.getElementsByTagName('track');
-
- // Loop through and remove one by one
- for (var t = 0; t < tracks.length; t++) {
- plyr.media.removeChild(tracks[t]);
- }
- }
- }
- }
-
- // Setup fullscreen
- function _setupFullscreen() {
- if (!plyr.supported.full) {
- return;
- }
-
- if ((plyr.type != 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
- // Check for native support
- var nativeSupport = fullscreen.supportsFullScreen;
-
- if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) {
- _log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
-
- // Add styling hook
- _toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
- }
- else {
- _log('Fullscreen not supported and fallback disabled');
- }
-
- // Toggle state
- _toggleState(plyr.buttons.fullscreen, false);
-
- // Setup focus trap
- _focusTrap();
-
- // Set control hide class hook
- if (config.fullscreen.hideControls) {
- _toggleClass(plyr.container, config.classes.fullscreen.hideControls, true);
- }
- }
- }
-
// Play media
function _play() {
if('play' in plyr.media) {
@@ -1642,7 +1676,8 @@
// The input parameter can be an event or a number
function _seek(input) {
var targetTime = 0,
- paused = plyr.media.paused;
+ paused = plyr.media.paused,
+ duration = _getDuration();
// Explicit position
if (typeof input === 'number') {
@@ -1652,15 +1687,15 @@
else if (typeof input === 'object' && (input.type === 'input' || input.type === 'change')) {
// It's the seek slider
// Seek to the selected time
- targetTime = ((input.target.value / input.target.max) * plyr.media.duration);
+ targetTime = ((input.target.value / input.target.max) * duration);
}
// Normalise targetTime
if (targetTime < 0) {
targetTime = 0;
}
- else if (targetTime > plyr.media.duration) {
- targetTime = plyr.media.duration;
+ else if (targetTime > duration) {
+ targetTime = duration;
}
// Set the current time
@@ -1702,6 +1737,15 @@
_seekManualCaptions(targetTime);
}
+ // Get the duration (or custom if set)
+ function _getDuration() {
+ // It should be a number, but parse it just incase
+ var duration = parseInt(config.duration);
+
+ // If custom duration is funky, use regular duration
+ return (isNaN(duration) ? plyr.media.duration : duration);
+ }
+
// Check playing state
function _checkPlaying() {
_toggleClass(plyr.container, config.classes.playing, !plyr.media.paused);
@@ -1932,14 +1976,15 @@
function _updateProgress(event) {
var progress = plyr.progress.played.bar,
text = plyr.progress.played.text,
- value = 0;
+ value = 0,
+ duration = _getDuration();
if (event) {
switch (event.type) {
// Video playing
case 'timeupdate':
case 'seeking':
- value = _getPercentage(plyr.media.currentTime, plyr.media.duration);
+ value = _getPercentage(plyr.media.currentTime, duration);
// Set seek range value only if it's a 'natural' time event
if (event.type == 'timeupdate' && plyr.buttons.seek) {
@@ -1965,7 +2010,7 @@
// HTML5
if (buffered && buffered.length) {
- return _getPercentage(buffered.end(0), plyr.media.duration);
+ return _getPercentage(buffered.end(0), duration);
}
// YouTube returns between 0 and 1
else if (typeof buffered === 'number') {
@@ -2003,7 +2048,7 @@
plyr.hours = parseInt(((time / 60) / 60) % 60);
// Do we need to display hours?
- var displayHours = (parseInt(((plyr.media.duration / 60) / 60) % 60) > 0);
+ var displayHours = (parseInt(((_getDuration() / 60) / 60) % 60) > 0);
// Ensure it's two digits. For example, 03 rather than 3.
plyr.secs = ('0' + plyr.secs).slice(-2);
@@ -2020,7 +2065,7 @@
}
// Determine duration
- var duration = plyr.media.duration || 0;
+ var duration = _getDuration() || 0;
// If there's only one time display, display duration there
if (!plyr.duration && config.displayDuration && plyr.media.paused) {
@@ -2084,14 +2129,14 @@
}
// Display the time a click would seek to
- _updateTimeDisplay(((plyr.media.duration / 100) * percent), plyr.progress.tooltip);
+ _updateTimeDisplay(((_getDuration() / 100) * percent), plyr.progress.tooltip);
// Set position
plyr.progress.tooltip.style.left = percent + "%";
// Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds
- if(_inArray(['mouseenter', 'mouseleave'], event.type)) {
+ if(event && _inArray(['mouseenter', 'mouseleave'], event.type)) {
_toggleClass(plyr.progress.tooltip, visible, (event.type === 'mouseenter'));
}
}
@@ -2273,6 +2318,9 @@
config.title = source.title;
_setTitle();
}
+
+ // Reset media object
+ plyr.container.plyr.media = plyr.media;
}
// Update poster
@@ -2635,6 +2683,9 @@
// Update the UI
_checkPlaying();
+
+ // Display duration
+ _displayDuration();
}
// Initialize instance
@@ -2729,12 +2780,9 @@
elements = document.querySelectorAll(defaults.selectors.container);
}
- // Extend the default options with user specified
- config = _extend(defaults, options);
-
// Bail if disabled or no basic support
// You may want to disable certain UAs etc
- if (!config.enabled || !api.supported().basic || !elements.length) {
+ if (!api.supported().basic || !elements.length) {
return false;
}
@@ -2745,8 +2793,16 @@
// Setup a player instance and add to the element
if (typeof element.plyr === 'undefined') {
+ // Create instance-specific config
+ var config = _extend(defaults, options, JSON.parse(element.getAttribute("data-plyr")));
+
+ // Bail if not enabled
+ if(!config.enabled) {
+ return;
+ }
+
// Create new instance
- var instance = new Plyr(element);
+ var instance = new Plyr(element, config);
// Set plyr to false if setup failed
element.plyr = (Object.keys(instance).length ? instance : false);
diff --git a/src/less/plyr.less b/src/less/plyr.less
index 73e14c56..156ac5f9 100644
--- a/src/less/plyr.less
+++ b/src/less/plyr.less
@@ -7,57 +7,58 @@
// -------------------------------
// Colors
-@plyr-blue: #3498DB;
-@plyr-gray-dark: #343F4A;
-@plyr-gray: #565D64;
-@plyr-gray-light: #6B7D86;
-@plyr-gray-lighter: #CBD0D3;
-@plyr-off-white: #D6DADD;
+@plyr-blue: #3498DB;
+@plyr-gray-dark: #343F4A;
+@plyr-gray: #565D64;
+@plyr-gray-light: #6B7D86;
+@plyr-gray-lighter: #CBD0D3;
+@plyr-off-white: #D6DADD;
// Font sizes
-@plyr-font-size-small: 14px;
-@plyr-font-size-base: 16px;
+@plyr-font-size-small: 14px;
+@plyr-font-size-base: 16px;
// Captions
-@plyr-font-size-captions-base: ceil(@plyr-font-size-base * 1.25);
-@plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5);
-@plyr-font-size-captions-large: (@plyr-font-size-base * 2);
+@plyr-font-size-captions-base: ceil(@plyr-font-size-base * 1.25);
+@plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5);
+@plyr-font-size-captions-large: (@plyr-font-size-base * 2);
// Controls
-@plyr-control-spacing: 10px;
-@plyr-controls-bg: #fff;
-@plyr-control-bg-hover: @plyr-blue;
+@plyr-control-spacing: 10px;
+@plyr-controls-bg: #fff;
+@plyr-control-bg-hover: @plyr-blue;
.contrast-control-color(@plyr-controls-bg);
.contrast-control-color-hover(@plyr-control-bg-hover);
// Tooltips
-@plyr-tooltip-bg: @plyr-controls-bg;
-@plyr-tooltip-border-color: fade(darken(@plyr-controls-bg, 5%), 10%);
-@plyr-tooltip-border-width: 1px;
-@plyr-tooltip-shadow: 0 0 5px @plyr-tooltip-border-color, 0 0 0 @plyr-tooltip-border-width @plyr-tooltip-border-color;
-@plyr-tooltip-color: @plyr-control-color;
-@plyr-tooltip-padding: @plyr-control-spacing;
-@plyr-tooltip-arrow-size: 6px;
-@plyr-tooltip-radius: 3px;
+@plyr-tooltip-bg: @plyr-controls-bg;
+@plyr-tooltip-border-color: fade(darken(@plyr-controls-bg, 75%), 10%);
+@plyr-tooltip-arrow-border-color: fade(darken(@plyr-controls-bg, 75%), 20%);
+@plyr-tooltip-border-width: 1px;
+@plyr-tooltip-shadow: 0 0 5px @plyr-tooltip-border-color, 0 0 0 @plyr-tooltip-border-width @plyr-tooltip-border-color;
+@plyr-tooltip-color: @plyr-control-color;
+@plyr-tooltip-padding: @plyr-control-spacing;
+@plyr-tooltip-arrow-size: 6px;
+@plyr-tooltip-radius: 3px;
// Progress
-@plyr-progress-bg: fade(@plyr-gray, 20%);
-@plyr-progress-playing-bg: @plyr-blue;
-@plyr-progress-buffered-bg: fade(@plyr-gray, 25%);
-@plyr-progress-loading-size: 40px;
-@plyr-progress-loading-bg: fade(#000, 15%);
+@plyr-progress-bg: fade(@plyr-gray, 20%);
+@plyr-progress-playing-bg: @plyr-blue;
+@plyr-progress-buffered-bg: fade(@plyr-gray, 25%);
+@plyr-progress-loading-size: 40px;
+@plyr-progress-loading-bg: fade(#000, 15%);
// Volume
-@plyr-volume-track-height: 6px;
-@plyr-volume-track-bg: darken(@plyr-controls-bg, 10%);
-@plyr-volume-thumb-height: (@plyr-volume-track-height * 2);
-@plyr-volume-thumb-width: (@plyr-volume-track-height * 2);
-@plyr-volume-thumb-bg: @plyr-control-color;
-@plyr-volume-thumb-bg-focus: @plyr-control-bg-hover;
+@plyr-volume-track-height: 6px;
+@plyr-volume-track-bg: darken(@plyr-controls-bg, 10%);
+@plyr-volume-thumb-height: (@plyr-volume-track-height * 2);
+@plyr-volume-thumb-width: (@plyr-volume-track-height * 2);
+@plyr-volume-thumb-bg: @plyr-control-color;
+@plyr-volume-thumb-bg-focus: @plyr-control-bg-hover;
// Breakpoints
-@plyr-bp-control-split: 560px; // When controls split into left/right
-@plyr-bp-captions-large: 768px; // When captions jump to the larger font size
+@plyr-bp-control-split: 560px; // When controls split into left/right
+@plyr-bp-captions-large: 768px; // When captions jump to the larger font size
// Animation
// ---------------------------------------
@@ -366,7 +367,7 @@
@plyr-border-arrow-size: (@plyr-tooltip-arrow-size + (@plyr-tooltip-border-width * 1));
bottom: -(@plyr-border-arrow-size + @plyr-tooltip-border-width);
border-right: @plyr-border-arrow-size solid transparent;
- border-top: @plyr-border-arrow-size solid @plyr-tooltip-border-color;
+ border-top: @plyr-border-arrow-size solid @plyr-tooltip-arrow-border-color;
border-left: @plyr-border-arrow-size solid transparent;
z-index: 1;
}
diff --git a/src/sass/plyr.scss b/src/sass/plyr.scss
index f0d1df6f..966a7966 100644
--- a/src/sass/plyr.scss
+++ b/src/sass/plyr.scss
@@ -7,69 +7,71 @@
// -------------------------------
// Colors
-$plyr-blue: #3498DB !default;
-$plyr-gray-dark: #343F4A !default;
-$plyr-gray: #565D64 !default;
-$plyr-gray-light: #6B7D86 !default;
-$plyr-gray-lighter: #CBD0D3 !default;
-$plyr-off-white: #D6DADD !default;
+$plyr-blue: #3498DB !default;
+$plyr-gray-dark: #343F4A !default;
+$plyr-gray: #565D64 !default;
+$plyr-gray-light: #6B7D86 !default;
+$plyr-gray-lighter: #CBD0D3 !default;
+$plyr-off-white: #D6DADD !default;
// Font sizes
-$plyr-font-size-small: 14px !default;
-$plyr-font-size-base: 16px !default;
+$plyr-font-size-small: 14px !default;
+$plyr-font-size-base: 16px !default;
// Captions
-$plyr-font-size-captions-base: ceil($plyr-font-size-base * 1.25) !default;
-$plyr-font-size-captions-medium: ceil($plyr-font-size-base * 1.5) !default;
-$plyr-font-size-captions-large: ($plyr-font-size-base * 2) !default;
+$plyr-font-size-captions-base: ceil($plyr-font-size-base * 1.25) !default;
+$plyr-font-size-captions-medium: ceil($plyr-font-size-base * 1.5) !default;
+$plyr-font-size-captions-large: ($plyr-font-size-base * 2) !default;
// Controls
-$plyr-control-spacing: 10px !default;
-$plyr-controls-bg: #fff !default;
-$plyr-control-bg-hover: $plyr-blue !default;
+$plyr-control-spacing: 10px !default;
+$plyr-controls-bg: #fff !default;
+$plyr-control-bg-hover: $plyr-blue !default;
// Contrast
@if lightness($plyr-controls-bg) >= 65% {
- $plyr-control-color: $plyr-gray-light !default;
+ $plyr-control-color: $plyr-gray-light !default;
}
@else {
- $plyr-control-color: $plyr-gray-lighter !default;
+ $plyr-control-color: $plyr-gray-lighter !default;
}
@if lightness($plyr-control-bg-hover) >= 65% {
- $plyr-control-color-hover: $plyr-gray !default;
+ $plyr-control-color-hover: $plyr-gray !default;
}
@else {
- $plyr-control-color-hover: #fff !default;
+ $plyr-control-color-hover: #fff !default;
}
// Tooltips
-$plyr-tooltip-bg: $plyr-controls-bg !default;
-$plyr-tooltip-border-color: transparentize($plyr-gray-dark, .1) !default;
-$plyr-tooltip-border-width: 1px;
-$plyr-tooltip-shadow: 0 0 5px $plyr-tooltip-border-color, 0 0 0 $plyr-tooltip-border-width $plyr-tooltip-border-color;
-$plyr-tooltip-color: $plyr-control-color !default;
-$plyr-tooltip-padding: $plyr-control-spacing !default;
-$plyr-tooltip-arrow-size: 6px !default;
-$plyr-tooltip-radius: 3px !default;
+$plyr-tooltip-bg: $plyr-controls-bg !default;
+$plyr-tooltip-border-color: transparentize(darken($plyr-controls-bg, 75%), .1) !default;
+$plyr-tooltip-arrow-border-color: transparentize(darken($plyr-controls-bg, 75%), .2) !default;
+
+$plyr-tooltip-border-width: 1px;
+$plyr-tooltip-shadow: 0 0 5px $plyr-tooltip-border-color, 0 0 0 $plyr-tooltip-border-width $plyr-tooltip-border-color;
+$plyr-tooltip-color: $plyr-control-color !default;
+$plyr-tooltip-padding: $plyr-control-spacing !default;
+$plyr-tooltip-arrow-size: 6px !default;
+$plyr-tooltip-radius: 3px !default;
// Progress
-$plyr-progress-bg: transparentize($plyr-gray, .2) !default;
-$plyr-progress-playing-bg: $plyr-blue !default;
-$plyr-progress-buffered-bg: transparentize($plyr-gray, .25) !default;
-$plyr-progress-loading-size: 40px !default;
-$plyr-progress-loading-bg: transparentize(#000, .15) !default;
+$plyr-progress-bg: transparentize($plyr-gray, .2) !default;
+$plyr-progress-playing-bg: $plyr-blue !default;
+$plyr-progress-buffered-bg: transparentize($plyr-gray, .25) !default;
+$plyr-progress-loading-size: 40px !default;
+$plyr-progress-loading-bg: transparentize(#000, .15) !default;
// Volume
-$plyr-volume-track-height: 6px !default;
-$plyr-volume-track-bg: darken($plyr-controls-bg, 10%) !default;
-$plyr-volume-thumb-height: ($plyr-volume-track-height * 2) !default;
-$plyr-volume-thumb-width: ($plyr-volume-track-height * 2) !default;
-$plyr-volume-thumb-bg: $plyr-control-color !default;
-$plyr-volume-thumb-bg-focus: $plyr-control-bg-hover !default;
+$plyr-volume-track-height: 6px !default;
+$plyr-volume-track-bg: darken($plyr-controls-bg, 10%) !default;
+$plyr-volume-thumb-height: ($plyr-volume-track-height * 2) !default;
+$plyr-volume-thumb-width: ($plyr-volume-track-height * 2) !default;
+$plyr-volume-thumb-bg: $plyr-control-color !default;
+$plyr-volume-thumb-bg-focus: $plyr-control-bg-hover !default;
// Breakpoints
-$plyr-bp-control-split: 560px !default; // When controls split into left/right
-$plyr-bp-captions-large: 768px !default; // When captions jump to the larger font size
+$plyr-bp-control-split: 560px !default; // When controls split into left/right
+$plyr-bp-captions-large: 768px !default; // When captions jump to the larger font size
// Animation
// ---------------------------------------
@@ -365,7 +367,7 @@ $plyr-bp-captions-large: 768px !default; // When captions jump to the la
$plyr-border-arrow-size: ($plyr-tooltip-arrow-size + ($plyr-tooltip-border-width * 1));
bottom: -($plyr-border-arrow-size + $plyr-tooltip-border-width);
border-right: $plyr-border-arrow-size solid transparent;
- border-top: $plyr-border-arrow-size solid $plyr-tooltip-border-color;
+ border-top: $plyr-border-arrow-size solid $plyr-tooltip-arrow-border-color;
border-left: $plyr-border-arrow-size solid transparent;
z-index: 1;
}