Merge branch 'feature/Change-view-to-fit-new-supermodel' into feature/loading-views

Conflicts:
	app/views/play/ladder/ladder_tab.coffee
	app/views/play/ladder_view.coffee
This commit is contained in:
Ting-Kuan 2014-04-16 11:38:05 -04:00
commit 2e50d7b15d
19 changed files with 262 additions and 297 deletions

View file

@ -6,9 +6,15 @@ class NameLoader extends CocoClass
loadNames: (ids) -> loadNames: (ids) ->
toLoad = (id for id in ids when not namesCache[id]) toLoad = (id for id in ids when not namesCache[id])
return false unless toLoad.length return false unless toLoad.length
jqxhr = $.ajax('/db/user/x/names', {type:'POST', data:{ids:toLoad}}) jqxhrOptions = {
jqxhr.done @loadedNames url: '/db/user/x/names',
type:'POST',
data:{ids:toLoad},
success: @loadedNames
}
return jqxhrOptions
loadedNames: (newNames) => loadedNames: (newNames) =>
_.extend namesCache, newNames _.extend namesCache, newNames

View file

@ -397,6 +397,7 @@
hard: "Hard" hard: "Hard"
player: "Player" player: "Player"
about: about:
who_is_codecombat: "Who is CodeCombat?" who_is_codecombat: "Who is CodeCombat?"
why_codecombat: "Why CodeCombat?" why_codecombat: "Why CodeCombat?"
@ -667,4 +668,9 @@
leaderboard: "Leaderboard" leaderboard: "Leaderboard"
user_schema: "User Schema" user_schema: "User Schema"
user_profile: "User Profile" user_profile: "User Profile"
patches: "Patches" level_session: "LevelSession"
level_sessions_collection: 'LevelSessionsCollection'
opponent_session: "OpponentSession"
simulator: 'Simulator'
level_document: 'Level Document'
thang_document: 'Thang Document'

View file

@ -6,7 +6,7 @@ ThangType = require './ThangType'
module.exports = class Level extends CocoModel module.exports = class Level extends CocoModel
@className: "Level" @className: "Level"
urlRoot: "/db/level" urlRoot: "/db/level"
serialize: (supermodel) -> serialize: (supermodel) ->
o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs
@ -29,6 +29,7 @@ module.exports = class Level extends CocoModel
visit = (system) -> visit = (system) ->
return if system.original of originalsSeen return if system.original of originalsSeen
systemModel = _.find systemModels, {original: system.original} systemModel = _.find systemModels, {original: system.original}
console.error "Couldn't find model for original", system.original, "from", systemModels unless systemModel console.error "Couldn't find model for original", system.original, "from", systemModels unless systemModel
for d in systemModel.dependencies or [] for d in systemModel.dependencies or []
system2 = _.find levelSystems, {original: d.original} system2 = _.find levelSystems, {original: d.original}

View file

