diff --git a/js/client-tournament.js b/js/client-tournament.js new file mode 100644 index 000000000..2b308b413 --- /dev/null +++ b/js/client-tournament.js @@ -0,0 +1,271 @@ +(function($) { + + function arrayToPhrase(array, finalSeparator) { + if (array.length <= 1) + return array.join(); + finalSeparator = finalSeparator || "and"; + return array.slice(0, -1).join(", ") + " " + finalSeparator + " " + array.slice(-1)[0]; + } + + var TournamentBox = this.TournamentBox = (function () { + function TournamentBox(room, $wrapper) { + this.room = room; + this.$wrapper = $wrapper; + + $wrapper.html( + '
Tournament
' + + '
' + + '
' + + '
' + + '' + + '
There are currently no new matches available for you. Please wait for some other battles to end.
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '
' + + '
'); + + this.$title = $wrapper.find('.tournament-title'); + this.$format = $wrapper.find('.tournament-format'); + this.$generator = $wrapper.find('.tournament-generator'); + this.$box = $wrapper.find('.tournament-box'); + this.$bracket = $wrapper.find('.tournament-bracket'); + this.$tools = $wrapper.find('.tournament-tools'); + this.$join = $wrapper.find('.tournament-join'); + this.$leave = $wrapper.find('.tournament-leave'); + this.$noMatches = $wrapper.find('.tournament-nomatches'); + this.$challenge = $wrapper.find('.tournament-challenge'); + this.$challengeUser = $wrapper.find('.tournament-challenge-user'); + this.$challengeTeam = $wrapper.find('.tournament-challenge-team'); + this.$challengeChallenge = $wrapper.find('.tournament-challenge-challenge'); + this.$challengeBy = $wrapper.find('.tournament-challengeby'); + this.$challenging = $wrapper.find('.tournament-challenging'); + this.$challenged = $wrapper.find('.tournament-challenged'); + this.$challengedMessage = $wrapper.find('.tournament-challenged-message'); + this.$challengeAccept = $wrapper.find('.tournament-challenge-accept'); + + this.isActive = false; + this.info = null; + this.bracketData = null; + this.challenges = null; + this.challengeBys = null; + + var self = this; + this.$title.on('click', function() { + self.$box.toggleClass('active'); + self.$box.css('transition', ''); + self.$box.css('max-height', self.$box.hasClass('active') ? self.$box[0].scrollHeight: ''); + }); + this.$box.on('transitionend webkitTransitionEnd oTransitionEnd otransitionend', function() { + if (self.$box.hasClass('active')) + self.$box.css('transition', 'none'); + if (!self.isActive) + self.$wrapper.removeClass('active'); + }); + this.$join.on('click', function() { + self.room.send('/tournament join'); + }); + this.$leave.on('click', function() { + self.room.send('/tournament leave'); + }); + this.$challengeChallenge.on('click', function() { + var team = app.user.teams[self.$challengeTeam.children().val()]; + self.room.send('/utm ' + JSON.stringify(team ? team.team : null)); + self.room.send('/tournament challenge ' + self.$challengeUser.children().val()); + }); + this.$challengeAccept.on('click', function() { + var team = app.user.teams[self.$challengeTeam.children().val()]; + self.room.send('/utm ' + JSON.stringify(team ? team.team : null)); + self.room.send('/tournament acceptchallenge'); + }); + } + + TournamentBox.prototype.parseMessage = function (data, isBroadcast) { + if (isBroadcast) { + // TODO + return true; + } else { + if (!this.isActive) { + this.$wrapper.addClass("active"); + this.$box.addClass("active"); + this.isActive = true; + } + + var cmd = data.shift().toLowerCase(); + switch (cmd) { + case 'create': + this.room.$chat.append("
A " + BattleFormats[data.shift()].name + " " + data.join('|') + " Tournament has been created.
"); + break; + + case 'update': + this.$tools.find('.active').removeClass('active'); + if (this.info && this.info.isStarted) + this.$noMatches.addClass('active'); + this.challenges = null; + this.challengeBys = null; + break; + + case 'info': + this.info = JSON.parse(data.join('|')); + this.$format.text(BattleFormats[this.info.format].name); + this.$generator.text(this.info.generator); + break; + + case 'bracketdata': + this.bracketData = JSON.parse(data.join('|')); + this.showBracket(this.bracketData); + break; + + case 'challenges': + this.$noMatches.removeClass('active'); + this.challenges = data.join('|').split(','); + this.$challengeUser.html(this.renderChallengeUsers()); + this.$challengeTeam.html(app.rooms[''].renderTeams(this.info.format)); + this.$challengeTeam.children().data('type', 'challengeTeam'); + this.$challengeTeam.children().attr('name', 'tournamentButton'); + this.$challenge.addClass("active"); + break; + + case 'challengebys': + this.$noMatches.removeClass('active'); + this.challengeBys = data.join('|').split(','); + this.$challengeBy.text((this.challenges ? "Or" : "Please") + " wait for " + arrayToPhrase(this.challengeBys, "or") + " to challenge you."); + this.$challengeBy.addClass("active"); + break; + + case 'challenging': + this.$noMatches.removeClass('active'); + this.$challenging.text("Challenging " + data[0] + "...").addClass("active"); + break; + + case 'challenged': + this.$noMatches.removeClass('active'); + this.$challengedMessage.text(data[0] + " has challenged you."); + this.$challengeTeam.html(app.rooms[''].renderTeams(this.info.format)); + this.$challengeTeam.children().data('type', 'challengeTeam'); + this.$challengeTeam.children().attr('name', 'tournamentButton'); + this.$challenged.addClass("active"); + break; + + case 'end': + this.room.$chat.append("
Congratulations to " + Tools.escapeHTML(arrayToPhrase(data[0].split(','))) + " for winning the tournament!
"); + if (data[1]) + this.room.$chat.append("
Runner-up" + (data[1].length > 1 ? "s" : "") +": " + Tools.escapeHTML(arrayToPhrase(data[1].split(','))) + "
"); + // Fallthrough + + case 'forceend': + this.isActive = false; + this.info = null; + this.bracketData = null; + + // A quick start and end will not fire the transitionend event, so we delay a bit so the transition happens + var self = this; + setTimeout(function () { + if (self.isActive) + return; + self.$box.removeClass("active"); + self.$box.css('max-height', ''); + self.$box.css('transition', ''); + }, 0); + + if (cmd === 'forceend') + this.room.$chat.append("
The tournament was forcibly ended.
"); + break; + + default: + return true; + } + + this.$box.css('max-height', this.$box.hasClass('active') ? this.$box[0].scrollHeight : ''); + } + }; + + TournamentBox.prototype.showBracket = function (data) { + var isJoined = false; + if (data.type === 'tree') { + // TODO + } else if (data.type === 'table') { + this.$bracket.empty(); + var $table = $('
'); + + var $colHeaders = $(''); + $table.append($colHeaders); + data.tableHeaders.cols.forEach(function (name) { + $colHeaders.append($('').text(name)); + if (app.user.attributes.name === name) + isJoined = true; + }); + + data.tableHeaders.rows.forEach(function (name, r) { + var $row = $(''); + $table.append($row); + $row.append($('').text(name)); + data.tableContents[r].forEach(function (cell) { + var $cell = $(''); + $row.append($cell); + if (!cell) { + $cell.addClass('tournament-bracket-table-cell-null'); + return; + } + $cell.addClass('tournament-bracket-table-cell-' + cell.state); + if (cell.state === 'unavailable') { + $cell.text("Unavailable"); + } else if (cell.state === 'available') { + $cell.text("Waiting"); + } else if (cell.state === "inprogress") { + $cell.html('In-progress'); + } else if (cell.state === 'finished') { + $cell.addClass('tournament-bracket-table-cell-result-' + cell.result); + $cell.text(cell.score.join(" - ")); + } + }); + $row.append($('').text(data.scores[r])); + }); + + if (data.tableContents.length > 0) + this.$bracket.append($table); + } + + if (!this.info.isStarted) + if (isJoined) + this.$leave.addClass('active'); + else + this.$join.addClass('active'); + }, + + TournamentBox.prototype.renderChallengeUsers = function () { + return ''; + }; + TournamentBox.prototype.challengeUser = function (user, button) { + app.addPopup(UserPopup, {user: user, users: this.challenges, sourceEl: button}); + }; + + TournamentBox.prototype.challengeTeam = function (team, button) { + app.addPopup(TeamPopup, {team: team, format: this.info.format, sourceEl: button}); + }; + + return TournamentBox; + })(); + + var UserPopup = this.Popup.extend({ + initialize: function (data) { + this.$el.html(''); + }, + selectUser: function (user) { + this.sourceEl.val(toId(user)).text(user); + this.close(); + } + }); + +}).call(this, jQuery);