fix broadcast layout

sync_v2
Raz 6 months ago
parent 6d92dbd491
commit 7742fde718
  1. 16
      tournaments/models/match.py
  2. 6
      tournaments/models/player_registration.py
  3. 3
      tournaments/models/round.py
  4. 6
      tournaments/models/team_registration.py
  5. 8
      tournaments/models/team_score.py
  6. 4
      tournaments/models/tournament.py
  7. 120
      tournaments/static/tournaments/js/tournament_bracket.js
  8. 10
      tournaments/templates/tournaments/broadcast/broadcasted_bracket.html

@ -184,7 +184,7 @@ class Match(SideStoreModel):
def is_ready(self): def is_ready(self):
return self.team_scores.count() == 2 return self.team_scores.count() == 2
def live_teams(self, hide_names=False): def live_teams(self, hide_names=False, short_names=False):
#print('player names from match') #print('player names from match')
##return map(lambda ts: ts.player_names(), self.team_scores.all()) ##return map(lambda ts: ts.player_names(), self.team_scores.all())
# List to hold the names of the teams # List to hold the names of the teams
@ -247,7 +247,7 @@ class Match(SideStoreModel):
teams.append(team) teams.append(team)
elif len(team_scores) == 1: elif len(team_scores) == 1:
# Only one team score, handle missing one # Only one team score, handle missing one
existing_team = team_scores[0].live_team(self) existing_team = team_scores[0].live_team(self, short_names=short_names)
if (self.group_stage): if (self.group_stage):
teams.append(existing_team) teams.append(existing_team)
names = ["Équipe de poule"] names = ["Équipe de poule"]
@ -287,19 +287,19 @@ class Match(SideStoreModel):
elif len(team_scores) == 2: elif len(team_scores) == 2:
# Both team scores present # Both team scores present
teams.extend([team_score.live_team(self) for team_score in team_scores]) teams.extend([team_score.live_team(self, short_names=short_names) for team_score in team_scores])
if self.round is not None and self.round.parent is None: if self.round is not None and self.round.parent is None:
pos1 = team_scores[0].team_registration.bracket_position if hasattr(team_scores[0], 'team_registration') and team_scores[0].team_registration else None pos1 = team_scores[0].team_registration.bracket_position if hasattr(team_scores[0], 'team_registration') and team_scores[0].team_registration else None
pos2 = team_scores[1].team_registration.bracket_position if hasattr(team_scores[1], 'team_registration') and team_scores[1].team_registration else None pos2 = team_scores[1].team_registration.bracket_position if hasattr(team_scores[1], 'team_registration') and team_scores[1].team_registration else None
if pos1 is not None and pos2 is not None and pos1 // 2 == self.index and pos2 // 2 == self.index: if pos1 is not None and pos2 is not None and pos1 // 2 == self.index and pos2 // 2 == self.index:
if pos1 > pos2: if pos1 > pos2:
teams = [team_scores[1].live_team(self), team_scores[0].live_team(self)] teams = [team_scores[1].live_team(self, short_names=short_names), team_scores[0].live_team(self, short_names=short_names)]
else: else:
teams = [team_scores[0].live_team(self), team_scores[1].live_team(self)] teams = [team_scores[0].live_team(self, short_names=short_names), team_scores[1].live_team(self, short_names=short_names)]
else: else:
teams.extend([team_score.live_team(self) for team_score in team_scores if team_score.walk_out != 1]) teams.extend([team_score.live_team(self, short_names=short_names) for team_score in team_scores if team_score.walk_out != 1])
return teams return teams
@ -426,7 +426,7 @@ class Match(SideStoreModel):
else: else:
return self.round.tournament.short_full_name() return self.round.tournament.short_full_name()
def live_match(self, hide_teams=False, event_mode=False): def live_match(self, hide_teams=False, event_mode=False, short_names=False):
title = self.computed_name() title = self.computed_name()
date = self.formatted_start_date() date = self.formatted_start_date()
time_indication = self.time_indication() time_indication = self.time_indication()
@ -447,7 +447,7 @@ class Match(SideStoreModel):
livematch = LiveMatch(self.index, title, date, time_indication, court, self.started(), ended, group_stage_name, live_format, self.start_date, self.court_index, self.disabled, bracket_name, self.should_show_lucky_loser_status(), tournament_title) livematch = LiveMatch(self.index, title, date, time_indication, court, self.started(), ended, group_stage_name, live_format, self.start_date, self.court_index, self.disabled, bracket_name, self.should_show_lucky_loser_status(), tournament_title)
for team in self.live_teams(hide_teams): for team in self.live_teams(hide_teams, short_names):
livematch.add_team(team) livematch.add_team(team)
return livematch return livematch

