Merge pull request #415 from codecombat/master

Merge master into production
This commit is contained in:
Michael Schmatz 2014-02-24 17:58:02 -08:00
commit ce56e5df03
50 changed files with 543 additions and 330 deletions

View file

@ -1,6 +1,7 @@
app = require 'application' app = require 'application'
auth = require 'lib/auth'
$ -> init = ->
app.initialize() app.initialize()
Backbone.history.start({ pushState: true }) Backbone.history.start({ pushState: true })
handleNormalUrls() handleNormalUrls()
@ -9,6 +10,15 @@ $ ->
treemaExt.setup() treemaExt.setup()
filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z') filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z')
$ ->
# Make sure we're "logged in" first.
if auth.me.id
init()
else
Backbone.Mediator.subscribeOnce 'me:synced', init
window.init = init
handleNormalUrls = -> handleNormalUrls = ->
# http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/ # http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/
$(document).on "click", "a[href^='/']", (event) -> $(document).on "click", "a[href^='/']", (event) ->

View file

@ -141,8 +141,8 @@ module.exports = class SpriteBuilder
return unless shapes.length return unless shapes.length
colors = @initColorMap(shapes) colors = @initColorMap(shapes)
@adjustHuesForColorMap(colors, config.hue) @adjustHuesForColorMap(colors, config.hue)
@adjustValueForColorMap(colors, 1, config.lightness) @adjustValueForColorMap(colors, 1, config.saturation)
@adjustValueForColorMap(colors, 2, config.saturation) @adjustValueForColorMap(colors, 2, config.lightness)
@applyColorMap(shapes, colors) @applyColorMap(shapes, colors)
initColorMap: (shapes) -> initColorMap: (shapes) ->

View file

@ -0,0 +1,48 @@
CocoClass = require 'lib/CocoClass'
module.exports = class CastingScreen extends CocoClass
subscriptions:
'tome:cast-spells': 'onCastingBegins'
'god:new-world-created': 'onCastingEnds'
constructor: (options) ->
super()
options ?= {}
@camera = options.camera
@layer = options.layer
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
@build()
onCastingBegins: ->
@show()
onCastingEnds: ->
@hide()
toString: -> "<CastingScreen>"
build: ->
@dimLayer = new createjs.Container()
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
@dimLayer.layerIndex = -11
@dimLayer.addChild @dimScreen = new createjs.Shape()
@dimScreen.graphics.beginFill("rgba(0,0,0,0.5)").rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimLayer.cache 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimLayer.alpha = 0
@layer.addChild @dimLayer
show: ->
return if @on
@on = true
@dimLayer.alpha = 0
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:1}, 500)
hide: ->
return unless @on
@on = false
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:0}, 500)

View file

@ -65,13 +65,13 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@age = 0 @age = 0
@displayObject = new createjs.Container() @displayObject = new createjs.Container()
if @thangType.get('actions') if @thangType.get('actions')
@onThangTypeLoaded() @setupSprite()
else else
@stillLoading = true @stillLoading = true
@thangType.fetch() @thangType.fetch()
@thangType.once 'sync', @onThangTypeLoaded, @ @thangType.once 'sync', @setupSprite, @
onThangTypeLoaded: -> setupSprite: ->
@stillLoading = false @stillLoading = false
@actions = @thangType.getActions() @actions = @thangType.getActions()
@buildFromSpriteSheet @buildSpriteSheet() @buildFromSpriteSheet @buildSpriteSheet()
@ -101,6 +101,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
# temp, until these are re-exported with perspective # temp, until these are re-exported with perspective
if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle'] if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle']
sprite.scaleY *= @options.camera.y2x sprite.scaleY *= @options.camera.y2x
@displayObject.removeChild(@imageObject) if @imageObject
@imageObject = sprite @imageObject = sprite
@displayObject.addChild(sprite) @displayObject.addChild(sprite)
@addHealthBar() @addHealthBar()
@ -157,6 +158,14 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@hiding = false @hiding = false
@updateAlpha() @updateAlpha()
stop: ->
@imageObject?.stop?()
mark.stop() for name, mark of @marks
play: ->
@imageObject?.play?()
mark.play() for name, mark of @marks
update: -> update: ->
# Gets the sprite to reflect what the current state of the thangs and surface are # Gets the sprite to reflect what the current state of the thangs and surface are
return if @stillLoading return if @stillLoading
@ -197,8 +206,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
if @thang.width isnt @lastThangWidth or @thang.height isnt @lastThangHeight if @thang.width isnt @lastThangWidth or @thang.height isnt @lastThangHeight
[@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height] [@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height]
bounds = @imageObject.getBounds() bounds = @imageObject.getBounds()
@imageObject.scaleX = @thang.width * Camera.PPM / bounds.width * @thangType.get('scale') ? 1 @imageObject.scaleX = @thang.width * Camera.PPM / bounds.width
@imageObject.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height * @thangType.get('scale') ? 1 @imageObject.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height
unless @thang.spriteName is 'Beam'
@imageObject.scaleX *= @thangType.get('scale') ? 1
@imageObject.scaleY *= @thangType.get('scale') ? 1
return return
scaleX = if @getActionProp 'flipX' then -1 else 1 scaleX = if @getActionProp 'flipX' then -1 else 1
scaleY = if @getActionProp 'flipY' then -1 else 1 scaleY = if @getActionProp 'flipY' then -1 else 1

View file

@ -54,17 +54,19 @@ module.exports = class Label extends CocoClass
buildLabelOptions: -> buildLabelOptions: ->
o = {} o = {}
st = {dialogue: 'D', say: 'S', name: 'N'}[@style] st = {dialogue: 'D', say: 'S', name: 'N'}[@style]
o.marginX = {D: 5, S: 2, N: 3}[st] o.marginX = {D: 5, S: 6, N: 3}[st]
o.marginY = {D: 6, S: 2, N: 3}[st] o.marginY = {D: 6, S: 4, N: 3}[st]
o.fontWeight = {D: "bold", S: "bold", N: "bold"}[st]
o.shadow = {D: false, S: true, N: true}[st] o.shadow = {D: false, S: true, N: true}[st]
o.fontSize = {D: 25, S: 19, N: 14}[st] o.shadowColor = {D: "#FFF", S: "#000", N: "#FFF"}[st]
o.fontSize = {D: 25, S: 12, N: 12}[st]
fontFamily = {D: "Arial", S: "Arial", N: "Arial"}[st] fontFamily = {D: "Arial", S: "Arial", N: "Arial"}[st]
o.fontDescriptor = "#{o.fontSize}px #{fontFamily}" o.fontDescriptor = "#{o.fontWeight} #{o.fontSize}px #{fontFamily}"
o.fontColor = {D: "#000", S: "#000", N: "#00a"}[st] o.fontColor = {D: "#000", S: "#FFF", N: "#00a"}[st]
o.backgroundFillColor = {D: "white", S: "rgba(255, 255, 255, 0.2)", N: "rgba(255, 255, 255, 0.5)"}[st] o.backgroundFillColor = {D: "white", S: "rgba(0, 0, 0, 0.4)", N: "rgba(255, 255, 255, 0.5)"}[st]
o.backgroundStrokeColor = {D: "black", S: "rgba(0, 0, 0, 0.2)", N: "rgba(0, 0, 0, 0.0)"}[st] o.backgroundStrokeColor = {D: "black", S: "rgba(0, 0, 0, .6)", N: "rgba(0, 0, 0, 0.0)"}[st]
o.backgroundStrokeStyle = {D: 2, S: 1, N: 1}[st] o.backgroundStrokeStyle = {D: 2, S: 1, N: 1}[st]
o.backgroundBorderRadius = {D: 10, S: 5, N: 3}[st] o.backgroundBorderRadius = {D: 10, S: 3, N: 3}[st]
o.layerPriority = {D: 10, S: 5, N: 5}[st] o.layerPriority = {D: 10, S: 5, N: 5}[st]
maxWidth = {D: 300, S: 300, N: 180}[st] maxWidth = {D: 300, S: 300, N: 180}[st]
maxWidth = Math.max @camera.canvasWidth / 2 - 100, maxWidth # Does this do anything? maxWidth = Math.max @camera.canvasWidth / 2 - 100, maxWidth # Does this do anything?
@ -79,7 +81,7 @@ module.exports = class Label extends CocoClass
label.lineHeight = o.fontSize + 2 label.lineHeight = o.fontSize + 2
label.x = o.marginX label.x = o.marginX
label.y = o.marginY label.y = o.marginY
label.shadow = new createjs.Shadow "#FFF", 1, 1, 0 if o.shadow label.shadow = new createjs.Shadow o.shadowColor, 1, 1, 0 if o.shadow
label.layerPriority = o.layerPriority label.layerPriority = o.layerPriority
label.name = "Sprite Label - #{@style}" label.name = "Sprite Label - #{@style}"
o.textHeight = label.getMeasuredHeight() o.textHeight = label.getMeasuredHeight()

View file