@ -1,5 +1,12 @@
module.exports = class SuperModel extends Backbone.Model module.exports = class SuperModel extends Backbone.Model
constructor: -> constructor: ->
@num = 0
@denom = 0
@showing = false
@progress = 0
@resources = {}
@rid = 0
@models = {} @models = {}
@collections = {} @collections = {}
@schemas = {} @schemas = {}
@ -8,14 +15,17 @@ module.exports = class SuperModel extends Backbone.Model
@mustPopulate = model @mustPopulate = model
model.saveBackups = @shouldSaveBackups(model) model.saveBackups = @shouldSaveBackups(model)
url = model.url() @addModel(model)
@models[url] = model unless @models[url]?
@modelLoaded(model) if model.loaded @modelLoaded(model) if model.loaded
resName = url unless resName resName = model.url unless resName
modelRes = @addModelResource(model, url) modelRes = @addModelResource(model, model.url)
schema = model.schema()
@schemas[schema.urlRoot] = schema
modelRes.load() modelRes.load()
return modelRes
# replace or overwrite # replace or overwrite
shouldLoadReference: (model) -> true shouldLoadReference: (model) -> true
@ -32,8 +42,10 @@ module.exports = class SuperModel extends Backbone.Model
@removeEventsFromModel(model) @removeEventsFromModel(model)
removeEventsFromModel: (model) -> removeEventsFromModel: (model) ->
model.off 'sync', @modelLoaded, @ # "Request" resource may have no off()
model.off 'error', @modelErrored, @ # "Something" resource may have no model.
model?.off? 'sync', @modelLoaded, @
model?.off? 'error', @modelErrored, @
getModel: (ModelClass_or_url, id) -> getModel: (ModelClass_or_url, id) ->
return @getModelByURL(ModelClass_or_url) if _.isString(ModelClass_or_url) return @getModelByURL(ModelClass_or_url) if _.isString(ModelClass_or_url)
@ -55,9 +67,7 @@ module.exports = class SuperModel extends Backbone.Model
return _.values @models return _.values @models
addModel: (model) -> addModel: (model) ->
url = model.url() url = model.url
return console.warn "Tried to add Model '#{url}' to SuperModel, but it wasn't loaded." unless model.loaded
#return console.warn "Tried to add Model '#{url}' to SuperModel when we already had it." if @models[url]?
@models[url] = model @models[url] = model
getCollection: (collection) -> getCollection: (collection) ->
@ -82,44 +92,44 @@ module.exports = class SuperModel extends Backbone.Model
collection collection
finished: -> finished: ->
return ResourceManager.progress is 1.0 or Object.keys(ResourceManager.resources).length is 0 return @progress is 1.0 or Object.keys(@resources).length is 0
addModelResource: (modelOrCollection, name, fetchOptions, value=1) ->
addModelResource: (modelOrCollection, name, fetchOptions, value=1)->
@checkName(name) @checkName(name)
@addModel(modelOrCollection)
res = new ModelResource(modelOrCollection, name, fetchOptions, value) res = new ModelResource(modelOrCollection, name, fetchOptions, value)
@storeResource(name, res, value) @storeResource(res, value)
return res return res
addRequestResource: (name, jqxhrOptions, value=1)-> addRequestResource: (name, jqxhrOptions, value=1) ->
@checkName(name) @checkName(name)
res = new RequestResource(name, jqxhrOptions, value) res = new RequestResource(name, jqxhrOptions, value)
@storeResource(name, res, value) @storeResource(res, value)
return res return res
addSomethingResource: (name, value=1)-> addSomethingResource: (name, value=1) ->
@checkName(name) @checkName(name)
res = new SomethingResource(name, value) res = new SomethingResource(name, value)
@storeResource(name, res, value) @storeResource(res, value)
return res return res
checkName: (name)-> checkName: (name) ->
if not name if not name
throw new Error('Resource name should not be empty.') throw new Error('Resource name should not be empty.')
if name in ResourceManager.resources
throw new Error('Resource name has been used.')
storeResource: (name, resource, value)-> storeResource: (resource, value) ->
ResourceManager.resources[name] = resource @rid++
resource.rid = @rid
@resources[@rid] = resource
@listenToOnce(resource, 'resource:loaded', @onResourceLoaded) @listenToOnce(resource, 'resource:loaded', @onResourceLoaded)
@listenToOnce(resource, 'resource:failed', @onResourceFailed) @listenToOnce(resource, 'resource:failed', @onResourceFailed)
ResourceManager.denom += value @denom += value
loadResources: ()-> loadResources: ->
for name, res of ResourceManager.resources for rid, res of @resources
res.load() res.load()
onResourceLoaded: (r)=> onResourceLoaded: (r) ->
@modelLoaded(r.model) @modelLoaded(r.model)
# Check if the model has references # Check if the model has references
if r.constructor.name is 'ModelResource' if r.constructor.name is 'ModelResource'
@ -129,10 +139,11 @@ module.exports = class SuperModel extends Backbone.Model
else else
@updateProgress(r) @updateProgress(r)
onResourceFailed: (r)=> onResourceFailed: (source) ->
@modelErrored(r.model) @trigger('resource:failed', source)
@modelErrored(source.resource.model)
addModelRefencesToLoad: (model)-> addModelRefencesToLoad: (model) ->
schema = model.schema?() schema = model.schema?()
return unless schema return unless schema
@ -149,57 +160,48 @@ module.exports = class SuperModel extends Backbone.Model
res = @addModelResource(ref, refURL) res = @addModelResource(ref, refURL)
res.load() res.load()
updateProgress: (r)=> updateProgress: (r) =>
ResourceManager.num += r.value @num += r.value
ResourceManager.progress = ResourceManager.num / ResourceManager.denom @progress = @num / @denom
@trigger('superModel:updateProgress', ResourceManager.progress) @trigger('superModel:updateProgress', @progress)
@trigger 'loaded-all' if @finished() @trigger('loaded-all') if @finished()
getResource: (name)-> getResource: (rid)->
return ResourceManager.resources[name] return @resources[rid]
getProgress: ()-> return ResourceManager.progress getProgress: -> return @progress
# Both SuperModel and Resource access this class.
# Set resources as static so no need to load resources multiple times when more than one view is used.
class ResourceManager
@num = 0
@denom = 0
@showing = false
@progress = 0
@resources: {}
class Resource extends Backbone.Model class Resource extends Backbone.Model
constructor: (name, value=1)-> constructor: (name, value=1) ->
@name = name @name = name
@value = value @value = value
@dependencies = [] @dependencies = []
@rid = -1 # Used for checking state and reloading
@isLoading = false @isLoading = false
@isLoaded = false @isLoaded = false
@model = null @model = null
@loadDeferred = null @loadDeferred = null
@value = 1 @value = 1
addDependency: (name)-> addDependency: (depRes) ->
depRes = ResourceManager.resources[name] return if depRes.isLoaded
throw new Error('Resource not found') unless depRes @dependencies.push(depRes)
return if (depRes.isLoaded or name is @name)
@dependencies.push(name)
markLoaded: ()-> markLoaded: ->
@trigger('resource:loaded', @) if not @isLoaded @trigger('resource:loaded', @) if not @isLoaded
@isLoaded = true @isLoaded = true
@isLoading = false @isLoading = false
markFailed: ()-> markFailed: (error) ->
@trigger('resource:failed', @) if not @isLoaded @trigger('resource:failed', {resource: @, error: error}) if not @isLoaded
@isLoaded = false @isLoaded = false
@isLoading = false @isLoading = false
load: ()-> load: ->
isReadyForLoad: ()-> return not (@isloaded and @isLoading) isReadyForLoad: -> return not (@isloaded and @isLoading)
getModel: ()-> @model getModel: -> @model
class ModelResource extends Resource class ModelResource extends Resource
constructor: (modelOrCollection, name, fetchOptions, value)-> constructor: (modelOrCollection, name, fetchOptions, value)->
@ -207,28 +209,27 @@ class ModelResource extends Resource
@model = modelOrCollection @model = modelOrCollection
@fetchOptions = fetchOptions @fetchOptions = fetchOptions
load: ()-> load: ->
return @loadDeferred.promise() if @isLoading or @isLoaded return @loadDeferred.promise() if @isLoading or @isLoaded
@isLoading = true @isLoading = true
@loadDeferred = $.Deferred() @loadDeferred = $.Deferred()
$.when.apply($, @loadDependencies()) $.when.apply($, @loadDependencies())
.then(@onLoadDependenciesSuccess, @onLoadDependenciesFailed) .then(@onLoadDependenciesSuccess, @onLoadDependenciesFailed)
.always(()=> @isLoading = false) .always(=> @isLoading = false)
return @loadDeferred.promise() return @loadDeferred.promise()
loadDependencies: ()-> loadDependencies: ->
promises = [] promises = []
for resName in @dependencies for dep in @dependencies
dep = ResourceManager.resources[resName]
continue if not dep.isReadyForLoad() continue if not dep.isReadyForLoad()
promises.push(dep.load()) promises.push(dep.load())
return promises return promises
onLoadDependenciesSuccess: ()=> onLoadDependenciesSuccess: =>
@model.fetch(@fetchOptions) @model.fetch(@fetchOptions)
@listenToOnce(@model, 'sync', -> @listenToOnce(@model, 'sync', ->
@ -237,23 +238,23 @@ class ModelResource extends Resource
) )
@listenToOnce(@model, 'error', -> @listenToOnce(@model, 'error', ->
@markFailed() @markFailed('Failed to load resource.')
@loadDeferred.reject(@) @loadDeferred.reject(@)
) )
onLoadDependenciesFailed: ()=> onLoadDependenciesFailed: =>
@markFailed() @markFailed('Failed to load dependencies.')
@loadDeferred.reject(@) @loadDeferred.reject(@)
class RequestResource extends Resource class RequestResource extends Resource
constructor: (name, jqxhrOptions, value)-> constructor: (name, jqxhrOptions, value) ->
super(name, value) super(name, value)
@model = $.ajax(jqxhrOptions) @model = $.ajax(jqxhrOptions)
@jqxhrOptions = jqxhrOptions @jqxhrOptions = jqxhrOptions
@loadDeferred = @model @loadDeferred = @model
load: ()-> load: ->
return @loadDeferred.promise() if @isLoading or @isLoaded return @loadDeferred.promise() if @isLoading or @isLoaded
@isLoading = true @isLoading = true
@ -263,36 +264,41 @@ class RequestResource extends Resource
return @loadDeferred.promise() return @loadDeferred.promise()
loadDependencies: ()-> loadDependencies: ->
promises = [] promises = []
for depName in @dependecies
dep = ResourceManager.resources[depName] for dep in @dependencies
continue if not dep.isReadyForLoad() continue if not dep.isReadyForLoad()
promises.push(dep.load()) promises.push(dep.load())
return promises return promises
onLoadDependenciesSuccess: ()-> onLoadDependenciesSuccess: =>
@model = $.ajax(@jqxhrOptions) @model = $.ajax(@jqxhrOptions)
@model.done(()=> @markLoaded()).failed(()=> @markFailed()) @model.done(
=> @markLoaded()
).fail(
(jqXHR, textStatus, errorThrown) =>
@markFailed(errorThrown)
)
onLoadDependenciesFailed: ()-> onLoadDependenciesFailed: =>
@markFailed() @markFailed('Failed to load dependencies.')
class SomethingResource extends Resource class SomethingResource extends Resource
constructor: (name, value)-> constructor: (name, value) ->
super(value) super(value)
@name = name @name = name
@loadDeferred = $.Deferred() @loadDeferred = $.Deferred()
load: ()-> load: ->
return @loadDeferred.promise() return @loadDeferred.promise()
markLoaded: ()-> markLoaded: ->
@loadDeferred.resolve() @loadDeferred.resolve()
super() super()
markFailed: ()-> markFailed: (error) ->
@loadDeferred.reject() @loadDeferred.reject()
super() super(error)

