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.
Files changed (226) hide show
  1. package/.eslintignore +4 -0
  2. package/.snyk +19 -0
  3. package/.travis.yml +8 -0
  4. package/CHANGELOG.md +329 -0
  5. package/LICENSE +21 -0
  6. package/README.md +87 -0
  7. package/dist/cld-video-player.css +2110 -0
  8. package/dist/cld-video-player.js +5249 -0
  9. package/dist/cld-video-player.light.css +1766 -0
  10. package/dist/cld-video-player.light.js +1399 -0
  11. package/dist/cld-video-player.light.min.css +1 -0
  12. package/dist/cld-video-player.light.min.js +2 -0
  13. package/dist/cld-video-player.light.min.js.LICENSE.txt +23 -0
  14. package/dist/cld-video-player.min.css +1 -0
  15. package/dist/cld-video-player.min.js +2 -0
  16. package/dist/cld-video-player.min.js.LICENSE.txt +26 -0
  17. package/dist/fonts/cloudinary_icon_for_black_bg.svg +69 -0
  18. package/dist/fonts/cloudinary_icon_for_white_bg.svg +69 -0
  19. package/docs/360.html +102 -0
  20. package/docs/_template.html +93 -0
  21. package/docs/adaptive-streaming.html +297 -0
  22. package/docs/analytics.html +140 -0
  23. package/docs/api.html +302 -0
  24. package/docs/audio.html +136 -0
  25. package/docs/autoplay-fallback.html +138 -0
  26. package/docs/autoplay-on-scroll.html +107 -0
  27. package/docs/codec-fallback.html +158 -0
  28. package/docs/colors.html +135 -0
  29. package/docs/components.html +284 -0
  30. package/docs/custom-cld-errors.html +134 -0
  31. package/docs/floating-player.html +98 -0
  32. package/docs/fluid.html +117 -0
  33. package/docs/force-hls-subtitles-ios.html +159 -0
  34. package/docs/index.html +83 -0
  35. package/docs/interaction-area.html +398 -0
  36. package/docs/live-customer.html +128 -0
  37. package/docs/multiple-players.html +125 -0
  38. package/docs/playlist-by-tag-cap.html +182 -0
  39. package/docs/playlist-by-tag.html +133 -0
  40. package/docs/playlist.html +133 -0
  41. package/docs/poster.html +155 -0
  42. package/docs/raw-url.html +104 -0
  43. package/docs/recommendations.html +155 -0
  44. package/docs/scripts.js +156 -0
  45. package/docs/seek-thumbs.html +90 -0
  46. package/docs/shoppable.html +335 -0
  47. package/docs/subtitles-and-captions.html +267 -0
  48. package/docs/transformations.html +171 -0
  49. package/docs/ui-config.html +108 -0
  50. package/docs/vast-vpaid.html +149 -0
  51. package/env.example.js +6 -0
  52. package/env.js +6 -0
  53. package/jest-puppeteer.config.js +14 -0
  54. package/jest.config.js +196 -0
  55. package/package.json +99 -0
  56. package/sandbox.config.json +3 -0
  57. package/setupJest.js +1 -0
  58. package/src/assets/fonts/VideoJS.svg +120 -0
  59. package/src/assets/fonts/VideoJS.ttf +0 -0
  60. package/src/assets/fonts/VideoJS.woff +0 -0
  61. package/src/assets/fonts/icons.json +120 -0
  62. package/src/assets/icons/cloudinary_icon_for_black_bg.svg +69 -0
  63. package/src/assets/icons/cloudinary_icon_for_white_bg.svg +69 -0
  64. package/src/assets/icons/cloudinary_logo_for_dark_bg.svg +188 -0
  65. package/src/assets/icons/cloudinary_logo_for_white_bg.svg +188 -0
  66. package/src/assets/icons/info-circle.svg +17 -0
  67. package/src/assets/styles/ads-label.scss +16 -0
  68. package/src/assets/styles/components/interaction-areas.scss +158 -0
  69. package/src/assets/styles/components/playlist.scss +213 -0
  70. package/src/assets/styles/components/themedButton.scss +48 -0
  71. package/src/assets/styles/components/thumbnail.scss +94 -0
  72. package/src/assets/styles/components/title-bar.scss +67 -0
  73. package/src/assets/styles/components/triangle-volume-bar.scss +52 -0
  74. package/src/assets/styles/icons.scss +257 -0
  75. package/src/assets/styles/main.scss +324 -0
  76. package/src/assets/styles/mixins/aspect-ratio.scss +16 -0
  77. package/src/assets/styles/mixins/disable-transition.scss +3 -0
  78. package/src/assets/styles/mixins/mixins.scss +5 -0
  79. package/src/assets/styles/mixins/skin.scss +64 -0
  80. package/src/assets/styles/variables.scss +2 -0
  81. package/src/assets/styles/videojs-ima.scss +252 -0
  82. package/src/components/component-utils.js +20 -0
  83. package/src/components/index.js +21 -0
  84. package/src/components/interaction-area/interaction-area.const.js +30 -0
  85. package/src/components/interaction-area/interaction-area.service.js +223 -0
  86. package/src/components/interaction-area/interaction-area.utils.js +236 -0
  87. package/src/components/jumpButtons/jump-10-minus.js +21 -0
  88. package/src/components/jumpButtons/jump-10-plus.js +20 -0
  89. package/src/components/logoButton/logo-button.const.js +3 -0
  90. package/src/components/logoButton/logo-button.js +30 -0
  91. package/src/components/logoButton/logo-button.scss +15 -0
  92. package/src/components/playlist/components/playlist-button.js +34 -0
  93. package/src/components/playlist/components/playlist-next-button.js +18 -0
  94. package/src/components/playlist/components/playlist-previous-button.js +18 -0
  95. package/src/components/playlist/components/playlist.js +5 -0
  96. package/src/components/playlist/components/playlist.scss +15 -0
  97. package/src/components/playlist/components/upcoming-video-overlay.js +149 -0
  98. package/src/components/playlist/components/upcoming-video-overlay.scss +86 -0
  99. package/src/components/playlist/layout/playlist-layout-custom.js +21 -0
  100. package/src/components/playlist/layout/playlist-layout-horizontal.js +16 -0
  101. package/src/components/playlist/layout/playlist-layout-vertical.js +19 -0
  102. package/src/components/playlist/layout/playlist-layout.js +110 -0
  103. package/src/components/playlist/panel/playlist-panel-item.js +86 -0
  104. package/src/components/playlist/panel/playlist-panel.js +92 -0
  105. package/src/components/playlist/playlist-widget.js +119 -0
  106. package/src/components/playlist/playlist.const.js +14 -0
  107. package/src/components/playlist/playlist.js +413 -0
  108. package/src/components/playlist/thumbnail/thumbnail.js +69 -0
  109. package/src/components/progress-control-events-blocker/progress-control-events-blocker.js +17 -0
  110. package/src/components/qualitySelector/quality-selector.scss +10 -0
  111. package/src/components/qualitySelector/qualitySelector.js +152 -0
  112. package/src/components/recommendations-overlay/index.js +3 -0
  113. package/src/components/recommendations-overlay/recommendations-overlay-content.js +57 -0
  114. package/src/components/recommendations-overlay/recommendations-overlay-hide-button.js +18 -0
  115. package/src/components/recommendations-overlay/recommendations-overlay-item.js +35 -0
  116. package/src/components/recommendations-overlay/recommendations-overlay-primary-item.js +81 -0
  117. package/src/components/recommendations-overlay/recommendations-overlay-secondary-item.js +48 -0
  118. package/src/components/recommendations-overlay/recommendations-overlay-secondary-items-container.js +35 -0
  119. package/src/components/recommendations-overlay/recommendations-overlay.js +94 -0
  120. package/src/components/recommendations-overlay/recommendations-overlay.scss +182 -0
  121. package/src/components/shoppable-bar/layout/bar-layout.js +111 -0
  122. package/src/components/shoppable-bar/layout/shoppable-panel-toggle.js +64 -0
  123. package/src/components/shoppable-bar/layout/shoppable-products-overlay.js +87 -0
  124. package/src/components/shoppable-bar/panel/shoppable-panel-item.js +105 -0
  125. package/src/components/shoppable-bar/panel/shoppable-panel.js +172 -0
  126. package/src/components/shoppable-bar/shoppable-post-widget.js +110 -0
  127. package/src/components/shoppable-bar/shoppable-widget.const.js +52 -0
  128. package/src/components/shoppable-bar/shoppable-widget.js +111 -0
  129. package/src/components/shoppable-bar/shoppable-widget.scss +359 -0
  130. package/src/components/themeButton/themedButton.const.js +3 -0
  131. package/src/components/themeButton/themedButton.js +25 -0
  132. package/src/components/title-bar/title-bar.js +79 -0
  133. package/src/config/defaults.js +25 -0
  134. package/src/extended-events.js +228 -0
  135. package/src/index.js +18 -0
  136. package/src/mixins/eventable.js +54 -0
  137. package/src/mixins/playlistable.js +106 -0
  138. package/src/plugins/analytics/index.js +245 -0
  139. package/src/plugins/autoplay-on-scroll/index.js +86 -0
  140. package/src/plugins/cloudinary/common.js +216 -0
  141. package/src/plugins/cloudinary/event-handler-registry.js +46 -0
  142. package/src/plugins/cloudinary/index.js +345 -0
  143. package/src/plugins/cloudinary/models/audio-source/audio-source.const.js +11 -0
  144. package/src/plugins/cloudinary/models/audio-source/audio-source.js +82 -0
  145. package/src/plugins/cloudinary/models/base-source.js +107 -0
  146. package/src/plugins/cloudinary/models/image-source.js +26 -0
  147. package/src/plugins/cloudinary/models/video-source/video-source.const.js +32 -0
  148. package/src/plugins/cloudinary/models/video-source/video-source.js +239 -0
  149. package/src/plugins/cloudinary/models/video-source/video-source.utils.js +57 -0
  150. package/src/plugins/colors/index.js +303 -0
  151. package/src/plugins/context-menu/components/context-menu-item.js +12 -0
  152. package/src/plugins/context-menu/components/context-menu.js +63 -0
  153. package/src/plugins/context-menu/context-menu.scss +30 -0
  154. package/src/plugins/context-menu/contextMenuContent.js +53 -0
  155. package/src/plugins/context-menu/index.js +134 -0
  156. package/src/plugins/dash/index.js +26 -0
  157. package/src/plugins/dash/setup-audio-tracks.js +112 -0
  158. package/src/plugins/dash/setup-text-tracks.js +195 -0
  159. package/src/plugins/dash/videojs-dash.js +372 -0
  160. package/src/plugins/floating-player/floating-player.scss +74 -0
  161. package/src/plugins/floating-player/index.js +129 -0
  162. package/src/plugins/ima/index.js +1775 -0
  163. package/src/plugins/index.js +31 -0
  164. package/src/plugins/interactive-plugin/index.js +10 -0
  165. package/src/plugins/videojs-http-source-selector/components/SourceMenuButton.js +98 -0
  166. package/src/plugins/videojs-http-source-selector/components/SourceMenuItem.js +52 -0
  167. package/src/plugins/videojs-http-source-selector/plugin.js +82 -0
  168. package/src/plugins/videojs-http-source-selector/plugin.scss +9 -0
  169. package/src/plugins/vtt-thumbnails/index.js +526 -0
  170. package/src/plugins/vtt-thumbnails/vtt-thumbnails.scss +29 -0
  171. package/src/utils/api.js +32 -0
  172. package/src/utils/apply-with-props.js +32 -0
  173. package/src/utils/array.js +22 -0
  174. package/src/utils/assign.js +27 -0
  175. package/src/utils/attributes-normalizer.js +72 -0
  176. package/src/utils/cloudinary.js +165 -0
  177. package/src/utils/css-prefix.js +43 -0
  178. package/src/utils/dom.js +74 -0
  179. package/src/utils/find.js +28 -0
  180. package/src/utils/fontFace.js +25 -0
  181. package/src/utils/groupBy.js +12 -0
  182. package/src/utils/index.js +29 -0
  183. package/src/utils/matches.js +11 -0
  184. package/src/utils/mixin.js +5 -0
  185. package/src/utils/object.js +26 -0
  186. package/src/utils/playButton.js +9 -0
  187. package/src/utils/positioning.js +78 -0
  188. package/src/utils/querystring.js +12 -0
  189. package/src/utils/slicing.js +21 -0
  190. package/src/utils/string.js +15 -0
  191. package/src/utils/throttle.js +30 -0
  192. package/src/utils/time.js +77 -0
  193. package/src/utils/type-inference.js +35 -0
  194. package/src/validators/validators-functions.js +48 -0
  195. package/src/validators/validators-types.js +78 -0
  196. package/src/validators/validators.js +110 -0
  197. package/src/video-player.const.js +68 -0
  198. package/src/video-player.js +761 -0
  199. package/src/video-player.utils.js +123 -0
  200. package/test/adaptive-streaming.test.js +38 -0
  201. package/test/ads.test.js +35 -0
  202. package/test/analytics.test.js +111 -0
  203. package/test/api.test.js +111 -0
  204. package/test/autoplay.scroll.test.js +23 -0
  205. package/test/basic-ui.test.js +59 -0
  206. package/test/colors.test.js +58 -0
  207. package/test/components.test.js +21 -0
  208. package/test/custom-error.test.js +24 -0
  209. package/test/fluid.test.js +36 -0
  210. package/test/isValidConfig.test.js +224 -0
  211. package/test/mocks/cloudinary-core-mock.js +0 -0
  212. package/test/mocks/styleMock.js +1 -0
  213. package/test/multiplayer.test.js +25 -0
  214. package/test/playlist.test.js +60 -0
  215. package/test/puppeteer/vp-env.js +19 -0
  216. package/test/recommendations.test.js +38 -0
  217. package/test/title-bar.test.js +28 -0
  218. package/test/ui-conf.test.js +49 -0
  219. package/test/unit/cloudinaryConfig.test.js +22 -0
  220. package/test/unit/cloudinaryUtils.test.js +53 -0
  221. package/test/unit/utils.test.js +27 -0
  222. package/test/unit/videoSource.test.js +454 -0
  223. package/tsconfig.json +15 -0
  224. package/types/video-player-tests.js +12 -0
  225. package/types/video-player-tests.ts +31 -0
  226. package/types/video-player.d.ts +570 -0