@ -48,7 +48,7 @@ module.exports = class Mark extends CocoClass
build: -> build: ->
unless @mark unless @mark
if @name is 'bounds' then @buildBounds() if @name is 'bounds' then @buildBounds()
else if @name is 'shadow' then @buildRadius() else if @name is 'shadow' then @buildShadow()
else if @name is 'debug' then @buildDebug() else if @name is 'debug' then @buildDebug()
else if @thangType then @buildSprite() else if @thangType then @buildSprite()
else console.error "Don't know how to build mark for", @name else console.error "Don't know how to build mark for", @name
@ -87,21 +87,31 @@ module.exports = class Mark extends CocoClass
@lastWidth = @sprite.thang.width @lastWidth = @sprite.thang.width
@lastHeight = @sprite.thang.height @lastHeight = @sprite.thang.height
buildRadius: -> buildShadow: ->
# TODO: make this not just a shadow width = (@sprite.thang?.width ? 0) + 0.5
# TODO: draw boxes and ellipses for non-circular Thangs height = (@sprite.thang?.height ? 0) + 0.5
diameter = @sprite.thangType.get('shadow') ? @sprite.thang?.width + 0.5 longest = Math.max width, height
diameter *= Camera.PPM actualLongest = @sprite.thangType.get('shadow') ? longest
width = width * actualLongest / longest
height = height * actualLongest / longest
width *= Camera.PPM
height *= Camera.PPM * @camera.y2x # TODO: doesn't work with rotation
@mark = new createjs.Shape() @mark = new createjs.Shape()
@mark.mouseEnabled = false @mark.mouseEnabled = false
@mark.graphics.beginFill "black" @mark.graphics.beginFill "black"
@mark.graphics.drawEllipse 0, 0, diameter, diameter * @camera.y2x if @sprite.thang.shape in ['ellipsoid', 'disc']
@mark.graphics.drawEllipse 0, 0, width, height
else
@mark.graphics.drawRect 0, 0, width, height
@mark.graphics.endFill() @mark.graphics.endFill()
@mark.regX = diameter / 2 @mark.regX = width / 2
@mark.regY = diameter / 2 * @camera.y2x @mark.regY = height / 2
@mark.layerIndex = 10 @mark.layerIndex = 10
#@mark.cache 0, 0, diameter, diameter # not actually faster than simple ellipse draw #@mark.cache 0, 0, diameter, diameter # not actually faster than simple ellipse draw
buildRadius: ->
return # not implemented
buildDebug: -> buildDebug: ->
@mark = new createjs.Shape() @mark = new createjs.Shape()
PX = 3 PX = 3
@ -152,7 +162,7 @@ module.exports = class Mark extends CocoClass
@mark.y += offset.y @mark.y += offset.y
updateRotation: -> updateRotation: ->
if @name is 'debug' if @name is 'debug' or (@name is 'shadow' and @sprite.thang?.shape in ["rectangle", "box"])
@mark.rotation = @sprite.thang.rotation * 180 / Math.PI @mark.rotation = @sprite.thang.rotation * 180 / Math.PI
updateScale: -> updateScale: ->
@ -174,3 +184,6 @@ module.exports = class Mark extends CocoClass
@mark.scaleX = @mark.scaleY = Math.min 1, scale @mark.scaleX = @mark.scaleY = Math.min 1, scale
if @name in ['selection', 'target', 'repair'] if @name in ['selection', 'target', 'repair']
@mark.scaleY *= @camera.y2x # code applies perspective @mark.scaleY *= @camera.y2x # code applies perspective
stop: -> @markSprite?.stop()
play: -> @markSprite?.play()

View file

@ -20,6 +20,7 @@ module.exports = class SpriteBoss extends CocoClass
'level-lock-select': 'onSetLockSelect' 'level-lock-select': 'onSetLockSelect'
'level:restarted': 'onLevelRestarted' 'level:restarted': 'onLevelRestarted'
'god:new-world-created': 'onNewWorld' 'god:new-world-created': 'onNewWorld'
'tome:cast-spells': 'onCastSpells'
constructor: (@options) -> constructor: (@options) ->
super() super()
@ -205,6 +206,14 @@ module.exports = class SpriteBoss extends CocoClass
onNewWorld: (e) -> onNewWorld: (e) ->
@world = @options.world = e.world @world = @options.world = e.world
sprite.imageObject.play() for thangID, sprite of @sprites
@selectionMark?.play()
@targetMark?.play()
onCastSpells: ->
sprite.imageObject.stop() for thangID, sprite of @sprites
@selectionMark?.stop()
@targetMark?.stop()
# Selection # Selection

View file

@ -8,6 +8,7 @@ CameraBorder = require './CameraBorder'
Layer = require './Layer' Layer = require './Layer'
Letterbox = require './Letterbox' Letterbox = require './Letterbox'
Dimmer = require './Dimmer' Dimmer = require './Dimmer'
CastingScreen = require './CastingScreen'
DebugDisplay = require './DebugDisplay' DebugDisplay = require './DebugDisplay'
CoordinateDisplay = require './CoordinateDisplay' CoordinateDisplay = require './CoordinateDisplay'
SpriteBoss = require './SpriteBoss' SpriteBoss = require './SpriteBoss'
@ -88,6 +89,7 @@ module.exports = Surface = class Surface extends CocoClass
@spriteBoss.destroy() @spriteBoss.destroy()
@chooser?.destroy() @chooser?.destroy()
@dimmer?.destroy() @dimmer?.destroy()
@castingScreen?.destroy()
@stage.clear() @stage.clear()
@musicPlayer?.destroy() @musicPlayer?.destroy()
@stage.removeAllChildren() @stage.removeAllChildren()
@ -224,7 +226,7 @@ module.exports = Surface = class Surface extends CocoClass
@currentFrame = actualCurrentFrame @currentFrame = actualCurrentFrame
# TODO: are these needed, or perhaps do they duplicate things? # TODO: are these needed, or perhaps do they duplicate things?
@spriteBoss.update() @spriteBoss.update true
@onFrameChanged() @onFrameChanged()
getCurrentFrame: -> getCurrentFrame: ->
@ -299,11 +301,18 @@ module.exports = Surface = class Surface extends CocoClass
@lastFrame = @currentFrame @lastFrame = @currentFrame
onCastSpells: (event) -> onCastSpells: (event) ->
@casting = true
@wasPlayingWhenCastingBegan = @playing
Backbone.Mediator.publish 'level-set-playing', { playing: false }
createjs.Tween.removeTweens(@surfaceLayer) createjs.Tween.removeTweens(@surfaceLayer)
createjs.Tween.get(@surfaceLayer).to({alpha:0.9}, 1000, createjs.Ease.getPowOut(4.0)) createjs.Tween.get(@surfaceLayer).to({alpha:0.9}, 1000, createjs.Ease.getPowOut(4.0))
onNewWorld: (event) -> onNewWorld: (event) ->
return unless event.world.name is @world.name return unless event.world.name is @world.name
@casting = false
Backbone.Mediator.publish 'level-set-playing', { playing: @wasPlayingWhenCastingBegan }
fastForwardTo = null fastForwardTo = null
if @playing if @playing
fastForwardTo = Math.min event.world.firstChangedFrame, @currentFrame fastForwardTo = Math.min event.world.firstChangedFrame, @currentFrame
@ -340,6 +349,7 @@ module.exports = Surface = class Surface extends CocoClass
@surfaceLayer.addChild @cameraBorder = new CameraBorder bounds: @camera.bounds @surfaceLayer.addChild @cameraBorder = new CameraBorder bounds: @camera.bounds
@screenLayer.addChild new Letterbox canvasWidth: canvasWidth, canvasHeight: canvasHeight @screenLayer.addChild new Letterbox canvasWidth: canvasWidth, canvasHeight: canvasHeight
@spriteBoss = new SpriteBoss camera: @camera, surfaceLayer: @surfaceLayer, surfaceTextLayer: @surfaceTextLayer, world: @world, thangTypes: @options.thangTypes, choosing: @options.choosing, navigateToSelection: @options.navigateToSelection, showInvisible: @options.showInvisible @spriteBoss = new SpriteBoss camera: @camera, surfaceLayer: @surfaceLayer, surfaceTextLayer: @surfaceTextLayer, world: @world, thangTypes: @options.thangTypes, choosing: @options.choosing, navigateToSelection: @options.navigateToSelection, showInvisible: @options.showInvisible
@castingScreen ?= new CastingScreen camera: @camera, layer: @screenLayer
@stage.enableMouseOver(10) @stage.enableMouseOver(10)
@stage.addEventListener 'stagemousemove', @onMouseMove @stage.addEventListener 'stagemousemove', @onMouseMove
@stage.addEventListener 'stagemousedown', @onMouseDown @stage.addEventListener 'stagemousedown', @onMouseDown
@ -497,7 +507,7 @@ module.exports = Surface = class Surface extends CocoClass
updateState: (frameChanged) -> updateState: (frameChanged) ->
# world state must have been restored in @updateSpriteSounds # world state must have been restored in @updateSpriteSounds
@camera.updateZoom() @camera.updateZoom()
@spriteBoss.update frameChanged @spriteBoss.update frameChanged unless @casting
@dimmer?.setSprites @spriteBoss.sprites @dimmer?.setSprites @spriteBoss.sprites
drawCurrentFrame: (e) -> drawCurrentFrame: (e) ->
@ -508,6 +518,7 @@ module.exports = Surface = class Surface extends CocoClass
updatePaths: -> updatePaths: ->
return unless @options.paths return unless @options.paths
return if @casting
@hidePaths() @hidePaths()
selectedThang = @spriteBoss.selectedSprite?.thang selectedThang = @spriteBoss.selectedSprite?.thang
return if @world.showPaths is 'never' return if @world.showPaths is 'never'

View file