View file

@ -18,31 +18,26 @@ module.exports = class ThangComponentEditView extends CocoView
@level = options.level @level = options.level
@callback = options.callback @callback = options.callback
render: => @componentCollection = @supermodel.getCollection new ComponentsCollection()
return if @destroyed @componentCollectionRes = @supermodel.addModelResource(@componentCollection, 'component_collection')
if not @componentCollection @listenToOnce(@componentCollectionRes, 'resource:loaded', @onComponentsSync)
@componentCollection = @supermodel.getCollection new ComponentsCollection() @componentCollectionRes.load()
unless @componentCollection.loaded
@listenToOnce(@componentCollection, 'sync', @onComponentsSync)
@componentCollection.fetch()
super() # do afterRender at the end
onLoaded: ->
afterRender: -> afterRender: ->
super() super()
return @showLoading() unless @componentCollection?.loaded
@hideLoading()
@buildExtantComponentTreema() @buildExtantComponentTreema()
@buildAddComponentTreema() @buildAddComponentTreema()
onComponentsSync: -> onComponentsSync: (res) ->
return if @destroyed return if @destroyed
@supermodel.addCollection @componentCollection @supermodel.addCollection @componentCollection
@render()
buildExtantComponentTreema: -> buildExtantComponentTreema: ->
level = new Level()
treemaOptions = treemaOptions =
supermodel: @supermodel supermodel: @supermodel
schema: Level.schema.properties.thangs.items.properties.components schema: level.schema().properties.thangs.items.properties.components
data: _.cloneDeep @components data: _.cloneDeep @components
callbacks: {select: @onSelectExtantComponent, change:@onChangeExtantComponents} callbacks: {select: @onSelectExtantComponent, change:@onChangeExtantComponents}
noSortable: true noSortable: true

View file

@ -22,13 +22,10 @@ module.exports = class AddThangsView extends View
constructor: (options) -> constructor: (options) ->
super options super options
@world = options.world @world = options.world
@thangTypes = @supermodel.getCollection new ThangTypeSearchCollection() # should load depended-on Components, too @thangTypes = @supermodel.getCollection new ThangTypeSearchCollection() # should load depended-on Components, too
@listenToOnce(@thangTypes, 'sync', @onThangTypesLoaded) @thangTypesRes = @supermodel.addModelResource(@thangTypes, 'add_thang_type_search_collection')
@thangTypes.fetch() @thangTypesRes.load()
onThangTypesLoaded: ->
return if @destroyed
@render() # do it again but without the loading screen
getRenderData: (context={}) -> getRenderData: (context={}) ->
context = super(context) context = super(context)
@ -59,7 +56,6 @@ module.exports = class AddThangsView extends View
context context
afterRender: -> afterRender: ->
return if @startsLoading
super() super()
runSearch: (e) => runSearch: (e) =>

View file

@ -22,6 +22,7 @@ module.exports = class ComponentsTabView extends View
events: events:
'click #create-new-component-button': 'createNewLevelComponent' 'click #create-new-component-button': 'createNewLevelComponent'
onLoaded: ->
onLevelThangsChanged: (e) -> onLevelThangsChanged: (e) ->
thangsData = e.thangsData thangsData = e.thangsData
presentComponents = {} presentComponents = {}

View file

@ -20,7 +20,6 @@ ErrorView = require '../../error_view'
module.exports = class EditorLevelView extends View module.exports = class EditorLevelView extends View
id: "editor-level-view" id: "editor-level-view"
template: template template: template
startsLoading: true
cache: false cache: false
events: events:
@ -28,7 +27,7 @@ module.exports = class EditorLevelView extends View
'click #commit-level-start-button': 'startCommittingLevel' 'click #commit-level-start-button': 'startCommittingLevel'
'click #fork-level-start-button': 'startForkingLevel' 'click #fork-level-start-button': 'startForkingLevel'
'click #history-button': 'showVersionHistory' 'click #history-button': 'showVersionHistory'
'click #patches-tab': -> @patchesView.load() 'click #patches-tab': -> @patchesView?.load()
'click #commit-level-patch-button': 'startPatchingLevel' 'click #commit-level-patch-button': 'startPatchingLevel'
constructor: (options, @levelID) -> constructor: (options, @levelID) ->
@ -46,33 +45,29 @@ module.exports = class EditorLevelView extends View
@supermodel.shouldSaveBackups = (model) -> @supermodel.shouldSaveBackups = (model) ->
model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem'] model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem']
@level = new Level _id: @levelID @worldRes = @supermodel.addSomethingResource('world')
@listenToOnce(@level, 'sync', @onLevelLoaded)
@listenToOnce(@supermodel, 'error', @level = new Level _id: @levelID
() => #@listenToOnce(@level, 'sync', @onLevelLoaded)
@listenToOnce(@supermodel, 'error', =>
@hideLoading() @hideLoading()
@insertSubView(new ErrorView()) @insertSubView(new ErrorView())
) )
@supermodel.populateModel(@level, 'level')
@levelRes = @supermodel.addModelResource(@level, 'level')
@listenToOnce(@levelRes, 'resource:loaded', ->
@world = new World @level.name
@worldRes.markLoaded()
)
@levelRes.load()
@files = new DocumentFiles(@level)
@supermodel.addModelResource(@files, 'level_document').load()
showLoading: ($el) -> showLoading: ($el) ->
$el ?= @$el.find('.tab-content') $el ?= @$el.find('.tab-content')
super($el) super($el)
onLevelLoaded: ->
@files = new DocumentFiles(@level)
@supermodel.addModelResource(@files, @files.url).load()
onAllLoaded: ->
@level.unset('nextLevel') if _.isString(@level.get('nextLevel'))
@initWorld()
@startsLoading = false
@render() # do it again but without the loading screen
initWorld: ->
@world = new World @level.name
getRenderData: (context={}) -> getRenderData: (context={}) ->
context = super(context) context = super(context)
context.level = @level context.level = @level
@ -81,9 +76,9 @@ module.exports = class EditorLevelView extends View
context context
afterRender: -> afterRender: ->
return if @startsLoading
super() super()
new LevelSystem # temp; trigger the LevelSystem schema to be loaded, if it isn't already return unless @world and @level
console.debug 'gintau', 'edit-afterRender'
@$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) => @$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
Backbone.Mediator.publish 'level:view-switched', e Backbone.Mediator.publish 'level:view-switched', e
@thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel @thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel

