mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-07 18:44:29 -04:00
Merge branch 'master' of https://github.com/codecombat/codecombat
This commit is contained in:
commit
8184d0b9d3
9 changed files with 94 additions and 48 deletions
app
styles/play/level/tome
templates/play
views/play
server/queues
|
@ -6,18 +6,33 @@
|
|||
|
||||
> .popover
|
||||
// Only those popovers which are our direct children (spell documentation)
|
||||
left: auto !important
|
||||
top: auto !important
|
||||
right: 100%
|
||||
bottom: 151px
|
||||
@include user-select(text)
|
||||
// Wish I could set max-width and max-height (and override Bootstrap's stuff)
|
||||
// but without explicitly setting height, child overflow-y: scroll doesn't work
|
||||
min-width: 100%
|
||||
height: 60%
|
||||
max-width: 600px
|
||||
|
||||
&.pinned
|
||||
@include box-shadow(0 0 500px white)
|
||||
left: auto !important
|
||||
top: auto !important
|
||||
right: 100%
|
||||
bottom: 151px
|
||||
@include user-select(text)
|
||||
// Wish I could set max-width and max-height (and override Bootstrap's stuff)
|
||||
// but without explicitly setting height, child overflow-y: scroll doesn't work
|
||||
min-width: 100%
|
||||
height: 60%
|
||||
|
||||
.arrow
|
||||
display: none
|
||||
|
||||
.close
|
||||
position: absolute
|
||||
top: 5%
|
||||
right: 5%
|
||||
font-size: 28px
|
||||
font-weight: bold
|
||||
@include opacity(0.6)
|
||||
text-shadow: 0 1px 0 white
|
||||
|
||||
&:hover
|
||||
@include opacity(1)
|
||||
|
||||
.popover
|
||||
padding: 10px 10px 30px 10px
|
||||
|
|
|
@ -11,33 +11,36 @@ block content
|
|||
for team in teams
|
||||
div.column.col-md-6
|
||||
a(href="/play/ladder/#{levelID}/team/#{team.id}", style="background-color: #{team.primaryColor}").play-button.btn.btn-danger.btn-block.btn-lg
|
||||
span Play
|
||||
span Play As
|
||||
span= team.name
|
||||
|
||||
table.table.table-bordered.table-condensed
|
||||
table.table.table-bordered.table-condensed.table-hover
|
||||
tr
|
||||
th(colspan=3, style="color: #{team.primaryColor}")
|
||||
span= team.name
|
||||
span Leaderboard
|
||||
tr
|
||||
th Score
|
||||
th Name
|
||||
|
||||
for session in team.leaderboard.topPlayers.models
|
||||
- var myRow = session.get('creator') == me.id
|
||||
tr(class=myRow ? "success" : "")
|
||||
td.score-cell= session.get('totalScore').toFixed(2)
|
||||
td= session.get('creatorName')
|
||||
td= session.get('creatorName') || "Anonymous"
|
||||
td
|
||||
if(!myRow)
|
||||
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") COMPETE
|
||||
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Compete!
|
||||
else
|
||||
a(href="/play/ladder/#{levelID}/team/#{team.id}") View details
|
||||
|
||||
unless me.attributes.anonymous
|
||||
hr
|
||||
button.btn.btn-warning.btn-lg.highlight#simulate-button(style="margin-bottom:10px;") Simulate Games!
|
||||
p(style="display:inline; margin-left:10px;")
|
||||
p(id="simulationStatusText", style="display:inline; margin-left:10px;")
|
||||
if simulationStatus
|
||||
| #{simulationStatus}
|
||||
else
|
||||
| By simulating games you can get your game ranked faster!
|
||||
if me.isAdmin()
|
||||
button.btn.btn-warning.btn-lg.highlight#simulate-all-button(style="margin-bottom:10px; float: right;") RESET AND SIMULATE GAMES
|
||||
button.btn.btn-danger.btn-lg.highlight#simulate-all-button(style="margin-bottom:10px; float: right;") RESET AND SIMULATE GAMES
|
|
@ -39,7 +39,7 @@ block content
|
|||
span.loss Loss
|
||||
if match.state === 'tie'
|
||||
span.tie Tie
|
||||
td.name-cell= match.opponentName
|
||||
td.name-cell= match.opponentName || "Anonymous"
|
||||
td.time-cell= match.when
|
||||
td.battle-cell
|
||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{match.sessionID}") Battle!
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
if me.get('anonymous')
|
||||
p Sign in or create an account and get your solution on the leaderboard!
|
||||
else
|
||||
#submit-session-button.btn.btn-primary Update Ladder Score
|
||||
a#go-to-leaderboard-button.btn.btn-primary(href="/play/ladder/#{levelSlug}/team/#{team}") Go to the leaderboard!
|
||||
p You can submit your game to be ranked from the leaderboard page.
|
||||
|
||||
.modal-footer
|
||||
a(href='#', data-dismiss="modal", aria-hidden="true", data-i18n="modal.close").btn.btn-primary Close
|
||||
|
|
|
@ -33,10 +33,13 @@ module.exports = class LadderView extends RootView
|
|||
method: 'POST'
|
||||
data:
|
||||
session: ID
|
||||
alert "Simulating all games!"
|
||||
alert "(do not push more than once pls)"
|
||||
$("#simulate-all-button").prop "disabled", true
|
||||
$("#simulate-all-button").text "Submitted all!"
|
||||
|
||||
onSimulateButtonClick: (e) ->
|
||||
$("#simulate-button").prop "disabled",true
|
||||
$("#simulate-button").text "Simulating..."
|
||||
|
||||
@simulator.fetchAndSimulateTask()
|
||||
|
||||
updateSimulationStatus: (simulationStatus, sessions)->
|
||||
|
@ -53,7 +56,7 @@ module.exports = class LadderView extends RootView
|
|||
@simulationStatus += "..."
|
||||
catch e
|
||||
console.log "There was a problem with the named simulation status: #{e}"
|
||||
@render()
|
||||
$("#simulationStatusText").text @simulationStatus
|
||||
|
||||
|
||||
constructor: (options, @levelID) ->
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports = class MultiplayerModal extends View
|
|||
events:
|
||||
'click textarea': 'onClickLink'
|
||||
'change #multiplayer': 'updateLinkSection'
|
||||
'click #submit-session-button': 'submitSession'
|
||||
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
|
@ -24,6 +24,8 @@ module.exports = class MultiplayerModal extends View
|
|||
'?session=' +
|
||||
@session.id)
|
||||
c.multiplayer = @session.get('multiplayer')
|
||||
c.team = @session.get 'team'
|
||||
c.levelSlug = @level?.get('slug')
|
||||
c.playableTeams = @playableTeams
|
||||
c.ladderGame = @level?.get('name') is 'Project DotA' and not me.get('isAnonymous')
|
||||
c
|
||||
|
@ -41,13 +43,6 @@ module.exports = class MultiplayerModal extends View
|
|||
la.toggle Boolean(multiplayer)
|
||||
true
|
||||
|
||||
submitSession: ->
|
||||
$.ajax('/queue/scoring', {
|
||||
method: 'POST'
|
||||
data:
|
||||
session: @session.id
|
||||
})
|
||||
|
||||
onHidden: ->
|
||||
multiplayer = Boolean(@$el.find('#multiplayer').prop('checked'))
|
||||
@session.set('multiplayer', multiplayer)
|
||||
|
|
|
@ -64,7 +64,7 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
|
|||
@$el.find('code').popover(
|
||||
animation: true
|
||||
html: true
|
||||
placement: 'left'
|
||||
placement: 'bottom'
|
||||
trigger: 'hover'
|
||||
content: @formatPopover doc
|
||||
container: @$el.parent()
|
||||
|
|
|
@ -64,6 +64,8 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
|
||||
subscriptions:
|
||||
'surface:frame-changed': "onFrameChanged"
|
||||
'tome:palette-hovered': "onPaletteHovered"
|
||||
'tome:palette-pin-toggled': "onPalettePinToggled"
|
||||
|
||||
events:
|
||||
'mouseenter': 'onMouseEnter'
|
||||
|
@ -100,13 +102,13 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
@$el.popover(
|
||||
animation: false
|
||||
html: true
|
||||
placement: 'left'
|
||||
placement: 'top'
|
||||
trigger: 'manual' # Hover, until they click, which will then pin it until unclick.
|
||||
content: @formatPopover()
|
||||
container: '#tome-view'
|
||||
)
|
||||
@$el.on 'show.bs.popover', =>
|
||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name
|
||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name, entry: @
|
||||
|
||||
formatPopover: ->
|
||||
content = popoverTemplate doc: @doc, value: @formatValue(), marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in @doc.args ? [])
|
||||
|
@ -143,31 +145,45 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||
@$el.data('bs.popover').options.content = @formatPopover()
|
||||
@$el.popover('setContent')
|
||||
@$el.popover 'show' unless @popoverPinned
|
||||
@$el.popover 'show' unless @popoverPinned or @otherPopoverPinned
|
||||
|
||||
onMouseLeave: (e) ->
|
||||
@$el.popover 'hide' unless @popoverPinned
|
||||
@$el.popover 'hide' unless @popoverPinned or @otherPopoverPinned
|
||||
|
||||
togglePinned: ->
|
||||
if @popoverPinned
|
||||
@popoverPinned = false
|
||||
@$el.add('#tome-view .popover').removeClass 'pinned'
|
||||
$('#tome-view .popover .close').remove()
|
||||
@$el.popover 'hide'
|
||||
else
|
||||
@popoverPinned = true
|
||||
@$el.popover 'show'
|
||||
@$el.add('#tome-view .popover').addClass 'pinned'
|
||||
x = $('<button type="button" data-dismiss="modal" aria-hidden="true" class="close">×</button>')
|
||||
$('#tome-view .popover').append x
|
||||
x.on 'click', @onClick
|
||||
Backbone.Mediator.publish 'tome:palette-pin-toggled', entry: @, pinned: @popoverPinned
|
||||
|
||||
onClick: (e) ->
|
||||
onClick: (e) =>
|
||||
unless @popoverPinned
|
||||
$(e.target).selectText()
|
||||
e.stopPropagation() # don't re-focus editor since we might want to select text
|
||||
@togglePinned()
|
||||
Backbone.Mediator.publish 'tome:palette-clicked', thang: @thang, prop: @doc.name
|
||||
Backbone.Mediator.publish 'tome:palette-clicked', thang: @thang, prop: @doc.name, entry: @
|
||||
|
||||
onFrameChanged: (e) ->
|
||||
return unless e.selectedThang?.id is @thang.id
|
||||
@options.thang = @thang = e.selectedThang # Update our thang to the current version
|
||||
|
||||
onPaletteHovered: (e) ->
|
||||
return if e.entry is @
|
||||
@togglePinned() if @popoverPinned
|
||||
|
||||
onPalettePinToggled: (e) ->
|
||||
return if e.entry is @
|
||||
@otherPopoverPinned = e.pinned
|
||||
|
||||
destroy: ->
|
||||
$('.popover.pinned').remove() if @popoverPinned # @$el.popover('destroy') doesn't work
|
||||
@togglePinned() if @popoverPinned
|
||||
|
|
|
@ -26,23 +26,26 @@ connectToScoringQueue = ->
|
|||
|
||||
module.exports.createNewTask = (req, res) ->
|
||||
requestSessionID = req.body.session
|
||||
if isUserAnonymous req then return errors.forbidden res, "You need to be logged in to be added to the leaderboard"
|
||||
return errors.badInput res, "The session ID is invalid" unless typeof requestSessionID is "string"
|
||||
validatePermissions req, requestSessionID, (error, permissionsAreValid) ->
|
||||
if err? then return errors.serverError res, "There was an error validating permissions"
|
||||
unless permissionsAreValid then return errors.forbidden res, "You do not have the permissions to submit that game to the leaderboard"
|
||||
|
||||
fetchSessionToSubmit requestSessionID, (err, sessionToSubmit) ->
|
||||
if err? then return errors.serverError res, "There was an error finding the given session."
|
||||
return errors.badInput res, "The session ID is invalid" unless typeof requestSessionID is "string"
|
||||
|
||||
updateSessionToSubmit sessionToSubmit, (err, data) ->
|
||||
if err? then return errors.serverError res, "There was an error updating the session"
|
||||
fetchSessionToSubmit requestSessionID, (err, sessionToSubmit) ->
|
||||
if err? then return errors.serverError res, "There was an error finding the given session."
|
||||
|
||||
fetchSessionsToRankAgainst (err, sessionsToRankAgainst) ->
|
||||
if err? then return errors.serverError res, "There was an error fetching the sessions to rank against"
|
||||
updateSessionToSubmit sessionToSubmit, (err, data) ->
|
||||
if err? then return errors.serverError res, "There was an error updating the session"
|
||||
|
||||
taskPairs = generateTaskPairs(sessionsToRankAgainst, sessionToSubmit)
|
||||
sendEachTaskPairToTheQueue taskPairs, (taskPairError) ->
|
||||
if taskPairError? then return errors.serverError res, "There was an error sending the task pairs to the queue"
|
||||
fetchSessionsToRankAgainst (err, sessionsToRankAgainst) ->
|
||||
if err? then return errors.serverError res, "There was an error fetching the sessions to rank against"
|
||||
|
||||
sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"}
|
||||
taskPairs = generateTaskPairs(sessionsToRankAgainst, sessionToSubmit)
|
||||
sendEachTaskPairToTheQueue taskPairs, (taskPairError) ->
|
||||
if taskPairError? then return errors.serverError res, "There was an error sending the task pairs to the queue"
|
||||
|
||||
sendResponseObject req, res, {"message":"All task pairs were succesfully sent to the queue"}
|
||||
|
||||
module.exports.dispatchTaskToConsumer = (req, res) ->
|
||||
if isUserAnonymous(req) then return errors.forbidden res, "You need to be logged in to simulate games"
|
||||
|
@ -95,6 +98,14 @@ module.exports.processTaskResult = (req, res) ->
|
|||
console.log "Sending response object"
|
||||
sendResponseObject req, res, {"message":"The scores were updated successfully!"}
|
||||
|
||||
validatePermissions = (req, sessionID, callback) ->
|
||||
if isUserAnonymous req then return callback null, false
|
||||
if isUserAdmin req then return callback null, true
|
||||
LevelSession.findOne(_id:sessionID).select('creator submittedCode code').lean().exec (err, retrievedSession) ->
|
||||
if err? then return callback err, retrievedSession
|
||||
code = retrievedSession.code
|
||||
submittedCode = retrievedSession.submittedCode
|
||||
callback null, (retrievedSession.creator is req.user?.id and not _.isEqual(code, submittedCode))
|
||||
|
||||
addMatchToSessions = (clientResponseObject, newScoreObject, callback) ->
|
||||
matchObject = {}
|
||||
|
@ -175,6 +186,8 @@ getUserIDFromRequest = (req) -> if req.user? then return req.user._id else retur
|
|||
|
||||
isUserAnonymous = (req) -> if req.user? then return req.user.get('anonymous') else return true
|
||||
|
||||
isUserAdmin = (req) -> return Boolean(req.user?.isAdmin())
|
||||
|
||||
parseTaskQueueMessage = (req, res, message) ->
|
||||
try
|
||||
if typeof message.getBody() is "object" then return message.getBody()
|
||||
|
|
Loading…
Add table
Reference in a new issue