@ -24,7 +24,7 @@ module.exports = class WizardSprite extends IndieSprite
constructor: (thangType, options) -> constructor: (thangType, options) ->
if options?.isSelf if options?.isSelf
options.colorConfig = me.get('wizard')?.colorConfig or {} options.colorConfig = _.cloneDeep(me.get('wizard')?.colorConfig) or {}
super thangType, options super thangType, options
@isSelf = options.isSelf @isSelf = options.isSelf
@targetPos = @thang.pos @targetPos = @thang.pos
@ -59,7 +59,12 @@ module.exports = class WizardSprite extends IndieSprite
onMeSynced: (e) -> onMeSynced: (e) ->
return unless @isSelf return unless @isSelf
@setNameLabel me.displayName() if @displayObject.visible # not if we hid the wiz @setNameLabel me.displayName() if @displayObject.visible # not if we hid the wiz
@setColorHue me.get('wizardColor1') newColorConfig = me.get('wizard')?.colorConfig or {}
shouldUpdate = not _.isEqual(newColorConfig, @options.colorConfig)
@options.colorConfig = _.cloneDeep(newColorConfig)
if shouldUpdate
@setupSprite()
@playAction(@currentAction)
onSpriteSelected: (e) -> onSpriteSelected: (e) ->
return unless @isSelf return unless @isSelf

View file

@ -55,7 +55,7 @@ module.exports = class World
@thangMap[thang.id] = thang @thangMap[thang.id] = thang
thangDialogueSounds: -> thangDialogueSounds: ->
if @frames.length < @totalFrames then worldShouldBeOverBeforeGrabbingDialogue if @frames.length < @totalFrames then throw new Error("World should be over before grabbing dialogue")
[sounds, seen] = [[], {}] [sounds, seen] = [[], {}]
for frame in @frames for frame in @frames
for thangID, state of frame.thangStateMap for thangID, state of frame.thangStateMap
@ -245,7 +245,7 @@ module.exports = class World
serialize: -> serialize: ->
# Code hotspot; optimize it # Code hotspot; optimize it
if @frames.length < @totalFrames then worldShouldBeOverBeforeSerialization if @frames.length < @totalFrames then throw new Error("World Should Be Over Before Serialization")
[transferableObjects, nontransferableObjects] = [0, 0] [transferableObjects, nontransferableObjects] = [0, 0]
o = {name: @name, totalFrames: @totalFrames, maxTotalFrames: @maxTotalFrames, frameRate: @frameRate, dt: @dt, victory: @victory, userCodeMap: {}, trackedProperties: {}} o = {name: @name, totalFrames: @totalFrames, maxTotalFrames: @maxTotalFrames, frameRate: @frameRate, dt: @dt, victory: @victory, userCodeMap: {}, trackedProperties: {}}
o.trackedProperties[prop] = @[prop] for prop in @trackedProperties or [] o.trackedProperties[prop] = @[prop] for prop in @trackedProperties or []

View file

@ -38,43 +38,3 @@
.form .form
max-width: 600px max-width: 600px
#wizard-settings-tab-view
#color-settings
float: left
width: 600px
margin-left: 30px
canvas
float: left
border: 2px solid black
margin: 20px
.color-group
clear: both
padding-bottom: 10px
margin-bottom: 10px
border-bottom: 1px solid gray
.name-cell
float: left
width: 100px
padding-top: 2px
input
margin-right: 10px
position: relative
top: -3px
.checkbox-cell
float: left
width: 40px
.slider-cell
margin-bottom: 10px
float: left
width: 120px
.selector
width: 100px

View file

@ -0,0 +1,42 @@
#wizard-settings-view
h3#loading
text-align: center
#color-settings
float: left
width: 600px
margin-left: 30px
canvas
float: left
border: 2px solid black
margin: 20px
.color-group
clear: both
padding-bottom: 10px
margin-bottom: 10px
border-bottom: 1px solid gray
.name-cell
float: left
width: 100px
padding-top: 2px
input
margin-right: 10px
position: relative
top: -3px
.checkbox-cell
float: left
width: 40px
.slider-cell
margin-bottom: 10px
float: left
width: 120px
.selector
width: 100px

View file

@ -24,9 +24,9 @@
width: 300px width: 300px
height: 80px height: 80px
//@include transition(color .10s linear) // buggy in chrome, coloring doesn't get the right edge of the word @include transition(color .10s linear)
&:hover a, &:active a &:hover button, &:active button
color: #8090AA color: #8090AA
canvas canvas

View file

@ -1,20 +1,17 @@
#wizard-settings-modal #wizard-settings-modal
color: black color: black
background: white
width: 400px #wizard-settings-view #color-settings
width: 480px
canvas canvas
border: 1px solid black margin: 0px auto 20px
float: left display: block
float: none
background: white
.settings .wizard-name-line
width: 225px text-align: center
margin: 10px margin-bottom: 10px
display: inline-block label
margin-right: 10px
.selector
margin: 10px 5px
button
margin-left: 10px
float: right

View file

@ -20,3 +20,5 @@
white-space: nowrap white-space: nowrap
overflow: hidden overflow: hidden
#must-log-in button
margin-right: 10px

View file

@ -5,3 +5,8 @@
#competitors-column .well #competitors-column .well
font-size: 18px font-size: 18px
padding: 7px padding: 7px
#your-score
margin-top: 20px
text-align: center
font-size: 20px

View file

@ -132,9 +132,21 @@
height: 100% height: 100%
width: 2% width: 2%
.footer:not(:hover) .footer
@include opacity(0.6) @media screen and (min-aspect-ratio: 17/10)
display: none
@media screen and (min-aspect-ratio: 17/10) &:not(:hover)
#level-view .footer @include opacity(0.6)
display: none
.hour-of-code-explanation
margin-top: 5px
color: white
font-size: 12px
&:not(:hover)
@include opacity(0.75)
a
color: white
text-decoration: underline

View file

@ -77,7 +77,7 @@
.executed .executed
background-color: rgba(245, 255, 6, 0.18) background-color: rgba(245, 255, 6, 0.18)
.problem-marker-info .problem-marker-info
background-color: rgba(96, 63, 84, 0.25) background-color: rgba(196, 163, 184, 0.25)
.problem-marker-warning .problem-marker-warning
background-color: rgba(100, 65, 20, 0.25) background-color: rgba(100, 65, 20, 0.25)
.problem-marker-error .problem-marker-error

View file