View file

@ -16,7 +16,8 @@ module.exports = class ScriptsTabView extends View
super options super options
@world = options.world @world = options.world
@files = options.files @files = options.files
onLoaded: ->
onLevelLoaded: (e) -> onLevelLoaded: (e) ->
@level = e.level @level = e.level
@dimensions = @level.dimensions() @dimensions = @level.dimensions()

View file

@ -22,6 +22,7 @@ module.exports = class SettingsTabView extends View
super options super options
@world = options.world @world = options.world
onLoaded: ->
onLevelLoaded: (e) -> onLevelLoaded: (e) ->
@level = e.level @level = e.level
data = _.pick @level.attributes, (value, key) => key in @editableSettings data = _.pick @level.attributes, (value, key) => key in @editableSettings

View file

@ -31,15 +31,17 @@ module.exports = class SystemsTabView extends View
url = "/db/level.system/#{system.original}/version/#{system.majorVersion}" url = "/db/level.system/#{system.original}/version/#{system.majorVersion}"
ls = new LevelSystem() ls = new LevelSystem()
ls.saveBackups = true ls.saveBackups = true
lsRes = @supermodel.addModelResource(ls, 'level_system_' + system.original);
do (url) -> ls.url = -> url do (url) -> ls.url = -> url
continue if @supermodel.getModelByURL ls.url continue if @supermodel.getModelByURL ls.url
ls.fetch() lsRes.load()
@listenToOnce ls, 'sync', @onSystemLoaded @listenToOnce(lsRes, 'resource:loaded', @onSystemLoaded)
++@toLoad ++@toLoad
@onDefaultSystemsLoaded() unless @toLoad @onDefaultSystemsLoaded() unless @toLoad
onSystemLoaded: (ls) -> onSystemLoaded: (lsRes) ->
@supermodel.addModel ls ls = lsRes.model
@supermodel.addModel(ls)
--@toLoad --@toLoad
@onDefaultSystemsLoaded() unless @toLoad @onDefaultSystemsLoaded() unless @toLoad
@ -48,9 +50,9 @@ module.exports = class SystemsTabView extends View
@render() # do it again but without the loading screen @render() # do it again but without the loading screen
@onLevelLoaded level: @level if @level @onLevelLoaded level: @level if @level
onLoaded: ->
onLevelLoaded: (e) -> onLevelLoaded: (e) ->
@level = e.level @level = e.level
return if @startsLoading
@buildSystemsTreema() @buildSystemsTreema()
buildSystemsTreema: -> buildSystemsTreema: ->
@ -145,9 +147,7 @@ class LevelSystemNode extends TreemaObjectNode
grabDBComponent: -> grabDBComponent: ->
unless _.isString @data.original unless _.isString @data.original
return alert('Press the "Add System" button at the bottom instead of the "+". Sorry.') return alert('Press the "Add System" button at the bottom instead of the "+". Sorry.')
@system = @settings.supermodel.getModelByOriginalAndMajorVersion LevelSystem, @data.original, @data.majorVersion @system = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelSystem, @data.original, @data.majorVersion)
#@system = _.find @settings.supermodel.getModels(LevelSystem), (m) =>
# m.get('original') is @data.original and m.get('version').major is @data.majorVersion
console.error "Couldn't find system for", @data.original, @data.majorVersion, "from models", @settings.supermodel.models unless @system console.error "Couldn't find system for", @data.original, @data.majorVersion, "from models", @settings.supermodel.models unless @system
getChildSchema: (key) -> getChildSchema: (key) ->

View file

@ -50,6 +50,7 @@ module.exports = class LevelThangEditView extends View
input.val(thangTypeName) input.val(thangTypeName)
@$el.find('#thang-type-link span').text(thangTypeName) @$el.find('#thang-type-link span').text(thangTypeName)
window.input = input window.input = input
@hideLoading()
saveThang: (e) -> saveThang: (e) ->
# Make sure it validates first? # Make sure it validates first?

View file

