From f4d796a717538ab705a4a555b037ba33d4e494a8 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Wed, 19 Aug 2015 15:30:37 -0700 Subject: [PATCH] More ladder page support for leagues. Linking to clan league pages from clans pages. --- app/locale/en.coffee | 3 + app/templates/clans/clan-details.jade | 100 ++++++++++-------- .../play/ladder/ladder-tab-view.jade | 6 +- app/templates/play/ladder/ladder.jade | 4 +- app/templates/play/ladder/simulate_tab.jade | 1 + app/views/clans/ClanDetailsView.coffee | 12 ++- app/views/ladder/LadderPlayModal.coffee | 42 +++++--- app/views/ladder/LadderTabView.coffee | 16 ++- app/views/ladder/LadderView.coffee | 2 +- app/views/ladder/MyMatchesTabView.coffee | 2 +- server/levels/level_handler.coffee | 2 +- 11 files changed, 118 insertions(+), 72 deletions(-) diff --git a/app/locale/en.coffee b/app/locale/en.coffee index d3173b371..b620be376 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -820,6 +820,7 @@ latest_achievement: "Latest Achievement" playtime: "Playtime" last_played: "Last played" + leagues_explanation: "Play in a league against other clan members in these multiplayer arena instances." classes: archmage_title: "Archmage" @@ -1009,6 +1010,7 @@ my_matches: "My Matches" simulate: "Simulate" simulation_explanation: "By simulating games you can get your game ranked faster!" + simulation_explanation_leagues: "You will mainly help simulate games for allied players in your clans and courses." simulate_games: "Simulate Games!" simulate_all: "RESET AND SIMULATE GAMES" games_simulated_by: "Games simulated by you:" @@ -1059,6 +1061,7 @@ tournament_blurb_blog: "on our blog" rules: "Rules" winners: "Winners" + league: "League" user: stats: "Stats" diff --git a/app/templates/clans/clan-details.jade b/app/templates/clans/clan-details.jade index ab1548311..072385987 100644 --- a/app/templates/clans/clan-details.jade +++ b/app/templates/clans/clan-details.jade @@ -26,52 +26,62 @@ block content button.btn(data-dismiss='modal', data-i18n="modal.close") Close button.btn.edit-description-save-btn(data-i18n="common.save_changes") Save changes - if clan - h1 #{clan.get('name')} - if clan.get('type') === 'private' - small(data-i18n="clans.private") (private) - if clan.get('ownerID') === me.id - span.spl - button.btn.btn-xs.edit-name-btn(data-toggle='modal', data-target='#editNameModal', data-i18n="clans.edit_name") edit name + .row + .col-lg-6 + if clan + h1 #{clan.get('name')} + if clan.get('type') === 'private' + small(data-i18n="clans.private") (private) + if clan.get('ownerID') === me.id + span.spl + button.btn.btn-xs.edit-name-btn(data-toggle='modal', data-target='#editNameModal', data-i18n="clans.edit_name") edit name + + if clan.get('description') + .clan-description + each line in clan.get('description').split('\n') + p= line + if clan.get('ownerID') === me.id + button.btn.btn-xs.edit-description-btn(data-toggle='modal', data-target='#editDescriptionModal', data-i18n="clans.edit_description") edit description + + h5(data-i18n="clans.summary") Summary + table.table.table-condensed.stats-table + if owner + tr + td + span.spr(data-i18n="clans.chieftain") Chieftain + td + span.spr.player-hero-icon(data-memberid="#{clan.get('ownerID')}") + a(href="/user/#{clan.get('ownerID')}")= owner.get('name') + if stats.averageLevel + tr + td(data-i18n="clans.average_level") Average Level + td= stats.averageLevel + if stats.averageAchievements && clan.get('type') === 'public' + tr + td(data-i18n="clans.average_achievements") Average Achievements + td= stats.averageAchievements + + p + if isOwner + button.btn.btn-xs.btn-warning.delete-clan-btn(data-i18n="clans.delete_clan") Delete Clan + else if isMember + button.btn.btn-xs.btn-warning.leave-clan-btn(data-i18n="clans.leave_clan") Leave Clan + else + button.btn.btn-lg.btn-success.join-clan-btn(data-i18n="clans.join_clan") Join Clan + + if clan.get('ownerID') === me.id || clan.get('type') === 'public' + div + span.spl.spr.join-link-prompt(data-i18n="clans.invite_1") Invite: + input.join-clan-link(type="text", readonly, value="#{joinClanLink}") + .small(data-i18n="clans.invite_2") *Invite players to this Clan by sending them this link. - if clan.get('description') - .clan-description - each line in clan.get('description').split('\n') - p= line - if clan.get('ownerID') === me.id - button.btn.btn-xs.edit-description-btn(data-toggle='modal', data-target='#editDescriptionModal', data-i18n="clans.edit_description") edit description - - h5(data-i18n="clans.summary") Summary - table.table.table-condensed.stats-table - if owner - tr - td - span.spr(data-i18n="clans.chieftain") Chieftain - td - span.spr.player-hero-icon(data-memberid="#{clan.get('ownerID')}") - a(href="/user/#{clan.get('ownerID')}")= owner.get('name') - if stats.averageLevel - tr - td(data-i18n="clans.average_level") Average Level - td= stats.averageLevel - if stats.averageAchievements && clan.get('type') === 'public' - tr - td(data-i18n="clans.average_achievements") Average Achievements - td= stats.averageAchievements - - p - if isOwner - button.btn.btn-xs.btn-warning.delete-clan-btn(data-i18n="clans.delete_clan") Delete Clan - else if isMember - button.btn.btn-xs.btn-warning.leave-clan-btn(data-i18n="clans.leave_clan") Leave Clan - else - button.btn.btn-lg.btn-success.join-clan-btn(data-i18n="clans.join_clan") Join Clan - - if clan.get('ownerID') === me.id || clan.get('type') === 'public' - div - span.spl.spr.join-link-prompt(data-i18n="clans.invite_1") Invite: - input.join-clan-link(type="text", readonly, value="#{joinClanLink}") - .small(data-i18n="clans.invite_2") *Invite players to this Clan by sending them this link. + if arenas && arenas.length + .col-lg-6 + h2(data-i18n="play.campaign_multiplayer") + p(data-i18n="clans.leagues_explanation") + for arena in arenas + h3 + a(href="/play/ladder/#{arena.slug}/clan/#{clan.id}")= i18n(arena, 'name') if members h3 diff --git a/app/templates/play/ladder/ladder-tab-view.jade b/app/templates/play/ladder/ladder-tab-view.jade index 23be6e709..3b24bcfe5 100644 --- a/app/templates/play/ladder/ladder-tab-view.jade +++ b/app/templates/play/ladder/ladder-tab-view.jade @@ -23,12 +23,13 @@ div#columns.row - if(!showJustTop && topSessions.length == 20) topSessions = topSessions.slice(0, 10); for session, rank in topSessions - var myRow = session.get('creator') == me.id + - var sessionStats = league ? (_.find(session.get('leagues') || [], {leagueID: league.id}) || {}).stats || {} : session.attributes; tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id) td.code-language-cell(style="background-image: url(/images/common/code_languages/" + session.get('submittedCodeLanguage') + "_icon.png)" title=capitalize(session.get('submittedCodeLanguage'))) if level.get('type', true) == 'hero-ladder' td.hero-portrait-cell(style="background-image: url(/file/db/thang.type/#{(session.get('heroConfig') || {}).thangType || '529ffbf1cf1818f2be000001'}/portrait.png)") td.rank-cell= rank + 1 - td.score-cell= Math.round(session.get('totalScore') * 100) + td.score-cell= Math.round(sessionStats.totalScore * 100) td.name-col-cell= session.get('creatorName') || "Anonymous" td.fight-cell a(href="/play/level/#{level.get('slug') || level.id}?team=#{team.otherTeam}&opponent=#{session.id}") @@ -41,12 +42,13 @@ div#columns.row td(colspan=4).ellipsis-row ... for session in team.leaderboard.nearbySessions() - var myRow = session.get('creator') == me.id + - var sessionStats = league ? (_.find(session.get('leagues'), {leagueID: league.id}) || {}).stats || {} : session.attributes; tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id) td.code-language-cell(style="background-image: url(/images/common/code_languages/" + session.get('submittedCodeLanguage') + "_icon.png)") if level.get('type', true) == 'hero-ladder' td.hero-portrait-cell(style="background-image: url(/file/db/thang.type/#{(session.get('heroConfig') || {}).thangType || '529ffbf1cf1818f2be000001'}/portrait.png)") td.rank-cell= session.rank - td.score-cell= Math.round(session.get('totalScore') * 100) + td.score-cell= Math.round(sessionStats.totalScore * 100) td.name-col-cell= session.get('creatorName') || "Anonymous" td.fight-cell a(href="/play/level/#{level.get('slug') || level.id}?team=#{team.otherTeam}&opponent=#{session.id}") diff --git a/app/templates/play/ladder/ladder.jade b/app/templates/play/ladder/ladder.jade index d0a7829b6..dd085a269 100644 --- a/app/templates/play/ladder/ladder.jade +++ b/app/templates/play/ladder/ladder.jade @@ -11,7 +11,9 @@ block content h1= level.get('name') if league - h1 #{league.get('name')} League + h1 + a(href="/#{leagueType == 'clan' ? 'clans' : leagueType}/#{league.id}")= league.get('name') + span.spl(data-i18n="ladder.league") League if level.get('name') == 'Greed' .tournament-blurb diff --git a/app/templates/play/ladder/simulate_tab.jade b/app/templates/play/ladder/simulate_tab.jade index dda0f4d02..b7adb8e64 100644 --- a/app/templates/play/ladder/simulate_tab.jade +++ b/app/templates/play/ladder/simulate_tab.jade @@ -3,6 +3,7 @@ p(id="simulation-status-text") | #{simulationStatus} else span(data-i18n="ladder.simulation_explanation") By simulating games you can get your game ranked faster! + span.spl(data-i18n="ladder.simulation_explanation_leagues") You will mainly help simulate games for allied players in your clans and courses. p button(data-i18n="ladder.simulate_games").btn.btn-warning.btn-lg.highlight#simulate-button Simulate Games! diff --git a/app/views/clans/ClanDetailsView.coffee b/app/views/clans/ClanDetailsView.coffee index 0ffa55e40..dd2e82821 100644 --- a/app/views/clans/ClanDetailsView.coffee +++ b/app/views/clans/ClanDetailsView.coffee @@ -10,6 +10,7 @@ LevelSession = require 'models/LevelSession' SubscribeModal = require 'views/core/SubscribeModal' ThangType = require 'models/ThangType' User = require 'models/User' +utils = require 'core/utils' # TODO: Add message for clan not found # TODO: Progress visual for premium levels? @@ -60,7 +61,7 @@ module.exports = class ClanDetailsView extends RootView @listenTo @memberAchievements, 'sync', @onMemberAchievementsSync @listenTo @memberSessions, 'sync', @onMemberSessionsSync - @supermodel.loadModel @campaigns, 'clan', cache: false + @supermodel.loadModel @campaigns, 'campaigns', cache: false @supermodel.loadModel @clan, 'clan', cache: false @supermodel.loadCollection(@members, 'members', {cache: false}) @supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false}) @@ -120,6 +121,8 @@ module.exports = class ClanDetailsView extends RootView context.lastUserCampaignLevelMap = lastUserCampaignLevelMap context.showExpandedProgress = maxLastUserCampaignLevel <= 30 or @showExpandedProgress context.userConceptsMap = userConceptsMap + context.arenas = @arenas + context.i18n = utils.i18n context afterRender: -> @@ -179,21 +182,24 @@ module.exports = class ClanDetailsView extends RootView return unless @campaigns.loaded @campaignLevelProgressions = [] @conceptsProgression = [] + @arenas = [] for campaign in @campaigns.models continue if campaign.get('slug') is 'auditions' campaignLevelProgression = ID: campaign.id slug: campaign.get('slug') - name: campaign.get('fullName') or campaign.get('name') + name: utils.i18n(campaign.attributes, 'fullName') or utils.i18n(campaign.attributes, 'name') levels: [] for levelID, level of campaign.get('levels') campaignLevelProgression.levels.push ID: levelID slug: level.slug - name: level.name + name: utils.i18n level, 'name' if level.concepts? for concept in level.concepts @conceptsProgression.push concept unless concept in @conceptsProgression + if level.type == 'hero-ladder' + @arenas.push level @campaignLevelProgressions.push campaignLevelProgression @render?() diff --git a/app/views/ladder/LadderPlayModal.coffee b/app/views/ladder/LadderPlayModal.coffee index d0c14ba17..6fa076ea6 100644 --- a/app/views/ladder/LadderPlayModal.coffee +++ b/app/views/ladder/LadderPlayModal.coffee @@ -43,11 +43,14 @@ module.exports = class LadderPlayModal extends ModalView # PART 1: Load challengers from the db unless some are in the matches startLoadingChallengersMaybe: -> - matches = @session?.get('matches') + if @options.league + matches = _.find(@session?.get('leagues'), leagueID: @options.league.id)?.stats.matches + else + matches = @session?.get('matches') if matches?.length then @loadNames() else @loadChallengers() loadChallengers: -> - @challengersCollection = new ChallengersData(@level, @team, @otherTeam, @session) + @challengersCollection = new ChallengersData(@level, @team, @otherTeam, @session, @options.league) @listenTo(@challengersCollection, 'sync', @loadNames) # PART 2: Loading the names of the other users @@ -156,7 +159,10 @@ module.exports = class LadderPlayModal extends ModalView mediumInfo = @challengeInfoFromSession(@challengersCollection.mediumPlayer.models[0]) hardInfo = @challengeInfoFromSession(@challengersCollection.hardPlayer.models[0]) else - matches = @session.get('matches') + if @options.league + matches = _.find(@session?.get('leagues'), leagueID: @options.league.id)?.stats.matches + else + matches = @session?.get('matches') won = (m for m in matches when m.metrics.rank < m.opponents[0].metrics.rank) lost = (m for m in matches when m.metrics.rank > m.opponents[0].metrics.rank) tied = (m for m in matches when m.metrics.rank is m.opponents[0].metrics.rank) @@ -195,18 +201,26 @@ module.exports = class LadderPlayModal extends ModalView } class ChallengersData - constructor: (@level, @team, @otherTeam, @session) -> + constructor: (@level, @team, @otherTeam, @session, @league) -> _.extend @, Backbone.Events - score = @session?.get('totalScore') or 25 - @easyPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score - 5, limit: 1, team: @otherTeam}) - @easyPlayer.fetch cache: false - @listenToOnce(@easyPlayer, 'sync', @challengerLoaded) - @mediumPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score, limit: 1, team: @otherTeam}) - @mediumPlayer.fetch cache: false - @listenToOnce(@mediumPlayer, 'sync', @challengerLoaded) - @hardPlayer = new LeaderboardCollection(@level, {order: -1, scoreOffset: score + 5, limit: 1, team: @otherTeam}) - @hardPlayer.fetch cache: false - @listenToOnce(@hardPlayer, 'sync', @challengerLoaded) + if @league + score = _.find(@session?.get('leagues'), leagueID: @league.id)?.stats?.totalScore or 10 + else + score = @session?.get('totalScore') or 10 + for player in [ + {type: 'easyPlayer', order: 1, scoreOffset: score - 5} + {type: 'mediumPlayer', order: 1, scoreOffset: score} + {type: 'hardPlayer', order: -1, scoreOffset: score + 5} + ] + playerResource = @[player.type] = new LeaderboardCollection(@level, @collectionParameters(order: player.order, scoreOffset: player.scoreOffset)) + playerResource.fetch cache: false + @listenToOnce playerResource, 'sync', @challengerLoaded + + collectionParameters: (parameters) -> + parameters.team = @otherTeam + parameters.limit = 1 + parameters['leagues.leagueID'] = @league.id if @league + parameters challengerLoaded: -> if @allLoaded() diff --git a/app/views/ladder/LadderTabView.coffee b/app/views/ladder/LadderTabView.coffee index c87729879..d3859cb4c 100644 --- a/app/views/ladder/LadderTabView.coffee +++ b/app/views/ladder/LadderTabView.coffee @@ -183,6 +183,8 @@ module.exports = class LadderTabView extends CocoView ctx.onFacebook = @facebookStatus is 'connected' ctx.onGPlus = application.gplusHandler.loggedIn ctx.capitalize = _.string.capitalize + ctx.league = @options.league + ctx._ = _ ctx generateHistogram: (histogramElement, histogramData, teamName) -> @@ -229,8 +231,11 @@ module.exports = class LadderTabView extends CocoView .attr('x', 1) .attr('width', width/20) .attr('height', (d) -> height - y(d.y)) - if @leaderboards[teamName].session? - playerScore = @leaderboards[teamName].session.get('totalScore') * 100 + if session = @leaderboards[teamName].session + if @options.league + playerScore = (_.find(session.get('leagues'), {leagueID: @options.league.id})?.stats.totalScore or 10) * 100 + else + playerScore = session.get('totalScore') * 100 scorebar = svg.selectAll('.specialbar') .data([playerScore]) .enter().append('g') @@ -319,14 +324,17 @@ module.exports.LeaderboardData = LeaderboardData = class LeaderboardData extends promises.push @topPlayers.fetch cache: false if @session - score = @session.get('totalScore') or 10 + if @league + score = _.find(@session.get('leagues'), {leagueID: @league.id})?.stats.totalScore or 10 + else + score = @session.get('totalScore') or 10 @playersAbove = new LeaderboardCollection(@level, @collectionParameters(order: 1, scoreOffset: score, limit: 4)) promises.push @playersAbove.fetch cache: false @playersBelow = new LeaderboardCollection(@level, @collectionParameters(order: -1, scoreOffset: score, limit: 4)) promises.push @playersBelow.fetch cache: false level = "#{@level.get('original')}.#{@level.get('version').major}" success = (@myRank) => - loadURL = "/db/level/#{level}/leaderboard_rank?scoreOffset=#{@session.get('totalScore')}&team=#{@team}" + loadURL = "/db/level/#{level}/leaderboard_rank?scoreOffset=#{score}&team=#{@team}" loadURL += '&leagues.leagueID=' + @league.id if @league promises.push $.ajax(loadURL, cache: false, success: success) @promise = $.when(promises...) diff --git a/app/views/ladder/LadderView.coffee b/app/views/ladder/LadderView.coffee index 48edcf5ee..5385da4e7 100644 --- a/app/views/ladder/LadderView.coffee +++ b/app/views/ladder/LadderView.coffee @@ -113,7 +113,7 @@ module.exports = class LadderView extends RootView showPlayModal: (teamID) -> session = (s for s in @sessions.models when s.get('team') is teamID)[0] - modal = new LadderPlayModal({}, @level, session, teamID) + modal = new LadderPlayModal({league: @league}, @level, session, teamID) @openModalView modal onClickedLink: (e) -> diff --git a/app/views/ladder/MyMatchesTabView.coffee b/app/views/ladder/MyMatchesTabView.coffee index 039513150..e6d3c34e7 100644 --- a/app/views/ladder/MyMatchesTabView.coffee +++ b/app/views/ladder/MyMatchesTabView.coffee @@ -129,7 +129,7 @@ module.exports = class MyMatchesTabView extends CocoView statsFromSession: (session) -> return null unless session if @options.league - return _.find(session.get('leagues') or [], leagueID: @options.league.id)?.stats + return _.find(session.get('leagues') or [], leagueID: @options.league.id)?.stats ? {} session.attributes generateScoreLineChart: (wrapperID, scoreHistory, teamName) => diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 09dfc9b7e..f841cafb7 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -200,7 +200,7 @@ LevelHandler = class LevelHandler extends Handler sortParameters = 'totalScore': req.query.order - selectProperties = ['totalScore', 'creatorName', 'creator', 'submittedCodeLanguage', 'heroConfig', 'leagues.leagueID'] + selectProperties = ['totalScore', 'creatorName', 'creator', 'submittedCodeLanguage', 'heroConfig', 'leagues.leagueID', 'leagues.stats.totalScore'] query = Session .find(sessionsQueryParameters)