@ -9,16 +9,18 @@
border: 1px solid transparent border: 1px solid transparent
cursor: pointer cursor: pointer
@include user-select(all) @include user-select(all)
::selection
background: transparent
&:hover &:hover
border: 1px solid #BFF border: 1px solid #000000
&.pinned &.pinned
background-color: darken(#BFF, 20%) background-color: darken(#FFFFFF, 25%)
// Pulling these colors from the most relevant textmate-theme classes // Pulling these colors from the most relevant textmate-theme classes
&.function &.function
color: #0000A2 color: #0066FF
&.object &.object
color: rgb(6, 150, 14) color: rgb(6, 150, 14)
&.string &.string

View file

@ -57,7 +57,7 @@ block content
a(href="http://en.gravatar.com/profiles/edit/?noclose#your-images", target="_blank", data-i18n="account_settings.gravatar_add_more_photos") Add more photos to your Gravatar account to access them here. a(href="http://en.gravatar.com/profiles/edit/?noclose#your-images", target="_blank", data-i18n="account_settings.gravatar_add_more_photos") Add more photos to your Gravatar account to access them here.
#wizard-pane.tab-pane #wizard-pane.tab-pane
#wizard-settings-tab-view #wizard-settings-view
#password-pane.tab-pane #password-pane.tab-pane
p p

View file

@ -8,7 +8,7 @@ canvas#tinting-display(width=200, height=200).img-rounded
span(data-i18n='wizard_settings.' + group.dasherized)= group.humanized span(data-i18n='wizard_settings.' + group.dasherized)= group.humanized
div.sliders div.sliders
div.slider-cell div.slider-cell
label(for=group.humanized+"_hue", data-i18n="wizard_settigs.hue") Hue label(for=group.humanized+"_hue", data-i18n="wizard_settings.hue") Hue
.selector(id=group.humanized+"_hue", name=group.name+'.hue', data-key='hue') .selector(id=group.humanized+"_hue", name=group.name+'.hue', data-key='hue')
div.slider-cell div.slider-cell
label(for=group.humanized+"_saturation", data-i18n="wizard_settings.saturation") Saturation label(for=group.humanized+"_saturation", data-i18n="wizard_settings.saturation") Saturation

View file

@ -4,19 +4,17 @@ block modal-header-content
h3(data-i18n="wizard_settings.title") Wizard Settings h3(data-i18n="wizard_settings.title") Wizard Settings
block modal-body-content block modal-body-content
h4(data-i18n="wizard_settings.customize_avatar") Customize Your Avatar div.wizard-name-line.form-group
label.control-label(for="name")
| Name
input#wizard-settings-name(name="name", type="text", value="#{me.get('name')||''}")
canvas(width="120px", height="150px") #wizard-settings-view
.settings
.form-vertical.form block modal-body-wait-content
.form-group h3 Saving...
label.control-label(for="name") .progress.progress-striped.active
| Name .progress-bar
button.btn.btn-mini.btn-primary#random-name Random
input#wizard-settings-name(name="name", type="text", value="#{me.get('name')||''}")
.form-group
label.control-label(for="wizardColor1") Hat Color
.selector#wizard-settings-color-1
block modal-footer-content block modal-footer-content
button.btn.btn-primary.btn-large#wizard-settings-done(type="button", data-dismiss="modal", aria-hidden="true") Done button.btn.btn-primary.btn-large#wizard-settings-done(type="button") Done

View file

@ -6,47 +6,58 @@ block content
div#level-description div#level-description
!{description} !{description}
a(href="http://www.youtube.com/watch?v=IFvfZiJGDsw&list=HL1392928835&feature=mh_lolz").intro-button.btn.btn-primary.btn-lg Watch the Video if !me.get('anonymous')
a(href="http://www.youtube.com/watch?v=IFvfZiJGDsw&list=HL1392928835&feature=mh_lolz").intro-button.btn.btn-primary.btn-lg Watch the Video
a(href="/play/level/ladder-tutorial").intro-button.btn.btn-primary.btn-lg Play the Tutorial a(href="/play/level/ladder-tutorial").intro-button.btn.btn-primary.btn-lg Play the Tutorial
hr hr
div#columns.row
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 As
span= team.name
table.table.table-bordered.table-condensed.table-hover if me.get('anonymous')
//(style="background-color: #{team.bgColor}") div#must-log-in
tr p
th(colspan=3, style="color: #{team.primaryColor}") strong Please log in first before playing a ladder game.
span= team.name button.btn.btn-primary(data-toggle="coco-modal", data-target="modal/login", data-i18n="login.log_in") Log In
span Leaderboard button.btn.btn-primary(data-toggle="coco-modal", data-target="modal/signup", data-i18n="login.sign_up") Create Account
tr
th Score
th.name-col-cell Name
th
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.name-col-cell= session.get('creatorName') || "Anonymous"
td
if(!myRow)
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Battle as #{team.otherTeam}!
else
a(href="/play/ladder/#{levelID}/team/#{team.id}") View your #{team.id} matches.
unless me.attributes.anonymous else
hr div#columns.row
button.btn.btn-warning.btn-lg.highlight#simulate-button(style="margin-bottom:10px;") Simulate Games! for team in teams
p(id="simulation-status-text", style="display:inline; margin-left:10px;") div.column.col-md-6
if simulationStatus a(href="/play/ladder/#{levelID}/team/#{team.id}", style="background-color: #{team.primaryColor}").play-button.btn.btn-danger.btn-block.btn-lg
| #{simulationStatus} span Play As
else span= team.name
| By simulating games you can get your game ranked faster!
if me.isAdmin() table.table.table-bordered.table-condensed.table-hover
button.btn.btn-danger.btn-lg.highlight#simulate-all-button(style="margin-bottom:10px; float: right;") RESET AND SIMULATE GAMES //(style="background-color: #{team.bgColor}")
tr
th(colspan=3, style="color: #{team.primaryColor}")
span= team.name
span Leaderboard
tr
th Score
th.name-col-cell Name
th
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.name-col-cell= session.get('creatorName') || "Anonymous"
td
if(!myRow)
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Battle as #{team.otherTeam}!
else
a(href="/play/ladder/#{levelID}/team/#{team.id}") View your #{team.id} matches.
unless me.attributes.anonymous
hr
button.btn.btn-warning.btn-lg.highlight#simulate-button(style="margin-bottom:10px;") Simulate Games!
p(id="simulation-status-text", 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-danger.btn-lg.highlight#simulate-all-button(style="margin-bottom:10px; float: right;") RESET AND SIMULATE GAMES

View file

@ -16,6 +16,13 @@ block content
p p
| After your first submission, your code will also continuously run against other players as they rank themselves. | After your first submission, your code will also continuously run against other players as they rank themselves.
if matches.length
p#your-score
span Your Current Score:
span
strong= score
div#columns.row div#columns.row
div#matches-column.col-md-6 div#matches-column.col-md-6
h3.pull-left Ranked Games h3.pull-left Ranked Games

View file

@ -27,3 +27,11 @@
.content .content
p(class='footer-link-text') p(class='footer-link-text')
a(title='Send CodeCombat a message', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Contact a(title='Send CodeCombat a message', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Contact
if explainHourOfCode
// Does not show up unless lang is en-US.
div.hour-of-code-explanation
| The 'Hour of Code' is a nationwide initiative by
a(href="http://csedweek.org") Computer Science Education Week
| and
a(href="http://code.org") Code.org
| to introduce millions of students to one hour of computer science and computer programming.

View file

@ -1,6 +1,7 @@
.thang-avatar-wrapper(class="team-" + (thang.team || "neutral")) .thang-avatar-wrapper(class="team-" + (thang.team || "neutral"))
//canvas(width=100, height=100, title=thang.id + " - " + thang.team) //canvas(width=100, height=100, title=thang.id + " - " + thang.team)
img.img-responsive(src=avatarURL, title=thang.id + " - " + thang.team) - var title = thang.id + " - " + thang.team + (thang.type ? ' - type: "' + thang.type + '"' : '')
img.img-responsive(src=avatarURL, title=title)
.badge.problems .badge.problems
.badge.shared-thangs .badge.shared-thangs
if includeName if includeName

View file

@ -4,7 +4,7 @@ template = require 'templates/account/settings'
forms = require('lib/forms') forms = require('lib/forms')
User = require('models/User') User = require('models/User')
WizardSettingsTabView = require './wizard_settings_tab_view' WizardSettingsView = require './wizard_settings_view'
module.exports = class SettingsView extends View module.exports = class SettingsView extends View
id: 'account-settings-view' id: 'account-settings-view'
@ -26,11 +26,12 @@ module.exports = class SettingsView extends View
refreshPicturePane: => refreshPicturePane: =>
h = $(@template(@getRenderData())) h = $(@template(@getRenderData()))
new_pane = $('#picture-pane', h) newPane = $('#picture-pane', h)
old_pane = $('#picture-pane') oldPane = $('#picture-pane')
active = old_pane.hasClass('active') active = oldPane.hasClass('active')
old_pane.replaceWith(new_pane) oldPane.replaceWith(newPane)
new_pane.addClass('active') if active newPane.i18n()
newPane.addClass('active') if active
afterRender: -> afterRender: ->
super() super()
@ -46,9 +47,9 @@ module.exports = class SettingsView extends View
@chooseTab(location.hash.replace('#','')) @chooseTab(location.hash.replace('#',''))
@updateWizardColor() @updateWizardColor()
wizardSettingsTabView = new WizardSettingsTabView() WizardSettingsView = new WizardSettingsView()
wizardSettingsTabView.on 'change', @save, @ WizardSettingsView.on 'change', @save, @
@insertSubView wizardSettingsTabView @insertSubView WizardSettingsView
chooseTab: (category) -> chooseTab: (category) ->
id = "##{category}-pane" id = "##{category}-pane"

View file

@ -1,12 +1,13 @@
RootView = require 'views/kinds/RootView' CocoView = require 'views/kinds/CocoView'
template = require 'templates/account/wizard_settings_tab' template = require 'templates/account/wizard_settings'
{me} = require('lib/auth') {me} = require('lib/auth')
ThangType = require 'models/ThangType' ThangType = require 'models/ThangType'
SpriteBuilder = require 'lib/sprites/SpriteBuilder' SpriteBuilder = require 'lib/sprites/SpriteBuilder'
module.exports = class WizardSettingsTabView extends RootView module.exports = class WizardSettingsView extends CocoView
id: 'wizard-settings-tab-view' id: 'wizard-settings-view'
template: template template: template
startsLoading: true
events: events:
'change .color-group-checkbox': (e) -> 'change .color-group-checkbox': (e) ->
@ -25,6 +26,7 @@ module.exports = class WizardSettingsTabView extends RootView
@wizardThangType.once 'sync', @initCanvas, @ @wizardThangType.once 'sync', @initCanvas, @
initCanvas: -> initCanvas: ->
@startsLoading = false
@render() @render()
@spriteBuilder = new SpriteBuilder(@wizardThangType) @spriteBuilder = new SpriteBuilder(@wizardThangType)
@initStage() @initStage()
@ -44,6 +46,7 @@ module.exports = class WizardSettingsTabView extends RootView
c c
afterRender: -> afterRender: ->
return if @startsLoading
wizardSettings = me.get('wizard') or {} wizardSettings = me.get('wizard') or {}
wizardSettings.colorConfig ?= {} wizardSettings.colorConfig ?= {}
@ -82,8 +85,6 @@ module.exports = class WizardSettingsTabView extends RootView
initStage: -> initStage: ->
@stage = new createjs.Stage(@$el.find('canvas')[0]) @stage = new createjs.Stage(@$el.find('canvas')[0])
@updateMovieClip() @updateMovieClip()
createjs.Ticker.setFPS 20
createjs.Ticker.addEventListener("tick", @stage)
updateMovieClip: -> updateMovieClip: ->
return unless @wizardThangType.loaded return unless @wizardThangType.loaded
@ -104,6 +105,3 @@ module.exports = class WizardSettingsTabView extends RootView
@movieClip.regY = reg.y @movieClip.regY = reg.y
@stage.addChild @movieClip @stage.addChild @movieClip
@stage.update() @stage.update()
destroy: ->
@stage?.removeAllEventListeners()

View file

@ -48,15 +48,10 @@ module.exports = class ThangsTabView extends View
'click #extant-thangs-filter button': 'onFilterExtantThangs' 'click #extant-thangs-filter button': 'onFilterExtantThangs'
shortcuts: shortcuts:
'esc': -> @selectAddThang() 'esc': 'selectAddThang'
'delete, del, backspace': 'deleteSelectedExtantThang'
onFilterExtantThangs: (e) -> 'left': -> @moveAddThangSelection -1
button = $(e.target).closest('button') 'right': -> @moveAddThangSelection 1
button.button('toggle')
val = button.val()
@thangsTreema.$el.removeClass(@lastHideClass) if @lastHideClass
@thangsTreema.$el.addClass(@lastHideClass = "hide-except-#{val}") if val
constructor: (options) -> constructor: (options) ->
super options super options
@ -102,12 +97,12 @@ module.exports = class ThangsTabView extends View
$('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList $('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList
@$el.find('#extant-thangs-filter button:first').button('toggle') @$el.find('#extant-thangs-filter button:first').button('toggle')
# TODO: move these into the shortcuts list onFilterExtantThangs: (e) ->
key 'left', _.bind @moveAddThangSelection, @, -1 button = $(e.target).closest('button')
key 'right', _.bind @moveAddThangSelection, @, 1 button.button('toggle')
key 'delete, del, backspace', @deleteSelectedExtantThang val = button.val()
key 'f', => Backbone.Mediator.publish('level-set-debug', debug: not @surface.debug) @thangsTreema.$el.removeClass(@lastHideClass) if @lastHideClass
key 'g', => Backbone.Mediator.publish('level-set-grid', grid: not @surface.gridShowing()) @thangsTreema.$el.addClass(@lastHideClass = "hide-except-#{val}") if val
preventBodyScrollingInThangList: (e) -> preventBodyScrollingInThangList: (e) ->
@scrollTop += (if e.deltaY < 0 then 1 else -1) * 30 @scrollTop += (if e.deltaY < 0 then 1 else -1) * 30

View file

@ -129,7 +129,7 @@ module.exports = class CocoView extends Backbone.View
# Loading RootViews # Loading RootViews
showLoading: ($el=@$el) -> showLoading: ($el=@$el) ->
$el.find('>').hide() $el.find('>').addClass('hidden')
$el.append($('<div class="loading-screen"></div>') $el.append($('<div class="loading-screen"></div>')
.append('<h2>Loading</h2>') .append('<h2>Loading</h2>')
.append('<div class="progress progress-striped active loading"><div class="progress-bar"></div></div>')) .append('<div class="progress progress-striped active loading"><div class="progress-bar"></div></div>'))
@ -138,7 +138,7 @@ module.exports = class CocoView extends Backbone.View
hideLoading: -> hideLoading: ->
return unless @_lastLoading? return unless @_lastLoading?
@_lastLoading.find('.loading-screen').remove() @_lastLoading.find('.loading-screen').remove()
@_lastLoading.find('>').show() @_lastLoading.find('>').removeClass('hidden')
@_lastLoading = null @_lastLoading = null
# Loading ModalViews # Loading ModalViews

View file

@ -22,8 +22,8 @@ module.exports = class RootView extends CocoView
logoutUser($('#login-email').val()) logoutUser($('#login-email').val())
showWizardSettingsModal: -> showWizardSettingsModal: ->
WizardSettingsView = require('views/modal/wizard_settings_modal') WizardSettingsModal = require('views/modal/wizard_settings_modal')
subview = new WizardSettingsView {} subview = new WizardSettingsModal {}
@openModalView subview @openModalView subview
showLoading: ($el) -> showLoading: ($el) ->

View file

@ -2,79 +2,44 @@ View = require 'views/kinds/ModalView'
template = require 'templates/modal/wizard_settings' template = require 'templates/modal/wizard_settings'
WizardSprite = require 'lib/surface/WizardSprite' WizardSprite = require 'lib/surface/WizardSprite'
ThangType = require 'models/ThangType' ThangType = require 'models/ThangType'
{me} = require 'lib/auth'
forms = require('lib/forms')
module.exports = class WizardSettingsView extends View module.exports = class WizardSettingsModal extends View
id: "wizard-settings-modal" id: "wizard-settings-modal"
template: template template: template
closesOnClickOutside: false closesOnClickOutside: false
events: events:
'change #wizard-settings-name': 'onNameChange' 'change #wizard-settings-name': 'onNameChange'
'click #random-name': 'onRandomNameClick' 'click #wizard-settings-done': 'onWizardSettingsDone'
'click #wizard-settings-done': 'saveSettings'
render: ->
me.set('name', @randomName()) if not me.get('name')
super()
onRandomNameClick: =>
$('#wizard-settings-name').val(@randomName())
@saveSettings()
randomName: ->
return NameGenerator.getName(7, 9)
afterRender: -> afterRender: ->
super() WizardSettingsView = require 'views/account/wizard_settings_view'
@colorSlider = $( "#wizard-settings-color-1", @$el).slider({ animate: "fast" }) view = new WizardSettingsView()
@colorSlider.slider('value', me.get('wizardColor1')*100) @insertSubView view
@colorSlider.on('slide',@onSliderChange)
@colorSlider.on('slidechange',@onSliderChange)
@stage = new createjs.Stage($('canvas', @$el)[0])
@saveChanges = _.debounce(@saveChanges, 1000)
wizOriginal = "52a00d55cf1818f2be00000b" onNameChange: ->
url = "/db/thang_type/#{wizOriginal}/version"
@wizardType = new ThangType()
@wizardType.url = -> url
@wizardType.fetch()
@wizardType.once 'sync', @initCanvas
initCanvas: =>
spriteOptions = thangID: "Config Wizard", resolutionFactor: 3
@wizardSprite = new WizardSprite @wizardType, spriteOptions
@wizardSprite.setColorHue(me.get('wizardColor1'))
@wizardDisplayObject = @wizardSprite.displayObject
@wizardDisplayObject.x = 10
@wizardDisplayObject.y = 15
@wizardDisplayObject.scaleX = @wizardDisplayObject.scaleY = 3.0
@stage.addChild(@wizardDisplayObject)
@updateSpriteColor()
@stage.update()
onSliderChange: =>
@updateSpriteColor()
@saveSettings()
getColorHue: ->
@colorSlider.slider('value') / 100
updateSpriteColor: ->
colorHue = @getColorHue()
@wizardSprite.setColorHue(colorHue)
@stage.update()
onNameChange: =>
@saveSettings()
saveSettings: ->
me.set('name', $('#wizard-settings-name').val()) me.set('name', $('#wizard-settings-name').val())
me.set('wizardColor1', @getColorHue())
@saveChanges()
saveChanges: -> onWizardSettingsDone: ->
forms.clearFormAlerts(@$el)
res = me.validate()
if res?
forms.applyErrorsToForm(@$el, res)
return
res = me.save()
return unless res
save = $('#save-button', @$el).text($.i18n.t('common.saving', defaultValue: 'Saving...'))
.addClass('btn-info').show().removeClass('btn-danger')
res.error =>
errors = JSON.parse(res.responseText)
forms.applyErrorsToForm(@$el, errors)
@disableModalInProgress(@$el)
res.success (model, response, options) =>
@hide()
@enableModalInProgress(@$el)
me.save() me.save()
destroy: ->
@wizardSprite?.destroy()
super()

View file

@ -90,6 +90,7 @@ module.exports = class LadderTeamView extends RootView
ctx.matches = (convertMatch(match) for match in @session.get('matches') or []) ctx.matches = (convertMatch(match) for match in @session.get('matches') or [])
ctx.matches.reverse() ctx.matches.reverse()
ctx.score = (@session.get('totalScore') or 10).toFixed(2)
ctx ctx
afterRender: -> afterRender: ->

View file

@ -36,8 +36,8 @@ module.exports = class PlaybackView extends View
shortcuts: shortcuts:
'⌘+p, p, ctrl+p': 'onTogglePlay' '⌘+p, p, ctrl+p': 'onTogglePlay'
'[': 'onScrubBack' '⌘+[, ctrl+[': 'onScrubBack'
']': 'onScrubForward' '⌘+], ctrl+]': 'onScrubForward'
constructor: -> constructor: ->
super(arguments...) super(arguments...)
@ -169,7 +169,7 @@ module.exports = class PlaybackView extends View
if @clickingSlider if @clickingSlider
@clickingSlider = false @clickingSlider = false
@wasPlaying = false @wasPlaying = false
@onSetPlaying {playing: false} Backbone.Mediator.publish 'level-set-playing', {playing: false}
@$el.find('.scrubber-handle').effect('bounce', {times: 2}) @$el.find('.scrubber-handle').effect('bounce', {times: 2})
) )

View file

@ -17,7 +17,7 @@ module.exports = class CastButtonView extends View
@spells = options.spells @spells = options.spells
@levelID = options.levelID @levelID = options.levelID
isMac = navigator.platform.toUpperCase().indexOf('MAC') isnt -1 isMac = navigator.platform.toUpperCase().indexOf('MAC') isnt -1
@castShortcut = "" @castShortcut = ""
@castShortcutVerbose = "Shift+Enter" @castShortcutVerbose = "Shift+Enter"
getRenderData: (context={}) -> getRenderData: (context={}) ->
@ -35,7 +35,7 @@ module.exports = class CastButtonView extends View
# TODO: use a User setting instead of localStorage # TODO: use a User setting instead of localStorage
delay = localStorage.getItem 'autocastDelay' delay = localStorage.getItem 'autocastDelay'
delay ?= 5000 delay ?= 5000
if @levelID is 'project-dota' if @levelID in ['project-dota', 'brawlwood', 'ladder-tutorial']
delay = 90019001 delay = 90019001
@setAutocastDelay delay @setAutocastDelay delay

View file

@ -21,6 +21,10 @@ module.exports = class DebugView extends View
@ace = options.ace @ace = options.ace
@thang = options.thang @thang = options.thang
@variableStates = {} @variableStates = {}
@globals = {Math: Math, _: _} # ... add more as documented
for className, klass of serializedClasses
@globals[className] = klass
@onMouseMove = _.throttle @onMouseMove, 25
afterRender: -> afterRender: ->
super() super()
@ -30,10 +34,11 @@ module.exports = class DebugView extends View
@update() @update()
onMouseMove: (e) => onMouseMove: (e) =>
return if @destroyed
pos = e.getDocumentPosition() pos = e.getDocumentPosition()
endOfDoc = pos.row is @ace.getSession().getDocument().getLength() - 1 endOfDoc = pos.row is @ace.getSession().getDocument().getLength() - 1
it = new TokenIterator e.editor.session, pos.row, pos.column it = new TokenIterator e.editor.session, pos.row, pos.column
isIdentifier = (t) -> t and (t.type is 'identifier' or t.value is 'this') isIdentifier = (t) => t and (t.type is 'identifier' or t.value is 'this' or @globals[t.value])
while it.getCurrentTokenRow() is pos.row and not isIdentifier(token = it.getCurrentToken()) while it.getCurrentTokenRow() is pos.row and not isIdentifier(token = it.getCurrentToken())
it.stepBackward() it.stepBackward()
break unless token break unless token
@ -52,7 +57,7 @@ module.exports = class DebugView extends View
token = prev token = prev
start = it.getCurrentTokenColumn() start = it.getCurrentTokenColumn()
chain.unshift token.value chain.unshift token.value
if token and (token.value of @variableStates or token.value is "this") if token and (token.value of @variableStates or token.value is "this" or @globals[token.value])
@variableChain = chain @variableChain = chain
offsetX = e.domEvent.offsetX ? e.clientX - $(e.domEvent.target).offset().left offsetX = e.domEvent.offsetX ? e.clientX - $(e.domEvent.target).offset().left
offsetY = e.domEvent.offsetY ? e.clientY - $(e.domEvent.target).offset().top offsetY = e.domEvent.offsetY ? e.clientY - $(e.domEvent.target).offset().top
@ -76,6 +81,10 @@ module.exports = class DebugView extends View
@$el.show().css(@pos) @$el.show().css(@pos)
else else
@$el.hide() @$el.hide()
if @variableChain?.length is 2
Backbone.Mediator.publish 'tome:spell-debug-property-hovered', property: @variableChain[1], owner: @variableChain[0]
else
Backbone.Mediator.publish 'tome:spell-debug-property-hovered', property: null
@updateMarker() @updateMarker()
updateMarker: -> updateMarker: ->
@ -92,7 +101,7 @@ module.exports = class DebugView extends View
return "<this #{value.id}>" if value is @thang and depth return "<this #{value.id}>" if value is @thang and depth
if depth is 2 if depth is 2
if value.constructor?.className is "Thang" if value.constructor?.className is "Thang"
value = "<#{value.spriteName} - #{value.id}, #{if value.pos then value.pos.toString() else 'non-physical'}>" value = "<#{value.type or value.spriteName} - #{value.id}, #{if value.pos then value.pos.toString() else 'non-physical'}>"
else else
value = value.toString() value = value.toString()
return value return value
@ -124,8 +133,11 @@ module.exports = class DebugView extends View
for prop, i in chain for prop, i in chain
if prop is "this" if prop is "this"
value = @thang value = @thang
else if i is 0
value = @variableStates[prop]
if typeof value is "undefined" then value = @globals[prop]
else else
value = (if i is 0 then @variableStates else value)[prop] value = value[prop]
keys.push prop keys.push prop
break unless value break unless value
if theClass = serializedClasses[value.CN] if theClass = serializedClasses[value.CN]

View file

@ -74,7 +74,7 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
formatPopover: (doc) -> formatPopover: (doc) ->
content = popoverTemplate doc: doc, marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in doc.args ? []) content = popoverTemplate doc: doc, marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in doc.args ? [])
owner = @thang owner = @thang
content = content.replace /#{spriteName}/g, @thang.spriteName # No quotes like we'd get with @formatValue content = content.replace /#{spriteName}/g, @thang.type ? @thang.spriteName # Prefer type, and excluded the quotes we'd get with @formatValue
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.')) content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
formatValue: (v) -> formatValue: (v) ->
@ -101,12 +101,15 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
onClick: (e) -> # Don't call super onClick: (e) -> # Don't call super
onDropdownClick: (e) -> onDropdownClick: (e) ->
return unless @controlsEnabled
Backbone.Mediator.publish 'tome:toggle-spell-list' Backbone.Mediator.publish 'tome:toggle-spell-list'
onCodeReload: -> onCodeReload: ->
return unless @controlsEnabled
Backbone.Mediator.publish "tome:reload-code", spell: @spell Backbone.Mediator.publish "tome:reload-code", spell: @spell
onBeautifyClick: -> onBeautifyClick: ->
return unless @controlsEnabled
Backbone.Mediator.publish "spell-beautify", spell: @spell Backbone.Mediator.publish "spell-beautify", spell: @spell
updateReloadButton: -> updateReloadButton: ->

View file

@ -66,6 +66,7 @@ module.exports = class SpellPaletteEntryView extends View
'surface:frame-changed': "onFrameChanged" 'surface:frame-changed': "onFrameChanged"
'tome:palette-hovered': "onPaletteHovered" 'tome:palette-hovered': "onPaletteHovered"
'tome:palette-pin-toggled': "onPalettePinToggled" 'tome:palette-pin-toggled': "onPalettePinToggled"
'tome:spell-debug-property-hovered': 'onSpellDebugPropertyHovered'
events: events:
'mouseenter': 'onMouseEnter' 'mouseenter': 'onMouseEnter'
@ -83,7 +84,11 @@ module.exports = class SpellPaletteEntryView extends View
@doc.shortName = @doc.shorterName = @doc.title = @doc.name @doc.shortName = @doc.shorterName = @doc.title = @doc.name
else else
@doc.owner ?= 'this' @doc.owner ?= 'this'
suffix = if @doc.type is 'function' then '()' else '' suffix = ''
if @doc.type is 'function'
argNames = (arg.name for arg in @doc.args ? []).join(', ')
argNames = '...' if argNames.length > 6
suffix = "(#{argNames})"
@doc.shortName = "#{@doc.owner}.#{@doc.name}#{suffix};" @doc.shortName = "#{@doc.owner}.#{@doc.name}#{suffix};"
if @doc.owner is 'this' or options.tabbify if @doc.owner is 'this' or options.tabbify
@doc.shorterName = "#{@doc.name}#{suffix}" @doc.shorterName = "#{@doc.name}#{suffix}"
@ -184,6 +189,16 @@ module.exports = class SpellPaletteEntryView extends View
return if e.entry is @ return if e.entry is @
@otherPopoverPinned = e.pinned @otherPopoverPinned = e.pinned
onSpellDebugPropertyHovered: (e) ->
matched = e.property is @doc.name and e.owner is @doc.owner
if matched and not @debugHovered
@debugHovered = true
@togglePinned() unless @popoverPinned
else if @debugHovered and not matched
@debugHovered = false
@togglePinned() if @popoverPinned
null
destroy: -> destroy: ->
$('.popover.pinned').remove() if @popoverPinned # @$el.popover('destroy') doesn't work $('.popover.pinned').remove() if @popoverPinned # @$el.popover('destroy') doesn't work
@togglePinned() if @popoverPinned @togglePinned() if @popoverPinned

View file

@ -46,24 +46,42 @@ module.exports = class SpellPaletteView extends View
for doc in (lc.get('propertyDocumentation') ? []) for doc in (lc.get('propertyDocumentation') ? [])
allDocs[doc.name] ?= [] allDocs[doc.name] ?= []
allDocs[doc.name].push doc allDocs[doc.name].push doc
if doc.type is 'snippet' then doc.owner = 'snippets'
#allDocs[doc.name] = doc for doc in (lc.get('propertyDocumentation') ? []) for lc in lcs #allDocs[doc.name] = doc for doc in (lc.get('propertyDocumentation') ? []) for lc in lcs
props = _.sortBy @thang.programmableProperties ? [] propStorage =
snippets = _.sortBy @thang.programmableSnippets ? [] 'this': 'programmableProperties'
shortenize = props.length + snippets.length > 6 more: 'moreProgrammableProperties'
tabbify = props.length + snippets.length >= 10 Math: 'programmableMathProperties'
Vector: 'programmableVectorProperties'
snippets: 'programmableSnippets'
count = 0
propGroups = {}
for owner, storage of propStorage
added = propGroups[owner] = _.sortBy(@thang[storage] ? []).slice()
count += added.length
shortenize = count > 6
tabbify = count >= 10
@entries = [] @entries = []
for type, props of {props: props.slice(), snippets: snippets.slice()} for owner, props of propGroups
for prop in props for prop in props
doc = allDocs[prop]?.shift() ? prop # Add one doc per instance of the prop name (this is super gimp) doc = _.find (allDocs[prop] ? []), (doc) ->
@entries.push @addEntry(doc, shortenize, tabbify, type is 'snippets') return true if doc.owner is owner
return (owner is 'this' or owner is 'more') and (not doc.owner? or doc.owner is 'this')
console.log 'could not find doc for', prop, 'from', allDocs[prop], 'for', owner, 'of', propGroups unless doc
doc ?= prop
@entries.push @addEntry(doc, shortenize, tabbify, owner is 'snippets')
groupForEntry = (entry) ->
return 'more' if entry.doc.owner is 'this' and entry.doc.name in propGroups.more
entry.doc.owner
@entries = _.sortBy @entries, (entry) -> @entries = _.sortBy @entries, (entry) ->
order = ['this', 'Math', 'Vector', 'snippets'] order = ['this', 'more', 'Math', 'Vector', 'snippets']
index = order.indexOf entry.doc.owner index = order.indexOf groupForEntry entry
index = String.fromCharCode if index is -1 then order.length else index index = String.fromCharCode if index is -1 then order.length else index
index += entry.doc.name index += entry.doc.name
if tabbify and _.find @entries, ((entry) -> entry.doc.owner isnt 'this') if tabbify and _.find @entries, ((entry) -> entry.doc.owner isnt 'this')
@entryGroups = _.groupBy @entries, (entry) -> entry.doc.owner @entryGroups = _.groupBy @entries, groupForEntry
else else
defaultGroup = $.i18n.t("play_level.tome_available_spells", defaultValue: "Available Spells") defaultGroup = $.i18n.t("play_level.tome_available_spells", defaultValue: "Available Spells")
@entryGroups = {} @entryGroups = {}

View file

@ -326,7 +326,10 @@ module.exports = class SpellView extends View
isCast = not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'} isCast = not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'}
@problems = [] @problems = []
annotations = [] annotations = []
seenProblemKeys = {}
for aetherProblem, problemIndex in aether.getAllProblems() for aetherProblem, problemIndex in aether.getAllProblems()
continue if aetherProblem.userInfo.key of seenProblemKeys
seenProblemKeys[aetherProblem.userInfo.key] = true
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast and problemIndex is 0, isCast @problems.push problem = new Problem aether, aetherProblem, @ace, isCast and problemIndex is 0, isCast
annotations.push problem.annotation if problem.annotation annotations.push problem.annotation if problem.annotation
@aceSession.setAnnotations annotations @aceSession.setAnnotations annotations
@ -452,11 +455,11 @@ module.exports = class SpellView extends View
markerRange.end.detach() markerRange.end.detach()
@aceSession.removeMarker markerRange.id @aceSession.removeMarker markerRange.id
@markerRanges = [] @markerRanges = []
@debugView.setVariableStates {}
@aceSession.removeGutterDecoration row, 'executing' for row in [0 ... @aceSession.getLength()] @aceSession.removeGutterDecoration row, 'executing' for row in [0 ... @aceSession.getLength()]
$(@ace.container).find('.ace_gutter-cell.executing').removeClass('executing') $(@ace.container).find('.ace_gutter-cell.executing').removeClass('executing')
if not executed.length or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20) if not executed.length or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20)
@toolbarView?.toggleFlow false @toolbarView?.toggleFlow false
@debugView.setVariableStates {}
return return
lastExecuted = _.last executed lastExecuted = _.last executed
@toolbarView?.toggleFlow true @toolbarView?.toggleFlow true
@ -464,6 +467,7 @@ module.exports = class SpellView extends View
@toolbarView?.setCallState states[currentCallIndex], statementIndex, currentCallIndex, @spellThang.castAether.metrics @toolbarView?.setCallState states[currentCallIndex], statementIndex, currentCallIndex, @spellThang.castAether.metrics
marked = {} marked = {}
lastExecuted = lastExecuted[0 .. @toolbarView.statementIndex] if @toolbarView?.statementIndex? lastExecuted = lastExecuted[0 .. @toolbarView.statementIndex] if @toolbarView?.statementIndex?
gotVariableStates = false
for state, i in lastExecuted for state, i in lastExecuted
[start, end] = state.range [start, end] = state.range
clazz = if i is lastExecuted.length - 1 then 'executing' else 'executed' clazz = if i is lastExecuted.length - 1 then 'executing' else 'executed'
@ -473,6 +477,7 @@ module.exports = class SpellView extends View
markerType = "fullLine" markerType = "fullLine"
else else
@debugView.setVariableStates state.variables @debugView.setVariableStates state.variables
gotVariableStates = true
markerType = "text" markerType = "text"
markerRange = new Range start.row, start.col, end.row, end.col markerRange = new Range start.row, start.col, end.row, end.col
markerRange.start = @aceDoc.createAnchor markerRange.start markerRange.start = @aceDoc.createAnchor markerRange.start
@ -480,6 +485,7 @@ module.exports = class SpellView extends View
markerRange.id = @aceSession.addMarker markerRange, clazz, markerType markerRange.id = @aceSession.addMarker markerRange, clazz, markerType
@markerRanges.push markerRange @markerRanges.push markerRange
@aceSession.addGutterDecoration start.row, clazz if clazz is 'executing' @aceSession.addGutterDecoration start.row, clazz if clazz is 'executing'
@debugView.setVariableStates {} unless gotVariableStates
null null
highlightComments: -> highlightComments: ->

