1
1
import './style.scss' ;
2
2
import { Participant , Match , MatchResults , ParticipantResult , ViewerData } from "brackets-model" ;
3
- import { splitBy , getRanking , rankingHeader } from "./helpers" ;
3
+ import { splitBy , getRanking , rankingHeader , isMajorRound } from "./helpers" ;
4
4
5
5
type ConnectionType = 'square' | 'straight' | false ;
6
6
type Placement = 'none' | 'before' | 'after' ;
7
+ type FinalType = 'consolation_final' | 'grand_final' ;
8
+ type MatchHint = ( ( i : number ) => string ) | undefined ;
7
9
8
10
interface Connection {
9
11
connectPrevious ?: ConnectionType ,
@@ -166,30 +168,21 @@ class BracketsViewer {
166
168
/**
167
169
* Renders a bracket.
168
170
*/
169
- private renderBracket ( root : JQuery , matchesByRound : Match [ ] [ ] , roundName : ( roundNumber : number ) => string , lowerBracket ?: boolean , connectFinal ?: boolean ) {
171
+ private renderBracket ( root : JQuery , matchesByRound : Match [ ] [ ] , roundName : ( roundNumber : number ) => string , inLowerBracket ?: boolean , connectFinal ?: boolean ) {
170
172
const bracket = $ ( '<section class="bracket">' ) ;
173
+ const roundCount = matchesByRound . length ;
171
174
172
175
let roundNumber = 1 ;
173
176
174
177
for ( const matches of matchesByRound ) {
175
178
const roundDOM = $ ( '<article class="round">' ) . append ( $ ( '<h3>' ) . text ( roundName ( roundNumber ) ) ) ;
176
179
177
180
for ( const match of matches ) {
178
- let connection : Connection ;
179
-
180
- if ( lowerBracket ) {
181
- connection = {
182
- connectPrevious : roundNumber > 1 && ( roundNumber % 2 === 1 ? 'square' : 'straight' ) ,
183
- connectNext : roundNumber < matchesByRound . length && ( roundNumber % 2 === 0 ? 'square' : 'straight' ) ,
184
- } ;
185
- } else {
186
- connection = {
187
- connectPrevious : roundNumber > 1 && 'square' ,
188
- connectNext : roundNumber < matchesByRound . length ? 'square' : ( connectFinal ? 'straight' : false ) ,
189
- } ;
190
- }
181
+ const connection = this . getConnection ( inLowerBracket , roundNumber , matchesByRound , connectFinal ) ;
182
+ const matchLabel = this . getMatchLabel ( match , roundNumber , roundCount , inLowerBracket ) ;
183
+ const matchHint = this . getMatchHint ( inLowerBracket , roundNumber , roundCount ) ;
191
184
192
- roundDOM . append ( this . renderMatch ( match , connection , `M ${ roundNumber } . ${ match . number } ` , lowerBracket ) ) ;
185
+ roundDOM . append ( this . renderMatch ( match , connection , matchLabel , matchHint , inLowerBracket ) ) ;
193
186
}
194
187
195
188
bracket . append ( roundDOM ) ;
@@ -199,26 +192,89 @@ class BracketsViewer {
199
192
root . append ( bracket ) ;
200
193
}
201
194
202
- private renderFinal ( type : 'consolation_final' | 'grand_final' , matches : Match [ ] ) {
195
+ private getMatchHint ( inLowerBracket : boolean | undefined , roundNumber : number , roundCount : number ) : MatchHint {
196
+ if ( ! inLowerBracket && roundNumber === 1 )
197
+ return ( i : number ) => `Seed ${ i } ` ;
198
+
199
+ if ( inLowerBracket && isMajorRound ( roundNumber ) ) {
200
+ const roundNumberWB = Math . ceil ( ( roundNumber + 1 ) / 2 ) ;
201
+
202
+ let hint = ( i : number ) => `Loser of WB ${ roundNumberWB } .${ i } ` ;
203
+
204
+ if ( roundNumber === roundCount - 2 )
205
+ hint = ( i : number ) => `Loser of WB Semi ${ i } ` ;
206
+
207
+ if ( roundNumber === roundCount )
208
+ hint = ( ) => 'Loser of WB Final' ;
209
+
210
+ return hint ;
211
+ }
212
+
213
+ return undefined ;
214
+ }
215
+
216
+ private getConnection ( inLowerBracket : boolean | undefined , roundNumber : number , matchesByRound : Match [ ] [ ] , connectFinal : boolean | undefined ) : Connection {
217
+ if ( inLowerBracket ) {
218
+ return {
219
+ connectPrevious : roundNumber > 1 && ( roundNumber % 2 === 1 ? 'square' : 'straight' ) ,
220
+ connectNext : roundNumber < matchesByRound . length && ( roundNumber % 2 === 0 ? 'square' : 'straight' ) ,
221
+ } ;
222
+ }
223
+
224
+ return {
225
+ connectPrevious : roundNumber > 1 && 'square' ,
226
+ connectNext : roundNumber < matchesByRound . length ? 'square' : ( connectFinal ? 'straight' : false ) ,
227
+ }
228
+ }
229
+
230
+ private getMatchLabel ( match : Match , roundNumber : number , roundCount : number , inLowerBracket : boolean | undefined ) {
231
+ let matchPrefix = 'M' ;
232
+
233
+ if ( inLowerBracket )
234
+ matchPrefix = 'LB' ;
235
+ else if ( inLowerBracket === false )
236
+ matchPrefix = 'WB' ;
237
+
238
+ const semiFinalRound = roundNumber === roundCount - 1 ;
239
+ const finalRound = roundNumber === roundCount ;
240
+
241
+ let matchLabel = `${ matchPrefix } ${ roundNumber } .${ match . number } ` ;
242
+
243
+ if ( ! inLowerBracket && semiFinalRound )
244
+ matchLabel = `Semi ${ match . number } ` ;
245
+
246
+ if ( finalRound )
247
+ matchLabel = 'Final' ;
248
+
249
+ return matchLabel ;
250
+ }
251
+
252
+ private renderFinal ( type : FinalType , matches : Match [ ] ) {
203
253
const upperBracket = $ ( '.bracket' ) . eq ( 0 ) ;
204
- const grandFinalName = matches . length === 1 ? ( ) => 'Grand Final' : ( i : number ) => `Grand Final R${ i + 1 } ` ;
254
+ const grandFinalName = matches . length === 1 ? ( ) => 'Grand Final' : ( i : number ) => `GF Round ${ i + 1 } ` ;
255
+ const grandFinalMatchHint = ( i : number ) => i === 0 ? ( ) => 'Winner of LB Final' : undefined ;
205
256
206
257
for ( let i = 0 ; i < matches . length ; i ++ ) {
258
+ const matchLabel = type === 'consolation_final' ? 'Consolation Final' : grandFinalName ( i ) ;
259
+ const matchHint = type === 'consolation_final' ? ( i : number ) => `Loser of Semi ${ i } ` : grandFinalMatchHint ( i ) ;
260
+
207
261
const matchDOM = this . renderMatch ( matches [ i ] , {
208
262
connectPrevious : type === 'grand_final' && ( i === 0 && 'straight' ) ,
209
263
connectNext : matches . length === 2 && i === 0 && 'straight' ,
210
- } ) ;
264
+ } , matchLabel , matchHint , undefined ) ;
211
265
212
- const roundDOM = $ ( '<article class="round">' ) . append ( $ ( '<h3>' ) . text ( type === 'grand_final' ? grandFinalName ( i ) : 'Consolation Final' ) ) ;
266
+ const roundDOM = $ ( '<article class="round">' ) . append ( $ ( '<h3>' ) . text ( matchLabel ) ) ;
213
267
roundDOM . append ( matchDOM ) ;
214
268
215
269
upperBracket . append ( roundDOM ) ;
216
270
}
217
271
}
218
272
219
- private renderMatch ( results : MatchResults , connection ?: Connection , label ?: string , lowerBracket ?: boolean ) {
220
- const team1 = this . renderTeam ( results . opponent1 , lowerBracket || false ) ;
221
- const team2 = this . renderTeam ( results . opponent2 , lowerBracket || false ) ;
273
+ private renderMatch ( results : MatchResults , connection ?: Connection , label ?: string , hint ?: MatchHint , inLowerBracket ?: boolean ) {
274
+ inLowerBracket = inLowerBracket || false ;
275
+
276
+ const team1 = this . renderTeam ( results . opponent1 , hint , inLowerBracket ) ;
277
+ const team2 = this . renderTeam ( results . opponent2 , hint , inLowerBracket ) ;
222
278
223
279
const teams = $ ( '<div class="teams">' ) ;
224
280
if ( label ) teams . append ( $ ( '<span>' ) . text ( label ) ) ;
@@ -242,7 +298,7 @@ class BracketsViewer {
242
298
return match ;
243
299
}
244
300
245
- private renderTeam ( team : ParticipantResult | null , lowerBracket : boolean ) {
301
+ private renderTeam ( team : ParticipantResult | null , hint : MatchHint , inLowerBracket : boolean ) {
246
302
const teamDOM = $ ( `<div class="team">` ) ;
247
303
const nameDOM = $ ( '<div class="name">' ) ;
248
304
const resultDOM = $ ( '<div class="result">' ) ;
@@ -254,7 +310,9 @@ class BracketsViewer {
254
310
255
311
if ( participant ) {
256
312
nameDOM . text ( participant . name ) ;
257
- this . renderTeamOrigin ( nameDOM , team , lowerBracket ) ;
313
+ this . renderTeamOrigin ( nameDOM , team , inLowerBracket ) ;
314
+ } else if ( hint && team . position ) {
315
+ this . renderHint ( nameDOM , hint ( team . position ) ) ;
258
316
}
259
317
260
318
resultDOM . text ( team . score === undefined ? '-' : team . score ) ;
@@ -292,14 +350,18 @@ class BracketsViewer {
292
350
return teamDOM ;
293
351
}
294
352
295
- private renderTeamOrigin ( name : JQuery , team : ParticipantResult , lowerBracket : boolean ) {
353
+ private renderHint ( name : JQuery , hint : string ) {
354
+ name . text ( hint ) ;
355
+ }
356
+
357
+ private renderTeamOrigin ( name : JQuery , team : ParticipantResult , inLowerBracket : boolean ) {
296
358
if ( team . position === undefined ) return ;
297
359
if ( this . config . participantOriginPlacement === 'none' ) return ;
298
360
if ( ! this . config . showSlotsOrigin ) return ;
299
- if ( ! this . config . showLowerBracketSlotsOrigin && lowerBracket ) return ;
361
+ if ( ! this . config . showLowerBracketSlotsOrigin && inLowerBracket ) return ;
300
362
301
363
// 'P' for position (where the participant comes from) and '#' for actual seeding.
302
- const text = lowerBracket ? `P${ team . position } ` : `#${ team . position } ` ;
364
+ const text = inLowerBracket ? `P${ team . position } ` : `#${ team . position } ` ;
303
365
304
366
this . addTeamOrigin ( name , text , this . config . participantOriginPlacement ) ;
305
367
}
0 commit comments