mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-20 21:46:04 -05:00
@@ -8,6 +8,10 @@ import { PageActions, MediaPageActions } from '../../utils/actions/';
|
||||
import { LinksContext, MemberContext, SiteContext } from '../../utils/contexts/';
|
||||
import { PopupMain, UserThumbnail } from '../_shared';
|
||||
|
||||
import './videojs-markers.js';
|
||||
import './videojs.markers.css';
|
||||
import {enableMarkers, addMarker} from './videojs-markers_config.js'
|
||||
|
||||
import './Comments.scss';
|
||||
|
||||
const commentsText = {
|
||||
@@ -426,6 +430,12 @@ export default function CommentsList(props) {
|
||||
|
||||
function onCommentsLoad() {
|
||||
const retrievedComments = [...MediaPageStore.get('media-comments')];
|
||||
const video = videojs('vjs_video_3');
|
||||
|
||||
if (MediaCMS.features.media.actions.timestampTimebar)
|
||||
{
|
||||
enableMarkers(video);
|
||||
}
|
||||
|
||||
if (MediaCMS.features.media.actions.comment_mention === true)
|
||||
{
|
||||
@@ -433,14 +443,18 @@ export default function CommentsList(props) {
|
||||
comment.text = setMentions(comment.text);
|
||||
});
|
||||
}
|
||||
retrievedComments.forEach(comment => {
|
||||
comment.text = setTimestampAnchors(comment.text);
|
||||
});
|
||||
|
||||
displayCommentsRelatedAlert();
|
||||
setComments(retrievedComments);
|
||||
}
|
||||
|
||||
video.one('loadedmetadata', () => {
|
||||
retrievedComments.forEach(comment => {
|
||||
comment.text = setTimestampAnchorsAndMarkers(comment.text, video);
|
||||
});
|
||||
|
||||
displayCommentsRelatedAlert();
|
||||
setComments([...retrievedComments]);
|
||||
});
|
||||
setComments([...retrievedComments]);
|
||||
}
|
||||
|
||||
function setMentions(text)
|
||||
{
|
||||
let sanitizedComment = text.split('@(_').join("<a href=\"/user/");
|
||||
@@ -448,7 +462,7 @@ export default function CommentsList(props) {
|
||||
return sanitizedComment.split('_]').join("</a>");
|
||||
}
|
||||
|
||||
function setTimestampAnchors(text)
|
||||
function setTimestampAnchorsAndMarkers(text, videoPlayer)
|
||||
{
|
||||
function wrapTimestampWithAnchor(match, string)
|
||||
{
|
||||
@@ -460,6 +474,10 @@ export default function CommentsList(props) {
|
||||
s += m * parseInt(split.pop(), 10);
|
||||
m *= 60;
|
||||
}
|
||||
if (MediaCMS.features.media.actions.timestampTimebar)
|
||||
{
|
||||
addMarker(videoPlayer, s, text);
|
||||
}
|
||||
|
||||
searchParameters.set('t', s)
|
||||
const wrapped = "<a href=\"" + MediaPageStore.get('media-url').split('?')[0] + "?" + searchParameters + "\">" + match + "</a>";
|
||||
|
||||
525
frontend/src/static/js/components/comments/videojs-markers.js
Normal file
525
frontend/src/static/js/components/comments/videojs-markers.js
Normal file
@@ -0,0 +1,525 @@
|
||||
// based on https://github.com/spchuang/videojs-markers
|
||||
|
||||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(['mediacms-player'], factory);
|
||||
} else if (typeof exports !== "undefined") {
|
||||
factory(require('mediacms-player'));
|
||||
} else {
|
||||
var mod = {
|
||||
exports: {}
|
||||
};
|
||||
global = window;
|
||||
factory(global.videojs);
|
||||
global.videojsMarkers = mod.exports;
|
||||
}
|
||||
})(this, function (_video) {
|
||||
/*! videojs-markers - v1.0.1 - 2018-02-03
|
||||
* Copyright (c) 2018 ; Licensed */
|
||||
'use strict';
|
||||
|
||||
var _video2 = _interopRequireDefault(_video);
|
||||
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
|
||||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
||||
return typeof obj;
|
||||
} : function (obj) {
|
||||
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
||||
};
|
||||
|
||||
// default setting
|
||||
var defaultSetting = {
|
||||
markerStyle: {
|
||||
'width': '7px',
|
||||
'border-radius': '30%',
|
||||
'background-color': 'red'
|
||||
},
|
||||
markerTip: {
|
||||
display: true,
|
||||
text: function text(marker) {
|
||||
return "Break: " + marker.text;
|
||||
},
|
||||
time: function time(marker) {
|
||||
return marker.time;
|
||||
}
|
||||
},
|
||||
breakOverlay: {
|
||||
display: true,
|
||||
displayTime: 3,
|
||||
text: function text(marker) {
|
||||
return "Break overlay: " + marker.overlayText;
|
||||
},
|
||||
style: {
|
||||
'width': '100%',
|
||||
'height': '20%',
|
||||
'background-color': 'rgba(0,0,0,0.7)',
|
||||
'color': 'white',
|
||||
'font-size': '17px'
|
||||
}
|
||||
},
|
||||
onMarkerClick: function onMarkerClick(marker) {},
|
||||
onMarkerReached: function onMarkerReached(marker, index) {},
|
||||
markers: []
|
||||
};
|
||||
|
||||
// create a non-colliding random number
|
||||
function generateUUID() {
|
||||
var d = new Date().getTime();
|
||||
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);
|
||||
});
|
||||
return uuid;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the size of an element and its position
|
||||
* a default Object with 0 on each of its properties
|
||||
* its return in case there's an error
|
||||
* @param {Element} element el to get the size and position
|
||||
* @return {DOMRect|Object} size and position of an element
|
||||
*/
|
||||
function getElementBounding(element) {
|
||||
var elementBounding;
|
||||
var defaultBoundingRect = {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
right: 0
|
||||
};
|
||||
|
||||
try {
|
||||
elementBounding = element.getBoundingClientRect();
|
||||
} catch (e) {
|
||||
elementBounding = defaultBoundingRect;
|
||||
}
|
||||
|
||||
return elementBounding;
|
||||
}
|
||||
|
||||
var NULL_INDEX = -1;
|
||||
|
||||
function registerVideoJsMarkersPlugin(options) {
|
||||
// copied from video.js/src/js/utils/merge-options.js since
|
||||
// videojs 4 doens't support it by defualt.
|
||||
if (!_video2.default.mergeOptions) {
|
||||
var isPlain = function isPlain(value) {
|
||||
return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && toString.call(value) === '[object Object]' && value.constructor === Object;
|
||||
};
|
||||
|
||||
var mergeOptions = function mergeOptions(source1, source2) {
|
||||
|
||||
var result = {};
|
||||
var sources = [source1, source2];
|
||||
sources.forEach(function (source) {
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
Object.keys(source).forEach(function (key) {
|
||||
var value = source[key];
|
||||
if (!isPlain(value)) {
|
||||
result[key] = value;
|
||||
return;
|
||||
}
|
||||
if (!isPlain(result[key])) {
|
||||
result[key] = {};
|
||||
}
|
||||
result[key] = mergeOptions(result[key], value);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
_video2.default.mergeOptions = mergeOptions;
|
||||
}
|
||||
|
||||
if (!_video2.default.createEl) {
|
||||
_video2.default.createEl = function (tagName, props, attrs) {
|
||||
var el = _video2.default.Player.prototype.createEl(tagName, props);
|
||||
if (!!attrs) {
|
||||
Object.keys(attrs).forEach(function (key) {
|
||||
el.setAttribute(key, attrs[key]);
|
||||
});
|
||||
}
|
||||
return el;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* register the markers plugin (dependent on jquery)
|
||||
*/
|
||||
var setting = _video2.default.mergeOptions(defaultSetting, options),
|
||||
markersMap = {},
|
||||
markersList = [],
|
||||
// list of markers sorted by time
|
||||
currentMarkerIndex = NULL_INDEX,
|
||||
player = this,
|
||||
markerTip = null,
|
||||
breakOverlay = null,
|
||||
overlayIndex = NULL_INDEX;
|
||||
|
||||
function sortMarkersList() {
|
||||
// sort the list by time in asc order
|
||||
markersList.sort(function (a, b) {
|
||||
return setting.markerTip.time(a) - setting.markerTip.time(b);
|
||||
});
|
||||
}
|
||||
|
||||
function addMarkers(newMarkers) {
|
||||
newMarkers.forEach(function (marker) {
|
||||
marker.key = generateUUID();
|
||||
|
||||
player.el().querySelector('.vjs-progress-holder').appendChild(createMarkerDiv(marker));
|
||||
|
||||
// store marker in an internal hash map
|
||||
markersMap[marker.key] = marker;
|
||||
markersList.push(marker);
|
||||
});
|
||||
|
||||
sortMarkersList();
|
||||
}
|
||||
|
||||
function getPosition(marker) {
|
||||
return setting.markerTip.time(marker) / player.duration() * 100;
|
||||
}
|
||||
|
||||
function setMarkderDivStyle(marker, markerDiv) {
|
||||
markerDiv.className = 'vjs-marker ' + (marker.class || "");
|
||||
|
||||
Object.keys(setting.markerStyle).forEach(function (key) {
|
||||
markerDiv.style[key] = setting.markerStyle[key];
|
||||
});
|
||||
|
||||
// hide out-of-bound markers
|
||||
var ratio = marker.time / player.duration();
|
||||
if (ratio < 0 || ratio > 1) {
|
||||
markerDiv.style.display = 'none';
|
||||
}
|
||||
|
||||
// set position
|
||||
markerDiv.style.left = getPosition(marker) + '%';
|
||||
if (marker.duration) {
|
||||
markerDiv.style.width = marker.duration / player.duration() * 100 + '%';
|
||||
markerDiv.style.marginLeft = '0px';
|
||||
} else {
|
||||
var markerDivBounding = getElementBounding(markerDiv);
|
||||
markerDiv.style.marginLeft = markerDivBounding.width / 2 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function createMarkerDiv(marker) {
|
||||
|
||||
var markerDiv = _video2.default.createEl('div', {}, {
|
||||
'data-marker-key': marker.key,
|
||||
'data-marker-time': setting.markerTip.time(marker)
|
||||
});
|
||||
|
||||
setMarkderDivStyle(marker, markerDiv);
|
||||
|
||||
// bind click event to seek to marker time
|
||||
markerDiv.addEventListener('click', function (e) {
|
||||
var preventDefault = false;
|
||||
if (typeof setting.onMarkerClick === "function") {
|
||||
// if return false, prevent default behavior
|
||||
preventDefault = setting.onMarkerClick(marker) === false;
|
||||
}
|
||||
|
||||
if (!preventDefault) {
|
||||
var key = this.getAttribute('data-marker-key');
|
||||
player.currentTime(setting.markerTip.time(markersMap[key]));
|
||||
}
|
||||
});
|
||||
|
||||
if (setting.markerTip.display) {
|
||||
registerMarkerTipHandler(markerDiv);
|
||||
}
|
||||
|
||||
return markerDiv;
|
||||
}
|
||||
|
||||
function updateMarkers(force) {
|
||||
// update UI for markers whose time changed
|
||||
markersList.forEach(function (marker) {
|
||||
var markerDiv = player.el().querySelector(".vjs-marker[data-marker-key='" + marker.key + "']");
|
||||
var markerTime = setting.markerTip.time(marker);
|
||||
|
||||
if (force || markerDiv.getAttribute('data-marker-time') !== markerTime) {
|
||||
setMarkderDivStyle(marker, markerDiv);
|
||||
markerDiv.setAttribute('data-marker-time', markerTime);
|
||||
}
|
||||
});
|
||||
sortMarkersList();
|
||||
}
|
||||
|
||||
function removeMarkers(indexArray) {
|
||||
// reset overlay
|
||||
if (!!breakOverlay) {
|
||||
overlayIndex = NULL_INDEX;
|
||||
breakOverlay.style.visibility = "hidden";
|
||||
}
|
||||
currentMarkerIndex = NULL_INDEX;
|
||||
|
||||
var deleteIndexList = [];
|
||||
indexArray.forEach(function (index) {
|
||||
var marker = markersList[index];
|
||||
if (marker) {
|
||||
// delete from memory
|
||||
delete markersMap[marker.key];
|
||||
deleteIndexList.push(index);
|
||||
|
||||
// delete from dom
|
||||
var el = player.el().querySelector(".vjs-marker[data-marker-key='" + marker.key + "']");
|
||||
el && el.parentNode.removeChild(el);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// clean up markers array
|
||||
deleteIndexList.reverse();
|
||||
deleteIndexList.forEach(function (deleteIndex) {
|
||||
markersList.splice(deleteIndex, 1);
|
||||
});
|
||||
} catch (error) {
|
||||
//Splice is the most likely culprit
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// sort again
|
||||
sortMarkersList();
|
||||
}
|
||||
|
||||
// attach hover event handler
|
||||
function registerMarkerTipHandler(markerDiv) {
|
||||
markerDiv.addEventListener('mouseover', function () {
|
||||
var marker = markersMap[markerDiv.getAttribute('data-marker-key')];
|
||||
if (!!markerTip) {
|
||||
markerTip.querySelector('.vjs-tip-inner').innerText = setting.markerTip.text(marker);
|
||||
// margin-left needs to minus the padding length to align correctly with the marker
|
||||
markerTip.style.left = getPosition(marker) + '%';
|
||||
var markerTipBounding = getElementBounding(markerTip);
|
||||
var markerDivBounding = getElementBounding(markerDiv);
|
||||
markerTip.style.marginLeft = -parseFloat(markerTipBounding.width / 2) + parseFloat(markerDivBounding.width / 4) + 'px';
|
||||
markerTip.style.visibility = 'visible';
|
||||
}
|
||||
});
|
||||
|
||||
markerDiv.addEventListener('mouseout', function () {
|
||||
if (!!markerTip) {
|
||||
markerTip.style.visibility = "hidden";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initializeMarkerTip() {
|
||||
markerTip = _video2.default.createEl('div', {
|
||||
className: 'vjs-tip',
|
||||
innerHTML: "<div class='vjs-tip-arrow'></div><div class='vjs-tip-inner'></div>"
|
||||
});
|
||||
player.el().querySelector('.vjs-progress-holder').appendChild(markerTip);
|
||||
}
|
||||
|
||||
// show or hide break overlays
|
||||
function updateBreakOverlay() {
|
||||
if (!setting.breakOverlay.display || currentMarkerIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentTime = player.currentTime();
|
||||
var marker = markersList[currentMarkerIndex];
|
||||
var markerTime = setting.markerTip.time(marker);
|
||||
|
||||
if (currentTime >= markerTime && currentTime <= markerTime + setting.breakOverlay.displayTime) {
|
||||
if (overlayIndex !== currentMarkerIndex) {
|
||||
overlayIndex = currentMarkerIndex;
|
||||
if (breakOverlay) {
|
||||
breakOverlay.querySelector('.vjs-break-overlay-text').innerHTML = setting.breakOverlay.text(marker);
|
||||
}
|
||||
}
|
||||
|
||||
if (breakOverlay) {
|
||||
breakOverlay.style.visibility = "visible";
|
||||
}
|
||||
} else {
|
||||
overlayIndex = NULL_INDEX;
|
||||
if (breakOverlay) {
|
||||
breakOverlay.style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// problem when the next marker is within the overlay display time from the previous marker
|
||||
function initializeOverlay() {
|
||||
breakOverlay = _video2.default.createEl('div', {
|
||||
className: 'vjs-break-overlay',
|
||||
innerHTML: "<div class='vjs-break-overlay-text'></div>"
|
||||
});
|
||||
Object.keys(setting.breakOverlay.style).forEach(function (key) {
|
||||
if (breakOverlay) {
|
||||
breakOverlay.style[key] = setting.breakOverlay.style[key];
|
||||
}
|
||||
});
|
||||
player.el().appendChild(breakOverlay);
|
||||
overlayIndex = NULL_INDEX;
|
||||
}
|
||||
|
||||
function onTimeUpdate() {
|
||||
onUpdateMarker();
|
||||
updateBreakOverlay();
|
||||
options.onTimeUpdateAfterMarkerUpdate && options.onTimeUpdateAfterMarkerUpdate();
|
||||
}
|
||||
|
||||
function onUpdateMarker() {
|
||||
/*
|
||||
check marker reached in between markers
|
||||
the logic here is that it triggers a new marker reached event only if the player
|
||||
enters a new marker range (e.g. from marker 1 to marker 2). Thus, if player is on marker 1 and user clicked on marker 1 again, no new reached event is triggered)
|
||||
*/
|
||||
if (!markersList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var getNextMarkerTime = function getNextMarkerTime(index) {
|
||||
if (index < markersList.length - 1) {
|
||||
return setting.markerTip.time(markersList[index + 1]);
|
||||
}
|
||||
// next marker time of last marker would be end of video time
|
||||
return player.duration();
|
||||
};
|
||||
var currentTime = player.currentTime();
|
||||
var newMarkerIndex = NULL_INDEX;
|
||||
|
||||
if (currentMarkerIndex !== NULL_INDEX) {
|
||||
// check if staying at same marker
|
||||
var nextMarkerTime = getNextMarkerTime(currentMarkerIndex);
|
||||
if (currentTime >= setting.markerTip.time(markersList[currentMarkerIndex]) && currentTime < nextMarkerTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for ending (at the end current time equals player duration)
|
||||
if (currentMarkerIndex === markersList.length - 1 && currentTime === player.duration()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check first marker, no marker is selected
|
||||
if (currentTime < setting.markerTip.time(markersList[0])) {
|
||||
newMarkerIndex = NULL_INDEX;
|
||||
} else {
|
||||
// look for new index
|
||||
for (var i = 0; i < markersList.length; i++) {
|
||||
nextMarkerTime = getNextMarkerTime(i);
|
||||
if (currentTime >= setting.markerTip.time(markersList[i]) && currentTime < nextMarkerTime) {
|
||||
newMarkerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set new marker index
|
||||
if (newMarkerIndex !== currentMarkerIndex) {
|
||||
// trigger event if index is not null
|
||||
if (newMarkerIndex !== NULL_INDEX && options.onMarkerReached) {
|
||||
options.onMarkerReached(markersList[newMarkerIndex], newMarkerIndex);
|
||||
}
|
||||
currentMarkerIndex = newMarkerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// setup the whole thing
|
||||
function initialize() {
|
||||
if (setting.markerTip.display) {
|
||||
initializeMarkerTip();
|
||||
}
|
||||
|
||||
// remove existing markers if already initialized
|
||||
player.markers.removeAll();
|
||||
addMarkers(setting.markers);
|
||||
|
||||
if (setting.breakOverlay.display) {
|
||||
initializeOverlay();
|
||||
}
|
||||
onTimeUpdate();
|
||||
player.on("timeupdate", onTimeUpdate);
|
||||
player.off("loadedmetadata");
|
||||
}
|
||||
|
||||
// setup the plugin after we loaded video's meta data
|
||||
player.on("loadedmetadata", function () {
|
||||
initialize();
|
||||
});
|
||||
|
||||
// exposed plugin API
|
||||
player.markers = {
|
||||
getMarkers: function getMarkers() {
|
||||
return markersList;
|
||||
},
|
||||
next: function next() {
|
||||
// go to the next marker from current timestamp
|
||||
var currentTime = player.currentTime();
|
||||
for (var i = 0; i < markersList.length; i++) {
|
||||
var markerTime = setting.markerTip.time(markersList[i]);
|
||||
if (markerTime > currentTime) {
|
||||
player.currentTime(markerTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
prev: function prev() {
|
||||
// go to previous marker
|
||||
var currentTime = player.currentTime();
|
||||
for (var i = markersList.length - 1; i >= 0; i--) {
|
||||
var markerTime = setting.markerTip.time(markersList[i]);
|
||||
// add a threshold
|
||||
if (markerTime + 0.5 < currentTime) {
|
||||
player.currentTime(markerTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
add: function add(newMarkers) {
|
||||
// add new markers given an array of index
|
||||
addMarkers(newMarkers);
|
||||
},
|
||||
remove: function remove(indexArray) {
|
||||
// remove markers given an array of index
|
||||
removeMarkers(indexArray);
|
||||
},
|
||||
removeAll: function removeAll() {
|
||||
var indexArray = [];
|
||||
for (var i = 0; i < markersList.length; i++) {
|
||||
indexArray.push(i);
|
||||
}
|
||||
removeMarkers(indexArray);
|
||||
},
|
||||
// force - force all markers to be updated, regardless of if they have changed or not.
|
||||
updateTime: function updateTime(force) {
|
||||
// notify the plugin to update the UI for changes in marker times
|
||||
updateMarkers(force);
|
||||
},
|
||||
reset: function reset(newMarkers) {
|
||||
// remove all the existing markers and add new ones
|
||||
player.markers.removeAll();
|
||||
addMarkers(newMarkers);
|
||||
},
|
||||
destroy: function destroy() {
|
||||
// unregister the plugins and clean up even handlers
|
||||
player.markers.removeAll();
|
||||
breakOverlay && breakOverlay.remove();
|
||||
markerTip && markerTip.remove();
|
||||
player.off("timeupdate", updateBreakOverlay);
|
||||
delete player.markers;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_video2.default.plugin('markers', registerVideoJsMarkersPlugin);
|
||||
});
|
||||
//# sourceMappingURL=videojs-markers.js.map
|
||||
@@ -0,0 +1,44 @@
|
||||
//markers on the timebar
|
||||
const markerStyle = {
|
||||
width: "15px",
|
||||
"background-color": "#DD7373"
|
||||
};
|
||||
|
||||
//the comment overlay
|
||||
const overlayStyle = {
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
};
|
||||
|
||||
function enableMarkers(video) {
|
||||
if (!(typeof video.markers === 'object')) {
|
||||
video.markers({
|
||||
markerStyle: markerStyle,
|
||||
markerTip: {
|
||||
display: true,
|
||||
text: function (marker) {
|
||||
return marker.text;
|
||||
}
|
||||
},
|
||||
breakOverlay: {
|
||||
display: true,
|
||||
displayTime: 20,
|
||||
text: function (marker) {
|
||||
return marker.text;
|
||||
},
|
||||
style : overlayStyle
|
||||
},
|
||||
markers: []
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addMarker(videoPlayer, time, text)
|
||||
{
|
||||
videoPlayer.markers.add([{
|
||||
time: time,
|
||||
text: text
|
||||
}]);
|
||||
}
|
||||
|
||||
export {enableMarkers, addMarker};
|
||||
@@ -0,0 +1,59 @@
|
||||
.vjs-marker {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0em;
|
||||
opacity: 1;
|
||||
height: 100%;
|
||||
transition: opacity .2s ease;
|
||||
-webkit-transition: opacity .2s ease;
|
||||
-moz-transition: opacity .2s ease;
|
||||
z-index: 100;
|
||||
}
|
||||
.vjs-marker:hover {
|
||||
cursor: pointer;
|
||||
-webkit-transform: scale(1.3, 1.3);
|
||||
-moz-transform: scale(1.3, 1.3);
|
||||
-o-transform: scale(1.3, 1.3);
|
||||
-ms-transform: scale(1.3, 1.3);
|
||||
transform: scale(1.3, 1.3);
|
||||
}
|
||||
.vjs-tip {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
opacity: 0.8;
|
||||
padding: 5px;
|
||||
font-size: 10px;
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
z-index: 100000;
|
||||
}
|
||||
.vjs-tip .vjs-tip-arrow {
|
||||
background: url(data:image/gif;base64,R0lGODlhCQAJAIABAAAAAAAAACH5BAEAAAEALAAAAAAJAAkAAAIRjAOnwIrcDJxvwkplPtchVQAAOw==) no-repeat top left;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
background-position: bottom left;
|
||||
position: absolute;
|
||||
width: 9px;
|
||||
height: 5px;
|
||||
}
|
||||
.vjs-tip .vjs-tip-inner {
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
padding: 5px 8px 4px 8px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
max-width: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
.vjs-break-overlay {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
z-index: 100000;
|
||||
top: 0;
|
||||
}
|
||||
.vjs-break-overlay .vjs-break-overlay-text {
|
||||
padding: 9px;
|
||||
text-align: center;
|
||||
}
|
||||
Reference in New Issue
Block a user