View file

@ -21,6 +21,7 @@ module.exports = class ThangListEntryView extends View
'surface:frame-changed': "onFrameChanged" 'surface:frame-changed': "onFrameChanged"
'level-set-letterbox': 'onSetLetterbox' 'level-set-letterbox': 'onSetLetterbox'
'tome:thang-list-entry-popover-shown': 'onThangListEntryPopoverShown' 'tome:thang-list-entry-popover-shown': 'onThangListEntryPopoverShown'
'surface:coordinates-shown': 'onSurfaceCoordinatesShown'
events: events:
'click': 'onClick' 'click': 'onClick'
@ -86,38 +87,47 @@ module.exports = class ThangListEntryView extends View
onMouseEnter: (e) -> onMouseEnter: (e) ->
return unless @controlsEnabled and @spells.length return unless @controlsEnabled and @spells.length
@showSpells() @clearTimeouts()
@showSpellsTimeout = _.delay @showSpells, 100
onMouseLeave: (e) -> onMouseLeave: (e) ->
return unless @controlsEnabled and @spells.length return unless @controlsEnabled and @spells.length
clearTimeout @hideSpellsTimeout if @hideSpellsTimeout @clearTimeouts()
@hideSpellsTimeout = _.delay @hideSpells, 100 @hideSpellsTimeout = _.delay @hideSpells, 100
clearTimeouts: ->
clearTimeout @showSpellsTimeout if @showSpellsTimeout
clearTimeout @hideSpellsTimeout if @hideSpellsTimeout
@showSpellsTimeout = @hideSpellsTimeout = null
onThangListEntryPopoverShown: (e) -> onThangListEntryPopoverShown: (e) ->
# I couldn't figure out how to get the mouseenter / mouseleave to always work, so this is a fallback # I couldn't figure out how to get the mouseenter / mouseleave to always work, so this is a fallback
# to hide our popover is another Thang's popover gets shown. # to hide our popover is another Thang's popover gets shown.
return if e.entry is @ return if e.entry is @
@hideSpells() @hideSpells()
onSurfaceCoordinatesShown: (e) ->
# Definitely aren't hovering over this.
@hideSpells()
showSpells: => showSpells: =>
@clearTimeouts()
@sortSpells() @sortSpells()
@$el.data('bs.popover').options.content = @getSpellListHTML() @$el.data('bs.popover').options.content = @getSpellListHTML()
@$el.popover('setContent').popover('show') @$el.popover('setContent').popover('show')
@$el.parent().parent().parent().i18n() @$el.parent().parent().parent().i18n()
clearTimeout @hideSpellsTimeout if @hideSpellsTimeout
@hideSpellsTimeout = null
@popover = @$el.parent().parent().parent().find('.popover') @popover = @$el.parent().parent().parent().find('.popover')
@popover.off 'mouseenter mouseleave' @popover.off 'mouseenter mouseleave'
@popover.mouseenter (e) => @onMouseEnter() @popover.mouseenter (e) => @showSpells() if @controlsEnabled
@popover.mouseleave (e) => @onMouseLeave() @popover.mouseleave (e) => @hideSpells()
thangID = @thang.id thangID = @thang.id
@popover.find('code').click (e) -> @popover.find('code').click (e) ->
Backbone.Mediator.publish "level-select-sprite", thangID: thangID, spellName: $(@).data 'spell-name' Backbone.Mediator.publish "level-select-sprite", thangID: thangID, spellName: $(@).data 'spell-name'
Backbone.Mediator.publish 'tome:thang-list-entry-popover-shown', entry: @ Backbone.Mediator.publish 'tome:thang-list-entry-popover-shown', entry: @
hideSpells: => hideSpells: =>
@clearTimeouts()
@$el.popover('hide') @$el.popover('hide')
@hideSpellsTimeout = null
getSpellListHTML: -> getSpellListHTML: ->
spellsPopoverTemplate {spells: @spells} spellsPopoverTemplate {spells: @spells}
@ -129,13 +139,16 @@ module.exports = class ThangListEntryView extends View
onSetLetterbox: (e) -> onSetLetterbox: (e) ->
if e.on then @reasonsToBeDisabled.letterbox = true else delete @reasonsToBeDisabled.letterbox if e.on then @reasonsToBeDisabled.letterbox = true else delete @reasonsToBeDisabled.letterbox
@updateControls() @updateControls()
onDisableControls: (e) -> onDisableControls: (e) ->
return if e.controls and not ('surface' in e.controls) # disable selection? return if e.controls and not ('surface' in e.controls) # disable selection?
@reasonsToBeDisabled.controls = true @reasonsToBeDisabled.controls = true
@updateControls() @updateControls()
onEnableControls: (e) -> onEnableControls: (e) ->
delete @reasonsToBeDisabled.controls delete @reasonsToBeDisabled.controls
@updateControls() @updateControls()
updateControls: -> updateControls: ->
enabled = _.keys(@reasonsToBeDisabled).length is 0 enabled = _.keys(@reasonsToBeDisabled).length is 0
return if enabled is @controlsEnabled return if enabled is @controlsEnabled

