diff options
Diffstat (limited to 'assets/netcut/lib/videojs-markers/videojs-markers.js')
m--------- | assets/netcut | 0 | ||||
-rw-r--r-- | assets/netcut/lib/videojs-markers/videojs-markers.js | 517 |
2 files changed, 517 insertions, 0 deletions
diff --git a/assets/netcut b/assets/netcut deleted file mode 160000 -Subproject 3dcf07d83e57191c79654d97310cbeb494ea52b diff --git a/assets/netcut/lib/videojs-markers/videojs-markers.js b/assets/netcut/lib/videojs-markers/videojs-markers.js new file mode 100644 index 0000000..7fc6822 --- /dev/null +++ b/assets/netcut/lib/videojs-markers/videojs-markers.js @@ -0,0 +1,517 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(['video.js'], factory); + } else if (typeof exports !== "undefined") { + factory(require('video.js')); + } else { + var mod = { + exports: {} + }; + factory(global.videojs); + global.videojsMarkers = mod.exports; + } +})(this, function (_video) { + /*! videojs-markers - v1.0.1 - 2018-04-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: false, + 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.dom.createEl) { + _video2.default.dom.createEl = function (tagName, props, attrs) { + var el = _video2.default.Player.prototype.dom.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.dom.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); + } + }); + + // clean up markers array + deleteIndexList.reverse(); + deleteIndexList.forEach(function (deleteIndex) { + markersList.splice(deleteIndex, 1); + }); + + // 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.dom.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.dom.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.registerPlugin('markers', registerVideoJsMarkersPlugin); +}); +//# sourceMappingURL=videojs-markers.js.map |