myetv-player 1.1.1 → 1.1.3

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.
@@ -466,7 +466,6 @@ constructor(videoElement, options = {}) {
466
466
  this.currentQualityIndex = 0;
467
467
  this.qualities = [];
468
468
  this.originalSources = [];
469
- this.setupMenuToggles(); // Initialize menu toggle system
470
469
  this.isPiPSupported = this.checkPiPSupport();
471
470
  this.seekTooltip = null;
472
471
  this.titleOverlay = null;
@@ -578,6 +577,7 @@ constructor(videoElement, options = {}) {
578
577
  this.interceptAutoLoading();
579
578
  this.createPlayerStructure();
580
579
  this.initializeElements();
580
+ this.setupMenuToggles(); // Initialize menu toggle system
581
581
  // audio player adaptation
582
582
  this.adaptToAudioFile = function () {
583
583
  if (this.options.audiofile) {
@@ -1194,74 +1194,84 @@ initializeElements() {
1194
1194
  this.speedMenu = this.controls?.querySelector('.speed-menu');
1195
1195
  this.qualityMenu = this.controls?.querySelector('.quality-menu');
1196
1196
  this.subtitlesMenu = this.controls?.querySelector('.subtitles-menu');
1197
+ // Apply seek handle shape from options
1198
+ if (this.progressHandle && this.options.seekHandleShape) {
1199
+ this.setSeekHandleShape(this.options.seekHandleShape);
1200
+ }
1197
1201
  }
1198
1202
 
1199
1203
  // Generic method to close all active menus (works with plugins too)
1200
1204
  closeAllMenus() {
1201
- // Find all elements with class ending in '-menu' that have 'active' class
1202
- const allMenus = this.controls?.querySelectorAll('[class*="-menu"].active');
1203
- allMenus?.forEach(menu => {
1204
- menu.classList.remove('active');
1205
- });
1205
+ if (!this.controls) return;
1206
1206
 
1207
- // Remove active state from all control buttons
1208
- const allButtons = this.controls?.querySelectorAll('.control-btn.active');
1209
- allButtons?.forEach(btn => {
1210
- btn.classList.remove('active');
1211
- });
1207
+ const menus = this.controls.querySelectorAll('.speed-menu, .quality-menu, .subtitles-menu, .settings-menu');
1208
+ const buttons = this.controls.querySelectorAll('.control-btn');
1209
+
1210
+ menus.forEach(menu => menu.classList.remove('active'));
1211
+ buttons.forEach(btn => btn.classList.remove('active'));
1212
+
1213
+ this.currentOpenMenu = null;
1214
+
1215
+ if (this.options.debug) {
1216
+ console.log('All menus closed');
1217
+ }
1212
1218
  }
1213
1219
 
1214
1220
  // Generic menu toggle setup (works with core menus and plugin menus)
1215
1221
  setupMenuToggles() {
1216
- // Delegate click events to control bar for any button with associated menu
1217
- if (this.controls) {
1218
- this.controls.addEventListener('click', (e) => {
1219
- // Find if clicked element is a control button or inside one
1220
- const button = e.target.closest('.control-btn');
1221
-
1222
- if (!button) return;
1223
-
1224
- // Get button classes to find associated menu
1225
- const buttonClasses = button.className.split(' ');
1226
- let menuClass = null;
1227
-
1228
- // Find if this button has an associated menu (e.g., speed-btn -> speed-menu)
1229
- for (const cls of buttonClasses) {
1230
- if (cls.endsWith('-btn')) {
1231
- const menuName = cls.replace('-btn', '-menu');
1232
- const menu = this.controls.querySelector('.' + menuName);
1233
- if (menu) {
1234
- menuClass = menuName;
1235
- break;
1236
- }
1237
- }
1222
+ if (!this.controls) return;
1223
+
1224
+ this.currentOpenMenu = null;
1225
+
1226
+ this.controls.addEventListener('click', (e) => {
1227
+ const button = e.target.closest('.control-btn');
1228
+ if (!button) return;
1229
+
1230
+ const buttonClasses = Array.from(button.classList);
1231
+ let menuElement = null;
1232
+
1233
+ for (const cls of buttonClasses) {
1234
+ if (cls.endsWith('-btn')) {
1235
+ const menuClass = cls.replace('-btn', '-menu');
1236
+ menuElement = this.controls.querySelector(`.${menuClass}`);
1237
+ if (menuElement) break;
1238
1238
  }
1239
+ }
1239
1240
 
1240
- if (!menuClass) return;
1241
+ if (!menuElement) return;
1241
1242
 
1242
- e.stopPropagation();
1243
+ e.stopPropagation();
1244
+ e.preventDefault();
1243
1245
 
1244
- // Get the menu element
1245
- const menu = this.controls.querySelector('.' + menuClass);
1246
- const isOpen = menu.classList.contains('active');
1246
+ const isOpen = menuElement.classList.contains('active');
1247
1247
 
1248
- // Close all menus first
1249
- this.closeAllMenus();
1248
+ this.closeAllMenus();
1250
1249
 
1251
- // If menu was closed, open it
1252
- if (!isOpen) {
1253
- menu.classList.add('active');
1254
- button.classList.add('active');
1250
+ if (!isOpen) {
1251
+ menuElement.classList.add('active');
1252
+ button.classList.add('active');
1253
+ this.currentOpenMenu = menuElement;
1254
+ if (this.options.debug) {
1255
+ console.log('Menu opened:', menuElement.className);
1255
1256
  }
1256
- });
1257
- }
1257
+ } else {
1258
+ this.currentOpenMenu = null;
1259
+ if (this.options.debug) {
1260
+ console.log('Menu closed:', menuElement.className);
1261
+ }
1262
+ }
1263
+ });
1258
1264
 
1259
- // Close menus when clicking outside controls
1260
1265
  document.addEventListener('click', (e) => {
1261
- if (!this.controls?.contains(e.target)) {
1266
+ if (!this.controls) return;
1267
+ if (!this.controls.contains(e.target)) {
1262
1268
  this.closeAllMenus();
1263
1269
  }
1264
1270
  });
1271
+
1272
+ if (this.options.debug) {
1273
+ console.log('✅ Menu toggle system initialized (click-based, auto-close)');
1274
+ }
1265
1275
  }
1266
1276
 
1267
1277
  updateVolumeSliderVisual() {
@@ -1572,9 +1582,11 @@ updateBuffer() {
1572
1582
  }
1573
1583
 
1574
1584
  startSeeking(e) {
1585
+ if (e.cancelable) e.preventDefault();
1575
1586
  if (this.isChangingQuality) return;
1576
1587
 
1577
1588
  this.isUserSeeking = true;
1589
+ this.progressContainer.classList.add('seeking');
1578
1590
  this.seek(e);
1579
1591
  e.preventDefault();
1580
1592
 
@@ -1586,6 +1598,7 @@ startSeeking(e) {
1586
1598
  }
1587
1599
 
1588
1600
  continueSeeking(e) {
1601
+ if (e.cancelable) e.preventDefault();
1589
1602
  if (this.isUserSeeking && !this.isChangingQuality) {
1590
1603
  this.seek(e);
1591
1604
  }
@@ -1593,9 +1606,13 @@ continueSeeking(e) {
1593
1606
 
1594
1607
  endSeeking() {
1595
1608
  this.isUserSeeking = false;
1609
+ this.progressContainer.classList.remove('seeking');
1596
1610
  }
1597
1611
 
1598
1612
  seek(e) {
1613
+ if (e.cancelable) {
1614
+ e.preventDefault();
1615
+ }
1599
1616
  if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
1600
1617
 
1601
1618
  const rect = this.progressContainer.getBoundingClientRect();
@@ -2016,7 +2033,7 @@ bindPosterEvents() {
2016
2033
  // Hide poster when video is loading/playing
2017
2034
  this.video.addEventListener('playing', () => {
2018
2035
  this.hidePoster();
2019
- });
2036
+ });
2020
2037
 
2021
2038
  // Show poster on load if not autoplay
2022
2039
  if (!this.options.autoplay) {
@@ -2460,6 +2477,7 @@ addEventListener(eventType, callback) {
2460
2477
  // Playback events
2461
2478
  this.video.addEventListener('playing', () => {
2462
2479
  this.hideLoading();
2480
+ this.closeAllMenus();
2463
2481
  // Trigger playing event - video is now actually playing
2464
2482
  this.triggerEvent('playing', {
2465
2483
  currentTime: this.getCurrentTime(),
@@ -2684,6 +2702,10 @@ addEventListener(eventType, callback) {
2684
2702
  // Mouse events (desktop)
2685
2703
  this.progressContainer.addEventListener('click', (e) => this.seek(e));
2686
2704
  this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
2705
+ if (this.progressHandle) {
2706
+ this.progressHandle.addEventListener('mousedown', this.startSeeking.bind(this));
2707
+ this.progressHandle.addEventListener('touchstart', this.startSeeking.bind(this), { passive: false });
2708
+ }
2687
2709
 
2688
2710
  // Touch events (mobile)
2689
2711
  this.progressContainer.addEventListener('touchstart', (e) => {
@@ -3106,13 +3128,13 @@ createControls() {
3106
3128
  const controlsHTML = `
3107
3129
  <div class="controls" id="${controlsId}">
3108
3130
  <div class="progress-container">
3109
- <div class="progress-bar">
3110
- <div class="progress-buffer"></div>
3111
- <div class="progress-filled"></div>
3112
- <div class="progress-handle progress-handle-${this.options.seekHandleShape}"></div>
3113
- </div>
3114
- ${this.options.showSeekTooltip ? '<div class="seek-tooltip">0:00</div>' : ''}
3115
- </div>
3131
+ <div class="progress-bar">
3132
+ <div class="progress-buffer"></div>
3133
+ <div class="progress-filled"></div>
3134
+ </div>
3135
+ <div class="progress-handle progress-handle-${this.options.seekHandleShape}"></div> <!-- ✅ Fuori da progress-bar -->
3136
+ ${this.options.showSeekTooltip ? '<div class="seek-tooltip">0:00</div>' : ''}
3137
+ </div>
3116
3138
 
3117
3139
  <div class="controls-main">
3118
3140
  <div class="controls-left">
@@ -4805,10 +4827,10 @@ createCustomSubtitleOverlay() {
4805
4827
  'bottom: 80px;' +
4806
4828
  'left: 50%;' +
4807
4829
  'transform: translateX(-50%);' +
4808
- 'z-index: 5;' +
4830
+ 'z-index: 999;' +
4809
4831
  'color: white;' +
4810
4832
  'font-family: Arial, sans-serif;' +
4811
- 'font-size: clamp(12px, 4vw, 18px);' + // RESPONSIVE font-size
4833
+ 'font-size: clamp(12px, 4vw, 18px);' +
4812
4834
  'font-weight: bold;' +
4813
4835
  'text-align: center;' +
4814
4836
  'text-shadow: 2px 2px 4px rgba(0, 0, 0, 1);' +
@@ -4835,52 +4857,29 @@ createCustomSubtitleOverlay() {
4835
4857
  if (this.options.debug) console.log('✅ Custom subtitle overlay created with responsive settings');
4836
4858
  }
4837
4859
 
4838
- loadCustomSubtitleTracks() {
4839
- var self = this;
4840
- var trackElements = document.querySelectorAll('track[kind="subtitles"], track[kind="captions"]');
4841
- var loadPromises = [];
4842
-
4843
- if (this.options.debug) console.log('📥 Loading ' + trackElements.length + ' subtitle files...');
4844
-
4845
- for (var i = 0; i < trackElements.length; i++) {
4846
- var track = trackElements[i];
4847
-
4848
- (function (trackElement, index) {
4849
- var promise = fetch(trackElement.src)
4850
- .then(function (response) {
4851
- return response.text();
4852
- })
4853
- .then(function (srtText) {
4854
- var subtitles = self.parseCustomSRT(srtText);
4855
- self.customSubtitles.push({
4856
- label: trackElement.label || 'Track ' + (index + 1),
4857
- language: trackElement.srclang || 'unknown',
4858
- subtitles: subtitles
4859
- });
4860
+ customTimeToSeconds(timeString) {
4861
+ if (!timeString) return 0;
4860
4862
 
4861
- if (self.options.debug) {
4862
- console.log('✅ Loaded: ' + trackElement.label + ' (' + subtitles.length + ' subtitles)');
4863
- }
4864
- })
4865
- .catch(function (error) {
4866
- if (self.options.debug) {
4867
- console.error('❌ Error loading ' + trackElement.src + ':', error);
4868
- }
4869
- });
4863
+ var parts = timeString.split(',');
4864
+ if (parts.length !== 2) return 0;
4870
4865
 
4871
- loadPromises.push(promise);
4872
- })(track, i);
4873
- }
4866
+ var time = parts[0];
4867
+ var millis = parts[1];
4874
4868
 
4875
- Promise.all(loadPromises).then(function () {
4876
- if (self.options.debug && self.customSubtitles.length > 0) {
4877
- console.log('✅ All custom subtitle tracks loaded');
4878
- }
4869
+ var timeParts = time.split(':');
4870
+ if (timeParts.length !== 3) return 0;
4879
4871
 
4880
- if (self.options.debug) {
4881
- console.log('📝 Subtitles loaded but NOT auto-enabled - user must activate manually');
4882
- }
4883
- });
4872
+ var hours = parseInt(timeParts[0], 10);
4873
+ var minutes = parseInt(timeParts[1], 10);
4874
+ var seconds = parseInt(timeParts[2], 10);
4875
+ var milliseconds = parseInt(millis, 10);
4876
+
4877
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) || isNaN(milliseconds)) {
4878
+ console.error('❌ customTimeToSeconds failed for:', timeString);
4879
+ return 0;
4880
+ }
4881
+
4882
+ return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000;
4884
4883
  }
4885
4884
 
4886
4885
  parseCustomSRT(srtText) {
@@ -4899,9 +4898,9 @@ parseCustomSRT(srtText) {
4899
4898
  if (timeMatch) {
4900
4899
  var startTime = this.customTimeToSeconds(timeMatch[1]);
4901
4900
  var endTime = this.customTimeToSeconds(timeMatch[2]);
4902
- var text = this.sanitizeSubtitleText(lines.slice(2).join('\n').trim());
4901
+ var text = lines.slice(2).join('\n').trim().replace(/<[^>]*>/g, '');
4903
4902
 
4904
- if (text.length > 0 && startTime < endTime) {
4903
+ if (text && text.length > 0 && startTime < endTime) {
4905
4904
  subtitles.push({
4906
4905
  start: startTime,
4907
4906
  end: endTime,
@@ -4912,20 +4911,97 @@ parseCustomSRT(srtText) {
4912
4911
  }
4913
4912
  }
4914
4913
 
4914
+ if (this.options.debug) console.log('✅ Parsed ' + subtitles.length + ' subtitles');
4915
4915
  return subtitles;
4916
4916
  }
4917
4917
 
4918
- customTimeToSeconds(timeString) {
4919
- var parts = timeString.split(',');
4920
- var time = parts[0];
4921
- var millis = parts[1];
4922
- var timeParts = time.split(':');
4923
- var hours = parseInt(timeParts[0], 10);
4924
- var minutes = parseInt(timeParts[1], 10);
4925
- var seconds = parseInt(timeParts[2], 10);
4926
- var milliseconds = parseInt(millis, 10);
4918
+ loadCustomSubtitleTracks() {
4919
+ var self = this;
4920
+ var tracks = this.video.querySelectorAll('track[kind="subtitles"]');
4921
+ if (tracks.length === 0) return;
4922
+
4923
+ tracks.forEach(function (track, index) {
4924
+ var src = track.getAttribute('src');
4925
+ var label = track.getAttribute('label') || 'Unknown';
4926
+ var srclang = track.getAttribute('srclang') || '';
4927
+
4928
+ // CREA L'OGGETTO PRIMA E AGGIUNGILO SUBITO
4929
+ var trackObj = {
4930
+ label: label,
4931
+ language: srclang,
4932
+ subtitles: [],
4933
+ trackIndex: index
4934
+ };
4935
+ self.customSubtitles.push(trackObj);
4936
+
4937
+ fetch(src)
4938
+ .then(function (response) {
4939
+ return response.text();
4940
+ })
4941
+ .then(function (srtText) {
4942
+ var normalizedText = srtText.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
4943
+ var blocks = normalizedText.trim().split('\n\n');
4944
+
4945
+ for (var i = 0; i < blocks.length; i++) {
4946
+ var block = blocks[i].trim();
4947
+ if (!block) continue;
4948
+ var lines = block.split('\n');
4949
+
4950
+ if (lines.length >= 3) {
4951
+ var timeLine = lines[1].trim();
4952
+ var timeMatch = timeLine.match(/(\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3})/);
4953
+
4954
+ if (timeMatch) {
4955
+ var startParts = timeMatch[1].split(',');
4956
+ var startTimeParts = startParts[0].split(':');
4957
+ var startTime = parseInt(startTimeParts[0], 10) * 3600 + parseInt(startTimeParts[1], 10) * 60 + parseInt(startTimeParts[2], 10) + parseInt(startParts[1], 10) / 1000;
4958
+
4959
+ var endParts = timeMatch[2].split(',');
4960
+ var endTimeParts = endParts[0].split(':');
4961
+ var endTime = parseInt(endTimeParts[0], 10) * 3600 + parseInt(endTimeParts[1], 10) * 60 + parseInt(endTimeParts[2], 10) + parseInt(endParts[1], 10) / 1000;
4962
+
4963
+ var text = lines.slice(2).join('\n').trim().replace(/<[^>]*>/g, '');
4964
+
4965
+ if (text && text.length > 0 && !isNaN(startTime) && !isNaN(endTime) && startTime < endTime) {
4966
+ trackObj.subtitles.push({
4967
+ start: startTime,
4968
+ end: endTime,
4969
+ text: text
4970
+ });
4971
+ }
4972
+ }
4973
+ }
4974
+ }
4927
4975
 
4928
- return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000;
4976
+ if (self.options.debug) {
4977
+ console.log('✅ Loaded ' + trackObj.subtitles.length + ' subtitles for ' + label);
4978
+ }
4979
+ })
4980
+ .catch(function (error) {
4981
+ console.error('❌ Error loading ' + label + ':', error);
4982
+ });
4983
+ });
4984
+ }
4985
+
4986
+ sanitizeSubtitleText(text) {
4987
+ if (!text) return '';
4988
+
4989
+ // Remove HTML tags
4990
+ var sanitized = text.replace(/<[^>]*>/g, '');
4991
+
4992
+ // Remove styling tags common in SRT files
4993
+ sanitized = sanitized.replace(/{\\.*?}/g, '');
4994
+ sanitized = sanitized.replace(/\\N/g, '\n');
4995
+
4996
+ // Clean up multiple spaces
4997
+ sanitized = sanitized.replace(/\s+/g, ' ').trim();
4998
+
4999
+ // Decode HTML entities if present
5000
+ var tempDiv = document.createElement('div');
5001
+ tempDiv.innerHTML = sanitized;
5002
+ sanitized = tempDiv.textContent || tempDiv.innerText || sanitized;
5003
+
5004
+ return sanitized;
4929
5005
  }
4930
5006
 
4931
5007
  enableCustomSubtitleTrack(trackIndex) {
@@ -5018,28 +5094,39 @@ detectTextTracks() {
5018
5094
  enableSubtitleTrack(trackIndex) {
5019
5095
  if (trackIndex < 0 || trackIndex >= this.textTracks.length) return;
5020
5096
 
5097
+ // Disable all tracks first
5021
5098
  this.disableAllTracks();
5022
5099
 
5100
+ // Enable ONLY the custom subtitle system (not native browser)
5023
5101
  var success = this.enableCustomSubtitleTrack(trackIndex);
5024
5102
 
5025
5103
  if (success) {
5026
5104
  this.currentSubtitleTrack = this.textTracks[trackIndex].track;
5027
5105
  this.subtitlesEnabled = true;
5028
5106
 
5107
+ // Make sure native tracks stay DISABLED
5108
+ if (this.video.textTracks && this.video.textTracks[trackIndex]) {
5109
+ this.video.textTracks[trackIndex].mode = 'disabled'; // Keep native disabled
5110
+ }
5111
+
5029
5112
  this.updateSubtitlesButton();
5030
5113
  this.populateSubtitlesMenu();
5031
5114
 
5032
5115
  if (this.options.debug) {
5033
- console.log('✅ Subtitles enabled: ' + this.textTracks[trackIndex].label);
5116
+ console.log('✅ Custom subtitles enabled:', this.textTracks[trackIndex].label);
5034
5117
  }
5035
5118
 
5036
- // Trigger evento
5119
+ // Trigger subtitle change event
5037
5120
  this.triggerEvent('subtitlechange', {
5038
5121
  enabled: true,
5039
5122
  trackIndex: trackIndex,
5040
5123
  trackLabel: this.textTracks[trackIndex].label,
5041
5124
  trackLanguage: this.textTracks[trackIndex].language
5042
5125
  });
5126
+ } else {
5127
+ if (this.options.debug) {
5128
+ console.error('❌ Failed to enable custom subtitles for track', trackIndex);
5129
+ }
5043
5130
  }
5044
5131
  }
5045
5132
 
@@ -5062,11 +5149,15 @@ disableSubtitles() {
5062
5149
  }
5063
5150
 
5064
5151
  disableAllTracks() {
5065
- if (this.video.textTracks) {
5066
- for (var i = 0; i < this.video.textTracks.length; i++) {
5067
- this.video.textTracks[i].mode = 'hidden';
5068
- }
5152
+ if (!this.video || !this.video.textTracks) return;
5153
+
5154
+ // Disable all native tracks
5155
+ for (var i = 0; i < this.video.textTracks.length; i++) {
5156
+ this.video.textTracks[i].mode = 'hidden';
5069
5157
  }
5158
+
5159
+ // Also disable custom subtitles
5160
+ this.disableCustomSubtitles();
5070
5161
  }
5071
5162
 
5072
5163
  getAvailableSubtitles() {
@@ -5107,11 +5198,11 @@ updateSubtitlesButton() {
5107
5198
  var subtitlesBtn = this.controls && this.controls.querySelector('.subtitles-btn');
5108
5199
  if (!subtitlesBtn) return;
5109
5200
 
5201
+ subtitlesBtn.classList.remove('active');
5202
+
5110
5203
  if (this.subtitlesEnabled) {
5111
- subtitlesBtn.classList.add('active');
5112
5204
  subtitlesBtn.title = this.t('subtitlesdisable');
5113
5205
  } else {
5114
- subtitlesBtn.classList.remove('active');
5115
5206
  subtitlesBtn.title = this.t('subtitlesenable');
5116
5207
  }
5117
5208
  }
@@ -5147,32 +5238,61 @@ updateSubtitlesUI() {
5147
5238
  bindSubtitleEvents() {
5148
5239
  var self = this;
5149
5240
 
5150
- var subtitlesBtn = this.controls && this.controls.querySelector('.subtitles-btn');
5151
- if (subtitlesBtn) {
5152
- subtitlesBtn.addEventListener('click', function (e) {
5153
- e.stopPropagation();
5154
- self.toggleSubtitles();
5241
+ if (this.video.textTracks) {
5242
+ this.isChangingSubtitles = false; // flag to prevent loops
5243
+
5244
+ this.video.textTracks.addEventListener('change', function () {
5245
+ // ignore changes initiated by the player itself
5246
+ if (self.isChangingSubtitles) {
5247
+ return;
5248
+ }
5249
+
5250
+ // only update ui
5251
+ self.updateSubtitlesUI();
5155
5252
  });
5156
5253
  }
5157
5254
 
5255
+ // Add timeupdate listener for custom subtitle display
5256
+ this.video.addEventListener('timeupdate', () => {
5257
+ if (this.customSubtitlesEnabled) {
5258
+ this.updateCustomSubtitleDisplay();
5259
+ }
5260
+ });
5261
+
5262
+ // Menu click events
5158
5263
  var subtitlesMenu = this.controls && this.controls.querySelector('.subtitles-menu');
5159
5264
  if (subtitlesMenu) {
5160
5265
  subtitlesMenu.addEventListener('click', function (e) {
5161
- self.handleSubtitlesMenuClick(e);
5266
+ var option = e.target.closest('.subtitles-option');
5267
+ if (!option) return;
5268
+
5269
+ self.isChangingSubtitles = true; // active flag
5270
+
5271
+ var trackIndex = option.getAttribute('data-track');
5272
+ if (trackIndex === 'off') {
5273
+ self.disableSubtitles();
5274
+ } else {
5275
+ self.enableSubtitleTrack(parseInt(trackIndex));
5276
+ }
5277
+
5278
+ setTimeout(function () {
5279
+ self.isChangingSubtitles = false; // disable flag
5280
+ }, 100);
5162
5281
  });
5163
5282
  }
5164
5283
  }
5165
5284
 
5166
5285
  handleSubtitlesMenuClick(e) {
5167
- if (!e.target.classList.contains('subtitles-option')) return;
5286
+ var option = e.target.closest('.subtitles-option');
5287
+ if (!option) return; // This prevents button clicks from toggling
5168
5288
 
5169
- var trackData = e.target.getAttribute('data-track');
5289
+ var trackIndex = option.getAttribute('data-track');
5170
5290
 
5171
- if (trackData === 'off') {
5291
+ if (trackIndex === 'off') {
5172
5292
  this.disableSubtitles();
5173
5293
  } else {
5174
- var trackIndex = parseInt(trackData, 10);
5175
- this.enableSubtitleTrack(trackIndex);
5294
+ // Don't check for 'toggle' - just enable the track
5295
+ this.enableSubtitleTrack(parseInt(trackIndex));
5176
5296
  }
5177
5297
 
5178
5298
  this.updateSubtitlesButton();