View file

@ -151,9 +151,15 @@ module.exports = class TomeView extends View
@cast() @cast()
cast: -> cast: ->
for spellKey, spell of @spells if @options.levelID is 'project-dota'
for thangID, spellThang of spell.thangs # For performance reasons, only includeFlow on the currently Thang.
spellThang.aether.options.includeFlow = spellThang.aether.originalOptions.includeFlow = spellThang is @spellView?.spellThang for spellKey, spell of @spells
for thangID, spellThang of spell.thangs
hadFlow = Boolean spellThang.aether.options.includeFlow
willHaveFlow = spellThang is @spellView?.spellThang
spellThang.aether.options.includeFlow = spellThang.aether.originalOptions.includeFlow = willHaveFlow
spellThang.aether.transpile spell.source unless hadFlow is willHaveFlow
#console.log "set includeFlow to", spellThang.aether.options.includeFlow, "for", thangID, "of", spellKey
Backbone.Mediator.publish 'tome:cast-spells', spells: @spells Backbone.Mediator.publish 'tome:cast-spells', spells: @spells
onToggleSpellList: (e) -> onToggleSpellList: (e) ->

View file

@ -116,6 +116,10 @@ module.exports = class PlayLevelView extends View
getRenderData: -> getRenderData: ->
c = super() c = super()
c.world = @world c.world = @world
if me.get('hourOfCode') and me.lang() is 'en-US'
# Show the Hour of Code footer explanation until it's been more than a day
elapsed = (new Date() - new Date(me.get('dateCreated')))
c.explainHourOfCode = elapsed < 86400 * 1000
c c
afterRender: -> afterRender: ->
@ -194,7 +198,7 @@ module.exports = class PlayLevelView extends View
afterInsert: -> afterInsert: ->
super() super()
# @showWizardSettingsModal() if not me.get('name') @showWizardSettingsModal() if not me.get('name')
# callbacks # callbacks

