myetv-player 1.1.0 → 1.1.2
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/README.md +69 -0
- package/css/myetv-player.css +726 -11937
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +254 -111
- package/dist/myetv-player.min.js +249 -106
- package/package.json +3 -1
- package/plugins/youtube/myetv-player-youtube-plugin.js +237 -19
- package/scss/_controls.scss +120 -317
- package/scss/_menus.scss +117 -4023
- package/scss/_progress-bar.scss +168 -2052
- package/scss/_title-overlay.scss +10 -2239
- package/scss/_video.scss +62 -2167
- package/scss/_volume.scss +25 -1846
- package/src/controls.js +7 -7
- package/src/core.js +121 -69
- package/src/events.js +123 -25
- package/src/subtitles.js +3 -10
package/src/controls.js
CHANGED
|
@@ -368,13 +368,13 @@ createControls() {
|
|
|
368
368
|
const controlsHTML = `
|
|
369
369
|
<div class="controls" id="${controlsId}">
|
|
370
370
|
<div class="progress-container">
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
371
|
+
<div class="progress-bar">
|
|
372
|
+
<div class="progress-buffer"></div>
|
|
373
|
+
<div class="progress-filled"></div>
|
|
374
|
+
</div>
|
|
375
|
+
<div class="progress-handle progress-handle-${this.options.seekHandleShape}"></div> <!-- ✅ Fuori da progress-bar -->
|
|
376
|
+
${this.options.showSeekTooltip ? '<div class="seek-tooltip">0:00</div>' : ''}
|
|
377
|
+
</div>
|
|
378
378
|
|
|
379
379
|
<div class="controls-main">
|
|
380
380
|
<div class="controls-left">
|
package/src/core.js
CHANGED
|
@@ -37,6 +37,7 @@ constructor(videoElement, options = {}) {
|
|
|
37
37
|
brandLogoEnabled: false, // Enable/disable brand logo
|
|
38
38
|
brandLogoUrl: '', // URL for brand logo image
|
|
39
39
|
brandLogoLinkUrl: '', // Optional URL to open when clicking the logo
|
|
40
|
+
brandLogoTooltipText: '', // Tooltip text for brand logo
|
|
40
41
|
playlistEnabled: true, // Enable/disable playlist detection
|
|
41
42
|
playlistAutoPlay: true, // Auto-play next video when current ends
|
|
42
43
|
playlistLoop: false, // Loop playlist when reaching the end
|
|
@@ -69,7 +70,6 @@ constructor(videoElement, options = {}) {
|
|
|
69
70
|
this.currentQualityIndex = 0;
|
|
70
71
|
this.qualities = [];
|
|
71
72
|
this.originalSources = [];
|
|
72
|
-
this.setupMenuToggles(); // Initialize menu toggle system
|
|
73
73
|
this.isPiPSupported = this.checkPiPSupport();
|
|
74
74
|
this.seekTooltip = null;
|
|
75
75
|
this.titleOverlay = null;
|
|
@@ -112,18 +112,42 @@ constructor(videoElement, options = {}) {
|
|
|
112
112
|
|
|
113
113
|
// Custom event system
|
|
114
114
|
this.eventCallbacks = {
|
|
115
|
-
|
|
116
|
-
'
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
|
|
115
|
+
// Core lifecycle events
|
|
116
|
+
'playerready': [], // Fired when player is fully initialized and ready
|
|
117
|
+
'played': [], // Fired when video starts playing
|
|
118
|
+
'paused': [], // Fired when video is paused
|
|
119
|
+
'ended': [], // Fired when video playback ends
|
|
120
|
+
|
|
121
|
+
// Playback state events
|
|
122
|
+
'playing': [], // Fired when video is actually playing (after buffering)
|
|
123
|
+
'waiting': [], // Fired when video is waiting for data (buffering)
|
|
124
|
+
'seeking': [], // Fired when seek operation starts
|
|
125
|
+
'seeked': [], // Fired when seek operation completes
|
|
126
|
+
|
|
127
|
+
// Loading events
|
|
128
|
+
'loadstart': [], // Fired when browser starts looking for media
|
|
129
|
+
'loadedmetadata': [], // Fired when metadata (duration, dimensions) is loaded
|
|
130
|
+
'loadeddata': [], // Fired when data for current frame is loaded
|
|
131
|
+
'canplay': [], // Fired when browser can start playing video
|
|
132
|
+
'progress': [], // Fired periodically while downloading media
|
|
133
|
+
'durationchange': [], // Fired when duration attribute changes
|
|
134
|
+
|
|
135
|
+
// Error events
|
|
136
|
+
'error': [], // Fired when media loading or playback error occurs
|
|
137
|
+
'stalled': [], // Fired when browser is trying to get data but it's not available
|
|
138
|
+
|
|
139
|
+
// Control events
|
|
140
|
+
'timeupdate': [], // Fired when current playback position changes
|
|
141
|
+
'volumechange': [], // Fired when volume or muted state changes
|
|
142
|
+
'speedchange': [], // Fired when playback speed changes
|
|
143
|
+
'qualitychange': [], // Fired when video quality changes
|
|
144
|
+
|
|
145
|
+
// Feature events
|
|
146
|
+
'subtitlechange': [], // Fired when subtitle track changes
|
|
147
|
+
'chapterchange': [], // Fired when video chapter changes
|
|
148
|
+
'pipchange': [], // Fired when picture-in-picture mode changes
|
|
149
|
+
'fullscreenchange': [], // Fired when fullscreen mode changes
|
|
150
|
+
'playlistchange': [] // Fired when playlist item changes
|
|
127
151
|
};
|
|
128
152
|
|
|
129
153
|
// Playlist management
|
|
@@ -157,6 +181,7 @@ constructor(videoElement, options = {}) {
|
|
|
157
181
|
this.interceptAutoLoading();
|
|
158
182
|
this.createPlayerStructure();
|
|
159
183
|
this.initializeElements();
|
|
184
|
+
this.setupMenuToggles(); // Initialize menu toggle system
|
|
160
185
|
// audio player adaptation
|
|
161
186
|
this.adaptToAudioFile = function () {
|
|
162
187
|
if (this.options.audiofile) {
|
|
@@ -485,6 +510,14 @@ markPlayerReady() {
|
|
|
485
510
|
this.container.classList.add('player-initialized');
|
|
486
511
|
}
|
|
487
512
|
|
|
513
|
+
this.triggerEvent('playerready', {
|
|
514
|
+
playerState: this.getPlayerState(),
|
|
515
|
+
qualities: this.qualities,
|
|
516
|
+
subtitles: this.textTracks,
|
|
517
|
+
chapters: this.chapters,
|
|
518
|
+
playlist: this.getPlaylistInfo()
|
|
519
|
+
});
|
|
520
|
+
|
|
488
521
|
if (this.video) {
|
|
489
522
|
this.video.style.visibility = '';
|
|
490
523
|
this.video.style.opacity = '';
|
|
@@ -765,74 +798,84 @@ initializeElements() {
|
|
|
765
798
|
this.speedMenu = this.controls?.querySelector('.speed-menu');
|
|
766
799
|
this.qualityMenu = this.controls?.querySelector('.quality-menu');
|
|
767
800
|
this.subtitlesMenu = this.controls?.querySelector('.subtitles-menu');
|
|
801
|
+
// Apply seek handle shape from options
|
|
802
|
+
if (this.progressHandle && this.options.seekHandleShape) {
|
|
803
|
+
this.setSeekHandleShape(this.options.seekHandleShape);
|
|
804
|
+
}
|
|
768
805
|
}
|
|
769
806
|
|
|
770
807
|
// Generic method to close all active menus (works with plugins too)
|
|
771
808
|
closeAllMenus() {
|
|
772
|
-
|
|
773
|
-
const allMenus = this.controls?.querySelectorAll('[class*="-menu"].active');
|
|
774
|
-
allMenus?.forEach(menu => {
|
|
775
|
-
menu.classList.remove('active');
|
|
776
|
-
});
|
|
809
|
+
if (!this.controls) return;
|
|
777
810
|
|
|
778
|
-
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
811
|
+
const menus = this.controls.querySelectorAll('.speed-menu, .quality-menu, .subtitles-menu, .settings-menu');
|
|
812
|
+
const buttons = this.controls.querySelectorAll('.control-btn');
|
|
813
|
+
|
|
814
|
+
menus.forEach(menu => menu.classList.remove('active'));
|
|
815
|
+
buttons.forEach(btn => btn.classList.remove('active'));
|
|
816
|
+
|
|
817
|
+
this.currentOpenMenu = null;
|
|
818
|
+
|
|
819
|
+
if (this.options.debug) {
|
|
820
|
+
console.log('All menus closed');
|
|
821
|
+
}
|
|
783
822
|
}
|
|
784
823
|
|
|
785
824
|
// Generic menu toggle setup (works with core menus and plugin menus)
|
|
786
825
|
setupMenuToggles() {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
const menu = this.controls.querySelector('.' + menuName);
|
|
804
|
-
if (menu) {
|
|
805
|
-
menuClass = menuName;
|
|
806
|
-
break;
|
|
807
|
-
}
|
|
808
|
-
}
|
|
826
|
+
if (!this.controls) return;
|
|
827
|
+
|
|
828
|
+
this.currentOpenMenu = null;
|
|
829
|
+
|
|
830
|
+
this.controls.addEventListener('click', (e) => {
|
|
831
|
+
const button = e.target.closest('.control-btn');
|
|
832
|
+
if (!button) return;
|
|
833
|
+
|
|
834
|
+
const buttonClasses = Array.from(button.classList);
|
|
835
|
+
let menuElement = null;
|
|
836
|
+
|
|
837
|
+
for (const cls of buttonClasses) {
|
|
838
|
+
if (cls.endsWith('-btn')) {
|
|
839
|
+
const menuClass = cls.replace('-btn', '-menu');
|
|
840
|
+
menuElement = this.controls.querySelector(`.${menuClass}`);
|
|
841
|
+
if (menuElement) break;
|
|
809
842
|
}
|
|
843
|
+
}
|
|
810
844
|
|
|
811
|
-
|
|
845
|
+
if (!menuElement) return;
|
|
812
846
|
|
|
813
|
-
|
|
847
|
+
e.stopPropagation();
|
|
848
|
+
e.preventDefault();
|
|
814
849
|
|
|
815
|
-
|
|
816
|
-
const menu = this.controls.querySelector('.' + menuClass);
|
|
817
|
-
const isOpen = menu.classList.contains('active');
|
|
850
|
+
const isOpen = menuElement.classList.contains('active');
|
|
818
851
|
|
|
819
|
-
|
|
820
|
-
this.closeAllMenus();
|
|
852
|
+
this.closeAllMenus();
|
|
821
853
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
854
|
+
if (!isOpen) {
|
|
855
|
+
menuElement.classList.add('active');
|
|
856
|
+
button.classList.add('active');
|
|
857
|
+
this.currentOpenMenu = menuElement;
|
|
858
|
+
if (this.options.debug) {
|
|
859
|
+
console.log('Menu opened:', menuElement.className);
|
|
826
860
|
}
|
|
827
|
-
}
|
|
828
|
-
|
|
861
|
+
} else {
|
|
862
|
+
this.currentOpenMenu = null;
|
|
863
|
+
if (this.options.debug) {
|
|
864
|
+
console.log('Menu closed:', menuElement.className);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
});
|
|
829
868
|
|
|
830
|
-
// Close menus when clicking outside controls
|
|
831
869
|
document.addEventListener('click', (e) => {
|
|
832
|
-
if (!this.controls
|
|
870
|
+
if (!this.controls) return;
|
|
871
|
+
if (!this.controls.contains(e.target)) {
|
|
833
872
|
this.closeAllMenus();
|
|
834
873
|
}
|
|
835
874
|
});
|
|
875
|
+
|
|
876
|
+
if (this.options.debug) {
|
|
877
|
+
console.log('✅ Menu toggle system initialized (click-based, auto-close)');
|
|
878
|
+
}
|
|
836
879
|
}
|
|
837
880
|
|
|
838
881
|
updateVolumeSliderVisual() {
|
|
@@ -1143,9 +1186,11 @@ updateBuffer() {
|
|
|
1143
1186
|
}
|
|
1144
1187
|
|
|
1145
1188
|
startSeeking(e) {
|
|
1189
|
+
if (e.cancelable) e.preventDefault();
|
|
1146
1190
|
if (this.isChangingQuality) return;
|
|
1147
1191
|
|
|
1148
1192
|
this.isUserSeeking = true;
|
|
1193
|
+
this.progressContainer.classList.add('seeking');
|
|
1149
1194
|
this.seek(e);
|
|
1150
1195
|
e.preventDefault();
|
|
1151
1196
|
|
|
@@ -1157,6 +1202,7 @@ startSeeking(e) {
|
|
|
1157
1202
|
}
|
|
1158
1203
|
|
|
1159
1204
|
continueSeeking(e) {
|
|
1205
|
+
if (e.cancelable) e.preventDefault();
|
|
1160
1206
|
if (this.isUserSeeking && !this.isChangingQuality) {
|
|
1161
1207
|
this.seek(e);
|
|
1162
1208
|
}
|
|
@@ -1164,9 +1210,13 @@ continueSeeking(e) {
|
|
|
1164
1210
|
|
|
1165
1211
|
endSeeking() {
|
|
1166
1212
|
this.isUserSeeking = false;
|
|
1213
|
+
this.progressContainer.classList.remove('seeking');
|
|
1167
1214
|
}
|
|
1168
1215
|
|
|
1169
1216
|
seek(e) {
|
|
1217
|
+
if (e.cancelable) {
|
|
1218
|
+
e.preventDefault();
|
|
1219
|
+
}
|
|
1170
1220
|
if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
|
|
1171
1221
|
|
|
1172
1222
|
const rect = this.progressContainer.getBoundingClientRect();
|
|
@@ -1346,7 +1396,14 @@ createBrandLogo() {
|
|
|
1346
1396
|
const logo = document.createElement('img');
|
|
1347
1397
|
logo.className = 'brand-logo';
|
|
1348
1398
|
logo.src = this.options.brandLogoUrl;
|
|
1349
|
-
logo.alt =
|
|
1399
|
+
logo.alt = 'Brand logo';
|
|
1400
|
+
|
|
1401
|
+
// Add tooltip ONLY if link URL is present
|
|
1402
|
+
if (this.options.brandLogoLinkUrl) {
|
|
1403
|
+
// Use custom tooltip text if provided, otherwise fallback to URL
|
|
1404
|
+
logo.title = this.options.brandLogoTooltipText || this.options.brandLogoLinkUrl;
|
|
1405
|
+
// NON usare data-tooltip per evitare che venga sovrascritto da updateTooltips()
|
|
1406
|
+
}
|
|
1350
1407
|
|
|
1351
1408
|
// Handle loading error
|
|
1352
1409
|
logo.onerror = () => {
|
|
@@ -1362,7 +1419,7 @@ createBrandLogo() {
|
|
|
1362
1419
|
if (this.options.brandLogoLinkUrl) {
|
|
1363
1420
|
logo.style.cursor = 'pointer';
|
|
1364
1421
|
logo.addEventListener('click', (e) => {
|
|
1365
|
-
e.stopPropagation();
|
|
1422
|
+
e.stopPropagation();
|
|
1366
1423
|
window.open(this.options.brandLogoLinkUrl, '_blank', 'noopener,noreferrer');
|
|
1367
1424
|
if (this.options.debug) console.log('Brand logo clicked, opening:', this.options.brandLogoLinkUrl);
|
|
1368
1425
|
});
|
|
@@ -1370,15 +1427,10 @@ createBrandLogo() {
|
|
|
1370
1427
|
logo.style.cursor = 'default';
|
|
1371
1428
|
}
|
|
1372
1429
|
|
|
1373
|
-
// Position the brand logo at the right of the controlbar (at the left of the buttons)
|
|
1374
1430
|
controlsRight.insertBefore(logo, controlsRight.firstChild);
|
|
1375
1431
|
|
|
1376
1432
|
if (this.options.debug) {
|
|
1377
|
-
|
|
1378
|
-
console.log('Brand logo with click handler created for:', this.options.brandLogoLinkUrl);
|
|
1379
|
-
} else {
|
|
1380
|
-
console.log('Brand logo created (no link)');
|
|
1381
|
-
}
|
|
1433
|
+
console.log('Brand logo created with tooltip:', logo.title || 'no tooltip');
|
|
1382
1434
|
}
|
|
1383
1435
|
}
|
|
1384
1436
|
|
|
@@ -1585,7 +1637,7 @@ bindPosterEvents() {
|
|
|
1585
1637
|
// Hide poster when video is loading/playing
|
|
1586
1638
|
this.video.addEventListener('playing', () => {
|
|
1587
1639
|
this.hidePoster();
|
|
1588
|
-
|
|
1640
|
+
});
|
|
1589
1641
|
|
|
1590
1642
|
// Show poster on load if not autoplay
|
|
1591
1643
|
if (!this.options.autoplay) {
|
package/src/events.js
CHANGED
|
@@ -165,36 +165,130 @@
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
bindEvents() {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
if (this.video) {
|
|
169
|
+
|
|
170
|
+
// Playback events
|
|
171
|
+
this.video.addEventListener('playing', () => {
|
|
172
|
+
this.hideLoading();
|
|
173
|
+
this.closeAllMenus();
|
|
174
|
+
// Trigger playing event - video is now actually playing
|
|
175
|
+
this.triggerEvent('playing', {
|
|
176
|
+
currentTime: this.getCurrentTime(),
|
|
177
|
+
duration: this.getDuration()
|
|
174
178
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
this.video.addEventListener('waiting', () => {
|
|
182
|
+
if (!this.isChangingQuality) {
|
|
183
|
+
this.showLoading();
|
|
184
|
+
// Trigger waiting event - video is buffering
|
|
185
|
+
this.triggerEvent('waiting', {
|
|
186
|
+
currentTime: this.getCurrentTime()
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
this.video.addEventListener('seeking', () => {
|
|
192
|
+
// Trigger seeking event - seek operation started
|
|
193
|
+
this.triggerEvent('seeking', {
|
|
194
|
+
currentTime: this.getCurrentTime(),
|
|
195
|
+
targetTime: this.video.currentTime
|
|
181
196
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
this.video.addEventListener('seeked', () => {
|
|
200
|
+
// Trigger seeked event - seek operation completed
|
|
201
|
+
this.triggerEvent('seeked', {
|
|
202
|
+
currentTime: this.getCurrentTime()
|
|
186
203
|
});
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Loading events
|
|
207
|
+
this.video.addEventListener('loadstart', () => {
|
|
208
|
+
if (!this.isChangingQuality) {
|
|
209
|
+
this.showLoading();
|
|
210
|
+
}
|
|
211
|
+
// Trigger loadstart event - browser started loading media
|
|
212
|
+
this.triggerEvent('loadstart');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
this.video.addEventListener('loadedmetadata', () => {
|
|
216
|
+
this.updateDuration();
|
|
217
|
+
|
|
218
|
+
// Trigger loadedmetadata event - video metadata loaded
|
|
219
|
+
this.triggerEvent('loadedmetadata', {
|
|
220
|
+
duration: this.getDuration(),
|
|
221
|
+
videoWidth: this.video.videoWidth,
|
|
222
|
+
videoHeight: this.video.videoHeight
|
|
192
223
|
});
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
|
|
225
|
+
// Initialize subtitles after metadata is loaded
|
|
226
|
+
setTimeout(() => {
|
|
227
|
+
this.initializeSubtitles();
|
|
228
|
+
}, 100);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
this.video.addEventListener('loadeddata', () => {
|
|
232
|
+
if (!this.isChangingQuality) {
|
|
233
|
+
this.hideLoading();
|
|
234
|
+
}
|
|
235
|
+
// Trigger loadeddata event - current frame data loaded
|
|
236
|
+
this.triggerEvent('loadeddata', {
|
|
237
|
+
currentTime: this.getCurrentTime()
|
|
197
238
|
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
this.video.addEventListener('canplay', () => {
|
|
242
|
+
if (!this.isChangingQuality) {
|
|
243
|
+
this.hideLoading();
|
|
244
|
+
}
|
|
245
|
+
// Trigger canplay event - video can start playing
|
|
246
|
+
this.triggerEvent('canplay', {
|
|
247
|
+
currentTime: this.getCurrentTime(),
|
|
248
|
+
duration: this.getDuration()
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
this.video.addEventListener('progress', () => {
|
|
253
|
+
this.updateBuffer();
|
|
254
|
+
// Trigger progress event - browser is downloading media
|
|
255
|
+
this.triggerEvent('progress', {
|
|
256
|
+
buffered: this.getBufferedTime(),
|
|
257
|
+
duration: this.getDuration()
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
this.video.addEventListener('durationchange', () => {
|
|
262
|
+
this.updateDuration();
|
|
263
|
+
// Trigger durationchange event - video duration changed
|
|
264
|
+
this.triggerEvent('durationchange', {
|
|
265
|
+
duration: this.getDuration()
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Error events
|
|
270
|
+
this.video.addEventListener('error', (e) => {
|
|
271
|
+
this.onVideoError(e);
|
|
272
|
+
// Trigger error event - media loading/playback error occurred
|
|
273
|
+
this.triggerEvent('error', {
|
|
274
|
+
code: this.video.error?.code,
|
|
275
|
+
message: this.video.error?.message,
|
|
276
|
+
src: this.video.currentSrc || this.video.src
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
this.video.addEventListener('stalled', () => {
|
|
281
|
+
// Trigger stalled event - browser is trying to fetch data but it's not available
|
|
282
|
+
this.triggerEvent('stalled', {
|
|
283
|
+
currentTime: this.getCurrentTime()
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
this.video.addEventListener('timeupdate', () => this.updateProgress());
|
|
289
|
+
|
|
290
|
+
this.video.addEventListener('ended', () => this.onVideoEnded());
|
|
291
|
+
|
|
198
292
|
// Complete video click logic with doubleTapPause support (DESKTOP)
|
|
199
293
|
this.video.addEventListener('click', () => {
|
|
200
294
|
if (!this.options.pauseClick) return;
|
|
@@ -301,6 +395,10 @@
|
|
|
301
395
|
// Mouse events (desktop)
|
|
302
396
|
this.progressContainer.addEventListener('click', (e) => this.seek(e));
|
|
303
397
|
this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
|
|
398
|
+
if (this.progressHandle) {
|
|
399
|
+
this.progressHandle.addEventListener('mousedown', this.startSeeking.bind(this));
|
|
400
|
+
this.progressHandle.addEventListener('touchstart', this.startSeeking.bind(this), { passive: false });
|
|
401
|
+
}
|
|
304
402
|
|
|
305
403
|
// Touch events (mobile)
|
|
306
404
|
this.progressContainer.addEventListener('touchstart', (e) => {
|
package/src/subtitles.js
CHANGED
|
@@ -343,11 +343,11 @@ updateSubtitlesButton() {
|
|
|
343
343
|
var subtitlesBtn = this.controls && this.controls.querySelector('.subtitles-btn');
|
|
344
344
|
if (!subtitlesBtn) return;
|
|
345
345
|
|
|
346
|
+
subtitlesBtn.classList.remove('active');
|
|
347
|
+
|
|
346
348
|
if (this.subtitlesEnabled) {
|
|
347
|
-
subtitlesBtn.classList.add('active');
|
|
348
349
|
subtitlesBtn.title = this.t('subtitlesdisable');
|
|
349
350
|
} else {
|
|
350
|
-
subtitlesBtn.classList.remove('active');
|
|
351
351
|
subtitlesBtn.title = this.t('subtitlesenable');
|
|
352
352
|
}
|
|
353
353
|
}
|
|
@@ -383,14 +383,6 @@ updateSubtitlesUI() {
|
|
|
383
383
|
bindSubtitleEvents() {
|
|
384
384
|
var self = this;
|
|
385
385
|
|
|
386
|
-
var subtitlesBtn = this.controls && this.controls.querySelector('.subtitles-btn');
|
|
387
|
-
if (subtitlesBtn) {
|
|
388
|
-
subtitlesBtn.addEventListener('click', function (e) {
|
|
389
|
-
e.stopPropagation();
|
|
390
|
-
self.toggleSubtitles();
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
|
|
394
386
|
var subtitlesMenu = this.controls && this.controls.querySelector('.subtitles-menu');
|
|
395
387
|
if (subtitlesMenu) {
|
|
396
388
|
subtitlesMenu.addEventListener('click', function (e) {
|
|
@@ -399,6 +391,7 @@ bindSubtitleEvents() {
|
|
|
399
391
|
}
|
|
400
392
|
}
|
|
401
393
|
|
|
394
|
+
|
|
402
395
|
handleSubtitlesMenuClick(e) {
|
|
403
396
|
if (!e.target.classList.contains('subtitles-option')) return;
|
|
404
397
|
|