@ -60,31 +60,34 @@ module.exports = class ThangsTabView extends View
constructor: (options) -> constructor: (options) ->
super options super options
@world = options.world @world = options.world
@thangTypes = @supermodel.getCollection new ThangTypeSearchCollection() # should load depended-on Components, too @thangTypes = @supermodel.getCollection new ThangTypeSearchCollection() # should load depended-on Components, too
@listenToOnce(@thangTypes, 'sync', @onThangTypesLoaded) @thangTypesRes = @supermodel.addModelResource(@thangTypes, 'thang_type_search_collection')
@thangTypes.fetch() @listenToOnce(@thangTypesRes, 'resource:loaded', @onThangTypesLoaded)
@thangTypesRes.load()
$(document).bind 'contextmenu', @preventDefaultContextMenu $(document).bind 'contextmenu', @preventDefaultContextMenu
# just loading all Components for now: https://github.com/codecombat/codecombat/issues/405 # just loading all Components for now: https://github.com/codecombat/codecombat/issues/405
@componentCollection = @supermodel.getCollection new ComponentsCollection() @componentCollection = @supermodel.getCollection new ComponentsCollection()
@listenToOnce(@componentCollection, 'sync', @onComponentsLoaded) @componentCollectionRes = @supermodel.addModelResource(@componentCollection, 'components_collection')
@componentCollection.fetch() @listenToOnce(@componentCollectionRes, 'resource:loaded', @onComponentsLoaded)
@componentCollectionRes.load()
onThangTypesLoaded: -> onThangTypesLoaded: ->
return if @destroyed return if @destroyed
@supermodel.addCollection @thangTypes @supermodel.addCollection @thangTypes
for model in @thangTypes.models for model in @thangTypes.models
@supermodel.populateModel(model, model.name) @supermodel.populateModel(model, model.name)
@startsLoading = not @componentCollection.loaded # @render() # do it again but without the loading screen
@render() # do it again but without the loading screen # @onLevelLoaded level: @level if @level and not @startsLoading
@onLevelLoaded level: @level if @level and not @startsLoading
onComponentsLoaded: -> onComponentsLoaded: ->
return if @destroyed return if @destroyed
@supermodel.addCollection @componentCollection @supermodel.addCollection @componentCollection
@startsLoading = not @thangTypes.loaded # @render() # do it again but without the loading screen
@render() # do it again but without the loading screen # @onLevelLoaded level: @level if @level and not @startsLoading
@onLevelLoaded level: @level if @level and not @startsLoading
getRenderData: (context={}) -> getRenderData: (context={}) ->
context = super(context) context = super(context)
@ -115,8 +118,8 @@ module.exports = class ThangsTabView extends View
oldHeight = $('#thangs-list').height() oldHeight = $('#thangs-list').height()
$('#thangs-list').height(oldHeight - thangsHeaderHeight - 80) $('#thangs-list').height(oldHeight - thangsHeaderHeight - 80)
onLoaded: ->
afterRender: -> afterRender: ->
return if @startsLoading
super() super()
$('.tab-content').click @selectAddThang $('.tab-content').click @selectAddThang
$('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList $('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList
@ -138,7 +141,7 @@ module.exports = class ThangsTabView extends View
onLevelLoaded: (e) -> onLevelLoaded: (e) ->
@level = e.level @level = e.level
return if @startsLoading
data = $.extend(true, {}, @level.attributes) data = $.extend(true, {}, @level.attributes)
treemaOptions = treemaOptions =
schema: Level.schema.properties.thangs schema: Level.schema.properties.thangs
@ -153,6 +156,7 @@ module.exports = class ThangsTabView extends View
thang: ThangNode thang: ThangNode
array: ThangsNode array: ThangsNode
world: @world world: @world
@thangsTreema = @$el.find('#thangs-treema').treema treemaOptions @thangsTreema = @$el.find('#thangs-treema').treema treemaOptions
@thangsTreema.build() @thangsTreema.build()
@thangsTreema.open() @thangsTreema.open()

View file

@ -20,19 +20,16 @@ module.exports = class PatchesView extends CocoView
initPatches: -> initPatches: ->
@startedLoading = false @startedLoading = false
@patches = new PatchesCollection([], {}, @model, @status) @patches = new PatchesCollection([], {}, @model, @status)
@listenToOnce @patches, 'sync', @gotPatches @patchesRes = @supermodel.addModelResource(@patches, 'patches')
@addResourceToLoad @patches, 'patches'
gotPatches: ->
ids = (p.get('creator') for p in @patches.models) ids = (p.get('creator') for p in @patches.models)
jqxhr = nameLoader.loadNames ids jqxhrOptions = nameLoader.loadNames ids
if jqxhr then @addRequestToLoad(jqxhr, 'user_names', 'gotPatches') else @render() @nameLoaderRes = @supermodel.addRequestResource('name_loader', jqxhrOptions)
@nameLoaderRes.addDependency(@patchesRes)
load: -> load: ->
return if @startedLoading @nameLoaderRes.load()
@patches.fetch()
@startedLoading = true
getRenderData: -> getRenderData: ->
c = super() c = super()
patch.userName = nameLoader.getName(patch.get('creator')) for patch in @patches.models patch.userName = nameLoader.getName(patch.get('creator')) for patch in @patches.models

View file

@ -61,20 +61,13 @@ module.exports = class ThangTypeEditView extends View
) )
thangRes = @supermodel.addModelResource(@thangType, 'thang_type') thangRes = @supermodel.addModelResource(@thangType, 'thang_type')
@files = new DocumentFiles(@thangType)
thangDocRes = @supermodel.addModelResource(@files, 'thang_document')
thangRes.addDependency(thangDocRes)
thangRes.load() thangRes.load()
@listenToOnce(@thangType.schema(), 'sync', @onThangTypeSync)
@listenToOnce(@thangType, 'sync', @onThangTypeSync)
@refreshAnimation = _.debounce @refreshAnimation, 500 @refreshAnimation = _.debounce @refreshAnimation, 500
onThangTypeSync: ->
return unless @thangType.loaded
@startsLoading = false
@files = new DocumentFiles(@thangType)
@supermodel.addModelResource(@files, @files.url).load()
@render()
getRenderData: (context={}) -> getRenderData: (context={}) ->
context = super(context) context = super(context)
context.thangType = @thangType context.thangType = @thangType
@ -90,7 +83,6 @@ module.exports = class ThangTypeEditView extends View
afterRender: -> afterRender: ->
super() super()
return unless @thangType.loaded
@initStage() @initStage()
@buildTreema() @buildTreema()
@initSliders() @initSliders()

View file

@ -43,8 +43,9 @@ module.exports = class CocoView extends Backbone.View
@updateProgressBar = _.debounce @updateProgressBar, 100 @updateProgressBar = _.debounce @updateProgressBar, 100
# Backbone.Mediator handles subscription setup/teardown automatically # Backbone.Mediator handles subscription setup/teardown automatically
@listenToOnce(@supermodel, 'loaded-all', ()=>@onLoaded) @listenToOnce(@supermodel, 'loaded-all', @onLoaded)
@listenToOnce(@supermodel, 'superModel:updateProgress', @updateProgress) @listenToOnce(@supermodel, 'superModel:updateProgress', @updateProgress)
@listenToOnce(@supermodel, 'resource:failed', @onResourceLoadFailed)
super options super options
@ -118,38 +119,20 @@ module.exports = class CocoView extends Backbone.View
@$el?.find('.loading-screen .progress-bar').css('width', prog) @$el?.find('.loading-screen .progress-bar').css('width', prog)
onLoaded: -> onLoaded: ->
#@render() @render?()
# Error handling for loading # Error handling for loading
onResourceLoadFailed: (source) ->
onResourceLoadFailed: (resource, jqxhr) ->
for r, index in @loadProgress.resources
break if r.resource is resource
@$el.find('.loading-screen .errors').append(loadingErrorTemplate({ @$el.find('.loading-screen .errors').append(loadingErrorTemplate({
status:jqxhr.status, status: 'error',
name: r.name name: source.resource.name
resourceIndex: index, resourceIndex: source.resource.rid,
responseText: jqxhr.responseText responseText: source.error
})).i18n() })).i18n()
onRetryResource: (e) -> onRetryResource: (e) ->
r = @loadProgress.resources[$(e.target).data('resource-index')] res = @supermodel.getResource($(e.target).data('resource-index'))
r.resource.fetch() res.load()
$(e.target).closest('.loading-error-alert').remove()
onRequestLoadFailed: (jqxhr) =>
for r, index in @loadProgress.requests
break if r.request is jqxhr
@$el.find('.loading-screen .errors').append(loadingErrorTemplate({
status:jqxhr.status,
name: r.name
requestIndex: index,
responseText: jqxhr.responseText
}))
onRetryRequest: (e) ->
r = @loadProgress.requests[$(e.target).data('request-index')]
@[r.retryFunc]?()
$(e.target).closest('.loading-error-alert').remove() $(e.target).closest('.loading-error-alert').remove()
# Modals # Modals

View file