View file

@ -8,5 +8,5 @@ current_directory = os.path.dirname(os.path.realpath(sys.argv[0]))
coco_path = os.getenv("COCO_DIR",os.path.join(current_directory,os.pardir)) coco_path = os.getenv("COCO_DIR",os.path.join(current_directory,os.pardir))
nodemon_path = coco_path + os.sep + "node_modules" + os.sep + ".bin" + os.sep + "nodemon" nodemon_path = coco_path + os.sep + "node_modules" + os.sep + ".bin" + os.sep + "nodemon"
call(nodemon_path + " . --ext \".coffee|.js\" --watch server --watch app.js --watch server_config.js",shell=True,cwd=coco_path) call(nodemon_path + " . --ext \".coffee|.js\" --watch server --watch app.js --watch server_config.js --watch server_setup.coffee",shell=True,cwd=coco_path)

View file

@ -24,6 +24,25 @@ connectToScoringQueue = ->
scoringTaskQueue = data scoringTaskQueue = data
log.info "Connected to scoring task queue!" log.info "Connected to scoring task queue!"
module.exports.addPairwiseTaskToQueue = (req, res) ->
taskPair = req.body.sessions
#unless isUserAdmin req then return errors.forbidden res, "You do not have the permissions to submit that game to the leaderboard"
#fetch both sessions
LevelSession.findOne(_id:taskPair[0]).lean().exec (err, firstSession) =>
if err? then return errors.serverError res, "There was an error fetching the first session in the pair"
LevelSession.find(_id:taskPair[1]).exec (err, secondSession) =>
if err? then return errors.serverError res, "There was an error fetching the second session"
try
taskPairs = generateTaskPairs(secondSession, firstSession)
catch e
if e then return errors.serverError res, "There was an error generating the task pairs"
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.createNewTask = (req, res) -> module.exports.createNewTask = (req, res) ->
requestSessionID = req.body.session requestSessionID = req.body.session
validatePermissions req, requestSessionID, (error, permissionsAreValid) -> validatePermissions req, requestSessionID, (error, permissionsAreValid) ->

