cloudinary-video-player 1.6.2-edge.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +4 -0
- package/.snyk +19 -0
- package/.travis.yml +8 -0
- package/CHANGELOG.md +329 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/dist/cld-video-player.css +2110 -0
- package/dist/cld-video-player.js +5249 -0
- package/dist/cld-video-player.light.css +1766 -0
- package/dist/cld-video-player.light.js +1399 -0
- package/dist/cld-video-player.light.min.css +1 -0
- package/dist/cld-video-player.light.min.js +2 -0
- package/dist/cld-video-player.light.min.js.LICENSE.txt +23 -0
- package/dist/cld-video-player.min.css +1 -0
- package/dist/cld-video-player.min.js +2 -0
- package/dist/cld-video-player.min.js.LICENSE.txt +26 -0
- package/dist/fonts/cloudinary_icon_for_black_bg.svg +69 -0
- package/dist/fonts/cloudinary_icon_for_white_bg.svg +69 -0
- package/docs/360.html +102 -0
- package/docs/_template.html +93 -0
- package/docs/adaptive-streaming.html +297 -0
- package/docs/analytics.html +140 -0
- package/docs/api.html +302 -0
- package/docs/audio.html +136 -0
- package/docs/autoplay-fallback.html +138 -0
- package/docs/autoplay-on-scroll.html +107 -0
- package/docs/codec-fallback.html +158 -0
- package/docs/colors.html +135 -0
- package/docs/components.html +284 -0
- package/docs/custom-cld-errors.html +134 -0
- package/docs/floating-player.html +98 -0
- package/docs/fluid.html +117 -0
- package/docs/force-hls-subtitles-ios.html +159 -0
- package/docs/index.html +83 -0
- package/docs/interaction-area.html +398 -0
- package/docs/live-customer.html +128 -0
- package/docs/multiple-players.html +125 -0
- package/docs/playlist-by-tag-cap.html +182 -0
- package/docs/playlist-by-tag.html +133 -0
- package/docs/playlist.html +133 -0
- package/docs/poster.html +155 -0
- package/docs/raw-url.html +104 -0
- package/docs/recommendations.html +155 -0
- package/docs/scripts.js +156 -0
- package/docs/seek-thumbs.html +90 -0
- package/docs/shoppable.html +335 -0
- package/docs/subtitles-and-captions.html +267 -0
- package/docs/transformations.html +171 -0
- package/docs/ui-config.html +108 -0
- package/docs/vast-vpaid.html +149 -0
- package/env.example.js +6 -0
- package/env.js +6 -0
- package/jest-puppeteer.config.js +14 -0
- package/jest.config.js +196 -0
- package/package.json +99 -0
- package/sandbox.config.json +3 -0
- package/setupJest.js +1 -0
- package/src/assets/fonts/VideoJS.svg +120 -0
- package/src/assets/fonts/VideoJS.ttf +0 -0
- package/src/assets/fonts/VideoJS.woff +0 -0
- package/src/assets/fonts/icons.json +120 -0
- package/src/assets/icons/cloudinary_icon_for_black_bg.svg +69 -0
- package/src/assets/icons/cloudinary_icon_for_white_bg.svg +69 -0
- package/src/assets/icons/cloudinary_logo_for_dark_bg.svg +188 -0
- package/src/assets/icons/cloudinary_logo_for_white_bg.svg +188 -0
- package/src/assets/icons/info-circle.svg +17 -0
- package/src/assets/styles/ads-label.scss +16 -0
- package/src/assets/styles/components/interaction-areas.scss +158 -0
- package/src/assets/styles/components/playlist.scss +213 -0
- package/src/assets/styles/components/themedButton.scss +48 -0
- package/src/assets/styles/components/thumbnail.scss +94 -0
- package/src/assets/styles/components/title-bar.scss +67 -0
- package/src/assets/styles/components/triangle-volume-bar.scss +52 -0
- package/src/assets/styles/icons.scss +257 -0
- package/src/assets/styles/main.scss +324 -0
- package/src/assets/styles/mixins/aspect-ratio.scss +16 -0
- package/src/assets/styles/mixins/disable-transition.scss +3 -0
- package/src/assets/styles/mixins/mixins.scss +5 -0
- package/src/assets/styles/mixins/skin.scss +64 -0
- package/src/assets/styles/variables.scss +2 -0
- package/src/assets/styles/videojs-ima.scss +252 -0
- package/src/components/component-utils.js +20 -0
- package/src/components/index.js +21 -0
- package/src/components/interaction-area/interaction-area.const.js +30 -0
- package/src/components/interaction-area/interaction-area.service.js +223 -0
- package/src/components/interaction-area/interaction-area.utils.js +236 -0
- package/src/components/jumpButtons/jump-10-minus.js +21 -0
- package/src/components/jumpButtons/jump-10-plus.js +20 -0
- package/src/components/logoButton/logo-button.const.js +3 -0
- package/src/components/logoButton/logo-button.js +30 -0
- package/src/components/logoButton/logo-button.scss +15 -0
- package/src/components/playlist/components/playlist-button.js +34 -0
- package/src/components/playlist/components/playlist-next-button.js +18 -0
- package/src/components/playlist/components/playlist-previous-button.js +18 -0
- package/src/components/playlist/components/playlist.js +5 -0
- package/src/components/playlist/components/playlist.scss +15 -0
- package/src/components/playlist/components/upcoming-video-overlay.js +149 -0
- package/src/components/playlist/components/upcoming-video-overlay.scss +86 -0
- package/src/components/playlist/layout/playlist-layout-custom.js +21 -0
- package/src/components/playlist/layout/playlist-layout-horizontal.js +16 -0
- package/src/components/playlist/layout/playlist-layout-vertical.js +19 -0
- package/src/components/playlist/layout/playlist-layout.js +110 -0
- package/src/components/playlist/panel/playlist-panel-item.js +86 -0
- package/src/components/playlist/panel/playlist-panel.js +92 -0
- package/src/components/playlist/playlist-widget.js +119 -0
- package/src/components/playlist/playlist.const.js +14 -0
- package/src/components/playlist/playlist.js +413 -0
- package/src/components/playlist/thumbnail/thumbnail.js +69 -0
- package/src/components/progress-control-events-blocker/progress-control-events-blocker.js +17 -0
- package/src/components/qualitySelector/quality-selector.scss +10 -0
- package/src/components/qualitySelector/qualitySelector.js +152 -0
- package/src/components/recommendations-overlay/index.js +3 -0
- package/src/components/recommendations-overlay/recommendations-overlay-content.js +57 -0
- package/src/components/recommendations-overlay/recommendations-overlay-hide-button.js +18 -0
- package/src/components/recommendations-overlay/recommendations-overlay-item.js +35 -0
- package/src/components/recommendations-overlay/recommendations-overlay-primary-item.js +81 -0
- package/src/components/recommendations-overlay/recommendations-overlay-secondary-item.js +48 -0
- package/src/components/recommendations-overlay/recommendations-overlay-secondary-items-container.js +35 -0
- package/src/components/recommendations-overlay/recommendations-overlay.js +94 -0
- package/src/components/recommendations-overlay/recommendations-overlay.scss +182 -0
- package/src/components/shoppable-bar/layout/bar-layout.js +111 -0
- package/src/components/shoppable-bar/layout/shoppable-panel-toggle.js +64 -0
- package/src/components/shoppable-bar/layout/shoppable-products-overlay.js +87 -0
- package/src/components/shoppable-bar/panel/shoppable-panel-item.js +105 -0
- package/src/components/shoppable-bar/panel/shoppable-panel.js +172 -0
- package/src/components/shoppable-bar/shoppable-post-widget.js +110 -0
- package/src/components/shoppable-bar/shoppable-widget.const.js +52 -0
- package/src/components/shoppable-bar/shoppable-widget.js +111 -0
- package/src/components/shoppable-bar/shoppable-widget.scss +359 -0
- package/src/components/themeButton/themedButton.const.js +3 -0
- package/src/components/themeButton/themedButton.js +25 -0
- package/src/components/title-bar/title-bar.js +79 -0
- package/src/config/defaults.js +25 -0
- package/src/extended-events.js +228 -0
- package/src/index.js +18 -0
- package/src/mixins/eventable.js +54 -0
- package/src/mixins/playlistable.js +106 -0
- package/src/plugins/analytics/index.js +245 -0
- package/src/plugins/autoplay-on-scroll/index.js +86 -0
- package/src/plugins/cloudinary/common.js +216 -0
- package/src/plugins/cloudinary/event-handler-registry.js +46 -0
- package/src/plugins/cloudinary/index.js +345 -0
- package/src/plugins/cloudinary/models/audio-source/audio-source.const.js +11 -0
- package/src/plugins/cloudinary/models/audio-source/audio-source.js +82 -0
- package/src/plugins/cloudinary/models/base-source.js +107 -0
- package/src/plugins/cloudinary/models/image-source.js +26 -0
- package/src/plugins/cloudinary/models/video-source/video-source.const.js +32 -0
- package/src/plugins/cloudinary/models/video-source/video-source.js +239 -0
- package/src/plugins/cloudinary/models/video-source/video-source.utils.js +57 -0
- package/src/plugins/colors/index.js +303 -0
- package/src/plugins/context-menu/components/context-menu-item.js +12 -0
- package/src/plugins/context-menu/components/context-menu.js +63 -0
- package/src/plugins/context-menu/context-menu.scss +30 -0
- package/src/plugins/context-menu/contextMenuContent.js +53 -0
- package/src/plugins/context-menu/index.js +134 -0
- package/src/plugins/dash/index.js +26 -0
- package/src/plugins/dash/setup-audio-tracks.js +112 -0
- package/src/plugins/dash/setup-text-tracks.js +195 -0
- package/src/plugins/dash/videojs-dash.js +372 -0
- package/src/plugins/floating-player/floating-player.scss +74 -0
- package/src/plugins/floating-player/index.js +129 -0
- package/src/plugins/ima/index.js +1775 -0
- package/src/plugins/index.js +31 -0
- package/src/plugins/interactive-plugin/index.js +10 -0
- package/src/plugins/videojs-http-source-selector/components/SourceMenuButton.js +98 -0
- package/src/plugins/videojs-http-source-selector/components/SourceMenuItem.js +52 -0
- package/src/plugins/videojs-http-source-selector/plugin.js +82 -0
- package/src/plugins/videojs-http-source-selector/plugin.scss +9 -0
- package/src/plugins/vtt-thumbnails/index.js +526 -0
- package/src/plugins/vtt-thumbnails/vtt-thumbnails.scss +29 -0
- package/src/utils/api.js +32 -0
- package/src/utils/apply-with-props.js +32 -0
- package/src/utils/array.js +22 -0
- package/src/utils/assign.js +27 -0
- package/src/utils/attributes-normalizer.js +72 -0
- package/src/utils/cloudinary.js +165 -0
- package/src/utils/css-prefix.js +43 -0
- package/src/utils/dom.js +74 -0
- package/src/utils/find.js +28 -0
- package/src/utils/fontFace.js +25 -0
- package/src/utils/groupBy.js +12 -0
- package/src/utils/index.js +29 -0
- package/src/utils/matches.js +11 -0
- package/src/utils/mixin.js +5 -0
- package/src/utils/object.js +26 -0
- package/src/utils/playButton.js +9 -0
- package/src/utils/positioning.js +78 -0
- package/src/utils/querystring.js +12 -0
- package/src/utils/slicing.js +21 -0
- package/src/utils/string.js +15 -0
- package/src/utils/throttle.js +30 -0
- package/src/utils/time.js +77 -0
- package/src/utils/type-inference.js +35 -0
- package/src/validators/validators-functions.js +48 -0
- package/src/validators/validators-types.js +78 -0
- package/src/validators/validators.js +110 -0
- package/src/video-player.const.js +68 -0
- package/src/video-player.js +761 -0
- package/src/video-player.utils.js +123 -0
- package/test/adaptive-streaming.test.js +38 -0
- package/test/ads.test.js +35 -0
- package/test/analytics.test.js +111 -0
- package/test/api.test.js +111 -0
- package/test/autoplay.scroll.test.js +23 -0
- package/test/basic-ui.test.js +59 -0
- package/test/colors.test.js +58 -0
- package/test/components.test.js +21 -0
- package/test/custom-error.test.js +24 -0
- package/test/fluid.test.js +36 -0
- package/test/isValidConfig.test.js +224 -0
- package/test/mocks/cloudinary-core-mock.js +0 -0
- package/test/mocks/styleMock.js +1 -0
- package/test/multiplayer.test.js +25 -0
- package/test/playlist.test.js +60 -0
- package/test/puppeteer/vp-env.js +19 -0
- package/test/recommendations.test.js +38 -0
- package/test/title-bar.test.js +28 -0
- package/test/ui-conf.test.js +49 -0
- package/test/unit/cloudinaryConfig.test.js +22 -0
- package/test/unit/cloudinaryUtils.test.js +53 -0
- package/test/unit/utils.test.js +27 -0
- package/test/unit/videoSource.test.js +454 -0
- package/tsconfig.json +15 -0
- package/types/video-player-tests.js +12 -0
- package/types/video-player-tests.ts +31 -0
- package/types/video-player.d.ts +570 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import Promise from 'promise-polyfill';
|
|
3
|
+
|
|
4
|
+
import './vtt-thumbnails.scss';
|
|
5
|
+
|
|
6
|
+
// Default options for the plugin.
|
|
7
|
+
let defaults = {};
|
|
8
|
+
|
|
9
|
+
// Cache for image elements
|
|
10
|
+
let cache = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Function to invoke when the player is ready.
|
|
14
|
+
*
|
|
15
|
+
* This is a great place for your plugin to initialize itself. When this
|
|
16
|
+
* function is called, the player will have its DOM and child components
|
|
17
|
+
* in place.
|
|
18
|
+
*
|
|
19
|
+
* @function onPlayerReady
|
|
20
|
+
* @param {Player} player
|
|
21
|
+
* A Video.js player object.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} [options={}]
|
|
24
|
+
* A plain object containing options for the plugin.
|
|
25
|
+
*/
|
|
26
|
+
const onPlayerReady = function onPlayerReady(player, options) {
|
|
27
|
+
player.addClass('vjs-vtt-thumbnails');
|
|
28
|
+
player.vttThumbnails = new VttThumbnailsPlugin(player, options);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A video.js plugin.
|
|
33
|
+
*
|
|
34
|
+
* In the plugin function, the value of `this` is a video.js `Player`
|
|
35
|
+
* instance. You cannot rely on the player being in a "ready" state here,
|
|
36
|
+
* depending on how the plugin is invoked. This may or may not be important
|
|
37
|
+
* to you; if not, remove the wait for "ready"!
|
|
38
|
+
*
|
|
39
|
+
* @function vttThumbnails
|
|
40
|
+
* @param {Object} [options={}]
|
|
41
|
+
* An object of options left to the plugin author to define.
|
|
42
|
+
*/
|
|
43
|
+
const vttThumbnails = function vttThumbnails(options) {
|
|
44
|
+
let _this = this;
|
|
45
|
+
|
|
46
|
+
this.ready(function () {
|
|
47
|
+
onPlayerReady(_this, videojs.mergeOptions(defaults, options));
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* VTT Thumbnails class.
|
|
53
|
+
*
|
|
54
|
+
* This class performs all functions related to displaying the vtt
|
|
55
|
+
* thumbnails.
|
|
56
|
+
*/
|
|
57
|
+
const VttThumbnailsPlugin = (function () {
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Plugin class constructor, called by videojs on
|
|
61
|
+
* ready event.
|
|
62
|
+
*
|
|
63
|
+
* @function constructor
|
|
64
|
+
* @param {Player} player
|
|
65
|
+
* A Video.js player object.
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} [options={}]
|
|
68
|
+
* A plain object containing options for the plugin.
|
|
69
|
+
*/
|
|
70
|
+
function VttThumbnailsPlugin(player, options) {
|
|
71
|
+
this.player = player;
|
|
72
|
+
this.options = options;
|
|
73
|
+
this.listenForDurationChange();
|
|
74
|
+
this.initializeThumbnails();
|
|
75
|
+
this.registeredEvents = {};
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
VttThumbnailsPlugin.prototype.src = function src(source) {
|
|
80
|
+
this.resetPlugin();
|
|
81
|
+
this.options.src = source;
|
|
82
|
+
this.initializeThumbnails();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
VttThumbnailsPlugin.prototype.detach = function detach() {
|
|
86
|
+
this.resetPlugin();
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
VttThumbnailsPlugin.prototype.resetPlugin = function resetPlugin() {
|
|
90
|
+
if (this.thumbnailHolder) {
|
|
91
|
+
this.thumbnailHolder.parentNode.removeChild(this.thumbnailHolder);
|
|
92
|
+
}
|
|
93
|
+
if (this.progressBar) {
|
|
94
|
+
this.progressBar.removeEventListener(
|
|
95
|
+
'mouseenter',
|
|
96
|
+
this.registeredEvents.progressBarMouseEnter
|
|
97
|
+
);
|
|
98
|
+
this.progressBar.removeEventListener(
|
|
99
|
+
'mouseleave',
|
|
100
|
+
this.registeredEvents.progressBarMouseLeave
|
|
101
|
+
);
|
|
102
|
+
this.progressBar.removeEventListener(
|
|
103
|
+
'mousemove',
|
|
104
|
+
this.registeredEvents.progressBarMouseMove
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
delete this.registeredEvents.progressBarMouseEnter;
|
|
108
|
+
delete this.registeredEvents.progressBarMouseLeave;
|
|
109
|
+
delete this.registeredEvents.progressBarMouseMove;
|
|
110
|
+
delete this.progressBar;
|
|
111
|
+
delete this.vttData;
|
|
112
|
+
delete this.thumbnailHolder;
|
|
113
|
+
delete this.lastStyle;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
VttThumbnailsPlugin.prototype.listenForDurationChange = function listenForDurationChange() {
|
|
117
|
+
this.player.on('durationchange', function () {
|
|
118
|
+
// ToDo
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Bootstrap the plugin.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
VttThumbnailsPlugin.prototype.initializeThumbnails = function initializeThumbnails() {
|
|
127
|
+
let _this2 = this;
|
|
128
|
+
|
|
129
|
+
if (!this.options.src) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let baseUrl = this.getBaseUrl();
|
|
133
|
+
let url = this.getFullyQualifiedUrl(this.options.src, baseUrl);
|
|
134
|
+
|
|
135
|
+
this.getVttFile(url).then(function (data) {
|
|
136
|
+
_this2.vttData = _this2.processVtt(data);
|
|
137
|
+
_this2.setupThumbnailElement();
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Builds a base URL should we require one.
|
|
143
|
+
*
|
|
144
|
+
* @returns {string}
|
|
145
|
+
*/
|
|
146
|
+
|
|
147
|
+
VttThumbnailsPlugin.prototype.getBaseUrl = function getBaseUrl() {
|
|
148
|
+
return [
|
|
149
|
+
window.location.protocol,
|
|
150
|
+
'//',
|
|
151
|
+
window.location.hostname,
|
|
152
|
+
window.location.port ? ':' + window.location.port : '',
|
|
153
|
+
window.location.pathname
|
|
154
|
+
]
|
|
155
|
+
.join('')
|
|
156
|
+
.split(/([^\/]*)$/gi)
|
|
157
|
+
.shift();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Grabs the contents of the VTT file.
|
|
162
|
+
*
|
|
163
|
+
* @param url
|
|
164
|
+
* @returns {Promise}
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
VttThumbnailsPlugin.prototype.getVttFile = function getVttFile(url) {
|
|
168
|
+
let _this3 = this;
|
|
169
|
+
|
|
170
|
+
return new Promise(function (resolve) {
|
|
171
|
+
let req = new XMLHttpRequest();
|
|
172
|
+
req.data = {
|
|
173
|
+
resolve: resolve
|
|
174
|
+
};
|
|
175
|
+
req.addEventListener('load', _this3.vttFileLoaded);
|
|
176
|
+
req.open('GET', url);
|
|
177
|
+
req.send();
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Callback for loaded VTT file.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
VttThumbnailsPlugin.prototype.vttFileLoaded = function vttFileLoaded() {
|
|
186
|
+
this.data.resolve(this.responseText);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
VttThumbnailsPlugin.prototype.setupThumbnailElement = function setupThumbnailElement() {
|
|
190
|
+
let _this4 = this;
|
|
191
|
+
|
|
192
|
+
let mouseDisplay = this.player.$('.vjs-mouse-display');
|
|
193
|
+
this.progressBar = this.player.$('.vjs-progress-control');
|
|
194
|
+
let thumbHolder = document.createElement('div');
|
|
195
|
+
thumbHolder.setAttribute('class', 'vjs-vtt-thumbnail-display');
|
|
196
|
+
this.progressBar.appendChild(thumbHolder);
|
|
197
|
+
this.thumbnailHolder = thumbHolder;
|
|
198
|
+
let timeHolder = document.createElement('div');
|
|
199
|
+
timeHolder.setAttribute('class', 'vjs-vtt-time-display');
|
|
200
|
+
this.thumbnailHolder.appendChild(timeHolder);
|
|
201
|
+
this.timeHolder = timeHolder;
|
|
202
|
+
if (mouseDisplay) {
|
|
203
|
+
mouseDisplay.classList.add('vjs-hidden');
|
|
204
|
+
}
|
|
205
|
+
this.registeredEvents.progressBarMouseEnter = function () {
|
|
206
|
+
return _this4.onBarMouseenter();
|
|
207
|
+
};
|
|
208
|
+
this.registeredEvents.progressBarMouseLeave = function () {
|
|
209
|
+
return _this4.onBarMouseleave();
|
|
210
|
+
};
|
|
211
|
+
this.progressBar.addEventListener(
|
|
212
|
+
'mouseenter',
|
|
213
|
+
this.registeredEvents.progressBarMouseEnter
|
|
214
|
+
);
|
|
215
|
+
this.progressBar.addEventListener(
|
|
216
|
+
'mouseleave',
|
|
217
|
+
this.registeredEvents.progressBarMouseLeave
|
|
218
|
+
);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
VttThumbnailsPlugin.prototype.onBarMouseenter = function onBarMouseenter() {
|
|
222
|
+
let _this5 = this;
|
|
223
|
+
|
|
224
|
+
if (this.progressBar.offsetWidth < 400) {
|
|
225
|
+
// Don't show in small players
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.mouseMoveCallback = function (e) {
|
|
230
|
+
_this5.onBarMousemove(e);
|
|
231
|
+
};
|
|
232
|
+
this.registeredEvents.progressBarMouseMove = this.mouseMoveCallback;
|
|
233
|
+
this.progressBar.addEventListener(
|
|
234
|
+
'mousemove',
|
|
235
|
+
this.registeredEvents.progressBarMouseMove
|
|
236
|
+
);
|
|
237
|
+
this.showThumbnailHolder();
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
VttThumbnailsPlugin.prototype.onBarMouseleave = function onBarMouseleave() {
|
|
241
|
+
if (this.registeredEvents.progressBarMouseMove) {
|
|
242
|
+
this.progressBar.removeEventListener(
|
|
243
|
+
'mousemove',
|
|
244
|
+
this.registeredEvents.progressBarMouseMove
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
this.hideThumbnailHolder();
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
VttThumbnailsPlugin.prototype.getXCoord = function getXCoord(bar, mouseX) {
|
|
251
|
+
let rect = bar.getBoundingClientRect();
|
|
252
|
+
let docEl = document.documentElement;
|
|
253
|
+
return (
|
|
254
|
+
mouseX - (rect.left + (window.pageXOffset || docEl.scrollLeft || 0))
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
VttThumbnailsPlugin.prototype.onBarMousemove = function onBarMousemove(
|
|
259
|
+
event
|
|
260
|
+
) {
|
|
261
|
+
this.updateThumbnailStyle(
|
|
262
|
+
videojs.dom.getPointerPosition(this.progressBar, event).x,
|
|
263
|
+
this.progressBar.offsetWidth
|
|
264
|
+
);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
VttThumbnailsPlugin.prototype.getStyleForTime = function getStyleForTime(
|
|
268
|
+
time
|
|
269
|
+
) {
|
|
270
|
+
for (let i = 0; i < this.vttData.length; ++i) {
|
|
271
|
+
let item = this.vttData[i];
|
|
272
|
+
if (time >= item.start && time < item.end) {
|
|
273
|
+
// Cache miss
|
|
274
|
+
if (item.css.url && !cache[item.css.url]) {
|
|
275
|
+
let image = new Image();
|
|
276
|
+
image.src = item.css.url;
|
|
277
|
+
cache[item.css.url] = image;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return item.css;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
VttThumbnailsPlugin.prototype.showThumbnailHolder = function showThumbnailHolder() {
|
|
286
|
+
this.thumbnailHolder.style.opacity = '1';
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
VttThumbnailsPlugin.prototype.hideThumbnailHolder = function hideThumbnailHolder() {
|
|
290
|
+
this.thumbnailHolder.style.opacity = '0';
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
VttThumbnailsPlugin.prototype.updateThumbnailStyle = function updateThumbnailStyle(
|
|
294
|
+
percent,
|
|
295
|
+
width
|
|
296
|
+
) {
|
|
297
|
+
let duration = this.player.duration();
|
|
298
|
+
let time = percent * duration;
|
|
299
|
+
let currentStyle = this.getStyleForTime(time);
|
|
300
|
+
|
|
301
|
+
if (!currentStyle) {
|
|
302
|
+
return this.hideThumbnailHolder();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let xPos = percent * width;
|
|
306
|
+
let thumbnailWidth = parseInt(currentStyle.width, 10);
|
|
307
|
+
let halfthumbnailWidth = thumbnailWidth / 2;
|
|
308
|
+
let marginRight = width - (xPos + halfthumbnailWidth);
|
|
309
|
+
let marginLeft = xPos - halfthumbnailWidth;
|
|
310
|
+
if (marginLeft > 0 && marginRight > 0) {
|
|
311
|
+
this.thumbnailHolder.style.transform =
|
|
312
|
+
'translateX(' + (xPos - halfthumbnailWidth) + 'px)';
|
|
313
|
+
} else if (marginLeft <= 0) {
|
|
314
|
+
this.thumbnailHolder.style.transform = 'translateX(' + 0 + 'px)';
|
|
315
|
+
} else if (marginRight <= 0) {
|
|
316
|
+
this.thumbnailHolder.style.transform =
|
|
317
|
+
'translateX(' + (width - thumbnailWidth) + 'px)';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
this.timeHolder.innerHTML = this.getTimestampFromSeconds(time);
|
|
321
|
+
|
|
322
|
+
if (this.lastStyle && this.lastStyle === currentStyle) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
this.lastStyle = currentStyle;
|
|
326
|
+
|
|
327
|
+
for (let style in currentStyle) {
|
|
328
|
+
if (Object.prototype.hasOwnProperty.call(currentStyle, style)) {
|
|
329
|
+
this.thumbnailHolder.style[style] = currentStyle[style];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
VttThumbnailsPlugin.prototype.processVtt = function processVtt(data) {
|
|
335
|
+
let _this6 = this;
|
|
336
|
+
|
|
337
|
+
let processedVtts = [];
|
|
338
|
+
let vttDefinitions = data.split(/[\r\n][\r\n]/i);
|
|
339
|
+
vttDefinitions.forEach(function (vttDef) {
|
|
340
|
+
if (
|
|
341
|
+
vttDef.match(
|
|
342
|
+
/([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?( ?--> ?)([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?[\r\n]{1}.*/gi
|
|
343
|
+
)
|
|
344
|
+
) {
|
|
345
|
+
let vttDefSplit = vttDef.split(/[\r\n]/i);
|
|
346
|
+
let vttTiming = vttDefSplit[0];
|
|
347
|
+
let vttTimingSplit = vttTiming.split(/ ?--> ?/i);
|
|
348
|
+
let vttTimeStart = vttTimingSplit[0];
|
|
349
|
+
let vttTimeEnd = vttTimingSplit[1];
|
|
350
|
+
|
|
351
|
+
let vttImageFullPath = vttDefSplit[1];
|
|
352
|
+
let vttImageDef = vttImageFullPath.split('\/').pop();
|
|
353
|
+
let vttCssDef = _this6.getVttCss(vttImageDef);
|
|
354
|
+
|
|
355
|
+
processedVtts.push({
|
|
356
|
+
start: _this6.getSecondsFromTimestamp(vttTimeStart),
|
|
357
|
+
end: _this6.getSecondsFromTimestamp(vttTimeEnd),
|
|
358
|
+
css: vttCssDef
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return processedVtts;
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
VttThumbnailsPlugin.prototype.getFullyQualifiedUrl = function getFullyQualifiedUrl(
|
|
366
|
+
path,
|
|
367
|
+
base
|
|
368
|
+
) {
|
|
369
|
+
// ToDo: remove this? also remove trim?
|
|
370
|
+
if (path.indexOf('//') >= 0) {
|
|
371
|
+
// We have a fully qualified path.
|
|
372
|
+
return path;
|
|
373
|
+
} else if (base.indexOf('//') === 0) {
|
|
374
|
+
// We don't have a fully qualified path, but need to
|
|
375
|
+
// be careful with trimming.
|
|
376
|
+
return [base.replace(/\/$/gi, ''), this.trim(path, '/')].join('/');
|
|
377
|
+
} else if (base.indexOf('//') > 0) {
|
|
378
|
+
// We don't have a fully qualified path, and should
|
|
379
|
+
// trim both sides of base and path.
|
|
380
|
+
return [this.trim(base, '/'), this.trim(path, '/')].join('/');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// If all else fails.
|
|
384
|
+
return path;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
VttThumbnailsPlugin.prototype.getPropsFromDef = function getPropsFromDef(
|
|
388
|
+
def
|
|
389
|
+
) {
|
|
390
|
+
let imageDefSplit = def.split(/#xywh=/i);
|
|
391
|
+
let imageUrl = imageDefSplit[0];
|
|
392
|
+
let imageCoords = imageDefSplit[1];
|
|
393
|
+
let splitCoords = imageCoords.match(/[0-9]+/gi);
|
|
394
|
+
return {
|
|
395
|
+
x: splitCoords[0],
|
|
396
|
+
y: splitCoords[1],
|
|
397
|
+
w: splitCoords[2],
|
|
398
|
+
h: splitCoords[3],
|
|
399
|
+
image: imageUrl
|
|
400
|
+
};
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
VttThumbnailsPlugin.prototype.getVttCss = function getVttCss(vttImageDef) {
|
|
404
|
+
let cssObj = {};
|
|
405
|
+
|
|
406
|
+
// If there isn't a protocol, use the VTT source URL.
|
|
407
|
+
let baseSplit = '';
|
|
408
|
+
if (this.options.src.indexOf('//') >= 0) {
|
|
409
|
+
baseSplit = this.options.src.split(/([^\/]*)$/gi).shift();
|
|
410
|
+
} else {
|
|
411
|
+
baseSplit =
|
|
412
|
+
this.getBaseUrl() + this.options.src.split(/([^\/]*)$/gi).shift();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
vttImageDef = this.getFullyQualifiedUrl(vttImageDef, baseSplit);
|
|
416
|
+
|
|
417
|
+
if (!vttImageDef.match(/#xywh=/i)) {
|
|
418
|
+
cssObj.background = 'url("' + vttImageDef + '")';
|
|
419
|
+
return cssObj;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
let imageProps = this.getPropsFromDef(vttImageDef);
|
|
423
|
+
cssObj.background =
|
|
424
|
+
'url("' +
|
|
425
|
+
imageProps.image +
|
|
426
|
+
'") no-repeat -' +
|
|
427
|
+
imageProps.x +
|
|
428
|
+
'px -' +
|
|
429
|
+
imageProps.y +
|
|
430
|
+
'px';
|
|
431
|
+
cssObj.width = imageProps.w + 'px';
|
|
432
|
+
cssObj.height = imageProps.h + 'px';
|
|
433
|
+
cssObj.url = imageProps.image;
|
|
434
|
+
|
|
435
|
+
return cssObj;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
VttThumbnailsPlugin.prototype.doconstructTimestamp = function doconstructTimestamp(
|
|
439
|
+
timestamp
|
|
440
|
+
) {
|
|
441
|
+
let splitStampMilliseconds = timestamp.split('.');
|
|
442
|
+
let timeParts = splitStampMilliseconds[0];
|
|
443
|
+
let timePartsSplit = timeParts.split(':');
|
|
444
|
+
return {
|
|
445
|
+
milliseconds: parseInt(splitStampMilliseconds[1], 10) || 0,
|
|
446
|
+
seconds: parseInt(timePartsSplit.pop(), 10) || 0,
|
|
447
|
+
minutes: parseInt(timePartsSplit.pop(), 10) || 0,
|
|
448
|
+
hours: parseInt(timePartsSplit.pop(), 10) || 0
|
|
449
|
+
};
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
VttThumbnailsPlugin.prototype.getSecondsFromTimestamp = function getSecondsFromTimestamp(
|
|
453
|
+
timestamp
|
|
454
|
+
) {
|
|
455
|
+
let timestampParts = this.doconstructTimestamp(timestamp);
|
|
456
|
+
return parseInt(
|
|
457
|
+
timestampParts.hours * (60 * 60) +
|
|
458
|
+
timestampParts.minutes * 60 +
|
|
459
|
+
timestampParts.seconds +
|
|
460
|
+
timestampParts.milliseconds / 1000
|
|
461
|
+
, 10);
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
VttThumbnailsPlugin.prototype.getTimestampFromSeconds = function getTimestampFromSeconds(
|
|
465
|
+
totalSeconds
|
|
466
|
+
) {
|
|
467
|
+
let minutes = Math.floor(totalSeconds / 60);
|
|
468
|
+
let seconds = Math.floor(totalSeconds % 60);
|
|
469
|
+
if (seconds < 10) {
|
|
470
|
+
seconds = '0' + seconds;
|
|
471
|
+
}
|
|
472
|
+
return minutes + ':' + seconds;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
VttThumbnailsPlugin.prototype.trim = function trim(str, charlist) {
|
|
476
|
+
let whitespace = [
|
|
477
|
+
' ',
|
|
478
|
+
'\n',
|
|
479
|
+
'\r',
|
|
480
|
+
'\t',
|
|
481
|
+
'\f',
|
|
482
|
+
'\x0b',
|
|
483
|
+
'\xa0',
|
|
484
|
+
'\u2000',
|
|
485
|
+
'\u2001',
|
|
486
|
+
'\u2002',
|
|
487
|
+
'\u2003',
|
|
488
|
+
'\u2004',
|
|
489
|
+
'\u2005',
|
|
490
|
+
'\u2006',
|
|
491
|
+
'\u2007',
|
|
492
|
+
'\u2008',
|
|
493
|
+
'\u2009',
|
|
494
|
+
'\u200A',
|
|
495
|
+
'\u200B',
|
|
496
|
+
'\u2028',
|
|
497
|
+
'\u2029',
|
|
498
|
+
'\u3000'
|
|
499
|
+
].join('');
|
|
500
|
+
let l = 0;
|
|
501
|
+
let i = 0;
|
|
502
|
+
str += '';
|
|
503
|
+
if (charlist) {
|
|
504
|
+
whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1');
|
|
505
|
+
}
|
|
506
|
+
l = str.length;
|
|
507
|
+
for (i = 0; i < l; i++) {
|
|
508
|
+
if (whitespace.indexOf(str.charAt(i)) === -1) {
|
|
509
|
+
str = str.substring(i);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
l = str.length;
|
|
514
|
+
for (i = l - 1; i >= 0; i--) {
|
|
515
|
+
if (whitespace.indexOf(str.charAt(i)) === -1) {
|
|
516
|
+
str = str.substring(0, i + 1);
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
return VttThumbnailsPlugin;
|
|
524
|
+
}());
|
|
525
|
+
|
|
526
|
+
export default vttThumbnails;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.vjs-vtt-thumbnail-display {
|
|
2
|
+
position: absolute;
|
|
3
|
+
left: 0;
|
|
4
|
+
bottom: 15px;
|
|
5
|
+
z-index: 1;
|
|
6
|
+
opacity: 0;
|
|
7
|
+
transition: opacity 0.2s;
|
|
8
|
+
bottom: 3em;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
border: 3px solid #fff;
|
|
11
|
+
// border: 3px solid var(--color-base);
|
|
12
|
+
border-radius: 3px;
|
|
13
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.vjs-vtt-time-display {
|
|
17
|
+
position: absolute;
|
|
18
|
+
bottom: -1.7em;
|
|
19
|
+
left: 0;
|
|
20
|
+
right: 0;
|
|
21
|
+
margin: auto;
|
|
22
|
+
color: #fff;
|
|
23
|
+
// color: var(--color-base);
|
|
24
|
+
text-shadow: 0 0 3px #000;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.vjs-vtt-thumbnails .vjs-time-tooltip {
|
|
28
|
+
display: none !important;
|
|
29
|
+
}
|
package/src/utils/api.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isPlainObject } from 'utils/type-inference';
|
|
2
|
+
import { camelize } from 'utils/string';
|
|
3
|
+
import { parseISO8601 } from 'utils/time';
|
|
4
|
+
|
|
5
|
+
const TIME_FIELDS = ['created_at', 'updated_at'];
|
|
6
|
+
|
|
7
|
+
const normalizeJsonResponse = (obj) => {
|
|
8
|
+
const agg = {};
|
|
9
|
+
|
|
10
|
+
if (isPlainObject(obj)) {
|
|
11
|
+
Object.keys(obj).reduce((agg, key) => {
|
|
12
|
+
const newKey = camelize(key);
|
|
13
|
+
|
|
14
|
+
if (TIME_FIELDS.indexOf(key) !== -1) {
|
|
15
|
+
agg[newKey] = new Date(parseISO8601(obj[key]));
|
|
16
|
+
} else {
|
|
17
|
+
agg[newKey] = normalizeJsonResponse(obj[key]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return agg;
|
|
21
|
+
}, agg);
|
|
22
|
+
|
|
23
|
+
return agg;
|
|
24
|
+
} else if (Array.isArray(obj)) {
|
|
25
|
+
return obj.map((item) => normalizeJsonResponse(item));
|
|
26
|
+
} else {
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export { normalizeJsonResponse };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { assign } from './assign';
|
|
2
|
+
import { isFunction } from './type-inference';
|
|
3
|
+
|
|
4
|
+
function applyWithProps(context, obj, { order = null } = {}) {
|
|
5
|
+
let _obj = obj;
|
|
6
|
+
|
|
7
|
+
const apply = (key) => {
|
|
8
|
+
const value = obj[key];
|
|
9
|
+
if (value === undefined) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (context[key] && isFunction(context[key])) {
|
|
14
|
+
context[key](value);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (order) {
|
|
19
|
+
_obj = assign({}, obj);
|
|
20
|
+
|
|
21
|
+
order.forEach((key) => {
|
|
22
|
+
apply(key);
|
|
23
|
+
delete _obj[key];
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Object.keys(_obj).forEach((key => {
|
|
28
|
+
apply(key);
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { applyWithProps };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
export const castArray = (value) => Array.isArray(value) ? value : [value];
|
|
3
|
+
|
|
4
|
+
export const forEach = (value, callback) => {
|
|
5
|
+
if (Array.isArray(value) && value.length) {
|
|
6
|
+
value.forEach(callback);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const some = (value, callback) => {
|
|
11
|
+
if (Array.isArray(value) && value.length) {
|
|
12
|
+
return value.some(callback);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return false;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const map = (value, callback) => {
|
|
19
|
+
if (Array.isArray(value) && value.length) {
|
|
20
|
+
return value.map(callback);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object.assign-style object shallow merge/extend.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} target
|
|
5
|
+
* @param {Object} ...sources
|
|
6
|
+
* @return {Object}
|
|
7
|
+
*/
|
|
8
|
+
function assign(target, ...sources) {
|
|
9
|
+
if (Object.assign) {
|
|
10
|
+
return Object.assign(target, ...sources);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
sources.forEach(source => {
|
|
14
|
+
if (!source) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Object.keys(source).forEach((key) => {
|
|
19
|
+
const value = source[key];
|
|
20
|
+
target[key] = value;
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return target;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { assign };
|