@ -32,7 +32,8 @@ module.exports = class LadderTabView extends CocoView
constructor: (options, @level, @sessions) -> constructor: (options, @level, @sessions) ->
super(options) super(options)
@addSomethingToLoad("social_network_apis") @socialNetworkRes = @supermodel.addSomethingResource("social_network_apis")
@teams = teamDataFromLevel @level @teams = teamDataFromLevel @level
@leaderboards = {} @leaderboards = {}
@refreshLadder() @refreshLadder()
@ -41,18 +42,23 @@ module.exports = class LadderTabView extends CocoView
checkFriends: -> checkFriends: ->
return if @checked or (not window.FB) or (not window.gapi) return if @checked or (not window.FB) or (not window.gapi)
@checked = true @checked = true
# @addSomethingToLoad("facebook_status")
@fbStatusRes = @supermodel.addSomethingResource("facebook_status")
@fbStatusRes.load()
@addSomethingToLoad("facebook_status")
FB.getLoginStatus (response) => FB.getLoginStatus (response) =>
@facebookStatus = response.status @facebookStatus = response.status
@loadFacebookFriends() if @facebookStatus is 'connected' @loadFacebookFriends() if @facebookStatus is 'connected'
@somethingLoaded("facebook_status") @fbStatusRes.markLoaded()
if application.gplusHandler.loggedIn is undefined if application.gplusHandler.loggedIn is undefined
@listenToOnce(application.gplusHandler, 'checked-state', @gplusSessionStateLoaded) @listenToOnce(application.gplusHandler, 'checked-state', @gplusSessionStateLoaded)
else else
@gplusSessionStateLoaded() @gplusSessionStateLoaded()
@somethingLoaded("social_network_apis")
@socialNetworkRes.markLoaded()
# FACEBOOK # FACEBOOK
@ -63,23 +69,39 @@ module.exports = class LadderTabView extends CocoView
onConnectedWithFacebook: -> location.reload() if @connecting onConnectedWithFacebook: -> location.reload() if @connecting
loadFacebookFriends: -> loadFacebookFriends: ->
@addSomethingToLoad("facebook_friends") # @addSomethingToLoad("facebook_friends")
FB.api '/me/friends', @onFacebookFriendsLoaded
@fbFriendRes = @supermodel.addSomethingResource("facebook_friends")
@fbFriendRes.load()
FB.api '/me/friends', @onFacebookFriendsLoaded
onFacebookFriendsLoaded: (response) => onFacebookFriendsLoaded: (response) =>
@facebookData = response.data @facebookData = response.data
@loadFacebookFriendSessions() @loadFacebookFriendSessions()
@somethingLoaded("facebook_friends") @fbFriendRes.markLoaded()
loadFacebookFriendSessions: -> loadFacebookFriendSessions: ->
levelFrag = "#{@level.get('original')}.#{@level.get('version').major}" levelFrag = "#{@level.get('original')}.#{@level.get('version').major}"
url = "/db/level/#{levelFrag}/leaderboard_facebook_friends" url = "/db/level/#{levelFrag}/leaderboard_facebook_friends"
###
jqxhr = $.ajax url, { jqxhr = $.ajax url, {
data: { friendIDs: (f.id for f in @facebookData) } data: { friendIDs: (f.id for f in @facebookData) }
method: 'POST' method: 'POST'
success: @onFacebookFriendSessionsLoaded success: @onFacebookFriendSessionsLoaded
} }
@addRequestToLoad(jqxhr, 'facebook_friend_sessions', 'loadFacebookFriendSessions') @addRequestToLoad(jqxhr, 'facebook_friend_sessions', 'loadFacebookFriendSessions')
###
@fbFriendSessionRes = @supermodel.addRequestResource('facebook_friend_sessions', {
url: url
data: { friendIDs: (f.id for f in @facebookData) }
method: 'POST'
success: @onFacebookFriendSessionsLoaded
})
@fbFriendSessionRes.load()
onFacebookFriendSessionsLoaded: (result) => onFacebookFriendSessionsLoaded: (result) =>
friendsMap = {} friendsMap = {}
@ -89,7 +111,7 @@ module.exports = class LadderTabView extends CocoView
friend.otherTeam = if friend.team is 'humans' then 'ogres' else 'humans' friend.otherTeam = if friend.team is 'humans' then 'ogres' else 'humans'
friend.imageSource = "http://graph.facebook.com/#{friend.facebookID}/picture" friend.imageSource = "http://graph.facebook.com/#{friend.facebookID}/picture"
@facebookFriendSessions = result @facebookFriendSessions = result
# GOOGLE PLUS # GOOGLE PLUS
onConnectGPlus: -> onConnectGPlus: ->
@ -98,26 +120,37 @@ module.exports = class LadderTabView extends CocoView
application.gplusHandler.reauthorize() application.gplusHandler.reauthorize()
onConnectedWithGPlus: -> location.reload() if @connecting onConnectedWithGPlus: -> location.reload() if @connecting
gplusSessionStateLoaded: -> gplusSessionStateLoaded: ->
if application.gplusHandler.loggedIn if application.gplusHandler.loggedIn
@addSomethingToLoad("gplus_friends", 0) # this might not load ever, so we can't wait for it #@addSomethingToLoad("gplus_friends")
@gpFriendRes = @supermodel.addSomethingResource("gplus_friends")
@gpFriendRes.load()
application.gplusHandler.loadFriends @gplusFriendsLoaded application.gplusHandler.loadFriends @gplusFriendsLoaded
gplusFriendsLoaded: (friends) => gplusFriendsLoaded: (friends) =>
@gplusData = friends.items @gplusData = friends.items
@loadGPlusFriendSessions() @loadGPlusFriendSessions()
@somethingLoaded("gplus_friends") @gpFriendRes.markLoaded()
loadGPlusFriendSessions: -> loadGPlusFriendSessions: ->
levelFrag = "#{@level.get('original')}.#{@level.get('version').major}" levelFrag = "#{@level.get('original')}.#{@level.get('version').major}"
url = "/db/level/#{levelFrag}/leaderboard_gplus_friends" url = "/db/level/#{levelFrag}/leaderboard_gplus_friends"
###
jqxhr = $.ajax url, { jqxhr = $.ajax url, {
data: { friendIDs: (f.id for f in @gplusData) } data: { friendIDs: (f.id for f in @gplusData) }
method: 'POST' method: 'POST'
success: @onGPlusFriendSessionsLoaded success: @onGPlusFriendSessionsLoaded
} }
@addRequestToLoad(jqxhr, 'gplus_friend_sessions', 'loadGPlusFriendSessions') @addRequestToLoad(jqxhr, 'gplus_friend_sessions', 'loadGPlusFriendSessions')
###
@gpFriendSessionRes = @supermodel.addRequestResource('gplus_friend_sessions', {
url: url
data: { friendIDs: (f.id for f in @gplusData) }
method: 'POST'
success: @onGPlusFriendSessionsLoaded
})
@gpFriendSessionRes.load()
onGPlusFriendSessionsLoaded: (result) => onGPlusFriendSessionsLoaded: (result) =>
friendsMap = {} friendsMap = {}
@ -127,7 +160,7 @@ module.exports = class LadderTabView extends CocoView
friend.otherTeam = if friend.team is 'humans' then 'ogres' else 'humans' friend.otherTeam = if friend.team is 'humans' then 'ogres' else 'humans'
friend.imageSource = friendsMap[friend.gplusID].image.url friend.imageSource = friendsMap[friend.gplusID].image.url
@gplusFriendSessions = result @gplusFriendSessions = result
# LADDER LOADING # LADDER LOADING
refreshLadder: -> refreshLadder: ->
@ -135,12 +168,13 @@ module.exports = class LadderTabView extends CocoView
@leaderboards[team.id]?.destroy() @leaderboards[team.id]?.destroy()
teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession) @leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession)
# @addResourceToLoad @leaderboards[team.id], 'leaderboard', 3
@addResourceToLoad @leaderboards[team.id], 'leaderboard', 3 @leaderboardRes = @supermodel.addModelResource(@leaderboards[team.id], 'leaderboard', 3)
@leaderboardRes.load()
render: -> render: ->
super() super()
@$el.find('.histogram-display').each (i, el) => @$el.find('.histogram-display').each (i, el) =>
histogramWrapper = $(el) histogramWrapper = $(el)
team = _.find @teams, name: histogramWrapper.data('team-name') team = _.find @teams, name: histogramWrapper.data('team-name')
@ -149,7 +183,7 @@ module.exports = class LadderTabView extends CocoView
$.get("/db/level/#{@level.get('slug')}/histogram_data?team=#{team.name.toLowerCase()}", (data) -> histogramData = data) $.get("/db/level/#{@level.get('slug')}/histogram_data?team=#{team.name.toLowerCase()}", (data) -> histogramData = data)
).then => ).then =>
@generateHistogram(histogramWrapper, histogramData, team.name.toLowerCase()) @generateHistogram(histogramWrapper, histogramData, team.name.toLowerCase())
getRenderData: -> getRenderData: ->
ctx = super() ctx = super()
ctx.level = @level ctx.level = @level
@ -166,7 +200,7 @@ module.exports = class LadderTabView extends CocoView
#renders twice, hack fix #renders twice, hack fix
if $("#"+histogramElement.attr("id")).has("svg").length then return if $("#"+histogramElement.attr("id")).has("svg").length then return
histogramData = histogramData.map (d) -> d*100 histogramData = histogramData.map (d) -> d*100
margin = margin =
top: 20 top: 20
right: 20 right: 20
@ -175,17 +209,17 @@ module.exports = class LadderTabView extends CocoView
width = 300 - margin.left - margin.right width = 300 - margin.left - margin.right
height = 125 - margin.top - margin.bottom height = 125 - margin.top - margin.bottom
formatCount = d3.format(",.0") formatCount = d3.format(",.0")
x = d3.scale.linear().domain([-3000,6000]).range([0,width]) x = d3.scale.linear().domain([-3000,6000]).range([0,width])
data = d3.layout.histogram().bins(x.ticks(20))(histogramData) data = d3.layout.histogram().bins(x.ticks(20))(histogramData)
y = d3.scale.linear().domain([0,d3.max(data, (d) -> d.y)]).range([height,0]) y = d3.scale.linear().domain([0,d3.max(data, (d) -> d.y)]).range([height,0])
#create the x axis #create the x axis
xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5).outerTickSize(0) xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5).outerTickSize(0)
svg = d3.select("#"+histogramElement.attr("id")).append("svg") svg = d3.select("#"+histogramElement.attr("id")).append("svg")
.attr("width", width + margin.left + margin.right) .attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom) .attr("height", height + margin.top + margin.bottom)
@ -194,25 +228,25 @@ module.exports = class LadderTabView extends CocoView
barClass = "bar" barClass = "bar"
if teamName.toLowerCase() is "ogres" then barClass = "ogres-bar" if teamName.toLowerCase() is "ogres" then barClass = "ogres-bar"
if teamName.toLowerCase() is "humans" then barClass = "humans-bar" if teamName.toLowerCase() is "humans" then barClass = "humans-bar"
bar = svg.selectAll(".bar") bar = svg.selectAll(".bar")
.data(data) .data(data)
.enter().append("g") .enter().append("g")
.attr("class",barClass) .attr("class",barClass)
.attr("transform", (d) -> "translate(#{x(d.x)},#{y(d.y)})") .attr("transform", (d) -> "translate(#{x(d.x)},#{y(d.y)})")
bar.append("rect") bar.append("rect")
.attr("x",1) .attr("x",1)
.attr("width",width/20) .attr("width",width/20)
.attr("height", (d) -> height - y(d.y)) .attr("height", (d) -> height - y(d.y))
if playerScore = @leaderboards[teamName].session?.get('totalScore') if @leaderboards[teamName].session?
playerScore *= 100 playerScore = @leaderboards[teamName].session.get('totalScore') * 100
scorebar = svg.selectAll(".specialbar") scorebar = svg.selectAll(".specialbar")
.data([playerScore]) .data([playerScore])
.enter().append("g") .enter().append("g")
.attr("class","specialbar") .attr("class","specialbar")
.attr("transform", "translate(#{x(playerScore)},#{y(9001)})") .attr("transform", "translate(#{x(playerScore)},#{y(9001)})")
scorebar.append("rect") scorebar.append("rect")
.attr("x",1) .attr("x",1)
.attr("width",3) .attr("width",3)
@ -220,7 +254,7 @@ module.exports = class LadderTabView extends CocoView
rankClass = "rank-text" rankClass = "rank-text"
if teamName.toLowerCase() is "ogres" then rankClass = "rank-text ogres-rank-text" if teamName.toLowerCase() is "ogres" then rankClass = "rank-text ogres-rank-text"
if teamName.toLowerCase() is "humans" then rankClass = "rank-text humans-rank-text" if teamName.toLowerCase() is "humans" then rankClass = "rank-text humans-rank-text"
message = "#{histogramData.length} players" message = "#{histogramData.length} players"
if @leaderboards[teamName].session? then message="#{@leaderboards[teamName].myRank}/#{histogramData.length}" if @leaderboards[teamName].session? then message="#{@leaderboards[teamName].myRank}/#{histogramData.length}"
svg.append("g") svg.append("g")
@ -230,14 +264,14 @@ module.exports = class LadderTabView extends CocoView
.attr("text-anchor","end") .attr("text-anchor","end")
.attr("x",width) .attr("x",width)
.text(message) .text(message)
#Translate the x-axis up #Translate the x-axis up
svg.append("g") svg.append("g")
.attr("class", "x axis") .attr("class", "x axis")
.attr("transform","translate(0," + height + ")") .attr("transform","translate(0," + height + ")")
.call(xAxis) .call(xAxis)
consolidateFriends: -> consolidateFriends: ->
allFriendSessions = (@facebookFriendSessions or []).concat(@gplusFriendSessions or []) allFriendSessions = (@facebookFriendSessions or []).concat(@gplusFriendSessions or [])
sessions = _.uniq allFriendSessions, false, (session) -> session._id sessions = _.uniq allFriendSessions, false, (session) -> session._id
@ -249,11 +283,11 @@ class LeaderboardData extends CocoClass
### ###
Consolidates what you need to load for a leaderboard into a single Backbone Model-like object. Consolidates what you need to load for a leaderboard into a single Backbone Model-like object.
### ###
constructor: (@level, @team, @session) -> constructor: (@level, @team, @session) ->
super() super()
@fetch() @fetch()
fetch: -> fetch: ->
@topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: 20}) @topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: 20})
promises = [] promises = []
@ -279,7 +313,7 @@ class LeaderboardData extends CocoClass
@trigger 'sync', @ @trigger 'sync', @
# TODO: cache user ids -> names mapping, and load them here as needed, # TODO: cache user ids -> names mapping, and load them here as needed,
# and apply them to sessions. Fetching each and every time is too costly. # and apply them to sessions. Fetching each and every time is too costly.
onFail: (resource, jqxhr) => onFail: (resource, jqxhr) =>
return if @destroyed return if @destroyed
@trigger 'error', @, jqxhr @trigger 'error', @, jqxhr

