154 lines
4.2 KiB
TypeScript
154 lines
4.2 KiB
TypeScript
import TournamentController from '../ctrl';
|
|
import { bind, onInsert, playerName } from './util';
|
|
import { h, VNode } from 'snabbdom';
|
|
import { TeamBattle, RankedTeam, MaybeVNode } from '../interfaces';
|
|
import modal from 'common/modal';
|
|
|
|
export function joinWithTeamSelector(ctrl: TournamentController) {
|
|
const onClose = () => {
|
|
ctrl.joinWithTeamSelector = false;
|
|
ctrl.redraw();
|
|
};
|
|
const tb = ctrl.data.teamBattle!;
|
|
return h(
|
|
'div.none',
|
|
{
|
|
hook: onInsert(el => modal($(el), 'team-battle__choice', onClose)),
|
|
},
|
|
[
|
|
h('div.team-picker', [
|
|
h('h2', 'Pick your team'),
|
|
h('br'),
|
|
...(tb.joinWith.length
|
|
? [
|
|
h('p', 'Which team will you represent in this battle?'),
|
|
...tb.joinWith.map(id =>
|
|
h(
|
|
'a.button',
|
|
{
|
|
hook: bind('click', () => ctrl.join(id), ctrl.redraw),
|
|
},
|
|
tb.teams[id]
|
|
)
|
|
),
|
|
]
|
|
: [
|
|
h('p', 'You must join one of these teams to participate!'),
|
|
h(
|
|
'ul',
|
|
shuffleArray(Object.keys(tb.teams)).map((t: string) =>
|
|
h(
|
|
'li',
|
|
h(
|
|
'a',
|
|
{
|
|
attrs: { href: '/team/' + t },
|
|
},
|
|
tb.teams[t]
|
|
)
|
|
)
|
|
)
|
|
),
|
|
]),
|
|
]),
|
|
]
|
|
);
|
|
}
|
|
|
|
export function teamStanding(ctrl: TournamentController, klass?: string): VNode | null {
|
|
const battle = ctrl.data.teamBattle,
|
|
standing = ctrl.data.teamStanding,
|
|
bigBattle = battle && Object.keys(battle.teams).length > 10;
|
|
return battle && standing
|
|
? h('table.slist.tour__team-standing' + (klass ? '.' + klass : ''), [
|
|
h('tbody', [
|
|
...standing.map(rt => teamTr(ctrl, battle, rt)),
|
|
...(bigBattle ? [extraTeams(ctrl), myTeam(ctrl, battle)] : []),
|
|
]),
|
|
])
|
|
: null;
|
|
}
|
|
|
|
function extraTeams(ctrl: TournamentController): VNode {
|
|
return h(
|
|
'tr',
|
|
h(
|
|
'td.more-teams',
|
|
{
|
|
attrs: { colspan: 4 },
|
|
},
|
|
h(
|
|
'a',
|
|
{
|
|
attrs: {
|
|
href: `/tournament/${ctrl.data.id}/teams`,
|
|
},
|
|
},
|
|
ctrl.trans('viewAllXTeams', Object.keys(ctrl.data.teamBattle!.teams).length)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
function myTeam(ctrl: TournamentController, battle: TeamBattle): MaybeVNode {
|
|
const team = ctrl.data.myTeam;
|
|
return team && team.rank > 10 ? teamTr(ctrl, battle, team) : undefined;
|
|
}
|
|
|
|
export function teamName(battle: TeamBattle, teamId: string): VNode {
|
|
return h(
|
|
battle.hasMoreThanTenTeams ? 'team' : 'team.ttc-' + Object.keys(battle.teams).indexOf(teamId),
|
|
battle.teams[teamId]
|
|
);
|
|
}
|
|
|
|
function teamTr(ctrl: TournamentController, battle: TeamBattle, team: RankedTeam) {
|
|
const players = [] as (string | VNode)[];
|
|
team.players.forEach((p, i) => {
|
|
if (i > 0) players.push('+');
|
|
players.push(
|
|
h(
|
|
'score.ulpt.user-link',
|
|
{
|
|
key: p.user.name,
|
|
class: { top: i === 0 },
|
|
attrs: {
|
|
'data-href': '/@/' + p.user.name,
|
|
'data-name': p.user.name,
|
|
},
|
|
hook: {
|
|
destroy: vnode => $.powerTip.destroy(vnode.elm as HTMLElement),
|
|
...bind('click', _ => ctrl.jumpToPageOf(p.user.name), ctrl.redraw),
|
|
},
|
|
},
|
|
[...(i === 0 ? [h('username', playerName(p.user)), ' '] : []), '' + p.score]
|
|
)
|
|
);
|
|
});
|
|
return h(
|
|
'tr',
|
|
{
|
|
key: team.id,
|
|
class: {
|
|
active: ctrl.teamInfo.requested == team.id,
|
|
},
|
|
hook: bind('click', _ => ctrl.showTeamInfo(team.id), ctrl.redraw),
|
|
},
|
|
[
|
|
h('td.rank', '' + team.rank),
|
|
h('td.team', [teamName(battle, team.id)]),
|
|
h('td.players', players),
|
|
h('td.total', [h('strong', '' + team.score)]),
|
|
]
|
|
);
|
|
}
|
|
|
|
/* Randomize array element order in-place. Using Durstenfeld shuffle algorithm. */
|
|
function shuffleArray<A>(array: A[]) {
|
|
for (let i = array.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[array[i], array[j]] = [array[j], array[i]];
|
|
}
|
|
return array;
|
|
}
|