package/src/index.js ADDED
@@ -0,0 +1,18 @@
1
+ import 'assets/styles/main.scss';
2
+ import cloudinary from 'cloudinary-core';
3
+ import VideoPlayer from './video-player';
4
+ import { assign } from 'utils/assign';
5
+
6
+ cloudinary.VideoPlayer = VideoPlayer;
7
+
8
+ const proto = cloudinary.Cloudinary.prototype;
9
+
10
+ proto.videoPlayer = function(id, options = {}, ready = null) {
11
+ assign(options, { cloudinaryConfig: this });
12
+ return new VideoPlayer(id, options, ready);
13
+ };
14
+
15
+ proto.videoPlayers = function(selector, options = {}, ready = null) {
16
+ assign(options, { cloudinaryConfig: this });
17
+ return VideoPlayer.all(selector, options, ready);
18
+ };
@@ -0,0 +1,54 @@
1
+ const Eventable = (superclass) => class extends superclass {
2
+ constructor() {
3
+ super();
4
+
5
+ const eventable = { data: {}, handlers: {} };
6
+
7
+ this.on = (...args) => {
8
+ const lastIndex = args.length - 1;
9
+ const func = args[lastIndex];
10
+
11
+ eventable.handlers[func] = (event, ..._args) => {
12
+ event.Player = this;
13
+ func(event, ..._args);
14
+ };
15
+
16
+ args[lastIndex] = eventable.handlers[func];
17
+
18
+ return this.videojs.on(...args);
19
+ };
20
+
21
+ this.one = (...args) => {
22
+ const lastIndex = args.length - 1;
23
+ const func = args[lastIndex];
24
+
25
+ eventable.handlers[func] = (event, ..._args) => {
26
+ event.Player = this;
27
+ func(event, ..._args);
28
+ delete eventable.handlers[func];
29
+ };
30
+
31
+ args[lastIndex] = eventable.handlers[func];
32
+
33
+ return this.videojs.one(...args);
34
+ };
35
+
36
+ this.off = (...args) => {
37
+ const lastIndex = args.length - 1;
38
+ const func = args[lastIndex];
39
+
40
+ args[lastIndex] = eventable.handlers[func];
41
+
42
+ const res = this.videojs.off(...args);
43
+ delete eventable.handlers[func];
44
+
45
+ return res;
46
+ };
47
+
48
+ this.trigger = (...args) => {
49
+ this.videojs.trigger(...args);
50
+ };
51
+ }
52
+ };
53
+
54
+ export default Eventable;
@@ -0,0 +1,106 @@
1
+ import Playlist from 'components/playlist/playlist';
2
+ import Promise from 'promise-polyfill';
3
+ import fetchPF from 'fetch-ponyfill/build/fetch-browser';
4
+ import { sliceProperties } from 'utils/slicing';
5
+ import { normalizeJsonResponse } from 'utils/api';
6
+ import { assign } from 'utils/assign';
7
+
8
+ const { fetch } = fetchPF({ Promise });
9
+
10
+ const LIST_BY_TAG_PARAMS = { format: 'json', resource_type: 'video', type: 'list' };
11
+
12
+ const Playlistable = (superclass) => class extends superclass {
13
+ constructor(player, options = {}) {
14
+ super();
15
+
16
+ const _chainTarget = sliceProperties(options, 'chainTarget').chainTarget;
17
+ let _playlist = null;
18
+ let _playlistDisposer = null;
19
+
20
+ this.playlist = (sources, options = {}) => {
21
+ if (sources === undefined) {
22
+ return _playlist;
23
+ }
24
+
25
+ if (this.playlist()) {
26
+ this.disposePlaylist();
27
+ }
28
+
29
+ createPlaylist(sources, options);
30
+ player.trigger('playlistcreated');
31
+
32
+ return _chainTarget;
33
+ };
34
+
35
+ this.disposePlaylist = () => {
36
+ player.removeClass('vjs-playlist');
37
+ const playlist = this.playlist();
38
+ _playlist = undefined;
39
+ playlist.dispose();
40
+ this.off('cldsourcechanged', _playlistDisposer);
41
+ };
42
+
43
+ const createPlaylist = (sources, options) => {
44
+ if (sources instanceof Playlist) {
45
+ _playlist = sources;
46
+ _playlist.resetState();
47
+ _playlist.currentIndex(_playlist.currentIndex());
48
+ } else {
49
+ _playlist = new Playlist(this, sources, options);
50
+ _playlist.currentIndex(0);
51
+ }
52
+
53
+ _playlistDisposer = addSourceChangedListener();
54
+ player.addClass('vjs-playlist');
55
+ };
56
+
57
+ const addSourceChangedListener = () => {
58
+ const disposer = () => {
59
+ if (this.playlist() &&
60
+ !this.playlist().currentSource().contains(this.player.currentSource())) {
61
+ this.disposePlaylist();
62
+ }
63
+ };
64
+
65
+ this.on('cldsourcechanged', disposer);
66
+
67
+ return disposer;
68
+ };
69
+ }
70
+
71
+ playlistByTag(tag, options = {}) {
72
+ return this.sourcesByTag(tag, options)
73
+ .then((sources) => this.playlist(sources, options));
74
+ }
75
+
76
+ sourcesByTag(tag, options = {}) {
77
+ const url = this.cloudinaryConfig().url(tag, LIST_BY_TAG_PARAMS);
78
+
79
+ return fetch(url)
80
+ .then((result) => result.json())
81
+ .then((json) => {
82
+ const resources = normalizeJsonResponse(json.resources);
83
+
84
+ if (options.sorter) {
85
+ resources.sort(options.sorter);
86
+ }
87
+
88
+ const sources = resources.map((resource) => {
89
+ let sourceParams = options.sourceParams || {};
90
+
91
+ if (typeof sourceParams === 'function') {
92
+ sourceParams = sourceParams(resource);
93
+ }
94
+
95
+ const info = resource.context && resource.context.custom || {};
96
+
97
+ const source = assign({ info }, sourceParams, { publicId: resource.publicId });
98
+ return this.buildSource(source);
99
+ });
100
+
101
+ return sources;
102
+ });
103
+ }
104
+ };
105
+
106
+ export default Playlistable;
@@ -0,0 +1,245 @@
1
+ import videojs from 'video.js';
2
+ import { sliceProperties } from 'utils/slicing';
3
+ import { normalizeEventsParam, default as ExtendedEvents } from 'extended-events';
4
+
5
+ const DEFAULT_EVENTS = [
6
+ 'play',
7
+ 'pause',
8
+ 'ended',
9
+ 'volumechange',
10
+ 'resize',
11
+ 'error',
12
+ 'fullscreenchange',
13
+ 'start',
14
+ 'videoload',
15
+ 'percentsplayed',
16
+ 'seek',
17
+ 'playerload'
18
+ ];
19
+
20
+ const EVENT_DEFAULTS = {
21
+ percentsplayed: {
22
+ percents: [25, 50, 75, 100]
23
+ }
24
+ };
25
+
26
+ const DEFAULT_OPTIONS = {
27
+ events: DEFAULT_EVENTS,
28
+ category: 'Video',
29
+ defaultLabel: (player) =>
30
+ (player.cloudinary && player.cloudinary.currentPublicId()) || player.currentSource().src
31
+ };
32
+
33
+ class AnalyticsPlugin {
34
+
35
+ constructor(player, initOptions = {}) {
36
+ this.player = player;
37
+ this.options = videojs.mergeOptions(DEFAULT_OPTIONS, initOptions);
38
+ this.events = normalizeEventsParam(this.options.events, EVENT_DEFAULTS);
39
+
40
+ const extendedEvents = sliceProperties(this.events, 'percentsplayed', 'timeplayed', 'pause', 'seek');
41
+
42
+ if (extendedEvents.pause) {
43
+ delete extendedEvents.pause;
44
+ extendedEvents.pausenoseek = {};
45
+ }
46
+
47
+ this._extendedEvents = new ExtendedEvents(player, { events: extendedEvents });
48
+
49
+ this._currentSource = null;
50
+ this._startTracked = null;
51
+ this._endTracked = null;
52
+
53
+ this.resetState();
54
+ }
55
+
56
+ init() {
57
+ const playerLoad = () => {
58
+ this.track({ action: 'Player Load', label: window.location.href, nonInteraction: true });
59
+ };
60
+
61
+ const play = () => {
62
+ this.track({ action: 'Play' });
63
+ };
64
+
65
+ const start = () => {
66
+ if (this._startTracked) {
67
+ this.track({ action: 'Start' });
68
+ this._startTracked = true;
69
+ }
70
+ };
71
+
72
+ const pause = () => {
73
+ this.track({ action: 'Pause' });
74
+ };
75
+
76
+ const ended = () => {
77
+ if (!this._endTracked) {
78
+ this.track({ action: 'Ended', nonInteraction: true });
79
+ this._endTracked = true;
80
+ }
81
+ };
82
+
83
+ const error = () => {
84
+ this.track({ action: 'Error', nonInteraction: true });
85
+ };
86
+
87
+ const volumechange = () => {
88
+ const value = this.player.muted() ? 0 : this.player.volume();
89
+ this.track({ action: 'Volume Change', value });
90
+ };
91
+
92
+ const resize = () => {
93
+ const action = `Resize - ${this.player.width()}x${this.player.height()}}`;
94
+ this.track({ action });
95
+ };
96
+
97
+ const fullscreenchange = () => {
98
+ const action = this.player.isFullscreen() ? 'Enter Fullscreen' : 'Exit Fullscreen';
99
+ this.track({ action });
100
+ };
101
+
102
+ const percentsPlayed = (event, data) => {
103
+ const { percent } = data;
104
+ this.track({ action: `${percent} Percents Played`, nonInteraction: true });
105
+ };
106
+
107
+ const timePlayed = (event, data) => {
108
+ const { time } = data;
109
+ this.track({ action: `${time} Seconds Played`, value: time, nonInteraction: true });
110
+ };
111
+
112
+ const seek = (event, data) => {
113
+ const { seekStart, seekEnd } = data;
114
+ this.track({ action: 'Seek Start', value: seekStart });
115
+ this.track({ action: 'Seek End', value: seekEnd });
116
+ };
117
+
118
+ const shoppableProductHover = (event, data) => {
119
+ this.track({ action: 'productHover', label: data.productName });
120
+ };
121
+
122
+ const shoppableProductClick = (event, data) => {
123
+ this.track({ action: 'productClick', label: data.productName });
124
+ };
125
+
126
+ const shoppableBarMax = () => {
127
+ this.track({ action: 'shoppableBar', label: 'opened' });
128
+ };
129
+
130
+ const shoppableBarMin = () => {
131
+ this.track({ action: 'shoppableBar', label: 'closed' });
132
+ };
133
+
134
+ const shoppableReplay = () => {
135
+ this.track({ action: 'replay' });
136
+ };
137
+
138
+ const shoppableProductClickPost = (event, data) => {
139
+ this.track({ action: 'productClickPostPlay', label: data.productName });
140
+ };
141
+ const shoppableProductHoverPost = (event, data) => {
142
+ this.track({ action: 'productHoverPostPlay', label: data.productName });
143
+ };
144
+
145
+ if (this.events.shoppable) {
146
+ this.player.on('productHover', shoppableProductHover.bind(this));
147
+ this.player.on('productClick', shoppableProductClick.bind(this));
148
+ this.player.on('productHoverPost', shoppableProductHoverPost.bind(this));
149
+ this.player.on('productClickPost', shoppableProductClickPost.bind(this));
150
+ this.player.on('productBarMin', shoppableBarMin.bind(this));
151
+ this.player.on('productBarMax', shoppableBarMax.bind(this));
152
+ this.player.on('replay', shoppableReplay.bind(this));
153
+ }
154
+
155
+ if (this.events.play) {
156
+ this.player.on('play', play.bind(this));
157
+ }
158
+
159
+ if (this.events.ended) {
160
+ this.player.on('ended', ended.bind(this));
161
+ }
162
+
163
+ if (this.events.volumechange) {
164
+ this.player.on('volumechange', volumechange.bind(this));
165
+ }
166
+
167
+ if (this.events.resize) {
168
+ this.player.on('resize', resize.bind(this));
169
+ }
170
+
171
+ if (this.events.error) {
172
+ this.player.on('error', error.bind(this));
173
+ }
174
+
175
+ if (this.events.start) {
176
+ this.player.on('playing', start.bind(this));
177
+ }
178
+
179
+ if (this.events.fullscreenchange) {
180
+ this.player.on('fullscreenchange', fullscreenchange.bind(this));
181
+ }
182
+
183
+ if (this.events.percentsplayed) {
184
+ this._extendedEvents.on('percentsplayed', percentsPlayed.bind(this));
185
+ }
186
+
187
+ if (this.events.timeplayed) {
188
+ this._extendedEvents.on('timeplayed', timePlayed.bind(this));
189
+ }
190
+
191
+ if (this.events.pause) {
192
+ this._extendedEvents.on('pausenoseek', pause.bind(this));
193
+ }
194
+
195
+ if (this.events.seek) {
196
+ this._extendedEvents.on('seek', seek.bind(this));
197
+ }
198
+
199
+ if (this.events.playerload) {
200
+ playerLoad();
201
+ }
202
+
203
+ this.player.on('loadedmetadata', this.loadedmetadata.bind(this));
204
+ }
205
+
206
+ track({ action, label, value = null, nonInteraction = false }) {
207
+ const eventData = {
208
+ eventCategory: this.options.category,
209
+ eventAction: action,
210
+ eventLabel: label || this.options.defaultLabel(this.player),
211
+ eventValue: value || Math.round(this.player.currentTime()),
212
+ nonInteraction: nonInteraction
213
+ };
214
+
215
+ window.ga('send', 'event', eventData);
216
+ }
217
+
218
+ videoload() {
219
+ this.track({ action: 'Video Load', nonInteraction: true });
220
+ }
221
+
222
+ resetState() {
223
+ this._currentSource = '';
224
+ this._startTracked = false;
225
+ this._endTracked = false;
226
+ }
227
+
228
+ loadedmetadata() {
229
+ const src = this.player.currentSource().src;
230
+
231
+ if (src !== this._currentSource) {
232
+ this.resetState();
233
+ this._currentSource = src;
234
+
235
+ if (this.events.videoload) {
236
+ this.videoload();
237
+ }
238
+ }
239
+ }
240
+
241
+ }
242
+
243
+ export default function(opts = {}) {
244
+ new AnalyticsPlugin(this, opts).init();
245
+ }
@@ -0,0 +1,86 @@
1
+ import { isElementInViewport } from 'utils/positioning';
2
+ import { sliceProperties } from 'utils/slicing';
3
+ import { assign } from 'utils/assign';
4
+
5
+ const defaults = {
6
+ fraction: 0.5,
7
+ isMuted: true
8
+ };
9
+
10
+ class AutoplayOnScrollPlugin {
11
+ constructor(player, opts = {}) {
12
+ opts = assign({}, defaults, opts);
13
+
14
+ this.player = player;
15
+ let _options = sliceProperties(opts, 'fraction');
16
+ let _pausedByScroll = false;
17
+ let _playedByScroll = false;
18
+ let _pauseHandler = null;
19
+ let _playHandler = null;
20
+
21
+ this.init = () => {
22
+ registerEventHandlers();
23
+ checkViewportState();
24
+ };
25
+
26
+ const clearEventHandlers = () => {
27
+ window.removeEventListener('DOMContentLoaded', checkViewportState, false);
28
+ window.removeEventListener('load', checkViewportState, false);
29
+ window.removeEventListener('scroll', checkViewportState, false);
30
+ window.removeEventListener('resize', checkViewportState, false);
31
+ this.player.off('pause', _pauseHandler);
32
+ this.player.off('play', _playHandler);
33
+ };
34
+
35
+ const pause = () => {
36
+ _pausedByScroll = true;
37
+ _playedByScroll = false;
38
+ this.player.pause();
39
+ };
40
+
41
+ const play = () => {
42
+ _pausedByScroll = false;
43
+ _playedByScroll = true;
44
+ this.player.play();
45
+ };
46
+
47
+ const checkViewportState = () => {
48
+ const visible = isElementInViewport(this.player.el(), { fraction: _options.fraction });
49
+
50
+ if (visible) {
51
+ if (this.player.paused()) {
52
+ play();
53
+ }
54
+ } else if (!this.player.paused() && !this.player.activePlugins_.floatingPlayer) {
55
+ pause();
56
+ }
57
+ };
58
+
59
+ const registerEventHandlers = () => {
60
+ // TODO: find a better replacement for 'pause' since it's being triggered
61
+ // by 'buffering' as well.
62
+ _pauseHandler = () => {
63
+ if (!this.player.waiting && !_pausedByScroll) {
64
+ clearEventHandlers();
65
+ }
66
+ };
67
+
68
+ _playHandler = () => {
69
+ if (!_playedByScroll) {
70
+ clearEventHandlers();
71
+ }
72
+ };
73
+
74
+ window.addEventListener('DOMContentLoaded', checkViewportState, false);
75
+ window.addEventListener('load', checkViewportState, false);
76
+ window.addEventListener('scroll', checkViewportState, false);
77
+ window.addEventListener('resize', checkViewportState, false);
78
+ this.player.on('pause', _pauseHandler);
79
+ this.player.on('play', _playHandler);
80
+ };
81
+ }
82
+ }
83
+
84
+ export default function(opts = {}) {
85
+ new AutoplayOnScrollPlugin(this, opts).init();
86
+ }