Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
f477fdf9e2 | |||
49038e3ca9 | |||
5f96172dbd | |||
2bd6a8390c | |||
3e68cec6ea | |||
b24d763d40 | |||
d690560fc2 | |||
d46d40fa17 | |||
18001e7799 | |||
aa39aa8a58 |
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v1.0.0
|
// plyr.js v1.0.9
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
||||||
@ -33,7 +33,11 @@
|
|||||||
captions: "[data-player='captions']",
|
captions: "[data-player='captions']",
|
||||||
fullscreen: "[data-player='fullscreen']"
|
fullscreen: "[data-player='fullscreen']"
|
||||||
},
|
},
|
||||||
progress: ".player-progress",
|
progress: {
|
||||||
|
container: ".player-progress",
|
||||||
|
buffer: ".player-progress-buffer",
|
||||||
|
played: ".player-progress-played"
|
||||||
|
},
|
||||||
captions: ".player-captions",
|
captions: ".player-captions",
|
||||||
duration: ".player-duration",
|
duration: ".player-duration",
|
||||||
seekTime: ".player-seek-time"
|
seekTime: ".player-seek-time"
|
||||||
@ -46,21 +50,41 @@
|
|||||||
playing: "playing",
|
playing: "playing",
|
||||||
muted: "muted",
|
muted: "muted",
|
||||||
captions: {
|
captions: {
|
||||||
active: "captions-active",
|
enabled: "captions-enabled",
|
||||||
enabled: "captions-enabled"
|
active: "captions-active"
|
||||||
},
|
},
|
||||||
fullscreen: {
|
fullscreen: {
|
||||||
enabled: "fullscreen-enabled"
|
enabled: "fullscreen-enabled",
|
||||||
|
active: "fullscreen-active"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
captions: {
|
captions: {
|
||||||
defaultActive: false
|
defaultActive: false
|
||||||
},
|
},
|
||||||
fullscreen: {
|
fullscreen: {
|
||||||
enabled: true
|
enabled: true,
|
||||||
|
fallback: true
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
enabled: true,
|
||||||
|
supported: function() {
|
||||||
|
try {
|
||||||
|
return "localStorage" in window && window.localStorage !== null;
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Debugging
|
||||||
|
function _log(text, error) {
|
||||||
|
if(config.debug && window.console) {
|
||||||
|
console[(error ? "error" : "log")](text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
||||||
// Unfortunately, due to scattered support, browser sniffing is required
|
// Unfortunately, due to scattered support, browser sniffing is required
|
||||||
function _browserSniff() {
|
function _browserSniff() {
|
||||||
@ -180,6 +204,16 @@
|
|||||||
element.addEventListener(event, callback, false);
|
element.addEventListener(event, callback, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unbind event
|
||||||
|
function _off(element, event, callback) {
|
||||||
|
element.removeEventListener(event, callback, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get percentage
|
||||||
|
function _getPercentage(current, max) {
|
||||||
|
return Math.floor((current / max) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
// Get click position relative to parent
|
// Get click position relative to parent
|
||||||
// http://www.kirupa.com/html5/getting_mouse_click_position.htm
|
// http://www.kirupa.com/html5/getting_mouse_click_position.htm
|
||||||
function _getClickPosition(event) {
|
function _getClickPosition(event) {
|
||||||
@ -266,7 +300,9 @@
|
|||||||
|
|
||||||
// Update methods to do something useful
|
// Update methods to do something useful
|
||||||
if (fullscreen.supportsFullScreen) {
|
if (fullscreen.supportsFullScreen) {
|
||||||
fullscreen.fullScreenEventName = fullscreen.prefix + "fullscreenchange";
|
// Yet again Microsoft awesomeness,
|
||||||
|
// Sometimes the prefix is "ms", sometimes "MS" to keep you on your toes
|
||||||
|
fullscreen.fullScreenEventName = (fullscreen.prefix == "ms" ? "MSFullscreenChange" : fullscreen.prefix + "fullscreenchange");
|
||||||
|
|
||||||
fullscreen.isFullScreen = function() {
|
fullscreen.isFullScreen = function() {
|
||||||
switch (this.prefix) {
|
switch (this.prefix) {
|
||||||
@ -361,12 +397,20 @@
|
|||||||
return _getElements(selector)[0];
|
return _getElements(selector)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine if we're in an iframe
|
||||||
|
function _inFrame() {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert controls
|
// Insert controls
|
||||||
function _injectControls() {
|
function _injectControls() {
|
||||||
// Insert custom video controls
|
// Insert custom video controls
|
||||||
if (config.debug) {
|
_log("Injecting custom controls.");
|
||||||
console.log("Injecting custom controls");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use specified html
|
// Use specified html
|
||||||
// Need to do a default?
|
// Need to do a default?
|
||||||
@ -384,30 +428,47 @@
|
|||||||
|
|
||||||
// Find the UI controls and store references
|
// Find the UI controls and store references
|
||||||
function _findElements() {
|
function _findElements() {
|
||||||
player.controls = _getElement(config.selectors.controls);
|
try {
|
||||||
|
player.controls = _getElement(config.selectors.controls);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
player.buttons = {};
|
player.buttons = {};
|
||||||
player.buttons.play = _getElement(config.selectors.buttons.play);
|
player.buttons.play = _getElement(config.selectors.buttons.play);
|
||||||
player.buttons.pause = _getElement(config.selectors.buttons.pause);
|
player.buttons.pause = _getElement(config.selectors.buttons.pause);
|
||||||
player.buttons.restart = _getElement(config.selectors.buttons.restart);
|
player.buttons.restart = _getElement(config.selectors.buttons.restart);
|
||||||
player.buttons.rewind = _getElement(config.selectors.buttons.rewind);
|
player.buttons.rewind = _getElement(config.selectors.buttons.rewind);
|
||||||
player.buttons.forward = _getElement(config.selectors.buttons.forward);
|
player.buttons.forward = _getElement(config.selectors.buttons.forward);
|
||||||
player.buttons.mute = _getElement(config.selectors.buttons.mute);
|
player.buttons.mute = _getElement(config.selectors.buttons.mute);
|
||||||
player.buttons.captions = _getElement(config.selectors.buttons.captions);
|
player.buttons.captions = _getElement(config.selectors.buttons.captions);
|
||||||
player.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
|
player.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
|
||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
player.progress = {};
|
player.progress = {};
|
||||||
player.progress.bar = _getElement(config.selectors.progress);
|
player.progress.container = _getElement(config.selectors.progress.container);
|
||||||
player.progress.text = player.progress.bar.getElementsByTagName("span")[0];
|
|
||||||
|
|
||||||
// Volume
|
// Progress - Buffering
|
||||||
player.volume = _getElement(config.selectors.buttons.volume);
|
player.progress.buffer = {};
|
||||||
|
player.progress.buffer.bar = _getElement(config.selectors.progress.buffer);
|
||||||
|
player.progress.buffer.text = player.progress.buffer.bar.getElementsByTagName("span")[0];
|
||||||
|
|
||||||
// Timing
|
// Progress - Played
|
||||||
player.duration = _getElement(config.selectors.duration);
|
player.progress.played = {};
|
||||||
player.seekTime = _getElements(config.selectors.seekTime);
|
player.progress.played.bar = _getElement(config.selectors.progress.played);
|
||||||
|
player.progress.played.text = player.progress.played.bar.getElementsByTagName("span")[0];
|
||||||
|
|
||||||
|
// Volume
|
||||||
|
player.volume = _getElement(config.selectors.buttons.volume);
|
||||||
|
|
||||||
|
// Timing
|
||||||
|
player.duration = _getElement(config.selectors.duration);
|
||||||
|
player.seekTime = _getElements(config.selectors.seekTime);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
_log("It looks like there's a problem with your controls html. Bailing.", true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup media
|
// Setup media
|
||||||
@ -416,7 +477,7 @@
|
|||||||
|
|
||||||
// If there's no media, bail
|
// If there's no media, bail
|
||||||
if(!player.media) {
|
if(!player.media) {
|
||||||
console.error("No audio or video element found!");
|
_log("No audio or video element found!", true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,14 +540,10 @@
|
|||||||
player.captionExists = true;
|
player.captionExists = true;
|
||||||
if (captionSrc === "") {
|
if (captionSrc === "") {
|
||||||
player.captionExists = false;
|
player.captionExists = false;
|
||||||
if (config.debug) {
|
_log("No caption track found.");
|
||||||
console.log("No caption track found.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (config.debug) {
|
_log("Caption track found; URI: " + captionSrc);
|
||||||
console.log("Caption track found; URI: " + captionSrc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no caption file exists, hide container for caption text
|
// If no caption file exists, hide container for caption text
|
||||||
@ -495,42 +552,38 @@
|
|||||||
}
|
}
|
||||||
// If caption file exists, process captions
|
// If caption file exists, process captions
|
||||||
else {
|
else {
|
||||||
var track = {}, tracks, j;
|
// 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 = player.media.textTracks;
|
||||||
|
for (var x=0; x < tracks.length; x++) {
|
||||||
|
tracks[x].mode = "hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable UI
|
||||||
|
_showCaptions(player);
|
||||||
|
|
||||||
// If IE 10/11 or Firefox 31+ or Safari 7+, don"t use native captioning (still doesn"t work although they claim it"s now supported)
|
// If IE 10/11 or Firefox 31+ or Safari 7+, don"t use native captioning (still doesn"t work although they claim it"s now supported)
|
||||||
if ((player.browserName === "IE" && player.browserMajorVersion === 10) ||
|
if ((player.browserName === "IE" && player.browserMajorVersion === 10) ||
|
||||||
(player.browserName === "IE" && player.browserMajorVersion === 11) ||
|
(player.browserName === "IE" && player.browserMajorVersion === 11) ||
|
||||||
(player.browserName === "Firefox" && player.browserMajorVersion >= 31) ||
|
(player.browserName === "Firefox" && player.browserMajorVersion >= 31) ||
|
||||||
(player.browserName === "Safari" && player.browserMajorVersion >= 7)) {
|
(player.browserName === "Safari" && player.browserMajorVersion >= 7)) {
|
||||||
if (config.debug) {
|
// Debugging
|
||||||
console.log("Detected IE 10/11 or Firefox 31+ or Safari 7+");
|
_log("Detected IE 10/11 or Firefox 31+ or Safari 7+.");
|
||||||
}
|
|
||||||
// set to false so skips to "manual" captioning
|
// Set to false so skips to "manual" captioning
|
||||||
player.isTextTracks = false;
|
player.isTextTracks = false;
|
||||||
|
|
||||||
// turn off native caption rendering to avoid double captions [doesn"t work in Safari 7; see patch below]
|
|
||||||
track = {};
|
|
||||||
tracks = player.media.textTracks;
|
|
||||||
for (j=0; j < tracks.length; j++) {
|
|
||||||
track = player.media.textTracks[j];
|
|
||||||
track.mode = "hidden";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rendering caption tracks - native support required - http://caniuse.com/webvtt
|
// Rendering caption tracks
|
||||||
|
// Native support required - http://caniuse.com/webvtt
|
||||||
if (player.isTextTracks) {
|
if (player.isTextTracks) {
|
||||||
if (config.debug) {
|
_log("TextTracks supported.");
|
||||||
console.log("textTracks supported");
|
|
||||||
}
|
for (var y=0; y < tracks.length; y++) {
|
||||||
_showCaptions(player);
|
var track = tracks[y];
|
||||||
|
|
||||||
track = {};
|
|
||||||
tracks = player.media.textTracks;
|
|
||||||
for (j=0; j < tracks.length; j++) {
|
|
||||||
track = player.media.textTracks[j];
|
|
||||||
track.mode = "hidden";
|
|
||||||
if (track.kind === "captions") {
|
if (track.kind === "captions") {
|
||||||
_on(track, "cuechange",function() {
|
_on(track, "cuechange", function() {
|
||||||
if (this.activeCues[0]) {
|
if (this.activeCues[0]) {
|
||||||
if (this.activeCues[0].hasOwnProperty("text")) {
|
if (this.activeCues[0].hasOwnProperty("text")) {
|
||||||
player.captionsContainer.innerHTML = this.activeCues[0].text;
|
player.captionsContainer.innerHTML = this.activeCues[0].text;
|
||||||
@ -542,10 +595,7 @@
|
|||||||
}
|
}
|
||||||
// Caption tracks not natively supported
|
// Caption tracks not natively supported
|
||||||
else {
|
else {
|
||||||
if (config.debug) {
|
_log("TextTracks not supported so rendering captions manually.");
|
||||||
console.log("textTracks not supported so rendering captions manually");
|
|
||||||
}
|
|
||||||
_showCaptions(player);
|
|
||||||
|
|
||||||
// Render captions from array at appropriate time
|
// Render captions from array at appropriate time
|
||||||
player.currentCaption = "";
|
player.currentCaption = "";
|
||||||
@ -574,12 +624,12 @@
|
|||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState === 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
player.captions = [];
|
|
||||||
var records = [],
|
var records = [],
|
||||||
record,
|
record,
|
||||||
req = xhr.responseText;
|
req = xhr.responseText;
|
||||||
|
|
||||||
records = req.split("\n\n");
|
records = req.split("\n\n");
|
||||||
|
|
||||||
for (var r=0; r < records.length; r++) {
|
for (var r=0; r < records.length; r++) {
|
||||||
record = records[r];
|
record = records[r];
|
||||||
player.captions[r] = [];
|
player.captions[r] = [];
|
||||||
@ -589,12 +639,10 @@
|
|||||||
// Remove first element ("VTT")
|
// Remove first element ("VTT")
|
||||||
player.captions.shift();
|
player.captions.shift();
|
||||||
|
|
||||||
if (config.debug) {
|
_log("Successfully loaded the caption file via AJAX.");
|
||||||
console.log("Successfully loaded the caption file via ajax.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (config.debug) {
|
else {
|
||||||
console.error("There was a problem loading the caption file via ajax.");
|
_log("There was a problem loading the caption file via AJAX.", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -605,13 +653,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Safari 7, removing track from DOM [see "turn off native caption rendering" above]
|
// If Safari 7+, removing track from DOM [see "turn off native caption rendering" above]
|
||||||
if (player.browserName === "Safari" && player.browserMajorVersion === 7) {
|
if (player.browserName === "Safari" && player.browserMajorVersion >= 7) {
|
||||||
if (config.debug) {
|
_log("Safari 7+ detected; removing track from DOM.");
|
||||||
console.log("Safari 7 detected; removing track from DOM");
|
|
||||||
}
|
// Find all <track> elements
|
||||||
tracks = player.media.getElementsByTagName("track");
|
tracks = player.media.getElementsByTagName("track");
|
||||||
player.media.removeChild(tracks[0]);
|
|
||||||
|
// Loop through and remove one by one
|
||||||
|
for (var t=0; t < tracks.length; t++) {
|
||||||
|
player.media.removeChild(tracks[t]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -627,15 +679,17 @@
|
|||||||
// Setup fullscreen
|
// Setup fullscreen
|
||||||
function _setupFullscreen() {
|
function _setupFullscreen() {
|
||||||
if(player.type === "video" && config.fullscreen.enabled) {
|
if(player.type === "video" && config.fullscreen.enabled) {
|
||||||
if(fullscreen.supportsFullScreen) {
|
// Check for native support
|
||||||
if(config.debug) {
|
var nativeSupport = fullscreen.supportsFullScreen;
|
||||||
console.log("Fullscreen enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(nativeSupport || (config.fullscreen.fallback && !_inFrame())) {
|
||||||
|
_log((nativeSupport ? "Native" : "Fallback") + " fullscreen enabled.");
|
||||||
|
|
||||||
|
// Add styling hook
|
||||||
_toggleClass(player.container, config.classes.fullscreen.enabled, true);
|
_toggleClass(player.container, config.classes.fullscreen.enabled, true);
|
||||||
}
|
}
|
||||||
else if(config.debug) {
|
else {
|
||||||
console.warn("Fullscreen not supported");
|
_log("Fullscreen not supported and fallback disabled.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,11 +768,51 @@
|
|||||||
|
|
||||||
// Toggle fullscreen
|
// Toggle fullscreen
|
||||||
function _toggleFullscreen() {
|
function _toggleFullscreen() {
|
||||||
if(!fullscreen.isFullScreen()) {
|
// Check for native support
|
||||||
fullscreen.requestFullScreen(player.container);
|
var nativeSupport = fullscreen.supportsFullScreen;
|
||||||
|
|
||||||
|
// If it's a fullscreen change event, it's probably a native close
|
||||||
|
if(event.type === fullscreen.fullScreenEventName) {
|
||||||
|
config.fullscreen.active = fullscreen.isFullScreen();
|
||||||
|
}
|
||||||
|
// If there's native support, use it
|
||||||
|
else if(nativeSupport) {
|
||||||
|
// Request fullscreen
|
||||||
|
if(!fullscreen.isFullScreen()) {
|
||||||
|
fullscreen.requestFullScreen(player.container);
|
||||||
|
}
|
||||||
|
// Bail from fullscreen
|
||||||
|
else {
|
||||||
|
fullscreen.cancelFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're actually full screen (it could fail)
|
||||||
|
config.fullscreen.active = fullscreen.isFullScreen();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fullscreen.cancelFullScreen();
|
// Otherwise, it's a simple toggle
|
||||||
|
config.fullscreen.active = !config.fullscreen.active;
|
||||||
|
|
||||||
|
// Bind/unbind escape key
|
||||||
|
if(config.fullscreen.active) {
|
||||||
|
_on(document, "keyup", _handleEscapeFullscreen);
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_off(document, "keyup", _handleEscapeFullscreen);
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set class hook
|
||||||
|
_toggleClass(player.container, config.classes.fullscreen.active, config.fullscreen.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail from faux-fullscreen
|
||||||
|
function _handleEscapeFullscreen(event) {
|
||||||
|
// If it's a keypress and not escape, bail
|
||||||
|
if((event.which || event.charCode || event.keyCode) === 27 && config.fullscreen.active) {
|
||||||
|
_toggleFullscreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,7 +820,12 @@
|
|||||||
function _setVolume(volume) {
|
function _setVolume(volume) {
|
||||||
// Use default if needed
|
// Use default if needed
|
||||||
if(typeof volume === "undefined") {
|
if(typeof volume === "undefined") {
|
||||||
volume = config.volume;
|
if(config.storage.enabled && config.storage.supported) {
|
||||||
|
volume = window.localStorage.plyr_volume || config.volume;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
volume = config.volume;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Maximum is 10
|
// Maximum is 10
|
||||||
if(volume > 10) {
|
if(volume > 10) {
|
||||||
@ -736,6 +835,11 @@
|
|||||||
player.volume.value = volume;
|
player.volume.value = volume;
|
||||||
player.media.volume = parseFloat(volume / 10);
|
player.media.volume = parseFloat(volume / 10);
|
||||||
_checkMute();
|
_checkMute();
|
||||||
|
|
||||||
|
// Store the volume in storage
|
||||||
|
if(config.storage.enabled && config.storage.supported) {
|
||||||
|
window.localStorage.plyr_volume = volume;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mute
|
// Mute
|
||||||
@ -771,26 +875,56 @@
|
|||||||
_toggleClass(player.container, config.classes.muted, (player.media.volume === 0 || player.media.muted));
|
_toggleClass(player.container, config.classes.muted, (player.media.volume === 0 || player.media.muted));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for events
|
// Update <progress> elements
|
||||||
function _listeners() {
|
function _updateProgress(event) {
|
||||||
// Fullscreen
|
var progress, text, value = 0;
|
||||||
_on(player.buttons.fullscreen, "click", _toggleFullscreen);
|
|
||||||
|
|
||||||
// Click video
|
switch(event.type) {
|
||||||
if(player.type === "video" && config.click) {
|
// Video playing
|
||||||
_on(player.videoContainer, "click", function() {
|
case "timeupdate":
|
||||||
if(player.media.paused) {
|
progress = player.progress.played.bar;
|
||||||
_play();
|
text = player.progress.played.text;
|
||||||
}
|
value = _getPercentage(player.media.currentTime, player.media.duration);
|
||||||
else if(player.media.ended) {
|
break;
|
||||||
_restart();
|
|
||||||
}
|
// Check buffer status
|
||||||
else {
|
case "playing":
|
||||||
_pause();
|
case "progress":
|
||||||
}
|
progress = player.progress.buffer.bar;
|
||||||
});
|
text = player.progress.buffer.text;
|
||||||
|
value = (function() {
|
||||||
|
var buffered = player.media.buffered;
|
||||||
|
|
||||||
|
if(buffered.length) {
|
||||||
|
return _getPercentage(buffered.end(0), player.media.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (progress && value > 0) {
|
||||||
|
progress.value = value;
|
||||||
|
text.innerHTML = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the displayed play time
|
||||||
|
function _updateTimeDisplay() {
|
||||||
|
player.secs = parseInt(player.media.currentTime % 60);
|
||||||
|
player.mins = parseInt((player.media.currentTime / 60) % 60);
|
||||||
|
|
||||||
|
// Ensure it"s two digits. For example, 03 rather than 3.
|
||||||
|
player.secs = ("0" + player.secs).slice(-2);
|
||||||
|
player.mins = ("0" + player.mins).slice(-2);
|
||||||
|
|
||||||
|
// Render
|
||||||
|
player.duration.innerHTML = player.mins + ":" + player.secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for events
|
||||||
|
function _listeners() {
|
||||||
// Play
|
// Play
|
||||||
_on(player.buttons.play, "click", function() {
|
_on(player.buttons.play, "click", function() {
|
||||||
_play();
|
_play();
|
||||||
@ -825,32 +959,36 @@
|
|||||||
_on(player.buttons.mute, "change", function() {
|
_on(player.buttons.mute, "change", function() {
|
||||||
_toggleMute(this.checked);
|
_toggleMute(this.checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fullscreen
|
||||||
|
_on(player.buttons.fullscreen, "click", _toggleFullscreen);
|
||||||
|
|
||||||
|
// Handle user exiting fullscreen by escaping etc
|
||||||
|
_on(document, fullscreen.fullScreenEventName, _toggleFullscreen);
|
||||||
|
|
||||||
|
// Click video
|
||||||
|
if(player.type === "video" && config.click) {
|
||||||
|
_on(player.videoContainer, "click", function() {
|
||||||
|
if(player.media.paused) {
|
||||||
|
_play();
|
||||||
|
}
|
||||||
|
else if(player.media.ended) {
|
||||||
|
_restart();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Duration
|
// Duration
|
||||||
_on(player.media, "timeupdate", function() {
|
_on(player.media, "timeupdate", _updateTimeDisplay);
|
||||||
player.secs = parseInt(player.media.currentTime % 60);
|
|
||||||
player.mins = parseInt((player.media.currentTime / 60) % 60);
|
|
||||||
|
|
||||||
// Ensure it"s two digits. For example, 03 rather than 3.
|
|
||||||
player.secs = ("0" + player.secs).slice(-2);
|
|
||||||
player.mins = ("0" + player.mins).slice(-2);
|
|
||||||
|
|
||||||
// Render
|
// Playing progress
|
||||||
player.duration.innerHTML = player.mins + ":" + player.secs;
|
_on(player.media, "timeupdate", _updateProgress);
|
||||||
});
|
|
||||||
|
|
||||||
// Progress bar
|
|
||||||
_on(player.media, "timeupdate", function() {
|
|
||||||
player.percent = (100 / player.media.duration) * player.media.currentTime;
|
|
||||||
|
|
||||||
if (player.percent > 0) {
|
|
||||||
player.progress.bar.value = player.percent;
|
|
||||||
player.progress.text.innerHTML = player.percent;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Skip when clicking progress bar
|
// Skip when clicking progress bar
|
||||||
_on(player.progress.bar, "click", function(event) {
|
_on(player.progress.played.bar, "click", function(event) {
|
||||||
player.pos = _getClickPosition(event).x / this.offsetWidth;
|
player.pos = _getClickPosition(event).x / this.offsetWidth;
|
||||||
player.media.currentTime = player.pos * player.media.duration;
|
player.media.currentTime = player.pos * player.media.duration;
|
||||||
|
|
||||||
@ -873,6 +1011,11 @@
|
|||||||
_toggleClass(player.container, config.classes.stopped, true);
|
_toggleClass(player.container, config.classes.stopped, true);
|
||||||
_toggleClass(player.container, config.classes.playing);
|
_toggleClass(player.container, config.classes.playing);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check for buffer progress
|
||||||
|
_on(player.media, "progress", _updateProgress);
|
||||||
|
// Also check on start of playing
|
||||||
|
_on(player.media, "playing", _updateProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _init() {
|
function _init() {
|
||||||
@ -885,16 +1028,12 @@
|
|||||||
player.browserMajorVersion = player.browserInfo[1];
|
player.browserMajorVersion = player.browserInfo[1];
|
||||||
|
|
||||||
// Debug info
|
// Debug info
|
||||||
if(config.debug) {
|
_log(player.browserName + " " + player.browserMajorVersion);
|
||||||
console.log(player.browserName + " " + player.browserMajorVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If IE8, stop customization (use fallback)
|
// If IE8, stop customization (use fallback)
|
||||||
// If IE9, stop customization (use native controls)
|
// If IE9, stop customization (use native controls)
|
||||||
if (player.browserName === "IE" && (player.browserMajorVersion === 8 || player.browserMajorVersion === 9) ) {
|
if (player.browserName === "IE" && (player.browserMajorVersion === 8 || player.browserMajorVersion === 9) ) {
|
||||||
if(config.debug) {
|
_log("Browser not suppported.", true);
|
||||||
console.error("Browser not suppported.");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,17 +1055,19 @@
|
|||||||
_injectControls();
|
_injectControls();
|
||||||
|
|
||||||
// Find the elements
|
// Find the elements
|
||||||
_findElements();
|
if(!_findElements()) {
|
||||||
|
return false;
|
||||||
// Set volume
|
}
|
||||||
_setVolume(config.volume);
|
|
||||||
|
|
||||||
// Setup fullscreen
|
|
||||||
_setupFullscreen();
|
|
||||||
|
|
||||||
// Captions
|
// Captions
|
||||||
_setupCaptions();
|
_setupCaptions();
|
||||||
|
|
||||||
|
// Set volume
|
||||||
|
_setVolume();
|
||||||
|
|
||||||
|
// Setup fullscreen
|
||||||
|
_setupFullscreen();
|
||||||
|
|
||||||
// Seeking
|
// Seeking
|
||||||
_setupSeeking();
|
_setupSeeking();
|
||||||
|
|
||||||
@ -967,9 +1108,11 @@
|
|||||||
for (var i = elements.length - 1; i >= 0; i--) {
|
for (var i = elements.length - 1; i >= 0; i--) {
|
||||||
// Get the current element
|
// Get the current element
|
||||||
var element = elements[i];
|
var element = elements[i];
|
||||||
|
|
||||||
// Setup a player instance and add to the element
|
// Setup a player instance and add to the element
|
||||||
element.plyr = new Plyr(element);
|
if(typeof element.plyr === "undefined") {
|
||||||
|
element.plyr = new Plyr(element);
|
||||||
|
}
|
||||||
|
|
||||||
// Add to return array
|
// Add to return array
|
||||||
players.push(element.plyr);
|
players.push(element.plyr);
|
||||||
|
@ -30,12 +30,12 @@
|
|||||||
|
|
||||||
// Base
|
// Base
|
||||||
html {
|
html {
|
||||||
font-size: 62.5%;
|
//font-size: 62.5%;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
.font-size(16);
|
//.font-size(16);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #6D797F;
|
color: #6D797F;
|
||||||
@ -130,8 +130,8 @@ a {
|
|||||||
.example-video .player {
|
.example-video .player {
|
||||||
margin: 0 auto @padding-base;
|
margin: 0 auto @padding-base;
|
||||||
|
|
||||||
&:fullscreen,
|
&-fullscreen,
|
||||||
&-fullscreen {
|
&.fullscreen-active {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use rems for font sizing
|
// Use rems for font sizing
|
||||||
|
// Leave <body> at 100%/16px
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
.font-size(@font-size: 16){
|
.font-size(@font-size: 16){
|
||||||
@rem: (@font-size / 10);
|
@rem: round((@font-size / 16), 1);
|
||||||
font-size: @font-size * 1px;
|
font-size: (@font-size * 1px);
|
||||||
font-size: ~"@{rem}rem";
|
font-size: ~"@{rem}rem";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,16 +18,22 @@
|
|||||||
@control-spacing: 10px;
|
@control-spacing: 10px;
|
||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
@progress-bg: @gray;
|
@progress-bg: lighten(@gray, 10%);
|
||||||
@progress-value-bg: @blue;
|
@progress-playing-bg: @blue;
|
||||||
|
@progress-buffered-bg: @gray;
|
||||||
|
|
||||||
// Range
|
// Range
|
||||||
@range-track-height: 6px;
|
@range-track-height: 6px;
|
||||||
|
@range-track-bg: @gray;
|
||||||
@range-thumb-height: (@range-track-height * 2);
|
@range-thumb-height: (@range-track-height * 2);
|
||||||
@range-thumb-width: (@range-track-height * 2);
|
@range-thumb-width: (@range-track-height * 2);
|
||||||
@range-thumb-bg: @control-color;
|
@range-thumb-bg: @control-color;
|
||||||
@range-thumb-bg-focus: @control-color-active;
|
@range-thumb-bg-focus: @control-color-active;
|
||||||
|
|
||||||
|
// Breakpoints
|
||||||
|
@bp-control-split: 560px; // When controls split into left/right
|
||||||
|
@bg-captions-large: 768px; // When captions jump to the larger font size
|
||||||
|
|
||||||
// Utility classes & mixins
|
// Utility classes & mixins
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Screen reader only
|
// Screen reader only
|
||||||
@ -67,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
.range-track() {
|
.range-track() {
|
||||||
height: @range-track-height;
|
height: @range-track-height;
|
||||||
background: @gray;
|
background: @range-track-bg;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: (@range-track-height / 2);
|
border-radius: (@range-track-height / 2);
|
||||||
}
|
}
|
||||||
@ -91,9 +97,8 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 290px;
|
min-width: 290px;
|
||||||
overflow: hidden; // For the controls
|
overflow: hidden; // For the controls
|
||||||
background: #000;
|
|
||||||
|
|
||||||
// BORDER-BOX ALL THE THINGS!
|
// border-box everything
|
||||||
// http://paulirish.com/2012/box-sizing-border-box-ftw/
|
// http://paulirish.com/2012/box-sizing-border-box-ftw/
|
||||||
&,
|
&,
|
||||||
*,
|
*,
|
||||||
@ -125,14 +130,14 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-shadow:
|
text-shadow:
|
||||||
-1px -1px 0 rgba(red(@gray-dark), green(@gray-dark), blue(@gray-dark), .5),
|
-1px -1px 0 @gray,
|
||||||
1px -1px 0 rgba(red(@gray-dark), green(@gray-dark), blue(@gray-dark), .5),
|
1px -1px 0 @gray,
|
||||||
-1px 1px 0 rgba(red(@gray-dark), green(@gray-dark), blue(@gray-dark), .5),
|
-1px 1px 0 @gray,
|
||||||
1px 1px 0 rgba(red(@gray-dark), green(@gray-dark), blue(@gray-dark), .5);
|
1px 1px 0 @gray;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
.font-smoothing();
|
.font-smoothing();
|
||||||
|
|
||||||
@media (min-width: 560px) {
|
@media (min-width: @bg-captions-large) {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,13 +153,14 @@
|
|||||||
padding: (@control-spacing * 2) @control-spacing @control-spacing;
|
padding: (@control-spacing * 2) @control-spacing @control-spacing;
|
||||||
background: @controls-bg;
|
background: @controls-bg;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
&-sound {
|
&-sound {
|
||||||
display: block;
|
display: block;
|
||||||
margin: @control-spacing auto 0;
|
margin: @control-spacing auto 0;
|
||||||
}
|
}
|
||||||
@media (min-width: 560px) {
|
@media (min-width: @bp-control-split) {
|
||||||
&-playback {
|
&-playback {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
@ -197,21 +203,15 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
button:hover,
|
|
||||||
label:hover {
|
|
||||||
background: @control-color-active;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
input:focus + label,
|
input:focus + label,
|
||||||
button:focus {
|
button:focus {
|
||||||
.tab-focus();
|
.tab-focus();
|
||||||
|
color: #fff;
|
||||||
svg {
|
}
|
||||||
fill: #fff;
|
button:hover,
|
||||||
}
|
input + label:hover {
|
||||||
|
background: @control-color-active;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
.icon-exit-fullscreen,
|
.icon-exit-fullscreen,
|
||||||
.icon-muted {
|
.icon-muted {
|
||||||
@ -237,27 +237,48 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: @control-spacing;
|
height: @control-spacing;
|
||||||
margin: 0;
|
background: @progress-bg;
|
||||||
vertical-align: top;
|
|
||||||
|
&-buffer,
|
||||||
&[value] {
|
&-played {
|
||||||
-webkit-appearance: none;
|
position: absolute;
|
||||||
border: none;
|
left: 0;
|
||||||
background: @progress-bg;
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
&[value] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
|
||||||
|
&::-webkit-progress-bar {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit from currentColor;
|
||||||
|
&::-webkit-progress-value {
|
||||||
|
background: currentColor;
|
||||||
|
transition: width .1s ease;
|
||||||
|
}
|
||||||
|
&::-moz-progress-bar {
|
||||||
|
background: currentColor;
|
||||||
|
transition: width .1s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-played {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
&-played[value] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: @progress-value-bg;
|
color: @progress-playing-bg;
|
||||||
|
}
|
||||||
&::-webkit-progress-bar {
|
&-buffer[value] {
|
||||||
background: @progress-bg;
|
color: @progress-buffered-bg;
|
||||||
}
|
|
||||||
|
|
||||||
// Inherit from currentColor;
|
|
||||||
&::-webkit-progress-value {
|
|
||||||
background: currentColor;
|
|
||||||
}
|
|
||||||
&::-moz-progress-bar {
|
|
||||||
background: currentColor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,15 +364,15 @@
|
|||||||
|
|
||||||
// Full screen mode
|
// Full screen mode
|
||||||
&-fullscreen,
|
&-fullscreen,
|
||||||
&:fullscreen {
|
&.fullscreen-active {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 999999;
|
z-index: 10000000;
|
||||||
|
|
||||||
.player-video-wrapper {
|
.player-video-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -364,15 +385,13 @@
|
|||||||
top: auto;
|
top: auto;
|
||||||
bottom: 90px;
|
bottom: 90px;
|
||||||
|
|
||||||
@media (min-width: 560px) and (max-width: 767px) {
|
@media (min-width: @bp-control-split) and (max-width: (@bg-captions-large - 1)) {
|
||||||
bottom: 60px;
|
bottom: 60px;
|
||||||
}
|
}
|
||||||
|
@media (min-width: @bg-captions-large) {
|
||||||
@media (min-width: 768px) {
|
|
||||||
bottom: 80px;
|
bottom: 80px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.player-controls {
|
.player-controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
<div class="player-controls">
|
<div class="player-controls">
|
||||||
<progress class="player-progress" max="100" value="0">
|
<div class="player-progress">
|
||||||
<span>0</span>% played
|
<progress class="player-progress-played" max="100" value="0">
|
||||||
</progress>
|
<span>0</span>% played
|
||||||
|
</progress>
|
||||||
|
<progress class="player-progress-buffer" max="100" value="0">
|
||||||
|
<span>0</span>% buffered
|
||||||
|
</progress>
|
||||||
|
</div>
|
||||||
<span class="player-controls-playback">
|
<span class="player-controls-playback">
|
||||||
<button type="button" data-player="restart">
|
<button type="button" data-player="restart">
|
||||||
<svg><use xlink:href="#icon-refresh"></use></svg>
|
<svg><use xlink:href="#icon-refresh"></use></svg>
|
||||||
|
36
changelog.md
Normal file
36
changelog.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v1.0.9
|
||||||
|
- Added buffer progress bar
|
||||||
|
- Fixed Safari 8 caption track (it needs to be removed from the DOM like in Safari 7)
|
||||||
|
- Added validation (it works or it doesn't basically) of the `html` option passed
|
||||||
|
|
||||||
|
## v1.0.8
|
||||||
|
- Bug fix
|
||||||
|
|
||||||
|
## v1.0.7
|
||||||
|
- Storing user selected volume in local storage
|
||||||
|
|
||||||
|
## v1.0.6
|
||||||
|
- Fullscreen fallback for older browsers to use "full window"
|
||||||
|
|
||||||
|
## v1.0.5
|
||||||
|
- More minor bug fixes and improvements
|
||||||
|
|
||||||
|
## v1.0.4
|
||||||
|
- Fixed caption legibility issues
|
||||||
|
|
||||||
|
## v1.0.3
|
||||||
|
- Minor bug fixes
|
||||||
|
|
||||||
|
## v1.0.2
|
||||||
|
- Added OGG to <audio> example for Firefox
|
||||||
|
- Fixed IE11 fullscreen issues
|
||||||
|
|
||||||
|
## v1.0.1
|
||||||
|
- Bug fixes for IE (as per usual)
|
||||||
|
- Added CSS hooks for media type
|
||||||
|
- Return instances of Plyr to the element
|
||||||
|
|
||||||
|
## v1.0.0
|
||||||
|
- Initial release
|
2
dist/css/docs.css
vendored
2
dist/css/docs.css
vendored
@ -1 +1 @@
|
|||||||
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}*,::after,::before{box-sizing:border-box}html{font-size:62.5%}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;background:#fff;font-size:16px;font-size:1.6rem;line-height:1.5;text-align:center;color:#6D797F}h1,h2{letter-spacing:-.025em;color:#2E3C44;margin:0 0 10px;line-height:1.2;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}h1{font-size:64px;font-size:6.4rem;color:#3498DB}p,small{margin:0 0 20px}small{display:block;padding:0 10px;font-size:14px;font-size:1.4rem}header{padding:20px;margin-bottom:20px}header p{font-size:18px;font-size:1.8rem}@media (min-width:560px){header{padding-top:60px;padding-bottom:60px}}section{padding-bottom:20px}@media (min-width:560px){section{padding-bottom:40px}}a{text-decoration:none;color:#3498db;border-bottom:1px solid currentColor;transition:all .3s ease}a:focus,a:hover{color:#000}a:focus{outline:#343f4a dotted thin;outline-offset:1px}.btn{display:inline-block;padding:10px 30px;background:#3498db;border:0;color:#fff;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-weight:600;border-radius:3px}.btn:focus,.btn:hover{color:#fff;background:#258cd1}.example-audio .player{max-width:480px}.example-video .player{max-width:1200px}.example-audio .player,.example-video .player{margin:0 auto 20px}.example-audio .player-fullscreen,.example-audio .player:-webkit-full-screen,.example-video .player-fullscreen,.example-video .player:-webkit-full-screen{max-width:none}.example-audio .player-fullscreen,.example-audio .player:-moz-full-screen,.example-video .player-fullscreen,.example-video .player:-moz-full-screen{max-width:none}.example-audio .player-fullscreen,.example-audio .player:-ms-fullscreen,.example-video .player-fullscreen,.example-video .player:-ms-fullscreen{max-width:none}.example-audio .player-fullscreen,.example-audio .player:fullscreen,.example-video .player-fullscreen,.example-video .player:fullscreen{max-width:none}@font-face{font-family:Avenir;src:url(../../assets/fonts/AvenirLTStd-Medium.woff2) format("woff2"),url(../../assets/fonts/AvenirLTStd-Medium.woff) format("woff"),url(../../assets/fonts/AvenirLTStd-Medium.ttf) format("truetype");font-style:normal;font-weight:400}@font-face{font-family:Avenir;src:url(../../assets/fonts/AvenirLTStd-Heavy.woff2) format("woff2"),url(../../assets/fonts/AvenirLTStd-Heavy.woff) format("woff"),url(../../assets/fonts/AvenirLTStd-Heavy.ttf) format("truetype");font-style:normal;font-weight:600}
|
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}*,::after,::before{box-sizing:border-box}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;background:#fff;line-height:1.5;text-align:center;color:#6D797F}h1,h2{letter-spacing:-.025em;color:#2E3C44;margin:0 0 10px;line-height:1.2;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}h1{font-size:64px;font-size:4rem;color:#3498DB}p,small{margin:0 0 20px}small{display:block;padding:0 10px;font-size:14px;font-size:.9rem}header{padding:20px;margin-bottom:20px}header p{font-size:18px;font-size:1.1rem}@media (min-width:560px){header{padding-top:60px;padding-bottom:60px}}section{padding-bottom:20px}@media (min-width:560px){section{padding-bottom:40px}}a{text-decoration:none;color:#3498db;border-bottom:1px solid currentColor;transition:all .3s ease}a:focus,a:hover{color:#000}a:focus{outline:#343f4a dotted thin;outline-offset:1px}.btn{display:inline-block;padding:10px 30px;background:#3498db;border:0;color:#fff;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-weight:600;border-radius:3px}.btn:focus,.btn:hover{color:#fff;background:#258cd1}.example-audio .player{max-width:480px}.example-video .player{max-width:1200px}.example-audio .player,.example-video .player{margin:0 auto 20px}.example-audio .player-fullscreen,.example-audio .player.fullscreen-active,.example-video .player-fullscreen,.example-video .player.fullscreen-active{max-width:none}@font-face{font-family:Avenir;src:url(../../assets/fonts/AvenirLTStd-Medium.woff2) format("woff2"),url(../../assets/fonts/AvenirLTStd-Medium.woff) format("woff"),url(../../assets/fonts/AvenirLTStd-Medium.ttf) format("truetype");font-style:normal;font-weight:400}@font-face{font-family:Avenir;src:url(../../assets/fonts/AvenirLTStd-Heavy.woff2) format("woff2"),url(../../assets/fonts/AvenirLTStd-Heavy.woff) format("woff"),url(../../assets/fonts/AvenirLTStd-Heavy.ttf) format("truetype");font-style:normal;font-weight:600}
|
2
dist/css/plyr.css
vendored
2
dist/css/plyr.css
vendored
File diff suppressed because one or more lines are too long
2
dist/js/docs.js
vendored
2
dist/js/docs.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/plyr.js
vendored
2
dist/js/plyr.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/templates.js
vendored
2
dist/js/templates.js
vendored
@ -1,2 +1,2 @@
|
|||||||
var templates = {};
|
var templates = {};
|
||||||
templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <progress class=\"player-progress\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <span class=\"player-controls-playback\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-refresh\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind <span class=\"player-seek-time\">10</span> seconds</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" aria-label=\"{aria-label}\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Fast forward <span class=\"player-seek-time\">10</span> seconds</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Time</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-sound\">");t.b("\n" + i);t.b(" <input class=\"inverted sr-only\" id=\"mute{id}\" type=\"checkbox\" data-player=\"mute\">");t.b("\n" + i);t.b(" <label id=\"mute{id}\" for=\"mute{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-sound\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Mute</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume:</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" value=\"5\" data-player=\"volume\">");t.b("\n");t.b("\n" + i);t.b(" <input class=\"sr-only\" id=\"captions{id}\" type=\"checkbox\" data-player=\"captions\">");t.b("\n" + i);t.b(" <label for=\"captions{id}\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-bubble\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Captions</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-collapse\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-expand\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
|
templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <div class=\"player-progress\">");t.b("\n" + i);t.b(" <progress class=\"player-progress-played\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <progress class=\"player-progress-buffer\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% buffered");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <span class=\"player-controls-playback\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-refresh\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind <span class=\"player-seek-time\">10</span> seconds</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" aria-label=\"{aria-label}\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Fast forward <span class=\"player-seek-time\">10</span> seconds</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Time</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-sound\">");t.b("\n" + i);t.b(" <input class=\"inverted sr-only\" id=\"mute{id}\" type=\"checkbox\" data-player=\"mute\">");t.b("\n" + i);t.b(" <label id=\"mute{id}\" for=\"mute{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-sound\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Mute</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume:</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" value=\"5\" data-player=\"volume\">");t.b("\n");t.b("\n" + i);t.b(" <input class=\"sr-only\" id=\"captions{id}\" type=\"checkbox\" data-player=\"captions\">");t.b("\n" + i);t.b(" <label for=\"captions{id}\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-bubble\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Captions</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-collapse\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-expand\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
|
@ -26,7 +26,7 @@
|
|||||||
<source src="//cdn.sampotts.me/plyr/movie.webm" type="video/webm">
|
<source src="//cdn.sampotts.me/plyr/movie.webm" type="video/webm">
|
||||||
|
|
||||||
<!-- Text track file -->
|
<!-- Text track file -->
|
||||||
<track kind="captions" label="English captions" src="//cdn.sampotts.me/plyr/movie_captions.vtt" srclang="en" default>
|
<track kind="captions" label="English" srclang="en" src="assets/movie_en_captions.vtt" default>
|
||||||
|
|
||||||
<!-- Fallback for browsers that don't support the <video> element -->
|
<!-- Fallback for browsers that don't support the <video> element -->
|
||||||
<div>
|
<div>
|
||||||
|
@ -8,7 +8,7 @@ We wanted a lightweight, accessible and customisable media player that just supp
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **Accessible** - full support for captions and screen readers.
|
- **Accessible** - full support for captions and screen readers.
|
||||||
- **Lightweight** - just 4KB minified and gzipped.
|
- **Lightweight** - just 4.8KB minified and gzipped.
|
||||||
- **Customisable** - make the player look how you want with the markup you want.
|
- **Customisable** - make the player look how you want with the markup you want.
|
||||||
- **Semantic** - uses HTML5 form inputs for volume (range) and progress element for playback progress.
|
- **Semantic** - uses HTML5 form inputs for volume (range) and progress element for playback progress.
|
||||||
- **No dependencies** - written in native JS.
|
- **No dependencies** - written in native JS.
|
||||||
@ -20,6 +20,9 @@ We wanted a lightweight, accessible and customisable media player that just supp
|
|||||||
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
|
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
|
||||||
- Accept a selector for the `html` template property.
|
- Accept a selector for the `html` template property.
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
Check out [the changelog](changelog.md)
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
### Bower
|
### Bower
|
||||||
|
Reference in New Issue
Block a user