@ -62,11 +62,11 @@ class PlayerRegistration(SideStoreModel):
def name(self): def name(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"
def shortened_name(self): def shortened_name(self, forced=False):
name = self.name() name = self.name()
if len(name) > 20 and self.first_name: if (len(name) > 20 or forced) and self.first_name:
name = f"{self.first_name[0]}. {self.last_name}" name = f"{self.first_name[0]}. {self.last_name}"
if len(name) > 20: if len(name) > 20 or forced:
name_parts = self.last_name.split(" ") name_parts = self.last_name.split(" ")
name = f"{self.first_name[0]}. {name_parts[0]}" name = f"{self.first_name[0]}. {name_parts[0]}"
return name return name

@ -179,7 +179,8 @@ class Round(SideStoreModel):
name=name, name=name,
matches=first_half_matches, matches=first_half_matches,
round_id=self.id, round_id=self.id,
round_index=self.index round_index=self.index,
short_names=True
) )
return match_group return match_group

@ -72,7 +72,7 @@ class TeamRegistration(SideStoreModel):
else: else:
return self.player_names_as_list() return self.player_names_as_list()
def shortened_team_names(self): def shortened_team_names(self, forced=False):
if self.name: if self.name:
return [self.name] #add an empty line if it's a team name return [self.name] #add an empty line if it's a team name
else: else:
@ -85,9 +85,9 @@ class TeamRegistration(SideStoreModel):
else: else:
return ['Place réservée'] return ['Place réservée']
elif len(players) == 1: elif len(players) == 1:
return [players[0].shortened_name()] return [players[0].shortened_name(forced=forced)]
else: else:
return [pr.shortened_name() for pr in players] return [pr.shortened_name(forced=forced) for pr in players]
@property @property
def players_sorted_by_rank(self): def players_sorted_by_rank(self):

@ -49,10 +49,10 @@ class TeamScore(SideStoreModel):
else: else:
return "--" return "--"
def shortened_team_names(self): def shortened_team_names(self, forced=False):
names = [] names = []
if self.team_registration: if self.team_registration:
names = self.team_registration.shortened_team_names() names = self.team_registration.shortened_team_names(forced=forced)
return names return names
def team_names(self): def team_names(self):
@ -109,7 +109,7 @@ class TeamScore(SideStoreModel):
scores = self.scores() scores = self.scores()
return sum(scores) return sum(scores)
def live_team(self, match): def live_team(self, match, short_names=False):
if self.team_registration: if self.team_registration:
id = self.team_registration.id id = self.team_registration.id
image = self.team_registration.logo image = self.team_registration.logo
@ -123,7 +123,7 @@ class TeamScore(SideStoreModel):
image = None image = None
weight= None weight= None
is_winner = False is_winner = False
names = self.shortened_team_names() names = self.shortened_team_names(forced=short_names)
scores = self.parsed_scores() scores = self.parsed_scores()
walk_out = self.walk_out walk_out = self.walk_out
is_lucky_loser = self.lucky_loser is not None is_lucky_loser = self.lucky_loser is not None

@ -571,9 +571,9 @@ class Tournament(BaseModel):
return groups return groups
def create_match_group(self, name, matches, round_id=None, round_index=None, hide_teams=False, event_mode=False): def create_match_group(self, name, matches, round_id=None, round_index=None, hide_teams=False, event_mode=False, short_names=False):
matches = list(matches) matches = list(matches)
live_matches = [match.live_match(hide_teams, event_mode) for match in matches] live_matches = [match.live_match(hide_teams, event_mode, short_names) for match in matches]
# Filter out matches that have a start_date of None # Filter out matches that have a start_date of None
valid_matches = [match for match in matches if match.start_date is not None] valid_matches = [match for match in matches if match.start_date is not None]

