@gcorevideo/player 0.0.1

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 (192) hide show
  1. package/assets/icons/new/arrow-left.svg +5 -0
  2. package/assets/icons/new/arrow-right.svg +5 -0
  3. package/assets/icons/new/check.svg +5 -0
  4. package/assets/icons/new/close.svg +12 -0
  5. package/assets/icons/new/full.svg +8 -0
  6. package/assets/icons/new/fullscreen-off.svg +14 -0
  7. package/assets/icons/new/fullscreen-on.svg +14 -0
  8. package/assets/icons/new/gear-hd.svg +16 -0
  9. package/assets/icons/new/gear.svg +12 -0
  10. package/assets/icons/new/hd.svg +8 -0
  11. package/assets/icons/new/pause.svg +5 -0
  12. package/assets/icons/new/pip.svg +5 -0
  13. package/assets/icons/new/play.svg +10 -0
  14. package/assets/icons/new/replayleft.svg +5 -0
  15. package/assets/icons/new/replayright.svg +5 -0
  16. package/assets/icons/new/speed.svg +5 -0
  17. package/assets/icons/new/stats.svg +3 -0
  18. package/assets/icons/new/stop.svg +3 -0
  19. package/assets/icons/new/subtitles-off.svg +5 -0
  20. package/assets/icons/new/subtitles-on.svg +6 -0
  21. package/assets/icons/new/volume-max.svg +5 -0
  22. package/assets/icons/new/volume-min.svg +5 -0
  23. package/assets/icons/new/volume-off.svg +5 -0
  24. package/assets/icons/old/cardboard.svg +4 -0
  25. package/assets/icons/old/close-share.svg +13 -0
  26. package/assets/icons/old/close.svg +13 -0
  27. package/assets/icons/old/fb.svg +13 -0
  28. package/assets/icons/old/fullscreen.svg +12 -0
  29. package/assets/icons/old/language.svg +1 -0
  30. package/assets/icons/old/pause.svg +12 -0
  31. package/assets/icons/old/play.svg +12 -0
  32. package/assets/icons/old/quality-arrow.svg +13 -0
  33. package/assets/icons/old/reload.svg +4 -0
  34. package/assets/icons/old/share.svg +13 -0
  35. package/assets/icons/old/sound-off.svg +15 -0
  36. package/assets/icons/old/sound-on.svg +15 -0
  37. package/assets/icons/old/streams.svg +3 -0
  38. package/assets/icons/old/twitter.svg +13 -0
  39. package/assets/icons/old/wn.svg +15 -0
  40. package/assets/icons/standard/01-play.svg +3 -0
  41. package/assets/icons/standard/02-pause.svg +3 -0
  42. package/assets/icons/standard/03-stop.svg +3 -0
  43. package/assets/icons/standard/04-volume.svg +3 -0
  44. package/assets/icons/standard/05-mute.svg +3 -0
  45. package/assets/icons/standard/06-expand.svg +3 -0
  46. package/assets/icons/standard/07-shrink.svg +3 -0
  47. package/assets/icons/standard/08-hd.svg +3 -0
  48. package/assets/icons/standard/09-cc.svg +8 -0
  49. package/assets/icons/standard/10-reload.svg +4 -0
  50. package/assets/style/main.scss +50 -0
  51. package/assets/style/theme.scss +42 -0
  52. package/assets/style/variables.scss +7 -0
  53. package/dist/DashPlayback-6wKK0_pL.js +666 -0
  54. package/dist/DashPlayback-8U6_s4Jc.js +666 -0
  55. package/dist/DashPlayback-BeZz7mN9.js +663 -0
  56. package/dist/DashPlayback-CRdja67F.js +667 -0
  57. package/dist/DashPlayback-D0df6zGg.js +663 -0
  58. package/dist/DashPlayback-D7egS-CZ.js +664 -0
  59. package/dist/DashPlayback-DH5lZMRR.js +663 -0
  60. package/dist/DashPlayback-DZfIc9sK.js +665 -0
  61. package/dist/DashPlayback-VhCxbQhn.js +666 -0
  62. package/dist/HlsPlayback-Avwy8-0O.js +749 -0
  63. package/dist/index.css +125 -0
  64. package/dist/index.js +467 -0
  65. package/lib/Player.d.ts +50 -0
  66. package/lib/Player.d.ts.map +1 -0
  67. package/lib/Player.js +310 -0
  68. package/lib/backend.d.ts +3 -0
  69. package/lib/backend.d.ts.map +1 -0
  70. package/lib/backend.js +10 -0
  71. package/lib/constants.d.ts +19 -0
  72. package/lib/constants.d.ts.map +1 -0
  73. package/lib/constants.js +18 -0
  74. package/lib/index.d.ts +10 -0
  75. package/lib/index.d.ts.map +1 -0
  76. package/lib/index.js +9 -0
  77. package/lib/internal.types.d.ts +105 -0
  78. package/lib/internal.types.d.ts.map +1 -0
  79. package/lib/internal.types.js +1 -0
  80. package/lib/playback.types.d.ts +13 -0
  81. package/lib/playback.types.d.ts.map +1 -0
  82. package/lib/playback.types.js +1 -0
  83. package/lib/plugins/audio-selector/AudioSelector.d.ts +48 -0
  84. package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -0
  85. package/lib/plugins/audio-selector/AudioSelector.js +282 -0
  86. package/lib/plugins/big-mute-button/BigMuteButton.d.ts +33 -0
  87. package/lib/plugins/big-mute-button/BigMuteButton.d.ts.map +1 -0
  88. package/lib/plugins/big-mute-button/BigMuteButton.js +148 -0
  89. package/lib/plugins/bottom-gear/BottomGear.d.ts +30 -0
  90. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -0
  91. package/lib/plugins/bottom-gear/BottomGear.js +103 -0
  92. package/lib/plugins/click-to-pause/ClickToPause.d.ts +16 -0
  93. package/lib/plugins/click-to-pause/ClickToPause.d.ts.map +1 -0
  94. package/lib/plugins/click-to-pause/ClickToPause.js +73 -0
  95. package/lib/plugins/dash-playback/DashPlayback.d.ts +81 -0
  96. package/lib/plugins/dash-playback/DashPlayback.d.ts.map +1 -0
  97. package/lib/plugins/dash-playback/DashPlayback.js +658 -0
  98. package/lib/plugins/dash-plugin/DashPlayback.d.ts +86 -0
  99. package/lib/plugins/dash-plugin/DashPlayback.d.ts.map +1 -0
  100. package/lib/plugins/dash-plugin/DashPlayback.js +659 -0
  101. package/lib/plugins/disable-controls/DisableControls.d.ts +15 -0
  102. package/lib/plugins/disable-controls/DisableControls.d.ts.map +1 -0
  103. package/lib/plugins/disable-controls/DisableControls.js +69 -0
  104. package/lib/plugins/dvr-controls/DVRControls.d.ts +27 -0
  105. package/lib/plugins/dvr-controls/DVRControls.d.ts.map +1 -0
  106. package/lib/plugins/dvr-controls/DVRControls.js +110 -0
  107. package/lib/plugins/hls-playback/HlsPlayback.d.ts +102 -0
  108. package/lib/plugins/hls-playback/HlsPlayback.d.ts.map +1 -0
  109. package/lib/plugins/hls-playback/HlsPlayback.js +747 -0
  110. package/lib/plugins/level-selector/LevelSelector.d.ts +48 -0
  111. package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -0
  112. package/lib/plugins/level-selector/LevelSelector.js +287 -0
  113. package/lib/plugins/media-control/MediaControl.d.ts +186 -0
  114. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -0
  115. package/lib/plugins/media-control/MediaControl.js +1000 -0
  116. package/lib/plugins/poster/Poster.d.ts +41 -0
  117. package/lib/plugins/poster/Poster.d.ts.map +1 -0
  118. package/lib/plugins/poster/Poster.js +186 -0
  119. package/lib/trace/LogTracer.d.ts +12 -0
  120. package/lib/trace/LogTracer.d.ts.map +1 -0
  121. package/lib/trace/LogTracer.js +17 -0
  122. package/lib/trace/SentryTracer.d.ts +11 -0
  123. package/lib/trace/SentryTracer.d.ts.map +1 -0
  124. package/lib/trace/SentryTracer.js +18 -0
  125. package/lib/trace/Tracer.d.ts +13 -0
  126. package/lib/trace/Tracer.d.ts.map +1 -0
  127. package/lib/trace/Tracer.js +15 -0
  128. package/lib/trace/index.d.ts +18 -0
  129. package/lib/trace/index.d.ts.map +1 -0
  130. package/lib/trace/index.js +27 -0
  131. package/lib/trace/types.d.ts +8 -0
  132. package/lib/trace/types.d.ts.map +1 -0
  133. package/lib/trace/types.js +1 -0
  134. package/lib/types.d.ts +82 -0
  135. package/lib/types.d.ts.map +1 -0
  136. package/lib/types.js +1 -0
  137. package/lib/utils/Logger.d.ts +23 -0
  138. package/lib/utils/Logger.d.ts.map +1 -0
  139. package/lib/utils/Logger.js +81 -0
  140. package/lib/utils/canAutoplay.d.ts +6 -0
  141. package/lib/utils/canAutoplay.d.ts.map +1 -0
  142. package/lib/utils/canAutoplay.js +30 -0
  143. package/lib/utils/errors.d.ts +2 -0
  144. package/lib/utils/errors.d.ts.map +1 -0
  145. package/lib/utils/errors.js +6 -0
  146. package/lib/utils/queryParams.d.ts +2 -0
  147. package/lib/utils/queryParams.d.ts.map +1 -0
  148. package/lib/utils/queryParams.js +4 -0
  149. package/lib/utils/scripts-load.d.ts +2 -0
  150. package/lib/utils/scripts-load.d.ts.map +1 -0
  151. package/lib/utils/scripts-load.js +20 -0
  152. package/lib/utils/types.d.ts +4 -0
  153. package/lib/utils/types.d.ts.map +1 -0
  154. package/lib/utils/types.js +1 -0
  155. package/lib/utils/utils.d.ts +7 -0
  156. package/lib/utils/utils.d.ts.map +1 -0
  157. package/lib/utils/utils.js +57 -0
  158. package/package.json +57 -0
  159. package/rollup.config.js +34 -0
  160. package/src/Player.ts +390 -0
  161. package/src/backend.ts +12 -0
  162. package/src/constants.ts +17 -0
  163. package/src/index.ts +9 -0
  164. package/src/internal.types.ts +126 -0
  165. package/src/playback.types.ts +15 -0
  166. package/src/plugins/dash-playback/DashPlayback.ts +808 -0
  167. package/src/plugins/dash-playback/_DashPlayback.js +688 -0
  168. package/src/plugins/hls-playback/HlsPlayback.ts +909 -0
  169. package/src/plugins/hls-playback/hls.js +706 -0
  170. package/src/trace/LogTracer.ts +23 -0
  171. package/src/trace/SentryTracer.ts +18 -0
  172. package/src/trace/Tracer.ts +27 -0
  173. package/src/trace/index.ts +32 -0
  174. package/src/trace/types.ts +7 -0
  175. package/src/types.ts +100 -0
  176. package/src/typings/@clappr/core/error_mixin.d.ts +15 -0
  177. package/src/typings/@clappr/core/events.d.ts +7 -0
  178. package/src/typings/@clappr/core/html5_video.d.ts +28 -0
  179. package/src/typings/@clappr/core/playback.d.ts +5 -0
  180. package/src/typings/@clappr/core/player.d.ts +83 -0
  181. package/src/typings/@clappr/plugins.d.ts +29 -0
  182. package/src/typings/clappr-zepto.xd.xts +44 -0
  183. package/src/typings/globals.d.ts +8 -0
  184. package/src/utils/Logger.ts +107 -0
  185. package/src/utils/canAutoplay.ts +39 -0
  186. package/src/utils/errors.ts +6 -0
  187. package/src/utils/queryParams.ts +5 -0
  188. package/src/utils/scripts-load.ts +26 -0
  189. package/src/utils/types.ts +5 -0
  190. package/src/utils/utils.ts +64 -0
  191. package/tsconfig.json +43 -0
  192. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,1000 @@
