bep40 commited on
Commit
79e6720
·
verified ·
1 Parent(s): 4937047

Upload static/match_detail.js

Browse files
Files changed (1) hide show
  1. static/match_detail.js +34 -25
static/match_detail.js CHANGED
@@ -1,5 +1,5 @@
1
  // === VNEWS — Match Detail UI ===
2
- // Fetches & renders match detail (preview, lineups, H2H, overlay stats) from bongda.com.vn
3
  // Loaded after app_v2.js; extends the match overlay with a "Chi tiết" tab.
4
 
5
  (function(){
@@ -8,10 +8,9 @@
8
  const s = document.createElement('style');
9
  s.id = 'match-detail-css';
10
  s.textContent = `
11
- .mo-tab-detail {
12
-
13
- }
14
- .md-loading{display:flex;align-items:center;justify-content:center;padding:30px;color:#888;font-size:12px}
15
  .md-section{margin-bottom:16px}
16
  .md-section-title{font-size:13px;font-weight:800;color:#5cb87a;margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid #2a2a2a;display:flex;align-items:center;gap:6px}
17
  .md-preview-text{font-size:13px;color:#ccc;line-height:1.6;white-space:pre-wrap;background:#1a1a1a;border-radius:8px;padding:12px;border-left:3px solid #2d8659}
@@ -30,35 +29,49 @@
30
  .md-h2h-away{text-align:left;flex:1}
31
  .md-h2h-score{font-size:13px;font-weight:800;color:#f0c040;min-width:40px;text-align:center}
32
  .md-h2h-live{color:#e74c3c;font-size:9px;font-weight:700}
33
- .md-no-data{color:#777;font-size:12px;padding:20px;text-align:center}
 
 
 
 
 
 
 
 
34
  `;
35
  document.head.appendChild(s);
36
 
 
 
37
  // Store original loadMatchTab
38
  const _origLoadMatchTab = window.loadMatchTab;
39
 
40
  // Override loadMatchTab to handle detail tab
41
  window.loadMatchTab = async function(tab){
42
  if(tab === 'detail'){
43
- // Activate detail tab UI
44
  document.querySelectorAll('.mo-tab').forEach(t=>t.classList.remove('active'));
45
  document.querySelectorAll('.mo-tab').forEach(t=>{
46
  if(t.textContent.includes('Chi tiết') || t.textContent.includes('Detail')) t.classList.add('active');
47
  });
48
  const el = document.getElementById('mo-body');
49
  if(!el) return;
50
- el.innerHTML = '<div class="md-loading"> Đang tải chi tiết trận đấu...</div>';
51
  try{
52
  const eventId = window._currentEventId;
53
- if(!eventId){ el.innerHTML = '<div class="md-no-data">Không tìm thấy mã trận đấu</div>'; return; }
 
 
 
 
54
  const r = await fetch(`/api/match/${eventId}/detail`);
 
55
  const d = await r.json();
56
  renderMatchDetail(el, d);
57
  }catch(e){
58
- el.innerHTML = '<div class="md-no-data">Lỗi tải chi tiết: ' + esc(e.message) + '</div>';
 
59
  }
60
  } else {
61
- // Call original for comm/stats tabs
62
  _origLoadMatchTab(tab);
63
  }
64
  };
@@ -70,11 +83,11 @@
70
  if(data.commentaries_html && data.commentaries_html.length > 10){
71
  h += '<div class="md-section">';
72
  h += '<div class="md-section-title">📋 Thông tin trận đấu</div>';
73
- // Clean up the HTML - remove ads, scripts, iframes
74
  let cleanHtml = data.commentaries_html
75
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
76
  .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
77
  .replace(/<ins[^>]*>.*?<\/ins>/gi, '')
 
78
  .replace(/style="[^"]*display:\s*none[^"]*"/gi, 'style="display:none"');
79
  h += '<div class="md-preview-container">' + cleanHtml + '</div>';
80
  h += '</div>';
@@ -92,7 +105,8 @@
92
  let cleanLineups = data.lineups_html
93
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
94
  .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
95
- .replace(/<ins[^>]*>.*?<\/ins>/gi, '');
 
96
  h += '<div class="md-lineups-container">' + cleanLineups + '</div>';
97
  h += '</div>';
98
  } else if(data.lineups && (data.lineups.home_players || data.lineups.away_players)){
@@ -108,7 +122,8 @@
108
  h += '<div class="md-section-title">🔄 Đối đầu (H2H)</div>';
109
  let cleanH2h = data.h2h_html
110
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
111
- .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '');
 
112
  h += '<div class="md-h2h-container">' + cleanH2h + '</div>';
113
  h += '</div>';
114
  } else if(data.h2h && data.h2h.length > 0){
@@ -124,7 +139,8 @@
124
  h += '<div class="md-section-title">📊 Thống kê</div>';
125
  let cleanStats = data.stats_html
126
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
127
- .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '');
 
128
  h += '<div class="md-stats-container">' + cleanStats + '</div>';
129
  h += '</div>';
130
  }