View file

@ -10,8 +10,6 @@ application = require 'application'
LadderTabView = require './ladder/ladder_tab' LadderTabView = require './ladder/ladder_tab'
MyMatchesTabView = require './ladder/my_matches_tab' MyMatchesTabView = require './ladder/my_matches_tab'
LadderPlayModal = require './ladder/play_modal' LadderPlayModal = require './ladder/play_modal'
SimulatorsLeaderboardCollection = require 'collections/SimulatorsLeaderboardCollection'
CocoClass = require 'lib/CocoClass'
HIGHEST_SCORE = 1000000 HIGHEST_SCORE = 1000000
@ -39,13 +37,13 @@ module.exports = class LadderView extends RootView
constructor: (options, @levelID) -> constructor: (options, @levelID) ->
super(options) super(options)
@level = new Level(_id:@levelID) @level = new Level(_id:@levelID)
@level.fetch() levelRes = @supermodel.addModelResource(@level, 'level')
levelRes.load()
@sessions = new LevelSessionsCollection(levelID) @sessions = new LevelSessionsCollection(levelID)
@sessions.fetch({}) sessionRes = @supermodel.addModelResource(@sessions, 'level_sessions_collection')
@addResourceToLoad(@sessions, 'your_sessions') sessionRes.load()
@addResourceToLoad(@level, 'level')
@simulatorsLeaderboardData = new SimulatorsLeaderboardData(me)
@addResourceToLoad(@simulatorsLeaderboardData, 'top_simulators')
@simulator = new Simulator() @simulator = new Simulator()
@listenTo(@simulator, 'statusUpdate', @updateSimulationStatus) @listenTo(@simulator, 'statusUpdate', @updateSimulationStatus)
@teams = [] @teams = []
@ -62,13 +60,11 @@ module.exports = class LadderView extends RootView
ctx.teams = @teams ctx.teams = @teams
ctx.levelID = @levelID ctx.levelID = @levelID
ctx.levelDescription = marked(@level.get('description')) if @level.get('description') ctx.levelDescription = marked(@level.get('description')) if @level.get('description')
ctx.simulatorsLeaderboardData = @simulatorsLeaderboardData
ctx._ = _
ctx ctx
afterRender: -> afterRender: ->
super() super()
return if @loading() return unless @supermodel.finished()
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions)) @insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions)) @insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
@refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 10 * 1000) @refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 10 * 1000)
@ -77,7 +73,7 @@ module.exports = class LadderView extends RootView
@showPlayModal(hash) if @sessions.loaded @showPlayModal(hash) if @sessions.loaded
fetchSessionsAndRefreshViews: -> fetchSessionsAndRefreshViews: ->
return if @destroyed or application.userIsIdle or @$el.find('#simulate.active').length or (new Date() - 2000 < @lastRefreshTime) or @loading() return if @destroyed or application.userIsIdle or @$el.find('#simulate.active').length or (new Date() - 2000 < @lastRefreshTime) or not @supermodel.finished()
@sessions.fetch({"success": @refreshViews}) @sessions.fetch({"success": @refreshViews})
refreshViews: => refreshViews: =>
@ -127,17 +123,17 @@ module.exports = class LadderView extends RootView
onClickPlayButton: (e) -> onClickPlayButton: (e) ->
@showPlayModal($(e.target).closest('.play-button').data('team')) @showPlayModal($(e.target).closest('.play-button').data('team'))
resimulateAllSessions: -> resimulateAllSessions: ->
postData = postData =
originalLevelID: @level.get('original') originalLevelID: @level.get('original')
levelMajorVersion: @level.get('version').major levelMajorVersion: @level.get('version').major
console.log postData console.log postData
$.ajax $.ajax
url: '/queue/scoring/resimulateAllSessions' url: '/queue/scoring/resimulateAllSessions'
method: 'POST' method: 'POST'
data: postData data: postData
complete: (jqxhr) -> complete: (jqxhr) ->
console.log jqxhr.responseText console.log jqxhr.responseText
@ -162,53 +158,3 @@ module.exports = class LadderView extends RootView
clearInterval @refreshInterval clearInterval @refreshInterval
@simulator.destroy() @simulator.destroy()
super() super()
class SimulatorsLeaderboardData extends CocoClass
###
Consolidates what you need to load for a leaderboard into a single Backbone Model-like object.
###
constructor: (@me) ->
super()
@fetch()
fetch: ->
@topSimulators = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: -1, limit: 20})
promises = []
promises.push @topSimulators.fetch()
unless @me.get('anonymous')
score = @me.get('simulatedBy') or 0
@playersAbove = new SimulatorsLeaderboardCollection({order:1, scoreOffset: score, limit: 4})
promises.push @playersAbove.fetch()
if score
@playersBelow = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: score, limit: 4})
promises.push @playersBelow.fetch()
@promise = $.when(promises...)
@promise.then @onLoad
@promise.fail @onFail
@promise
onLoad: =>
return if @destroyed
@loaded = true
@trigger 'sync', @
onFail: (resource, jqxhr) =>
return if @destroyed
@trigger 'error', @, jqxhr
inTopSimulators: ->
return me.id in (user.id for user in @topSimulators.models)
nearbySimulators: ->
l = []
above = @playersAbove.models
above.reverse()
l = l.concat(above)
l.push @me
l = l.concat(@playersBelow.models) if @playersBelow
l
allResources: ->
resources = [@topSimulators, @playersAbove, @playersBelow]
return (r for r in resources when r)

View file

@ -23,7 +23,7 @@ module.exports = class LevelLoadingView extends View
@updateProgressBar() @updateProgressBar()
updateProgressBar: -> updateProgressBar: ->
@$el.find('.progress-bar').css('width', (100 * @progress) + '%') @$el?.find('.progress-bar').css('width', (100 * @progress) + '%')
showReady: -> showReady: ->
ready = $.i18n.t('play_level.loading_ready', defaultValue: 'Ready!') ready = $.i18n.t('play_level.loading_ready', defaultValue: 'Ready!')