View file

@ -5,6 +5,7 @@ UserHandler = require('../users/user_handler')
config = require '../../server_config' config = require '../../server_config'
errors = require '../commons/errors' errors = require '../commons/errors'
mail = require '../commons/mail' mail = require '../commons/mail'
languages = require '../routes/languages'
module.exports.setup = (app) -> module.exports.setup = (app) ->
authentication.serializeUser((user, done) -> done(null, user._id)) authentication.serializeUser((user, done) -> done(null, user._id))
@ -43,10 +44,36 @@ module.exports.setup = (app) ->
) )
app.get('/auth/whoami', (req, res) -> app.get('/auth/whoami', (req, res) ->
res.setHeader('Content-Type', 'text/json'); if req.user
sendSelf(req, res)
else
user = new User({anonymous:true})
user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth
user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages
makeNext = (req, res) -> -> sendSelf(req, res)
next = makeNext(req, res)
loginUser(req, res, user, false, next)
)
sendSelf = (req, res) ->
res.setHeader('Content-Type', 'text/json')
res.send(UserHandler.formatEntity(req, req.user)) res.send(UserHandler.formatEntity(req, req.user))
res.end() res.end()
)
loginUser = (req, res, user, send=true, next=null) ->
user.save((err) ->
if err
return @sendDatabaseError(res, err)
req.logIn(user, (err) ->
if err
return @sendDatabaseError(res, err)
if send
return @sendSuccess(res, user)
next() if next
)
)
app.post('/auth/logout', (req, res) -> app.post('/auth/logout', (req, res) ->
req.logout() req.logout()

View file

@ -6,6 +6,10 @@ scoringQueue = require '../queues/scoring'
module.exports.setup = (app) -> module.exports.setup = (app) ->
scoringQueue.setup() scoringQueue.setup()
#app.post '/queue/scoring/pairwise', (req, res) ->
# handler = loadQueueHandler 'scoring'
# handler.addPairwiseTaskToQueue req, res
app.all '/queue/*', (req, res) -> app.all '/queue/*', (req, res) ->
setResponseHeaderToJSONContentType res setResponseHeaderToJSONContentType res
@ -24,6 +28,7 @@ module.exports.setup = (app) ->
log.error error log.error error
sendQueueError req, res, error sendQueueError req, res, error
setResponseHeaderToJSONContentType = (res) -> res.setHeader('Content-Type', 'application/json') setResponseHeaderToJSONContentType = (res) -> res.setHeader('Content-Type', 'application/json')
getQueueNameFromPath = (path) -> getQueueNameFromPath = (path) ->

View file

@ -3,7 +3,6 @@ crypto = require 'crypto'
request = require 'request' request = require 'request'
User = require './User' User = require './User'
Handler = require '../commons/Handler' Handler = require '../commons/Handler'
languages = require '../routes/languages'
mongoose = require 'mongoose' mongoose = require 'mongoose'
config = require '../../server_config' config = require '../../server_config'
errors = require '../commons/errors' errors = require '../commons/errors'
@ -172,28 +171,3 @@ UserHandler = class UserHandler extends Handler
res.end() res.end()
module.exports = new UserHandler() module.exports = new UserHandler()
module.exports.setupMiddleware = (app) ->
app.use (req, res, next) ->
if req.user
next()
else
user = new User({anonymous:true})
user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth
user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages
loginUser(req, res, user, false, next)
loginUser = (req, res, user, send=true, next=null) ->
user.save((err) ->
if err
return @sendDatabaseError(res, err)
req.logIn(user, (err) ->
if err
return @sendDatabaseError(res, err)
if send
return @sendSuccess(res, user)
next() if next
)
)

View file

@ -40,9 +40,6 @@ setupOneSecondDelayMiddlware = (app) ->
if(config.slow_down) if(config.slow_down)
app.use((req, res, next) -> setTimeout((-> next()), 1000)) app.use((req, res, next) -> setTimeout((-> next()), 1000))
setupUserMiddleware = (app) ->
user.setupMiddleware(app)
setupMiddlewareToSendOldBrowserWarningWhenPlayersViewLevelDirectly = (app) -> setupMiddlewareToSendOldBrowserWarningWhenPlayersViewLevelDirectly = (app) ->
isOldBrowser = (req) -> isOldBrowser = (req) ->
# https://github.com/biggora/express-useragent/blob/master/lib/express-useragent.js # https://github.com/biggora/express-useragent/blob/master/lib/express-useragent.js
@ -66,7 +63,6 @@ exports.setupMiddleware = (app) ->
setupExpressMiddleware app setupExpressMiddleware app
setupPassportMiddleware app setupPassportMiddleware app
setupOneSecondDelayMiddlware app setupOneSecondDelayMiddlware app
setupUserMiddleware app
###Routing function implementations### ###Routing function implementations###