@@ -142,17 +158,15 @@
142
  }
143
 
144
  if(!h){
145
- h = '<div class="md-no-data">Chưa có chi tiết cho trận đấu này.<br><small style="color:#666">Dữ liệu sẽ cập nhật khi giải khởi tranh.</small></div>';
146
  }
147
 
148
  el.innerHTML = h;
149
- // Prevent link navigation inside overlay
150
  el.querySelectorAll('a').forEach(a=>a.addEventListener('click', e=>e.preventDefault()));
151
  }
152
 
153
  function renderLineups(lineups){
154
  let h = '<div class="md-lineups">';
155
- // Home team
156
  h += '<div class="md-team-box">';
157
  h += '<div class="md-team-name">' + esc(lineups.home_team || 'Đội nhà') + '</div>';
158
  if(lineups.home_formation) h += '<div class="md-formation">Đội hình: ' + esc(lineups.home_formation) + '</div>';
@@ -168,7 +182,6 @@
168
  });
169
  }
170
  h += '</div>';
171
- // Away team
172
  h += '<div class="md-team-box">';
173
  h += '<div class="md-team-name">' + esc(lineups.away_team || 'Đội khách') + '</div>';
174
  if(lineups.away_formation) h += '<div class="md-formation">Đội hình: ' + esc(lineups.away_formation) + '</div>';
@@ -207,23 +220,20 @@
207
 
208
  // Add the "Chi tiết" tab to the match overlay
209
  function injectDetailTab(){
210
- // Wait for overlay to exist
211
  const check = setInterval(()=>{
212
  const tabsContainer = document.querySelector('.mo-tabs');
213
  if(tabsContainer && !document.querySelector('.mo-tab-detail')){
214
- // Remove existing detail tab if any (old)
215
  const existing = document.querySelector('.mo-tab-detail');
216
  if(existing) existing.remove();
217
- // Add new tab
218
  const detailTab = document.createElement('span');
219
  detailTab.className = 'mo-tab mo-tab-detail';
220
  detailTab.textContent = '📋 Chi tiết';
221
  detailTab.onclick = ()=>window.loadMatchTab('detail');
222
- tabsContainer.appendChild(detailTab);
 
223
  clearInterval(check);
224
  }
225
  }, 500);
226
- // Stop checking after 30s
227
  setTimeout(()=>clearInterval(check), 30000);
228
  }
229
 
@@ -236,7 +246,6 @@
236
  };
237
  }
238
 