@ -443,64 +443,64 @@ function renderBracket(options) {
bracket.appendChild(roundDiv); bracket.appendChild(roundDiv);
}); });
if (isBroadcast == false || isBroadcast == undefined) { // if (isBroadcast == false || isBroadcast == undefined) {
setTimeout(() => { // setTimeout(() => {
const roundDivs = document.querySelectorAll(".butterfly-round"); // const roundDivs = document.querySelectorAll(".butterfly-round");
// First, find the maximum bottom position across all rounds // // First, find the maximum bottom position across all rounds
let globalMaxBottom = 0; // let globalMaxBottom = 0;
roundDivs.forEach((roundDiv) => { // roundDivs.forEach((roundDiv) => {
const matches = roundDiv.querySelectorAll(".butterfly-match"); // const matches = roundDiv.querySelectorAll(".butterfly-match");
matches.forEach((match) => { // matches.forEach((match) => {
const bottom = match.offsetTop + match.offsetHeight; // const bottom = match.offsetTop + match.offsetHeight;
if (bottom > globalMaxBottom) { // if (bottom > globalMaxBottom) {
globalMaxBottom = bottom; // globalMaxBottom = bottom;
} // }
}); // });
}); // });
// Now create and position footers for all rounds at the same y-position // // Now create and position footers for all rounds at the same y-position
roundDivs.forEach((roundDiv, index) => { // roundDivs.forEach((roundDiv, index) => {
// Get the match templates from this round to extract data // // Get the match templates from this round to extract data
const roundMatches = rounds[index] || []; // const roundMatches = rounds[index] || [];
if (roundMatches.length > 0) { // if (roundMatches.length > 0) {
const firstMatchTemplate = roundMatches[0].closest(".match-template"); // const firstMatchTemplate = roundMatches[0].closest(".match-template");
const roundId = firstMatchTemplate.dataset.roundId; // const roundId = firstMatchTemplate.dataset.roundId;
const realRoundIndex = firstMatchTemplate.dataset.roundIndex; // const realRoundIndex = firstMatchTemplate.dataset.roundIndex;
if (realRoundIndex > 1) { // if (realRoundIndex > 1) {
// Create footer div // // Create footer div
const footerDiv = document.createElement("div"); // const footerDiv = document.createElement("div");
footerDiv.className = "round-footer"; // footerDiv.className = "round-footer";
footerDiv.style.width = `${responsiveMatchWidth}px`; // footerDiv.style.width = `${responsiveMatchWidth}px`;
footerDiv.style.paddingBottom = "40px"; // footerDiv.style.paddingBottom = "40px";
footerDiv.style.textAlign = "center"; // footerDiv.style.textAlign = "center";
// Create footer content // // Create footer content
let linkSpan = document.createElement("a"); // let linkSpan = document.createElement("a");
linkSpan.className = "small styled-link"; // linkSpan.className = "small styled-link";
linkSpan.textContent = "accès au tableau de classement"; // linkSpan.textContent = "accès au tableau de classement";
if (roundId) { // if (roundId) {
linkSpan.href = `/tournament/${tournamentId}/round/${roundId}/bracket/`; // linkSpan.href = `/tournament/${tournamentId}/round/${roundId}/bracket/`;
linkSpan.style.cursor = "pointer"; // linkSpan.style.cursor = "pointer";
} // }
footerDiv.appendChild(linkSpan); // footerDiv.appendChild(linkSpan);
// Create a container that will sit at the same position for all rounds // // Create a container that will sit at the same position for all rounds
const footerContainer = document.createElement("div"); // const footerContainer = document.createElement("div");
footerContainer.style.position = "absolute"; // footerContainer.style.position = "absolute";
footerContainer.style.top = `${globalMaxBottom}px`; // Same position for all footers // footerContainer.style.top = `${globalMaxBottom}px`; // Same position for all footers
footerContainer.style.width = "100%"; // footerContainer.style.width = "100%";
footerContainer.appendChild(footerDiv); // footerContainer.appendChild(footerDiv);
// Add to the round div // // Add to the round div
const matchesContainer = // const matchesContainer =
roundDiv.querySelector(".matches-container"); // roundDiv.querySelector(".matches-container");
matchesContainer.appendChild(footerContainer); // matchesContainer.appendChild(footerContainer);
} // }
} // }
}); // });
}, 100); // }, 1000);
} // }
} }

@ -4,6 +4,7 @@
<html> <html>
<head> <head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="{% static 'tournaments/css/foundation.min.css' %}" /> <link rel="stylesheet" href="{% static 'tournaments/css/foundation.min.css' %}" />
<link rel="stylesheet" href="{% static 'tournaments/css/basics.css' %}" /> <link rel="stylesheet" href="{% static 'tournaments/css/basics.css' %}" />
<link rel="stylesheet" href="{% static 'tournaments/css/style.css' %}" /> <link rel="stylesheet" href="{% static 'tournaments/css/style.css' %}" />
@ -108,6 +109,15 @@
</head> </head>
<body> <body>
<div x-data="{
loop() {
this.fetchAndRenderBracket()
setInterval(() => {
this.fetchAndRenderBracket()
}, 15000)
},
}" x-init="loop()">
<header> <header>
<div id="screen-size-overlay"> <div id="screen-size-overlay">
<div class="left-content bubble-header screen-size-overlay"> <div class="left-content bubble-header screen-size-overlay">

Loading…
Cancel
Save