Added support for multiple instances
This commit is contained in:
parent
4499bf39ef
commit
383fdf0af4
@ -4,14 +4,9 @@
|
||||
|
||||
/*global simpleMedia, templates */
|
||||
|
||||
// Register a callback
|
||||
simpleMedia.on("setup", function() {
|
||||
//console.log(this);
|
||||
});
|
||||
|
||||
//execute shout
|
||||
// Setup the player
|
||||
simpleMedia.setup({
|
||||
//debug: true,
|
||||
debug: true,
|
||||
title: "Video demo",
|
||||
html: templates.controls.render({})
|
||||
});
|
@ -8,15 +8,12 @@
|
||||
|
||||
/*global ActiveXObject*/
|
||||
|
||||
(function(api){
|
||||
(function (api) {
|
||||
"use strict";
|
||||
|
||||
// Globals
|
||||
var fullscreen, config;
|
||||
|
||||
// Object cache
|
||||
var player = {};
|
||||
|
||||
// Handler cache
|
||||
var handlers = {};
|
||||
|
||||
@ -69,7 +66,7 @@
|
||||
|
||||
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
||||
// Unfortunately, due to scattered support, browser sniffing is required
|
||||
function browserSniff() {
|
||||
function _browserSniff() {
|
||||
var nAgt = navigator.userAgent,
|
||||
browserName = navigator.appName,
|
||||
fullVersion = ""+parseFloat(navigator.appVersion),
|
||||
@ -130,60 +127,14 @@
|
||||
// Return data
|
||||
return [browserName, majorVersion];
|
||||
}
|
||||
// Utilities for caption time codes
|
||||
function video_timecode_min(tc) {
|
||||
var tcpair = [];
|
||||
tcpair = tc.split(" --> ");
|
||||
return videosub_tcsecs(tcpair[0]);
|
||||
}
|
||||
function video_timecode_max(tc) {
|
||||
var tcpair = [];
|
||||
tcpair = tc.split(" --> ");
|
||||
return videosub_tcsecs(tcpair[1]);
|
||||
}
|
||||
function videosub_tcsecs(tc) {
|
||||
if (tc === null || tc === undefined) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
var tc1 = [],
|
||||
tc2 = [],
|
||||
seconds;
|
||||
tc1 = tc.split(",");
|
||||
tc2 = tc1[0].split(":");
|
||||
seconds = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
|
||||
return seconds;
|
||||
}
|
||||
}
|
||||
// For "manual" captions, adjust caption position when play time changed (via rewind, clicking progress bar, etc.)
|
||||
// http://paypal.github.io/accessible-html5-video-player/
|
||||
function adjustManualCaptions(player) {
|
||||
player.subcount = 0;
|
||||
while (video_timecode_max(player.captions[player.subcount][0]) < player.media.currentTime.toFixed(1)) {
|
||||
player.subcount++;
|
||||
if (player.subcount > player.captions.length-1) {
|
||||
player.subcount = player.captions.length-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Display captions container and button (for initialization)
|
||||
function showCaptions(player) {
|
||||
player.container.className += " " + config.classes.captions.enabled;
|
||||
|
||||
if (config.captions.defaultActive) {
|
||||
player.container.className += " " + config.classes.captions.active;
|
||||
player.buttons.captions.setAttribute("checked", "checked");
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all
|
||||
function replaceAll(string, find, replace) {
|
||||
function _replaceAll(string, find, replace) {
|
||||
return string.replace(new RegExp(find.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"), "g"), replace);
|
||||
}
|
||||
|
||||
// Wrap an element
|
||||
function wrap(elements, wrapper) {
|
||||
function _wrap(elements, wrapper) {
|
||||
// Convert `elms` to an array, if necessary.
|
||||
if (!elements.length) {
|
||||
elements = [elements];
|
||||
@ -214,6 +165,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle class on an element
|
||||
function _toggleClass(element, name, state) {
|
||||
if(element){
|
||||
if(element.classList) {
|
||||
element.classList[state ? "add" : "remove"](name);
|
||||
}
|
||||
else {
|
||||
var className = (" " + element.className + " ").replace(/\s+/g, " ").replace(" " + name + " ", "");
|
||||
element.className = className + (state ? " " + name : "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind event
|
||||
function _on(element, event, callback) {
|
||||
element.addEventListener(event, callback, false);
|
||||
}
|
||||
|
||||
// Get click position relative to parent
|
||||
// http://www.kirupa.com/html5/getting_mouse_click_position.htm
|
||||
function _getClickPosition(event) {
|
||||
@ -321,23 +290,72 @@
|
||||
return fullscreen;
|
||||
}
|
||||
|
||||
// Our internal function that executes handlers with a given name
|
||||
function executeHandlers(eventName){
|
||||
// Get all handlers with the selected name
|
||||
var handler = handlers[eventName] || [],
|
||||
len = handler.length,
|
||||
i;
|
||||
// Player instance
|
||||
function Player(container) {
|
||||
var player = this;
|
||||
player.container = container;
|
||||
|
||||
// Execute each
|
||||
for(i = 0; i< len; i++){
|
||||
// You can use apply to specify what "this" and parameters the callback gets
|
||||
handler[i].apply(player.media,[]);
|
||||
// Captions functions
|
||||
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
||||
|
||||
// For "manual" captions, adjust caption position when play time changed (via rewind, clicking progress bar, etc.)
|
||||
function _adjustManualCaptions() {
|
||||
player.subcount = 0;
|
||||
while (_timecodeMax(player.captions[player.subcount][0]) < player.media.currentTime.toFixed(1)) {
|
||||
player.subcount++;
|
||||
if (player.subcount > player.captions.length-1) {
|
||||
player.subcount = player.captions.length-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Display captions container and button (for initialization)
|
||||
function _showCaptions() {
|
||||
_toggleClass(player.container, config.classes.captions.enabled, true);
|
||||
|
||||
if (config.captions.defaultActive) {
|
||||
_toggleClass(player.container, config.classes.captions.active, true);
|
||||
player.buttons.captions.setAttribute("checked", "checked");
|
||||
}
|
||||
}
|
||||
// Utilities for caption time codes
|
||||
function _timecodeMin(tc) {
|
||||
var tcpair = [];
|
||||
tcpair = tc.split(" --> ");
|
||||
return _subTcSecs(tcpair[0]);
|
||||
}
|
||||
function _timecodeMax(tc) {
|
||||
var tcpair = [];
|
||||
tcpair = tc.split(" --> ");
|
||||
return _subTcSecs(tcpair[1]);
|
||||
}
|
||||
function _subTcSecs(tc) {
|
||||
if (tc === null || tc === undefined) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
var tc1 = [],
|
||||
tc2 = [],
|
||||
seconds;
|
||||
tc1 = tc.split(",");
|
||||
tc2 = tc1[0].split(":");
|
||||
seconds = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
|
||||
return seconds;
|
||||
}
|
||||
}
|
||||
|
||||
// Find all elements
|
||||
function _getElements(selector) {
|
||||
return player.container.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
// Find a single element
|
||||
function _getElement(selector) {
|
||||
return _getElements(selector)[0];
|
||||
}
|
||||
|
||||
// Insert controls
|
||||
function injectControls() {
|
||||
function _injectControls() {
|
||||
// Insert custom video controls
|
||||
if (config.debug) {
|
||||
console.log("Injecting custom controls");
|
||||
@ -348,98 +366,45 @@
|
||||
var html = config.html;
|
||||
|
||||
// Replace aria label instances
|
||||
html = replaceAll(html, "{aria-label}", config.playAriaLabel);
|
||||
html = _replaceAll(html, "{aria-label}", config.playAriaLabel);
|
||||
|
||||
// Replace all id references
|
||||
html = replaceAll(html, "{id}", player.random);
|
||||
html = _replaceAll(html, "{id}", player.random);
|
||||
|
||||
// Inject into the container
|
||||
player.container.insertAdjacentHTML("beforeend", html);
|
||||
}
|
||||
|
||||
// Find all elements
|
||||
function getElements(selector) {
|
||||
return player.container.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
// Find a single element
|
||||
function getElement(selector) {
|
||||
return getElements(selector)[0];
|
||||
}
|
||||
|
||||
// Find the UI controls and store references
|
||||
function findElements() {
|
||||
player.controls = getElement(config.selectors.controls);
|
||||
function _findElements() {
|
||||
player.controls = _getElement(config.selectors.controls);
|
||||
|
||||
// Buttons
|
||||
player.buttons = {};
|
||||
player.buttons.play = getElement(config.selectors.buttons.play);
|
||||
player.buttons.pause = getElement(config.selectors.buttons.pause);
|
||||
player.buttons.restart = getElement(config.selectors.buttons.restart);
|
||||
player.buttons.rewind = getElement(config.selectors.buttons.rewind);
|
||||
player.buttons.forward = getElement(config.selectors.buttons.forward);
|
||||
player.buttons.mute = getElement(config.selectors.buttons.mute);
|
||||
player.buttons.captions = getElement(config.selectors.buttons.captions);
|
||||
player.buttons.fullscreen = getElement(config.selectors.buttons.fullscreen);
|
||||
player.buttons.play = _getElement(config.selectors.buttons.play);
|
||||
player.buttons.pause = _getElement(config.selectors.buttons.pause);
|
||||
player.buttons.restart = _getElement(config.selectors.buttons.restart);
|
||||
player.buttons.rewind = _getElement(config.selectors.buttons.rewind);
|
||||
player.buttons.forward = _getElement(config.selectors.buttons.forward);
|
||||
player.buttons.mute = _getElement(config.selectors.buttons.mute);
|
||||
player.buttons.captions = _getElement(config.selectors.buttons.captions);
|
||||
player.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
|
||||
|
||||
// Progress
|
||||
player.progress = {};
|
||||
player.progress.bar = getElement(config.selectors.progress);
|
||||
player.progress.bar = _getElement(config.selectors.progress);
|
||||
player.progress.text = player.progress.bar.getElementsByTagName("span")[0];
|
||||
|
||||
// Volume
|
||||
player.volume = getElement(config.selectors.buttons.volume);
|
||||
player.volume = _getElement(config.selectors.buttons.volume);
|
||||
|
||||
// Timing
|
||||
player.duration = getElement(config.selectors.duration);
|
||||
player.seekTime = getElements(config.selectors.seekTime);
|
||||
}
|
||||
|
||||
// Play media
|
||||
function play() {
|
||||
player.media.play();
|
||||
player.container.className = player.container.className.replace(config.classes.stopped, config.classes.playing);
|
||||
}
|
||||
|
||||
// Pause media
|
||||
function pause() {
|
||||
player.media.pause();
|
||||
player.container.className = player.container.className.replace(config.classes.playing, config.classes.stopped);
|
||||
}
|
||||
|
||||
// Restart playback
|
||||
function restart() {
|
||||
// Move to beginning
|
||||
player.media.currentTime = 0;
|
||||
|
||||
// Special handling for "manual" captions
|
||||
if (!player.isTextTracks) {
|
||||
player.subcount = 0;
|
||||
}
|
||||
|
||||
// Play and ensure the play button is in correct state
|
||||
play();
|
||||
}
|
||||
|
||||
// Set volume
|
||||
function setVolume() {
|
||||
player.volume.value = config.volume;
|
||||
player.media.volume = parseFloat(config.volume / 10);
|
||||
checkMute();
|
||||
}
|
||||
|
||||
// Check mute state
|
||||
function checkMute() {
|
||||
if(player.media.volume === 0 || player.media.muted) {
|
||||
player.container.className += " " + config.classes.muted;
|
||||
}
|
||||
else {
|
||||
player.container.className = player.container.className.replace(config.classes.muted, "");
|
||||
}
|
||||
player.duration = _getElement(config.selectors.duration);
|
||||
player.seekTime = _getElements(config.selectors.seekTime);
|
||||
}
|
||||
|
||||
// Setup media
|
||||
function setupMedia() {
|
||||
function _setupMedia() {
|
||||
player.media = player.container.querySelectorAll("audio, video")[0];
|
||||
|
||||
// If there's no media, bail
|
||||
@ -449,9 +414,7 @@
|
||||
}
|
||||
|
||||
// If there's no autoplay attribute, assume the video is stopped
|
||||
if(player.media.getAttribute("autoplay") === null) {
|
||||
player.container.className += " " + config.classes.stopped;
|
||||
}
|
||||
_toggleClass(player.container, config.classes.stopped, (player.media.getAttribute("autoplay") === null));
|
||||
|
||||
// Remove native video controls
|
||||
player.media.removeAttribute("controls");
|
||||
@ -466,7 +429,7 @@
|
||||
wrapper.setAttribute("class", config.classes.videoContainer);
|
||||
|
||||
// Wrap the video in a container
|
||||
wrap(player.media, wrapper);
|
||||
_wrap(player.media, wrapper);
|
||||
|
||||
// Cache the container
|
||||
player.videoContainer = wrapper;
|
||||
@ -474,13 +437,13 @@
|
||||
}
|
||||
|
||||
// Setup captions
|
||||
function setupCaptions() {
|
||||
function _setupCaptions() {
|
||||
if(player.type === "video") {
|
||||
// Inject the container
|
||||
player.videoContainer.insertAdjacentHTML("afterbegin", "<div class='" + config.selectors.captions.replace(".", "") + "'></div>");
|
||||
|
||||
// Cache selector
|
||||
player.captionsContainer = getElement(config.selectors.captions);
|
||||
player.captionsContainer = _getElement(config.selectors.captions);
|
||||
|
||||
// Determine if HTML5 textTracks is supported
|
||||
player.isTextTracks = false;
|
||||
@ -518,9 +481,8 @@
|
||||
|
||||
// If no caption file exists, hide container for caption text
|
||||
if (!player.captionExists) {
|
||||
player.container.className = player.container.className.replace(config.classes.captions.enabled, "");
|
||||
_toggleClass(player.container, config.classes.captions.enabled);
|
||||
}
|
||||
|
||||
// If caption file exists, process captions
|
||||
else {
|
||||
var track = {}, tracks, j;
|
||||
@ -550,7 +512,7 @@
|
||||
if (config.debug) {
|
||||
console.log("textTracks supported");
|
||||
}
|
||||
showCaptions(player);
|
||||
_showCaptions(player);
|
||||
|
||||
track = {};
|
||||
tracks = player.media.textTracks;
|
||||
@ -558,13 +520,13 @@
|
||||
track = player.media.textTracks[j];
|
||||
track.mode = "hidden";
|
||||
if (track.kind === "captions") {
|
||||
track.addEventListener("cuechange",function() {
|
||||
_on(track, "cuechange",function() {
|
||||
if (this.activeCues[0]) {
|
||||
if (this.activeCues[0].hasOwnProperty("text")) {
|
||||
player.captionsContainer.innerHTML = this.activeCues[0].text;
|
||||
}
|
||||
}
|
||||
},false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -573,27 +535,27 @@
|
||||
if (config.debug) {
|
||||
console.log("textTracks not supported so rendering captions manually");
|
||||
}
|
||||
showCaptions(player);
|
||||
_showCaptions(player);
|
||||
|
||||
// Render captions from array at appropriate time
|
||||
player.currentCaption = "";
|
||||
player.subcount = 0;
|
||||
player.captions = [];
|
||||
|
||||
player.media.addEventListener("timeupdate", function() {
|
||||
_on(player.media, "timeupdate", function() {
|
||||
// Check if the next caption is in the current time range
|
||||
if (player.media.currentTime.toFixed(1) > video_timecode_min(player.captions[player.subcount][0]) &&
|
||||
player.media.currentTime.toFixed(1) < video_timecode_max(player.captions[player.subcount][0])) {
|
||||
if (player.media.currentTime.toFixed(1) > _timecodeMin(player.captions[player.subcount][0]) &&
|
||||
player.media.currentTime.toFixed(1) < _timecodeMax(player.captions[player.subcount][0])) {
|
||||
player.currentCaption = player.captions[player.subcount][1];
|
||||
}
|
||||
// Is there a next timecode?
|
||||
if (player.media.currentTime.toFixed(1) > video_timecode_max(player.captions[player.subcount][0]) &&
|
||||
if (player.media.currentTime.toFixed(1) > _timecodeMax(player.captions[player.subcount][0]) &&
|
||||
player.subcount < (player.captions.length-1)) {
|
||||
player.subcount++;
|
||||
}
|
||||
// Render the caption
|
||||
player.captionsContainer.innerHTML = player.currentCaption;
|
||||
}, false);
|
||||
});
|
||||
|
||||
if (captionSrc !== "") {
|
||||
// Create XMLHttpRequest Object
|
||||
@ -627,7 +589,8 @@
|
||||
if (config.debug) {
|
||||
console.log("Successfully loaded the caption file via ajax.");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (config.debug) {
|
||||
console.log("There was a problem loading the caption file via ajax.");
|
||||
}
|
||||
@ -652,14 +615,14 @@
|
||||
}
|
||||
|
||||
// Setup seeking
|
||||
function setupSeeking() {
|
||||
function _setupSeeking() {
|
||||
// Update number of seconds in rewind and fast forward buttons
|
||||
player.seekTime[0].innerHTML = config.seekInterval;
|
||||
player.seekTime[1].innerHTML = config.seekInterval;
|
||||
}
|
||||
|
||||
// Setup fullscreen
|
||||
function setupFullscreen() {
|
||||
function _setupFullscreen() {
|
||||
if(player.type === "video" && config.fullscreen.enabled) {
|
||||
|
||||
if(config.debug) {
|
||||
@ -670,7 +633,7 @@
|
||||
console.log("Fullscreen enabled");
|
||||
}
|
||||
|
||||
player.container.className += " " + config.classes.fullscreen.enabled;
|
||||
_toggleClass(player.container, config.classes.fullscreen.enabled, true);
|
||||
}
|
||||
else if(config.debug) {
|
||||
console.warn("Fullscreen not supported");
|
||||
@ -678,50 +641,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for events
|
||||
function listeners() {
|
||||
// Fullscreen
|
||||
player.buttons.fullscreen.addEventListener("click", function() {
|
||||
if(!fullscreen.isFullScreen()) {
|
||||
fullscreen.requestFullScreen(player.container);
|
||||
}
|
||||
else {
|
||||
fullscreen.cancelFullScreen();
|
||||
}
|
||||
}, false);
|
||||
// Play media
|
||||
function _play() {
|
||||
player.media.play();
|
||||
|
||||
// Click video
|
||||
if(player.type === "video" && config.clickToPause) {
|
||||
player.videoContainer.addEventListener("click", function() {
|
||||
if(player.media.paused) {
|
||||
play();
|
||||
}
|
||||
else if(player.media.ended) {
|
||||
restart();
|
||||
}
|
||||
else {
|
||||
pause();
|
||||
}
|
||||
}, false);
|
||||
_toggleClass(player.container, config.classes.stopped);
|
||||
_toggleClass(player.container, config.classes.playing, true);
|
||||
}
|
||||
|
||||
// Play
|
||||
player.buttons.play.addEventListener("click", function() {
|
||||
play();
|
||||
player.buttons.pause.focus();
|
||||
}, false);
|
||||
// Pause media
|
||||
function _pause() {
|
||||
player.media.pause();
|
||||
|
||||
// Pause
|
||||
player.buttons.pause.addEventListener("click", function() {
|
||||
pause();
|
||||
player.buttons.play.focus();
|
||||
}, false);
|
||||
_toggleClass(player.container, config.classes.playing);
|
||||
_toggleClass(player.container, config.classes.stopped, true);
|
||||
}
|
||||
|
||||
// Restart
|
||||
player.buttons.restart.addEventListener("click", restart, false);
|
||||
// Restart playback
|
||||
function _restart() {
|
||||
// Move to beginning
|
||||
player.media.currentTime = 0;
|
||||
|
||||
// Special handling for "manual" captions
|
||||
if (!player.isTextTracks) {
|
||||
player.subcount = 0;
|
||||
}
|
||||
|
||||
// Play and ensure the play button is in correct state
|
||||
_play();
|
||||
}
|
||||
|
||||
// Rewind
|
||||
player.buttons.rewind.addEventListener("click", function() {
|
||||
function _rewind() {
|
||||
var targetTime = player.media.currentTime - config.seekInterval;
|
||||
|
||||
if (targetTime < 0) {
|
||||
@ -732,12 +683,12 @@
|
||||
}
|
||||
// Special handling for "manual" captions
|
||||
if (!player.isTextTracks && player.type === "video") {
|
||||
adjustManualCaptions(player);
|
||||
_adjustManualCaptions(player);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Fast forward
|
||||
player.buttons.forward.addEventListener("click", function() {
|
||||
function _forward() {
|
||||
var targetTime = player.media.currentTime + config.seekInterval;
|
||||
|
||||
if (targetTime > player.media.duration) {
|
||||
@ -748,29 +699,113 @@
|
||||
}
|
||||
// Special handling for "manual" captions
|
||||
if (!player.isTextTracks && player.type === "video") {
|
||||
adjustManualCaptions(player);
|
||||
_adjustManualCaptions(player);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Get the HTML5 range input element and append audio volume adjustment on change
|
||||
player.volume.addEventListener("change", function() {
|
||||
config.volume = this.value;
|
||||
setVolume();
|
||||
}, false);
|
||||
|
||||
// Mute
|
||||
player.buttons.mute.addEventListener("click", function() {
|
||||
if (player.media.muted === true) {
|
||||
player.media.muted = false;
|
||||
// Toggle fullscreen
|
||||
function _toggleFullscreen() {
|
||||
if(!fullscreen.isFullScreen()) {
|
||||
fullscreen.requestFullScreen(player.container);
|
||||
}
|
||||
else {
|
||||
player.media.muted = true;
|
||||
fullscreen.cancelFullScreen();
|
||||
}
|
||||
checkMute();
|
||||
}, false);
|
||||
}
|
||||
|
||||
// Set volume
|
||||
function _setVolume(volume) {
|
||||
player.volume.value = volume;
|
||||
player.media.volume = parseFloat(volume / 10);
|
||||
_checkMute();
|
||||
}
|
||||
|
||||
// Mute
|
||||
function _toggleMute(muted) {
|
||||
// If the method is called without parameter, toggle based on current value
|
||||
if(typeof active === "undefined") {
|
||||
muted = !player.media.muted;
|
||||
player.buttons.mute.checked = muted;
|
||||
}
|
||||
|
||||
player.media.muted = muted;
|
||||
_checkMute();
|
||||
}
|
||||
|
||||
// Toggle captions
|
||||
function _toggleCaptions(active) {
|
||||
// If the method is called without parameter, toggle based on current value
|
||||
if(typeof active === "undefined") {
|
||||
active = (player.container.className.indexOf(config.classes.captions.active) === -1);
|
||||
player.buttons.captions.checked = active;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
_toggleClass(player.container, config.classes.captions.active, true);
|
||||
}
|
||||
else {
|
||||
_toggleClass(player.container, config.classes.captions.active);
|
||||
}
|
||||
}
|
||||
|
||||
// Check mute state
|
||||
function _checkMute() {
|
||||
_toggleClass(player.container, config.classes.muted, (player.media.volume === 0 || player.media.muted));
|
||||
}
|
||||
|
||||
// Listen for events
|
||||
function _listeners() {
|
||||
// Fullscreen
|
||||
_on(player.buttons.fullscreen, "click", _toggleFullscreen);
|
||||
|
||||
// Click video
|
||||
if(player.type === "video" && config.clickToPause) {
|
||||
_on(player.videoContainer, "click", function() {
|
||||
if(player.media.paused) {
|
||||
_play();
|
||||
}
|
||||
else if(player.media.ended) {
|
||||
_restart();
|
||||
}
|
||||
else {
|
||||
_pause();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Play
|
||||
_on(player.buttons.play, "click", function() {
|
||||
_play();
|
||||
player.buttons.pause.focus();
|
||||
});
|
||||
|
||||
// Pause
|
||||
_on(player.buttons.pause, "click", function() {
|
||||
_pause();
|
||||
player.buttons.play.focus();
|
||||
});
|
||||
|
||||
// Restart
|
||||
_on(player.buttons.restart, "click", _restart);
|
||||
|
||||
// Rewind
|
||||
_on(player.buttons.rewind, "click", _rewind);
|
||||
|
||||
// Fast forward
|
||||
_on(player.buttons.forward, "click", _forward);
|
||||
|
||||
// Get the HTML5 range input element and append audio volume adjustment on change
|
||||
_on(player.volume, "change", function() {
|
||||
_setVolume(this.value);
|
||||
});
|
||||
|
||||
// Mute
|
||||
_on(player.buttons.mute, "change", function() {
|
||||
_toggleMute(this.checked);
|
||||
});
|
||||
|
||||
// Duration
|
||||
player.media.addEventListener("timeupdate", function() {
|
||||
_on(player.media, "timeupdate", function() {
|
||||
player.secs = parseInt(player.media.currentTime % 60);
|
||||
player.mins = parseInt((player.media.currentTime / 60) % 60);
|
||||
|
||||
@ -780,103 +815,50 @@
|
||||
|
||||
// Render
|
||||
player.duration.innerHTML = player.mins + ":" + player.secs;
|
||||
}, false);
|
||||
});
|
||||
|
||||
// Progress bar
|
||||
player.media.addEventListener("timeupdate", function() {
|
||||
_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;
|
||||
}
|
||||
}, false);
|
||||
});
|
||||
|
||||
// Skip when clicking progress bar
|
||||
player.progress.bar.addEventListener("click", function(event) {
|
||||
_on(player.progress.bar, "click", function(event) {
|
||||
player.pos = _getClickPosition(event).x / this.offsetWidth;
|
||||
player.media.currentTime = player.pos * player.media.duration;
|
||||
|
||||
// Special handling for "manual" captions
|
||||
if (!player.isTextTracks && player.type === "video") {
|
||||
adjustManualCaptions(player);
|
||||
_adjustManualCaptions(player);
|
||||
}
|
||||
});
|
||||
|
||||
// Captions
|
||||
player.buttons.captions.addEventListener("click", function() {
|
||||
if (this.checked) {
|
||||
player.container.className += " " + config.classes.captions.active;
|
||||
}
|
||||
else {
|
||||
player.container.className = player.container.className.replace(config.classes.captions.active, "");
|
||||
}
|
||||
}, false);
|
||||
_on(player.buttons.captions, "click", function() {
|
||||
_toggleCaptions(this.checked);
|
||||
});
|
||||
|
||||
// Clear captions at end of video
|
||||
player.media.addEventListener("ended", function() {
|
||||
_on(player.media, "ended", function() {
|
||||
if(player.type === "video") {
|
||||
player.captionsContainer.innerHTML = "";
|
||||
}
|
||||
player.container.className = player.container.className.replace(config.classes.playing, config.classes.stopped);
|
||||
_toggleClass(player.container, config.classes.stopped, true);
|
||||
_toggleClass(player.container, config.classes.playing);
|
||||
});
|
||||
}
|
||||
|
||||
function setupPlayer(element) {
|
||||
player.container = element;
|
||||
|
||||
// Setup media
|
||||
setupMedia();
|
||||
|
||||
// Generate random number for id/for attribute values for controls
|
||||
player.random = Math.floor(Math.random() * (10000));
|
||||
|
||||
// Inject custom controls
|
||||
injectControls();
|
||||
|
||||
// Find the elements
|
||||
findElements();
|
||||
|
||||
// Set volume
|
||||
setVolume();
|
||||
|
||||
// Setup fullscreen
|
||||
setupFullscreen();
|
||||
|
||||
// Captions
|
||||
setupCaptions();
|
||||
|
||||
// Seeking
|
||||
setupSeeking();
|
||||
|
||||
// Listeners
|
||||
listeners();
|
||||
}
|
||||
|
||||
// Our "on" function which collects handlers
|
||||
api.on = function(eventName, handler){
|
||||
// If no handler collection exists, create one
|
||||
if(!handlers[eventName]){
|
||||
handlers[eventName] = [];
|
||||
}
|
||||
handlers[eventName].push(handler);
|
||||
}
|
||||
|
||||
// Expose setup function
|
||||
api.setup = function(options){
|
||||
// Extend the default options with user specified
|
||||
config = _extend(defaults, options);
|
||||
|
||||
// If enabled carry on
|
||||
if(!config.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function _init() {
|
||||
// Setup the fullscreen api
|
||||
fullscreen = _fullscreen();
|
||||
|
||||
// Sniff
|
||||
player.browserInfo = browserSniff();
|
||||
player.browserInfo = _browserSniff();
|
||||
player.browserName = player.browserInfo[0];
|
||||
player.browserMajorVersion = player.browserInfo[1];
|
||||
|
||||
@ -902,24 +884,73 @@
|
||||
config.playAriaLabel = "Play " + config.title;
|
||||
}
|
||||
|
||||
// Get the container and video container
|
||||
var element = document.querySelector(config.selectors.container);
|
||||
if(element === null) {
|
||||
if(config.debug) {
|
||||
console.error("Selector " + config.selectors.container + " not found!");
|
||||
// Setup media
|
||||
_setupMedia();
|
||||
|
||||
// Generate random number for id/for attribute values for controls
|
||||
player.random = Math.floor(Math.random() * (10000));
|
||||
|
||||
// Inject custom controls
|
||||
_injectControls();
|
||||
|
||||
// Find the elements
|
||||
_findElements();
|
||||
|
||||
// Set volume
|
||||
_setVolume(config.volume);
|
||||
|
||||
// Setup fullscreen
|
||||
_setupFullscreen();
|
||||
|
||||
// Captions
|
||||
_setupCaptions();
|
||||
|
||||
// Seeking
|
||||
_setupSeeking();
|
||||
|
||||
// Listeners
|
||||
_listeners();
|
||||
}
|
||||
|
||||
_init();
|
||||
|
||||
return {
|
||||
media: player.media,
|
||||
play: _play,
|
||||
pause: _pause,
|
||||
restart: _restart,
|
||||
rewind: _rewind,
|
||||
forward: _forward,
|
||||
setVolume: _setVolume,
|
||||
toggleMute: _toggleMute,
|
||||
toggleCaptions: _toggleCaptions
|
||||
}
|
||||
}
|
||||
|
||||
// Expose setup function
|
||||
api.setup = function(options){
|
||||
// Extend the default options with user specified
|
||||
config = _extend(defaults, options);
|
||||
|
||||
// If enabled carry on
|
||||
// You may want to disable certain UAs etc
|
||||
if(!config.enabled) {
|
||||
return false;
|
||||
}
|
||||
setupPlayer(element);
|
||||
|
||||
/*var elements = document.querySelectorAll(config.selectors.container);
|
||||
// Get the players
|
||||
var elements = document.querySelectorAll(config.selectors.container);
|
||||
|
||||
// Create a player instance for each element
|
||||
for (var i = elements.length - 1; i >= 0; i--) {
|
||||
setupPlayer(elements[i]);
|
||||
}*/
|
||||
// Get the current element
|
||||
var element = elements[i];
|
||||
|
||||
// Trigger the setup event
|
||||
executeHandlers("setup");
|
||||
// Setup a player instance
|
||||
var player = new Player(element);
|
||||
|
||||
// Add the player object to the element
|
||||
element.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
}(this.simpleMedia = this.simpleMedia || {}));
|
@ -35,14 +35,14 @@ html {
|
||||
}
|
||||
body {
|
||||
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
.font-size(18);
|
||||
color: #6D797F;
|
||||
line-height: 1.5;
|
||||
background: #fff;
|
||||
.font-size(16);
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
color: #6D797F;
|
||||
}
|
||||
h1 {
|
||||
.font-size(48);
|
||||
h1,
|
||||
h2 {
|
||||
letter-spacing: -.025em;
|
||||
color: #2E3C44;
|
||||
margin: 0 0 10px;
|
||||
@ -50,16 +50,27 @@ h1 {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
h1 {
|
||||
.font-size(48);
|
||||
}
|
||||
h2 {
|
||||
.font-size(32);
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
header {
|
||||
margin: 40px 0;
|
||||
|
||||
p {
|
||||
.font-size(18);
|
||||
}
|
||||
}
|
||||
|
||||
.example-audio .player,
|
||||
.example-video .player {
|
||||
margin: 0 auto;
|
||||
margin: 0 auto 40px;
|
||||
|
||||
&:fullscreen {
|
||||
max-width: none;
|
||||
|
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:focus{outline:dotted thin}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"}small{font-size:80%}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}@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}*,::after,::before{box-sizing:border-box}html{font-size:62.5%}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-size:1.8rem;color:#6D797F;line-height:1.5;background:#fff;text-align:center}h1{font-size:48px;font-size:4.8rem;letter-spacing:-.025em;color:#2E3C44;margin:0 0 10px;line-height:1.2;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}p{margin:0 0 20px}header{margin:40px 0}.example-audio .player,.example-video .player{margin:0 auto}.example-audio .player:-webkit-full-screen,.example-video .player:-webkit-full-screen{max-width:none}.example-audio .player:-moz-full-screen,.example-video .player:-moz-full-screen{max-width:none}.example-audio .player:-ms-fullscreen,.example-video .player:-ms-fullscreen{max-width:none}.example-audio .player:fullscreen,.example-video .player:fullscreen{max-width:none}.example-audio .player{max-width:480px}.example-video .player{max-width:1200px}
|
||||
/*! 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:focus{outline:dotted thin}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"}small{font-size:80%}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}@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}*,::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;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1{font-size:48px;font-size:4.8rem}h2{font-size:32px;font-size:3.2rem;margin:0 0 20px}p{margin:0 0 20px}header{margin:40px 0}header p{font-size:18px;font-size:1.8rem}.example-audio .player,.example-video .player{margin:0 auto 40px}.example-audio .player:-webkit-full-screen,.example-video .player:-webkit-full-screen{max-width:none}.example-audio .player:-moz-full-screen,.example-video .player:-moz-full-screen{max-width:none}.example-audio .player:-ms-fullscreen,.example-video .player:-ms-fullscreen{max-width:none}.example-audio .player:fullscreen,.example-video .player:fullscreen{max-width:none}.example-audio .player{max-width:480px}.example-video .player{max-width:1200px}
|
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/simple-media.js
vendored
2
dist/js/simple-media.js
vendored
File diff suppressed because one or more lines are too long
@ -1,41 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" class="example-audio">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple Media</title>
|
||||
<meta name="description" content="Custom HTML5 video controls and WebVTT captions.">
|
||||
<meta name="author" content="Sam Potts">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="../dist/css/simple-media.css">
|
||||
<link rel="stylesheet" href="../dist/css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Simple Media</h1>
|
||||
<p>A simple HTML5 media player</p>
|
||||
</header>
|
||||
|
||||
<div class="player">
|
||||
<audio controls>
|
||||
<!-- Audio files -->
|
||||
<source src="../media/Covox_-_Switchblade_Squadron.mp3" type="audio/mp3">
|
||||
|
||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
||||
<div>
|
||||
<a href="../media/Covox_-_Switchblade_Squadron.mp3">Download it</a>
|
||||
</div>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<!-- Load SVG defs -->
|
||||
<script>(function(d,p){var a=new XMLHttpRequest(),b=d.body; a.open("GET",p,!0);a.send();a.onload=function(){var c=d.createElement("div");c.style.display="none";c.innerHTML=a.responseText;b.insertBefore(c,b.childNodes[0])}})(document,"../dist/svg/sprite.svg");</script>
|
||||
|
||||
<!-- Core player -->
|
||||
<script src="../dist/js/simple-media.js"></script>
|
||||
|
||||
<!-- Docs setup -->
|
||||
<script src="../dist/js/docs.js"></script>
|
||||
</body>
|
||||
</html>
|
67
docs/index.html
Normal file
67
docs/index.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple Media</title>
|
||||
<meta name="description" content="Custom HTML5 video controls and WebVTT captions.">
|
||||
<meta name="author" content="Sam Potts">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="../dist/css/simple-media.css">
|
||||
<link rel="stylesheet" href="../dist/css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Simple Media</h1>
|
||||
<p>A simple HTML5 media player</p>
|
||||
</header>
|
||||
|
||||
<section class="example-video">
|
||||
<h2>Video</h2>
|
||||
<p>Using the native <video> element.</p>
|
||||
<div class="player">
|
||||
<video poster="../media/poster_PayPal_Austin2.jpg" controls>
|
||||
<!-- Video files -->
|
||||
<source src="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4" type="video/mp4">
|
||||
<source src="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.webm" type="video/webm">
|
||||
|
||||
<!-- Text track file -->
|
||||
<track kind="captions" label="English captions" src="../media/captions_PayPal_Austin_en.vtt" srclang="en" default>
|
||||
|
||||
<!-- Fallback for browsers that don't support the <video> element -->
|
||||
<div>
|
||||
<a href="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4">
|
||||
<img src="../media/poster_PayPal_Austin2.jpg" width="640" height="360" alt="download video">
|
||||
</a>
|
||||
</div>
|
||||
</video>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="example-audio">
|
||||
<h2>Audio</h2>
|
||||
<p>Yep, it does <audio> too.</p>
|
||||
<div class="player">
|
||||
<audio controls>
|
||||
<!-- Audio files -->
|
||||
<source src="../media/Covox_-_Switchblade_Squadron.mp3" type="audio/mp3">
|
||||
|
||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
||||
<div>
|
||||
<a href="../media/Covox_-_Switchblade_Squadron.mp3">Download it</a>
|
||||
</div>
|
||||
</audio>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Load SVG defs -->
|
||||
<script>(function(d,p){var a=new XMLHttpRequest(),b=d.body; a.open("GET",p,!0);a.send();a.onload=function(){var c=d.createElement("div");c.style.display="none";c.innerHTML=a.responseText;b.insertBefore(c,b.childNodes[0])}})(document,"../dist/svg/sprite.svg");</script>
|
||||
|
||||
<!-- Core player -->
|
||||
<script src="../dist/js/simple-media.js"></script>
|
||||
|
||||
<!-- Docs setup -->
|
||||
<script src="../dist/js/docs.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,47 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" class="example-video">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Simple Media</title>
|
||||
<meta name="description" content="Custom HTML5 video controls and WebVTT captions.">
|
||||
<meta name="author" content="Sam Potts">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="../dist/css/simple-media.css">
|
||||
<link rel="stylesheet" href="../dist/css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Simple Media</h1>
|
||||
<p>A simple HTML5 media player</p>
|
||||
</header>
|
||||
|
||||
<div class="player">
|
||||
<video poster="../media/poster_PayPal_Austin2.jpg" controls>
|
||||
<!-- Video files -->
|
||||
<source src="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4" type="video/mp4">
|
||||
<source src="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.webm" type="video/webm">
|
||||
|
||||
<!-- Text track file -->
|
||||
<track kind="captions" label="English captions" src="../media/captions_PayPal_Austin_en.vtt" srclang="en" default>
|
||||
|
||||
<!-- Fallback for browsers that don't support the <video> element -->
|
||||
<div>
|
||||
<a href="https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4">
|
||||
<img src="../media/poster_PayPal_Austin2.jpg" width="640" height="360" alt="download video">
|
||||
</a>
|
||||
</div>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<!-- Load SVG defs -->
|
||||
<script>(function(d,p){var a=new XMLHttpRequest(),b=d.body; a.open("GET",p,!0);a.send();a.onload=function(){var c=d.createElement("div");c.style.display="none";c.innerHTML=a.responseText;b.insertBefore(c,b.childNodes[0])}})(document,"../dist/svg/sprite.svg");</script>
|
||||
|
||||
<!-- Core player -->
|
||||
<script src="../dist/js/simple-media.js"></script>
|
||||
|
||||
<!-- Docs setup -->
|
||||
<script src="../dist/js/docs.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user