239
- // Also inject on DOM ready
240
  if(document.readyState === 'loading'){
241
  document.addEventListener('DOMContentLoaded', ()=>setTimeout(injectDetailTab, 1000));
242
  } else {
 
1
  // === VNEWS — Match Detail UI ===
2
+ // Fetches & renders match detail (preview, lineups, H2H, stats) from bongda.com.vn
3
  // Loaded after app_v2.js; extends the match overlay with a "Chi tiết" tab.
4
 
5
  (function(){
 
8
  const s = document.createElement('style');
9
  s.id = 'match-detail-css';
10
  s.textContent = `
11
+ .md-loading{display:flex;align-items:center;justify-content:center;padding:30px;color:#888;font-size:12px;flex-direction:column;gap:8px}
12
+ .md-spinner{width:24px;height:24px;border:3px solid #333;border-top-color:#5cb87a;border-radius:50%;animation:md-spin .8s linear infinite}
13
+ @keyframes md-spin{to{transform:rotate(360deg)}}
 
14
  .md-section{margin-bottom:16px}
15
  .md-section-title{font-size:13px;font-weight:800;color:#5cb87a;margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid #2a2a2a;display:flex;align-items:center;gap:6px}
16
  .md-preview-text{font-size:13px;color:#ccc;line-height:1.6;white-space:pre-wrap;background:#1a1a1a;border-radius:8px;padding:12px;border-left:3px solid #2d8659}
 
29
  .md-h2h-away{text-align:left;flex:1}
30
  .md-h2h-score{font-size:13px;font-weight:800;color:#f0c040;min-width:40px;text-align:center}
31
  .md-h2h-live{color:#e74c3c;font-size:9px;font-weight:700}
32
+ .md-no-data{color:#777;font-size:12px;padding:20px;text-align:center;line-height:1.6}
33
+ .md-preview-container{font-size:13px;color:#ccc;line-height.6}
34
+ .md-preview-container img{max-width:100%;border-radius:6px;margin:8px 0}
35
+ .md-preview-container p{margin-bottom:8px}
36
+ .md-preview-container h2,.md-preview-container h3{color:#eee;margin:12px 0 6px}
37
+ .md-lineups-container,.md-h2h-container,.md-stats-container{font-size:12px;color:#ccc}
38
+ .md-lineups-container table,.md-h2h-container table,.md-stats-container table{width:100%;border-collapse:collapse}
39
+ .md-lineups-container td,.md-h2h-container td,.md-stats-container td{padding:4px 6px;border-bottom:1px solid #1a1a1a}
40
+ .md-lineups-container tr:hover,.md-h2h-container tr:hover{background:#1a2a1f}
41
  `;
42
  document.head.appendChild(s);
43
 
44
+ function esc(s){return String(s||'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]))}
45
+
46
  // Store original loadMatchTab
47
  const _origLoadMatchTab = window.loadMatchTab;
48
 
49
  // Override loadMatchTab to handle detail tab
50
  window.loadMatchTab = async function(tab){
51
  if(tab === 'detail'){
 
52
  document.querySelectorAll('.mo-tab').forEach(t=>t.classList.remove('active'));
53
  document.querySelectorAll('.mo-tab').forEach(t=>{
54
  if(t.textContent.includes('Chi tiết') || t.textContent.includes('Detail')) t.classList.add('active');
55
  });
56
  const el = document.getElementById('mo-body');
57
  if(!el) return;
58
+ el.innerHTML = '<div class="md-loading"><div class="md-spinner"></div>Đang tải chi tiết trận đấu...</div>';
59
  try{
60
  const eventId = window._currentEventId;
61
+ if(!eventId){
62
+ // Try to extract from overlay title or page
63
+ el.innerHTML = '<div class="md-no-data">⚠️ Không tìm thấy mã trận đấu.<br><small>Vui lòng đóng và mở lại từ danh sách livescore.</small></div>';
64
+ return;
65
+ }
66
  const r = await fetch(`/api/match/${eventId}/detail`);
67
+ if(!r.ok){ throw new Error('HTTP ' + r.status); }
68
  const d = await r.json();
69
  renderMatchDetail(el, d);
70
  }catch(e){
71
+ console.error('Match detail error:', e);
72
+ el.innerHTML = '<div class="md-no-data">⚠️ Lỗi tải chi tiết: ' + esc(e.message) + '<br><small>Vui lòng thử lại sau hoặc chuyển sang tab "Diễn biến".</small></div>';
73
  }
74
  } else {
 
75
  _origLoadMatchTab(tab);
76
  }
77
  };
 
83
  if(data.commentaries_html && data.commentaries_html.length > 10){
84
  h += '<div class="md-section">';
85
  h += '<div class="md-section-title">📋 Thông tin trận đấu</div>';
 
86
  let cleanHtml = data.commentaries_html
87
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
88
  .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
89
  .replace(/<ins[^>]*>.*?<\/ins>/gi, '')
90
+ .replace(/<style[^>]*>.*?<\/style>/gi, '')
91
  .replace(/style="[^"]*display:\s*none[^"]*"/gi, 'style="display:none"');
92
  h += '<div class="md-preview-container">' + cleanHtml + '</div>';
93
  h += '</div>';
 
105
  let cleanLineups = data.lineups_html
106
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
107
  .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
108
+ .replace(/<ins[^>]*>.*?<\/ins>/gi, '')
109
+ .replace(/<style[^>]*>.*?<\/style>/gi, '');
110
  h += '<div class="md-lineups-container">' + cleanLineups + '</div>';
111
  h += '</div>';
112
  } else if(data.lineups && (data.lineups.home_players || data.lineups.away_players)){
 
122
  h += '<div class="md-section-title">🔄 Đối đầu (H2H)</div>';
123
  let cleanH2h = data.h2h_html
124
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
125
+ .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
126
+ .replace(/<style[^>]*>.*?<\/style>/gi, '');
127
  h += '<div class="md-h2h-container">' + cleanH2h + '</div>';
128
  h += '</div>';
129
  } else if(data.h2h && data.h2h.length > 0){
 
139
  h += '<div class="md-section-title">📊 Thống kê</div>';
140
  let cleanStats = data.stats_html
141
  .replace(/<script[^>]*>.*?<\/script>/gi, '')
142
+ .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
143
+ .replace(/<style[^>]*>.*?<\/style>/gi, '');
144
  h += '<div class="md-stats-container">' + cleanStats + '</div>';
145
  h += '</div>';
146
  }
 
158
  }
159
 
160
  if(!h){
161
+ h = '<div class="md-no-data">Chưa có chi tiết cho trận đấu này.<br><small style="color:#666">Dữ liệu sẽ cập nhật khi giải khởi tranh hoặc trận đấu bắt đầu.</small><br><br><button onclick="window.loadMatchTab(\'comm\')" style="background:#2d8659;border:0;color:#fff;padding:8px 16px;border-radius:8px;font-size:11px;cursor:pointer">Xem Diễn biến</button></div>';
162
  }
163
 
164
  el.innerHTML = h;
 
165
  el.querySelectorAll('a').forEach(a=>a.addEventListener('click', e=>e.preventDefault()));
166
  }
167
 
168
  function renderLineups(lineups){
169
  let h = '<div class="md-lineups">';
 
170
  h += '<div class="md-team-box">';
171
  h += '<div class="md-team-name">' + esc(lineups.home_team || 'Đội nhà') + '</div>';
172
  if(lineups.home_formation) h += '<div class="md-formation">Đội hình: ' + esc(lineups.home_formation) + '</div>';
 
182
  });
183
  }
184
  h += '</div>';
 
185
  h += '<div class="md-team-box">';
186
  h += '<div class="md-team-name">' + esc(lineups.away_team || 'Đội khách') + '</div>';
187
  if(lineups.away_formation) h += '<div class="md-formation">Đội hình: ' + esc(lineups.away_formation) + '</div>';
 
220
 
221
  // Add the "Chi tiết" tab to the match overlay
222
  function injectDetailTab(){
 
223
  const check = setInterval(()=>{
224
  const tabsContainer = document.querySelector('.mo-tabs');
225
  if(tabsContainer && !document.querySelector('.mo-tab-detail')){
 
226
  const existing = document.querySelector('.mo-tab-detail');
227
  if(existing) existing.remove();
 
228
  const detailTab = document.createElement('span');
229
  detailTab.className = 'mo-tab mo-tab-detail';
230
  detailTab.textContent = '📋 Chi tiết';
231
  detailTab.onclick = ()=>window.loadMatchTab('detail');
232
+ // Insert as first tab
233
+ tabsContainer.insertBefore(detailTab, tabsContainer.firstChild);
234
  clearInterval(check);
235
  }
236
  }, 500);
 
237
  setTimeout(()=>clearInterval(check), 30000);
238
  }
239
 
 
246
  };
247
  }
248
 
 
249
  if(document.readyState === 'loading'){
250
  document.addEventListener('DOMContentLoaded', ()=>setTimeout(injectDetailTab, 1000));
251
  } else {