1
+ // Copyright 2014 Globo.com Player authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+ /**
5
+ * The MediaControl is responsible for displaying the Player controls.
6
+ */
7
+ import assert from 'assert';
8
+ import { Events, UICorePlugin, Browser, Playback, Utils, template, $, } from '@clappr/core';
9
+ import { reportError, trace } from '../../trace/index.js';
10
+ import '../../../assets/plugins/media-control/media-control.scss';
11
+ import '../../../assets/plugins/media-control/plugins.scss';
12
+ import Kibo from 'kibo';
13
+ import { isFullscreen } from '../../utils/utils.js';
14
+ import mediaControlHTML from '../../../assets/plugins/media-control/media-control.ejs';
15
+ import playIcon from '../../../assets/icons/new/play.svg';
16
+ import pauseIcon from '../../../assets/icons/new/pause.svg';
17
+ import stopIcon from '../../../assets/icons/new/stop.svg';
18
+ import volumeMaxIcon from '../../../assets/icons/new/volume-max.svg';
19
+ import volumeOffIcon from '../../../assets/icons/new/volume-off.svg';
20
+ import fullscreenOffIcon from '../../../assets/icons/new/fullscreen-off.svg';
21
+ import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg';
22
+ assert(process.env.CLAPPR_VERSION, 'CLAPPR_VERSION is required');
23
+ const CLAPPR_VERSION = process.env.CLAPPR_VERSION;
24
+ const T = 'plugins.media_control';
25
+ const { Config, Fullscreen, formatTime, extend, removeArrayItem } = Utils;
26
+ function orderByOrderPattern(arr, order) {
27
+ const arrWithoutDuplicates = [...new Set(arr)];
28
+ const ordered = order.filter(item => arrWithoutDuplicates.includes(item));
29
+ const rest = arrWithoutDuplicates.filter(item => !order.includes(item));
30
+ return [...ordered, ...rest];
31
+ }
32
+ export default class MediaControl extends UICorePlugin {
33
+ advertisementPlaying = false;
34
+ buttonsColor = null;
35
+ currentDurationValue = 0;
36
+ currentPositionValue = 0;
37
+ currentSeekBarPercentage = null;
38
+ disabledClickableList = [];
39
+ displayedDuration = null;
40
+ displayedPosition = null;
41
+ displayedSeekBarPercentage = null;
42
+ draggingSeekBar = false;
43
+ draggingVolumeBar = false;
44
+ fullScreenOnVideoTagSupported = null;
45
+ hideId = null;
46
+ hideVolumeId = null;
47
+ intendedVolume = 100;
48
+ isHD = false;
49
+ keepVisible = false;
50
+ kibo;
51
+ lastMouseX = 0;
52
+ lastMouseY = 0;
53
+ persistConfig;
54
+ rendered = false;
55
+ settings = {};
56
+ svgMask = null;
57
+ userDisabled = false;
58
+ userKeepVisible = false;
59
+ verticalVolume = false;
60
+ $audioTracksSelector = null;
61
+ $bottomGear = null;
62
+ $clipText = null;
63
+ $clipTextContainer = null;
64
+ $duration = null;
65
+ $fullscreenToggle = null;
66
+ $multiCameraSelector = null;
67
+ $pip = null;
68
+ $playPauseToggle = null;
69
+ $playStopToggle = null;
70
+ $playbackRate = null;
71
+ $position = null;
72
+ $seekBarContainer = null;
73
+ $seekBarHover = null;
74
+ $seekBarLoaded = null;
75
+ $seekBarPosition = null;
76
+ $seekBarScrubber = null;
77
+ $subtitlesSelector = null;
78
+ $volumeBarContainer = null;
79
+ $volumeBarBackground = null;
80
+ $volumeBarFill = null;
81
+ $volumeBarScrubber = null;
82
+ $volumeContainer = null;
83
+ $volumeIcon = null;
84
+ get name() {
85
+ return 'media_control';
86
+ }
87
+ get supportedVersion() {
88
+ return { min: CLAPPR_VERSION };
89
+ }
90
+ get disabled() {
91
+ const playbackIsNOOP = this.container && this.container.getPlaybackType() === Playback.NO_OP;
92
+ return this.userDisabled || playbackIsNOOP;
93
+ }
94
+ get container() {
95
+ return this.core && this.core.activeContainer;
96
+ }
97
+ get playback() {
98
+ return this.core && this.core.activePlayback;
99
+ }
100
+ get attributes() {
101
+ return {
102
+ 'class': 'media-control-skin-1',
103
+ 'data-media-control-skin-1': ''
104
+ };
105
+ }
106
+ get events() {
107
+ return {
108
+ 'click [data-play]': 'play',
109
+ 'click [data-pause]': 'pause',
110
+ 'click [data-playpause]': 'togglePlayPause',
111
+ 'click [data-stop]': 'stop',
112
+ 'click [data-playstop]': 'togglePlayStop',
113
+ 'click [data-fullscreen]': 'handleFullScreenOnBtn',
114
+ 'click .bar-container[data-seekbar]': 'seek',
115
+ 'click .bar-container[data-volume]': 'onVolumeClick',
116
+ 'click .drawer-icon[data-volume]': 'toggleMute',
117
+ 'mouseenter .drawer-container[data-volume]': 'showVolumeBar',
118
+ 'mouseleave .drawer-container[data-volume]': 'hideVolumeBar',
119
+ 'mousedown .bar-container[data-volume]': 'startVolumeDrag',
120
+ 'touchstart .bar-container[data-volume]': 'startVolumeDrag',
121
+ 'mousemove .bar-container[data-volume]': 'mousemoveOnVolumeBar',
122
+ 'touchmove .bar-container[data-volume]': 'mousemoveOnVolumeBar',
123
+ 'mousedown .bar-scrubber[data-seekbar]': 'startSeekDrag',
124
+ 'mousedown .bar-container[data-seekbar]': 'startSeekDrag',
125
+ 'touchstart .bar-scrubber[data-seekbar]': 'startSeekDrag',
126
+ 'touchstart .bar-container[data-seekbar]': 'startSeekDrag',
127
+ 'mousemove .bar-container[data-seekbar]': 'mousemoveOnSeekBar',
128
+ 'touchmove .bar-container[data-seekbar]': 'mousemoveOnSeekBar',
129
+ 'mouseleave .bar-container[data-seekbar]': 'mouseleaveOnSeekBar',
130
+ 'touchend .bar-container[data-seekbar]': 'mouseleaveOnSeekBar',
131
+ 'mouseenter .media-control-layer[data-controls]': 'setUserKeepVisible',
132
+ 'mouseleave .media-control-layer[data-controls]': 'resetUserKeepVisible'
133
+ };
134
+ }
135
+ get template() {
136
+ return template(mediaControlHTML);
137
+ }
138
+ get volume() {
139
+ return (this.container && this.container.isReady) ? this.container.volume : this.intendedVolume;
140
+ }
141
+ get muted() {
142
+ return this.volume === 0;
143
+ }
144
+ constructor(core) {
145
+ super(core);
146
+ this.persistConfig = this.options.persistConfig;
147
+ this.setInitialVolume();
148
+ this.kibo = new Kibo(this.options.focusElement);
149
+ this.bindKeyEvents();
150
+ this.userDisabled = false;
151
+ if ((this.container && this.container.mediaControlDisabled) || this.options.chromeless) {
152
+ this.disable();
153
+ }
154
+ $(document).bind('mouseup', this.stopDrag);
155
+ $(document).bind('mousemove', this.updateDrag);
156
+ $(document).bind('touchend', this.stopDrag);
157
+ $(document).bind('touchmove', this.updateDrag);
158
+ }
159
+ getExternalInterface() {
160
+ return {
161
+ setVolume: this.setVolume,
162
+ getVolume: () => this.volume,
163
+ };
164
+ }
165
+ bindEvents() {
166
+ // @ts-ignore
167
+ this.stopListening();
168
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
169
+ this.listenTo(this.core, Events.CORE_MOUSE_MOVE, this.show);
170
+ this.listenTo(this.core, Events.CORE_MOUSE_LEAVE, () => this.hide(this.options.hideMediaControlDelay));
171
+ this.listenTo(this.core, Events.CORE_FULLSCREEN, this.show);
172
+ this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.configure);
173
+ this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
174
+ this.bindContainerEvents();
175
+ this.listenTo(this.core, 'core:advertisement:start', this.onStartAd);
176
+ this.listenTo(this.core, 'core:advertisement:finish', this.onFinishAd);
177
+ // const has360 = this.core?.getPlugin('video_360');
178
+ // if (Browser.isiOS && has360) {
179
+ // this.container?.el.addEventListener('click', e => {
180
+ // e.preventDefault();
181
+ // e.stopPropagation();
182
+ // // feature detect
183
+ // if (typeof DeviceMotionEvent.requestPermission === 'function') {
184
+ // DeviceMotionEvent.requestPermission()
185
+ // .then(permissionState => {
186
+ // if (permissionState === 'granted') {
187
+ // console.warn('Permission granted');
188
+ // }
189
+ // })
190
+ // .catch(console.error);
191
+ // } else {
192
+ // // handle regular non iOS 13+ devices
193
+ // }
194
+ // });
195
+ // }
196
+ }
197
+ bindContainerEvents() {
198
+ if (!this.container) {
199
+ return;
200
+ }
201
+ this.listenTo(this.container, Events.CONTAINER_PLAY, this.changeTogglePlay);
202
+ this.listenTo(this.container, Events.CONTAINER_PAUSE, this.changeTogglePlay);
203
+ this.listenTo(this.container, Events.CONTAINER_STOP, this.changeTogglePlay);
204
+ this.listenTo(this.container, Events.CONTAINER_DBLCLICK, this.toggleFullscreen);
205
+ this.listenTo(this.container, Events.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
206
+ this.listenTo(this.container, Events.CONTAINER_PROGRESS, this.updateProgressBar);
207
+ this.listenTo(this.container, Events.CONTAINER_SETTINGSUPDATE, this.settingsUpdate);
208
+ this.listenTo(this.container, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.settingsUpdate);
209
+ this.listenTo(this.container, Events.CONTAINER_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
210
+ this.listenTo(this.container, Events.CONTAINER_MEDIACONTROL_DISABLE, this.disable);
211
+ this.listenTo(this.container, Events.CONTAINER_MEDIACONTROL_ENABLE, this.enable);
212
+ this.listenTo(this.container, Events.CONTAINER_ENDED, this.ended);
213
+ this.listenTo(this.container, Events.CONTAINER_VOLUME, this.onVolumeChanged);
214
+ this.listenTo(this.container, Events.CONTAINER_OPTIONS_CHANGE, this.setInitialVolume);
215
+ if (this.container.playback.el.nodeName.toLowerCase() === 'video') {
216
+ // wait until the metadata has loaded and then check if fullscreen on video tag is supported
217
+ this.listenToOnce(this.container, Events.CONTAINER_LOADEDMETADATA, this.onLoadedMetadataOnVideoTag);
218
+ }
219
+ }
220
+ disable() {
221
+ this.userDisabled = true;
222
+ this.hide();
223
+ this.unbindKeyEvents();
224
+ this.$el.hide();
225
+ }
226
+ enable() {
227
+ trace(`${T} enable`, {
228
+ userDisabled: this.userDisabled,
229
+ chromeless: this.options.chromeless,
230
+ });
231
+ if (this.options.chromeless) {
232
+ return;
233
+ }
234
+ this.userDisabled = false;
235
+ this.bindKeyEvents();
236
+ this.show();
237
+ }
238
+ play() {
239
+ trace(`${T} play`);
240
+ this.container && this.container.play();
241
+ }
242
+ pause() {
243
+ trace(`${T} pause`);
244
+ this.container && this.container.pause();
245
+ }
246
+ stop() {
247
+ trace(`${T} stop`);
248
+ this.container && this.container.stop();
249
+ }
250
+ setInitialVolume() {
251
+ const initialVolume = (this.persistConfig) ? Config.restore('volume') : 100;
252
+ const options = this.container && this.container.options || this.options;
253
+ this.setVolume(options.mute ? 0 : initialVolume, true);
254
+ }
255
+ onVolumeChanged() {
256
+ this.updateVolumeUI();
257
+ }
258
+ onLoadedMetadataOnVideoTag(event) {
259
+ const video = this.playback && this.playback.el;
260
+ trace(`${T} onLoadedMetadataOnVideoTag`, { event });
261
+ // video.webkitSupportsFullscreen is deprecated but iOS appears to only use this
262
+ // see https://github.com/clappr/clappr/issues/1127
263
+ if (!Fullscreen.fullscreenEnabled() && video.webkitSupportsFullscreen) {
264
+ this.fullScreenOnVideoTagSupported = true;
265
+ this.settingsUpdate(null);
266
+ }
267
+ }
268
+ updateVolumeUI() {
269
+ // this will be called after a render
270
+ if (!this.rendered) {
271
+ return;
272
+ }
273
+ assert.ok(this.$volumeBarContainer, 'volume bar container must be present');
274
+ // update volume bar scrubber/fill on bar mode
275
+ // this.$volumeBarContainer.find('.bar-fill-2').css({});
276
+ const containerWidth = this.$volumeBarContainer.width();
277
+ assert.ok(this.$volumeBarBackground, 'volume bar background must be present');
278
+ const barWidth = this.$volumeBarBackground.width();
279
+ const offset = (containerWidth - barWidth) / 2.0;
280
+ const pos = barWidth * this.volume / 100.0 + offset;
281
+ assert.ok(this.$volumeBarFill, 'volume bar fill must be present');
282
+ this.$volumeBarFill.css({ width: `${this.volume}%` });
283
+ this.$volumeBarFill.css({ width: `${this.volume}%` });
284
+ assert.ok(this.$volumeBarScrubber, 'volume bar scrubber must be present');
285
+ this.$volumeBarScrubber.css({ left: pos });
286
+ // update volume bar segments on segmented bar mode
287
+ this.$volumeBarContainer.find('.segmented-bar-element').removeClass('fill');
288
+ const item = Math.ceil(this.volume / 10.0);
289
+ this.$volumeBarContainer.find('.segmented-bar-element').slice(0, item).addClass('fill');
290
+ assert.ok(this.$volumeIcon, 'volume icon must be present');
291
+ this.$volumeIcon.html('');
292
+ this.$volumeIcon.removeClass('muted');
293
+ if (!this.muted) {
294
+ this.$volumeIcon.append(volumeMaxIcon);
295
+ }
296
+ else {
297
+ this.$volumeIcon.append(volumeOffIcon);
298
+ this.$volumeIcon.addClass('muted');
299
+ }
300
+ this.applyButtonStyle(this.$volumeIcon);
301
+ this.$volumeBarScrubber.css({ left: `${this.volume}%` });
302
+ this.$volumeIcon.html('');
303
+ this.$volumeIcon.removeClass('muted');
304
+ if (!this.muted) {
305
+ this.$volumeIcon.append(volumeMaxIcon);
306
+ }
307
+ else {
308
+ this.$volumeIcon.append(volumeOffIcon);
309
+ this.$volumeIcon.addClass('muted');
310
+ }
311
+ this.applyButtonStyle(this.$volumeIcon);
312
+ }
313
+ changeTogglePlay() {
314
+ // assert.ok(this.$playPauseToggle, 'play/pause toggle must be present');
315
+ this.$playPauseToggle?.html('');
316
+ // assert.ok(this.$playStopToggle, 'play/stop toggle must be present');
317
+ this.$playStopToggle?.html('');
318
+ if (this.container && this.container.isPlaying()) {
319
+ this.$playPauseToggle?.append(pauseIcon);
320
+ this.$playStopToggle?.append(pauseIcon);
321
+ this.trigger(Events.MEDIACONTROL_PLAYING);
322
+ }
323
+ else {
324
+ this.$playPauseToggle?.append(playIcon);
325
+ this.$playStopToggle?.append(playIcon);
326
+ this.trigger(Events.MEDIACONTROL_NOTPLAYING);
327
+ if (Browser.isMobile) {
328
+ this.show();
329
+ }
330
+ }
331
+ this.applyButtonStyle(this.$playPauseToggle);
332
+ this.applyButtonStyle(this.$playStopToggle);
333
+ }
334
+ mousemoveOnSeekBar(event) {
335
+ if (this.settings.seekEnabled) {
336
+ // assert.ok(this.$seekBarHover && this.$seekBarContainer, 'seek bar elements must be present');
337
+ if (this.$seekBarHover && this.$seekBarContainer) {
338
+ const offsetX = MediaControl.getPageX(event) - this.$seekBarContainer.offset().left - this.$seekBarHover.width() / 2;
339
+ this.$seekBarHover.css({ left: offsetX });
340
+ }
341
+ }
342
+ this.trigger(Events.MEDIACONTROL_MOUSEMOVE_SEEKBAR, event);
343
+ }
344
+ mouseleaveOnSeekBar(event) {
345
+ this.trigger(Events.MEDIACONTROL_MOUSELEAVE_SEEKBAR, event);
346
+ }
347
+ onVolumeClick(event) {
348
+ this.setVolume(this.getVolumeFromUIEvent(event));
349
+ }
350
+ mousemoveOnVolumeBar(event) {
351
+ this.draggingVolumeBar && this.setVolume(this.getVolumeFromUIEvent(event));
352
+ }
353
+ playerResize(size) {
354
+ // assert.ok(this.$fullscreenToggle, 'fullscreen toggle must be present');
355
+ if (isFullscreen(this.container.el)) {
356
+ this.$fullscreenToggle?.html(fullscreenOnIcon);
357
+ }
358
+ else {
359
+ this.$fullscreenToggle?.html(fullscreenOffIcon);
360
+ }
361
+ this.applyButtonStyle(this.$fullscreenToggle);
362
+ this.$el.removeClass('w370');
363
+ this.$el.removeClass('w270');
364
+ this.verticalVolume = false;
365
+ try {
366
+ const skinWidth = this.container.$el.width() || size.width;
367
+ if (skinWidth <= 370 || this.options.hideVolumeBar) {
368
+ this.$el.addClass('w370');
369
+ }
370
+ if (skinWidth <= 270 && !Browser.isMobile) {
371
+ this.verticalVolume = true;
372
+ this.$el.addClass('w270');
373
+ }
374
+ }
375
+ catch (e) {
376
+ reportError(e);
377
+ }
378
+ }
379
+ togglePlayPause() {
380
+ this.container.isPlaying() ? this.container.pause() : this.container.play();
381
+ return false;
382
+ }
383
+ togglePlayStop() {
384
+ this.container.isPlaying() ? this.container.stop() : this.container.play();
385
+ }
386
+ startSeekDrag(event) {
387
+ if (!this.settings.seekEnabled) {
388
+ return;
389
+ }
390
+ this.draggingSeekBar = true;
391
+ this.$el.addClass('dragging');
392
+ // assert.ok(this.$seekBarLoaded && this.$seekBarPosition && this.$seekBarScrubber, 'seek bar elements must be present');
393
+ this.$seekBarLoaded?.addClass('media-control-notransition');
394
+ this.$seekBarPosition?.addClass('media-control-notransition');
395
+ this.$seekBarScrubber?.addClass('media-control-notransition');
396
+ event && event.preventDefault();
397
+ }
398
+ startVolumeDrag(event) {
399
+ this.draggingVolumeBar = true;
400
+ this.$el.addClass('dragging');
401
+ event && event.preventDefault();
402
+ }
403
+ stopDrag = (event) => {
404
+ this.draggingSeekBar && this.seek(event);
405
+ this.$el.removeClass('dragging');
406
+ this.$seekBarLoaded?.removeClass('media-control-notransition');
407
+ this.$seekBarPosition?.removeClass('media-control-notransition');
408
+ this.$seekBarScrubber?.removeClass('media-control-notransition dragging');
409
+ this.draggingSeekBar = false;
410
+ this.draggingVolumeBar = false;
411
+ };
412
+ updateDrag = (event) => {
413
+ if (this.draggingSeekBar) {
414
+ event.preventDefault();
415
+ const pageX = MediaControl.getPageX(event);
416
+ assert.ok(this.$seekBarContainer, 'seek bar container must be present');
417
+ const offsetX = pageX - this.$seekBarContainer.offset().left;
418
+ let pos = offsetX / this.$seekBarContainer.width() * 100;
419
+ pos = Math.min(100, Math.max(pos, 0));
420
+ this.setSeekPercentage(pos);
421
+ }
422
+ else if (this.draggingVolumeBar) {
423
+ event.preventDefault();
424
+ this.setVolume(this.getVolumeFromUIEvent(event));
425
+ }
426
+ };
427
+ getVolumeFromUIEvent(event) {
428
+ let volumeFromUI = 0;
429
+ assert.ok(this.$volumeBarContainer, 'volume bar container must be present');
430
+ if (!this.verticalVolume) {
431
+ const offsetY = MediaControl.getPageX(event) - this.$volumeBarContainer.offset().left;
432
+ volumeFromUI = (offsetY / this.$volumeBarContainer.width()) * 100;
433
+ }
434
+ else {
435
+ const offsetX = 80 - Math.abs(this.$volumeBarContainer.offset().top - MediaControl.getPageY(event));
436
+ volumeFromUI = (offsetX / (this.$volumeBarContainer.height())) * 100;
437
+ }
438
+ return volumeFromUI;
439
+ }
440
+ toggleMute() {
441
+ this.setVolume(this.muted ? 100 : 0);
442
+ }
443
+ setVolume(value, isInitialVolume = false) {
444
+ value = Math.min(100, Math.max(value, 0));
445
+ // this will hold the intended volume
446
+ // it may not actually get set to this straight away
447
+ // if the container is not ready etc
448
+ this.intendedVolume = value;
449
+ this.persistConfig && !isInitialVolume && Config.persist('volume', value);
450
+ const setWhenContainerReady = () => {
451
+ if (this.container && this.container.isReady) {
452
+ this.container.setVolume(value);
453
+ }
454
+ else {
455
+ this.listenToOnce(this.container, Events.CONTAINER_READY, () => {
456
+ this.container.setVolume(value);
457
+ });
458
+ }
459
+ };
460
+ if (!this.container) {
461
+ this.listenToOnce(this, Events.MEDIACONTROL_CONTAINERCHANGED, () => setWhenContainerReady());
462
+ }
463
+ else {
464
+ setWhenContainerReady();
465
+ }
466
+ }
467
+ toggleFullscreen() {
468
+ if (!Browser.isMobile) {
469
+ this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name);
470
+ this.container.fullscreen();
471
+ this.core.toggleFullscreen();
472
+ this.resetUserKeepVisible();
473
+ }
474
+ }
475
+ onActiveContainerChanged() {
476
+ trace(`${T} onActiveContainerChanged`);
477
+ this.fullScreenOnVideoTagSupported = null;
478
+ this.bindEvents();
479
+ // set the new container to match the volume of the last one
480
+ this.setInitialVolume();
481
+ this.changeTogglePlay();
482
+ this.bindContainerEvents();
483
+ this.settingsUpdate(null);
484
+ this.container && this.container.trigger(Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.container.isDvrInUse());
485
+ this.container && this.container.mediaControlDisabled && this.disable();
486
+ this.trigger(Events.MEDIACONTROL_CONTAINERCHANGED);
487
+ if (this.container.$el) {
488
+ this.container.$el.addClass('container-skin-1');
489
+ }
490
+ if (this.options.cropVideo) {
491
+ this.container.$el.addClass('crop-video');
492
+ }
493
+ const spinnerPlugin = this.container.getPlugin('spinner');
494
+ spinnerPlugin?.$el.find('div').addClass('gcore-skin-main-color');
495
+ const seekTimePlugin = this.container.getPlugin('seek_time');
496
+ seekTimePlugin?.$el.addClass('gcore-skin-bg-color');
497
+ seekTimePlugin?.$el.find('span').addClass('gcore-skin-text-color');
498
+ }
499
+ showVolumeBar() {
500
+ this.hideVolumeId && clearTimeout(this.hideVolumeId);
501
+ this.$volumeBarContainer?.removeClass('volume-bar-hide');
502
+ }
503
+ hideVolumeBar(timeout = 400) {
504
+ if (!this.$volumeBarContainer) {
505
+ return;
506
+ }
507
+ if (this.draggingVolumeBar) {
508
+ this.hideVolumeId = setTimeout(() => this.hideVolumeBar(), timeout);
509
+ }
510
+ else {
511
+ this.hideVolumeId && clearTimeout(this.hideVolumeId);
512
+ this.hideVolumeId = setTimeout(() => this.$volumeBarContainer?.addClass('volume-bar-hide'), timeout);
513
+ }
514
+ }
515
+ ended() {
516
+ this.changeTogglePlay();
517
+ }
518
+ updateProgressBar(progress) {
519
+ const loadedStart = progress.start / progress.total * 100;
520
+ const loadedEnd = progress.current / progress.total * 100;
521
+ this.$seekBarLoaded?.css({ left: `${loadedStart}%`, width: `${loadedEnd - loadedStart}%` });
522
+ }
523
+ onTimeUpdate(timeProgress) {
524
+ if (this.draggingSeekBar) {
525
+ return;
526
+ }
527
+ // TODO why should current time ever be negative?
528
+ const position = timeProgress.current < 0 ? timeProgress.total : timeProgress.current;
529
+ this.currentPositionValue = position;
530
+ this.currentDurationValue = timeProgress.total;
531
+ if (!this.draggingSeekBar) {
532
+ this.renderSeekBar();
533
+ }
534
+ }
535
+ renderSeekBar() {
536
+ // this will be triggered as soon as these become available
537
+ if (this.currentPositionValue === null || this.currentDurationValue === null) {
538
+ return;
539
+ }
540
+ // default to 100%
541
+ this.currentSeekBarPercentage = 100;
542
+ if (this.container && (this.container.getPlaybackType() !== Playback.LIVE || this.container.isDvrInUse())) {
543
+ this.currentSeekBarPercentage = (this.currentPositionValue / this.currentDurationValue) * 100;
544
+ }
545
+ this.setSeekPercentage(this.currentSeekBarPercentage);
546
+ this.drawDurationAndPosition();
547
+ }
548
+ drawDurationAndPosition() {
549
+ const newPosition = formatTime(this.currentPositionValue);
550
+ const newDuration = formatTime(this.currentDurationValue);
551
+ if (newPosition !== this.displayedPosition) {
552
+ this.$position?.text(newPosition);
553
+ this.displayedPosition = newPosition;
554
+ }
555
+ if (newDuration !== this.displayedDuration) {
556
+ this.$duration?.text(newDuration);
557
+ this.displayedDuration = newDuration;
558
+ }
559
+ }
560
+ seek(event) {
561
+ if (!this.settings.seekEnabled) {
562
+ return;
563
+ }
564
+ assert.ok(this.$seekBarContainer, 'seek bar container must be present');
565
+ const offsetX = MediaControl.getPageX(event) - this.$seekBarContainer.offset().left;
566
+ let pos = offsetX / this.$seekBarContainer.width() * 100;
567
+ pos = Math.min(100, Math.max(pos, 0));
568
+ this.container && this.container.seekPercentage(pos);
569
+ this.setSeekPercentage(pos);
570
+ return false;
571
+ }
572
+ setKeepVisible() {
573
+ this.keepVisible = true;
574
+ }
575
+ resetKeepVisible() {
576
+ this.keepVisible = false;
577
+ }
578
+ setUserKeepVisible() {
579
+ this.userKeepVisible = true;
580
+ }
581
+ resetUserKeepVisible() {
582
+ this.userKeepVisible = false;
583
+ }
584
+ isVisible() {
585
+ return !this.$el.hasClass('media-control-hide');
586
+ }
587
+ show(event) {
588
+ if (this.disabled || this.options.disableControlPanel) {
589
+ return;
590
+ }
591
+ const timeout = 2000;
592
+ const mousePointerMoved = event && (event.clientX !== this.lastMouseX && event.clientY !== this.lastMouseY);
593
+ if (!event || mousePointerMoved || navigator.userAgent.match(/firefox/i)) {
594
+ if (this.hideId !== null) {
595
+ clearTimeout(this.hideId);
596
+ this.hideId = null;
597
+ }
598
+ this.$el.show();
599
+ this.trigger(Events.MEDIACONTROL_SHOW, this.name);
600
+ this.container && this.container.trigger(Events.CONTAINER_MEDIACONTROL_SHOW, this.name);
601
+ this.$el.removeClass('media-control-hide');
602
+ this.hideId = setTimeout(() => this.hide(), timeout);
603
+ if (event) {
604
+ this.lastMouseX = event.clientX;
605
+ this.lastMouseY = event.clientY;
606
+ }
607
+ }
608
+ const showing = true;
609
+ this.updateCursorStyle(showing);
610
+ }
611
+ hide(delay = 0) {
612
+ if (!this.isVisible()) {
613
+ return;
614
+ }
615
+ const timeout = delay || 2000;
616
+ if (this.hideId !== null) {
617
+ clearTimeout(this.hideId);
618
+ }
619
+ if (!this.disabled && this.options.hideMediaControl === false) {
620
+ return;
621
+ }
622
+ const hasKeepVisibleRequested = this.userKeepVisible || this.keepVisible;
623
+ const hasDraggingAction = this.draggingSeekBar || this.draggingVolumeBar;
624
+ if (!this.disabled && (delay || hasKeepVisibleRequested || hasDraggingAction)) {
625
+ this.hideId = setTimeout(() => this.hide(), timeout);
626
+ }
627
+ else {
628
+ if (!this.options.controlsDontHide || isFullscreen(this.container.el)) {
629
+ this.trigger(Events.MEDIACONTROL_HIDE, this.name);
630
+ this.$el.addClass('media-control-hide');
631
+ this.hideVolumeBar(0);
632
+ const showing = false;
633
+ this.updateCursorStyle(showing);
634
+ }
635
+ }
636
+ }
637
+ updateCursorStyle(showing) {
638
+ if (showing) {
639
+ this.core.$el.removeClass('nocursor');
640
+ }
641
+ else if (this.core.isFullscreen()) {
642
+ this.core.$el.addClass('nocursor');
643
+ }
644
+ }
645
+ settingsUpdate(event) {
646
+ const newSettings = this.getSettings();
647
+ trace(`${T} settingsUpdate`, {
648
+ event,
649
+ newSettings,
650
+ settings: this.settings,
651
+ });
652
+ $.extend(true, newSettings, {
653
+ left: [],
654
+ default: [],
655
+ right: [],
656
+ });
657
+ const LEFT_ORDER = ['playpause', 'playstop', 'live', 'volume', 'position', 'duration'];
658
+ newSettings.left = orderByOrderPattern([...newSettings.left, 'clipsText', 'volume'], LEFT_ORDER);
659
+ newSettings.right = [
660
+ 'fullscreen',
661
+ 'pip',
662
+ 'bottomgear',
663
+ 'subtitles',
664
+ 'multicamera',
665
+ 'playbackrate',
666
+ 'vr',
667
+ 'audiotracks',
668
+ ];
669
+ if ((!this.fullScreenOnVideoTagSupported && !Fullscreen.fullscreenEnabled()) || this.options.fullscreenDisable) {
670
+ // remove fullscreen from settings if it is present
671
+ removeArrayItem(newSettings.default, 'fullscreen');
672
+ removeArrayItem(newSettings.left, 'fullscreen');
673
+ removeArrayItem(newSettings.right, 'fullscreen');
674
+ }
675
+ removeArrayItem(newSettings.default, 'hd-indicator');
676
+ removeArrayItem(newSettings.left, 'hd-indicator');
677
+ if (this.core.activePlayback.name === 'html5_video') {
678
+ newSettings.seekEnabled = this.isSeekEnabledForHtml5Playback();
679
+ }
680
+ const settingsChanged = JSON.stringify(this.settings) !== JSON.stringify(newSettings);
681
+ if (settingsChanged) {
682
+ this.settings = newSettings;
683
+ this.render();
684
+ }
685
+ }
686
+ getSettings() {
687
+ // TODO show live and remove duration/position if live
688
+ return $.extend(true, {}, this.container && this.container.settings);
689
+ }
690
+ highDefinitionUpdate(isHD) {
691
+ this.isHD = isHD;
692
+ }
693
+ createCachedElements() {
694
+ const $layer = this.$el.find('.media-control-layer');
695
+ this.$duration = $layer.find('.media-control-indicator[data-duration]');
696
+ this.$fullscreenToggle = $layer.find('button.media-control-button[data-fullscreen]');
697
+ this.$playPauseToggle = $layer.find('button.media-control-button[data-playpause]');
698
+ this.$playStopToggle = $layer.find('button.media-control-button[data-playstop]');
699
+ this.$position = $layer.find('.media-control-indicator[data-position]');
700
+ this.$seekBarContainer = $layer.find('.bar-container[data-seekbar]');
701
+ this.$seekBarLoaded = $layer.find('.bar-fill-1[data-seekbar]');
702
+ this.$seekBarPosition = $layer.find('.bar-fill-2[data-seekbar]');
703
+ this.$seekBarScrubber = $layer.find('.bar-scrubber[data-seekbar]');
704
+ this.$seekBarHover = $layer.find('.bar-hover[data-seekbar]');
705
+ this.$volumeBarContainer = $layer.find('.bar-container[data-volume]');
706
+ this.$volumeContainer = $layer.find('.drawer-container[data-volume]');
707
+ this.$volumeIcon = $layer.find('.drawer-icon[data-volume]');
708
+ this.$volumeBarBackground = this.$el.find('.bar-background[data-volume]');
709
+ this.$volumeBarFill = this.$el.find('.bar-fill-1[data-volume]');
710
+ this.$volumeBarScrubber = this.$el.find('.bar-scrubber[data-volume]');
711
+ this.$bottomGear = this.$el.find('.media-control-bottomgear');
712
+ this.$pip = this.$el.find('.media-control-pip');
713
+ this.$audioTracksSelector = this.$el.find('.media-control-audio-tracks[data-audiotracks]');
714
+ this.$subtitlesSelector = this.$el.find('.media-control-subtitles[data-subtitles]');
715
+ this.$playbackRate = this.$el.find('.media-control-playbackrate[data-playbackrate]');
716
+ this.$multiCameraSelector = this.$el.find('.media-control-multicamera[data-multicamera]');
717
+ this.$clipText = this.$el.find('.media-clip-text[data-clipstext]');
718
+ this.$clipTextContainer = this.$el.find('.media-clip-container[data-clipstext]');
719
+ this.resetIndicators();
720
+ this.initializeIcons();
721
+ }
722
+ resetIndicators() {
723
+ assert.ok(this.$duration && this.$position, 'duration and position elements must be present');
724
+ this.displayedPosition = this.$position.text();
725
+ this.displayedDuration = this.$duration.text();
726
+ }
727
+ initializeIcons() {
728
+ const $layer = this.$el.find('.media-control-layer');
729
+ $layer.find('button.media-control-button[data-play]').append(playIcon);
730
+ $layer.find('button.media-control-button[data-pause]').append(pauseIcon);
731
+ $layer.find('button.media-control-button[data-stop]').append(stopIcon);
732
+ this.$playPauseToggle?.append(playIcon);
733
+ this.$playStopToggle?.append(playIcon);
734
+ this.$volumeIcon?.append(volumeMaxIcon);
735
+ this.$fullscreenToggle?.append(fullscreenOffIcon);
736
+ }
737
+ setSeekPercentage(value) {
738
+ value = Math.max(Math.min(value, 100.0), 0);
739
+ // not changed since last update
740
+ if (this.displayedSeekBarPercentage === value) {
741
+ return;
742
+ }
743
+ this.displayedSeekBarPercentage = value;
744
+ // assert.ok(this.$seekBarPosition && this.$seekBarScrubber, 'seek bar elements must be present');
745
+ this.$seekBarPosition?.removeClass('media-control-notransition');
746
+ this.$seekBarScrubber?.removeClass('media-control-notransition');
747
+ this.$seekBarPosition?.css({ width: `${value}%` });
748
+ this.$seekBarScrubber?.css({ left: `${value}%` });
749
+ }
750
+ seekRelative(delta) {
751
+ if (!this.settings.seekEnabled) {
752
+ return;
753
+ }
754
+ const currentTime = this.container.getCurrentTime();
755
+ const duration = this.container.getDuration();
756
+ let position = Math.min(Math.max(currentTime + delta, 0), duration);
757
+ position = Math.min(position * 100 / duration, 100);
758
+ this.container.seekPercentage(position);
759
+ }
760
+ bindKeyAndShow(key, callback) {
761
+ this.kibo.down(key, () => {
762
+ this.show();
763
+ return callback();
764
+ });
765
+ }
766
+ bindKeyEvents() {
767
+ if (Browser.isMobile || this.options.disableKeyboardShortcuts) {
768
+ return;
769
+ }
770
+ this.unbindKeyEvents();
771
+ this.kibo = new Kibo(this.options.focusElement || this.options.parentElement);
772
+ this.bindKeyAndShow('space', () => this.togglePlayPause());
773
+ this.bindKeyAndShow('left', () => this.seekRelative(-5));
774
+ this.bindKeyAndShow('right', () => this.seekRelative(5));
775
+ this.bindKeyAndShow('shift left', () => this.seekRelative(-10));
776
+ this.bindKeyAndShow('shift right', () => this.seekRelative(10));
777
+ this.bindKeyAndShow('shift ctrl left', () => this.seekRelative(-15));
778
+ this.bindKeyAndShow('shift ctrl right', () => this.seekRelative(15));
779
+ const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
780
+ keys.forEach((i) => {
781
+ this.bindKeyAndShow(i, () => {
782
+ this.settings.seekEnabled && this.container && this.container.seekPercentage(Number(i) * 10);
783
+ });
784
+ });
785
+ }
786
+ unbindKeyEvents() {
787
+ if (this.kibo) {
788
+ this.kibo.off('space');
789
+ this.kibo.off('left');
790
+ this.kibo.off('right');
791
+ this.kibo.off('shift left');
792
+ this.kibo.off('shift right');
793
+ this.kibo.off('shift ctrl left');
794
+ this.kibo.off('shift ctrl right');
795
+ this.kibo.off(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']);
796
+ }
797
+ }
798
+ parseColors() {
799
+ let { design } = this.options;
800
+ if (!design) {
801
+ design = {};
802
+ }
803
+ let variables = [];
804
+ if (!template) {
805
+ return;
806
+ }
807
+ if (design.background_color) {
808
+ variables = variables.concat([
809
+ `--theme-background-color: ${design.background_color};`
810
+ ]);
811
+ }
812
+ if (design.text_color) {
813
+ variables = variables.concat([
814
+ `--theme-text-color: ${design.text_color};`
815
+ ]);
816
+ }
817
+ if (design.foreground_color) {
818
+ variables = variables.concat([
819
+ `--theme-foreground-color: ${design.foreground_color};`
820
+ ]);
821
+ }
822
+ if (design.hover_color) {
823
+ variables = variables.concat([
824
+ `--theme-hover-color: ${design.hover_color};`
825
+ ]);
826
+ }
827
+ this.$el.append(`<style>:root {${variables.join('\n')}}</style>`);
828
+ }
829
+ applyButtonStyle(element) {
830
+ this.buttonsColor
831
+ && element
832
+ && $(element).find('svg path').css({ 'fill': this.buttonsColor });
833
+ }
834
+ destroy() {
835
+ $(document).unbind('mouseup', this.stopDrag);
836
+ $(document).unbind('mousemove', this.updateDrag);
837
+ this.unbindKeyEvents();
838
+ // @ts-ignore
839
+ this.stopListening();
840
+ return super.destroy();
841
+ }
842
+ configure() {
843
+ this.advertisementPlaying ? this.disable() : this.enable();
844
+ this.trigger(Events.MEDIACONTROL_OPTIONS_CHANGE);
845
+ }
846
+ render() {
847
+ trace(`${T} render`, {
848
+ settings: !!this.settings,
849
+ rendered: this.rendered,
850
+ disabled: this.disabled,
851
+ options: !!this.options,
852
+ $el: !!this.$el,
853
+ });
854
+ console.log(`${T} render settings`, JSON.stringify(this.settings));
855
+ const timeout = this.options.hideMediaControlDelay || 2000;
856
+ // if (this.settings) {
857
+ const html = this.template({ settings: this.settings ?? {} });
858
+ // trace(`${T} render html`, { html });
859
+ this.$el.html(html);
860
+ // }
861
+ // this.settings && this.$el.html(html);
862
+ // const style = Styler.getStyleFor(mediaControlStyle, { baseUrl: this.options.baseUrl });
863
+ // this.$el.append(style[0]);
864
+ this.createCachedElements();
865
+ this.drawDurationAndPosition();
866
+ this.$playPauseToggle?.addClass('paused');
867
+ this.$playStopToggle?.addClass('stopped');
868
+ this.changeTogglePlay();
869
+ if (this.container) {
870
+ this.hideId = setTimeout(() => this.hide(), timeout);
871
+ this.disabled && this.hide();
872
+ }
873
+ // Video volume cannot be changed with Safari on mobile devices
874
+ // Display mute/unmute icon only if Safari version >= 10
875
+ if (Browser.isSafari && Browser.isMobile) {
876
+ if (Browser.version < 10) {
877
+ this.$volumeContainer?.css({ 'display': 'none' });
878
+ }
879
+ else {
880
+ this.$volumeBarContainer?.css({ 'display': 'none' });
881
+ }
882
+ }
883
+ this.$seekBarPosition?.addClass('media-control-notransition');
884
+ this.$seekBarScrubber?.addClass('media-control-notransition');
885
+ let previousSeekPercentage = 0;
886
+ if (this.displayedSeekBarPercentage) {
887
+ previousSeekPercentage = this.displayedSeekBarPercentage;
888
+ }
889
+ this.displayedSeekBarPercentage = null;
890
+ this.setSeekPercentage(previousSeekPercentage);
891
+ setTimeout(() => {
892
+ !this.settings.seekEnabled && this.$seekBarContainer?.addClass('seek-disabled');
893
+ !Browser.isMobile && !this.options.disableKeyboardShortcuts && this.bindKeyEvents();
894
+ this.playerResize({ width: this.options.width, height: this.options.height });
895
+ this.hideVolumeBar(0);
896
+ }, 0);
897
+ this.parseColors();
898
+ this.highDefinitionUpdate(this.isHD);
899
+ this.core.$el.append(this.el);
900
+ this.rendered = true;
901
+ this.updateVolumeUI();
902
+ trace(`${T} render triggering rendered`);
903
+ this.trigger(Events.MEDIACONTROL_RENDERED);
904
+ trace(`${T} render triggered rendered`);
905
+ return this;
906
+ }
907
+ get bigPlayButton() {
908
+ return playIcon;
909
+ }
910
+ handleFullScreenOnBtn() {
911
+ this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name);
912
+ this.container.fullscreen();
913
+ // TODO: fix after it full screen will be fixed on iOS
914
+ if (Browser.isiOS) {
915
+ if (this.core.isFullscreen()) {
916
+ Fullscreen.cancelFullscreen(this.core.el);
917
+ }
918
+ else {
919
+ Fullscreen.requestFullscreen(this.core.el);
920
+ }
921
+ }
922
+ else {
923
+ this.core.toggleFullscreen();
924
+ }
925
+ this.resetUserKeepVisible();
926
+ }
927
+ onStartAd() {
928
+ this.advertisementPlaying = true;
929
+ this.disable();
930
+ }
931
+ onFinishAd() {
932
+ this.advertisementPlaying = false;
933
+ this.enable();
934
+ }
935
+ setClipText(txt) {
936
+ if (this.$clipText && txt) {
937
+ this.$clipTextContainer?.show();
938
+ this.$clipText.text(`${txt}`);
939
+ }
940
+ }
941
+ hideControllAds() {
942
+ if (this.container.advertisement && this.container.advertisement.type !== 'idle') {
943
+ this.hide();
944
+ }
945
+ }
946
+ setSVGMask(svg) {
947
+ if (this.svgMask) {
948
+ this.svgMask.remove();
949
+ }
950
+ if (this.$seekBarContainer?.get(0)) {
951
+ this.$seekBarContainer.addClass('clips');
952
+ }
953
+ this.svgMask = $(svg);
954
+ this.$seekBarContainer?.append(this.svgMask);
955
+ }
956
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=109212
957
+ setMuted(value) {
958
+ this.container.options.mute = value;
959
+ }
960
+ static getPageX(event) {
961
+ if (event.pageX) {
962
+ return event.pageX;
963
+ }
964
+ if (event.changedTouches) {
965
+ return event.changedTouches[event.changedTouches.length - 1].pageX;
966
+ }
967
+ return 0;
968
+ }
969
+ static getPageY(event) {
970
+ if (event.pageY) {
971
+ return event.pageY;
972
+ }
973
+ if (event.changedTouches) {
974
+ return event.changedTouches[event.changedTouches.length - 1].pageY;
975
+ }
976
+ return 0;
977
+ }
978
+ //Решают проблему, когда нам не нужно, чтобы с помощью контролов человек мог запускать
979
+ // или останавливать поток, контролы, которыми он управляет не должны работать
980
+ enableControlButton() {
981
+ this.disabledClickableList.forEach((element) => {
982
+ element.el.css({ 'pointer-events': element.pointerEventValue });
983
+ });
984
+ }
985
+ disabledControlButton() {
986
+ this.disabledClickableList.forEach((element) => {
987
+ element.el.css({ 'pointer-events': 'none' });
988
+ });
989
+ }
990
+ isSeekEnabledForHtml5Playback() {
991
+ if (this.core.getPlaybackType() === Playback.LIVE) {
992
+ return this.options.dvrEnabled;
993
+ }
994
+ return isFinite(this.core.activePlayback.getDuration());
995
+ }
996
+ }
997
+ // TODO drop?
998
+ MediaControl.extend = function (properties) {
999
+ return extend(MediaControl, properties);
1000
+ };