mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-05-02 08:53:38 -04:00
Set up a new loading/progress system for views.
This commit is contained in:
parent
c434325ec0
commit
3b3b825be0
8 changed files with 246 additions and 58 deletions
app
locale
styles
templates
views
|
@ -12,6 +12,7 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
|
||||||
manual: "Manual"
|
manual: "Manual"
|
||||||
fork: "Fork"
|
fork: "Fork"
|
||||||
play: "Play"
|
play: "Play"
|
||||||
|
retry: "Retry"
|
||||||
|
|
||||||
units:
|
units:
|
||||||
second: "second"
|
second: "second"
|
||||||
|
@ -602,3 +603,27 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
|
||||||
tutorial: "tutorial"
|
tutorial: "tutorial"
|
||||||
new_to_programming: ". New to programming? Hit our beginner campaign to skill up."
|
new_to_programming: ". New to programming? Hit our beginner campaign to skill up."
|
||||||
so_ready: "I Am So Ready for This"
|
so_ready: "I Am So Ready for This"
|
||||||
|
|
||||||
|
loading_error:
|
||||||
|
could_not_load: "Error loading from server"
|
||||||
|
connection_failure: "Connection failed."
|
||||||
|
unauthorized: "You need to be signed in. Do you have cookies disabled?"
|
||||||
|
forbidden: "You do not have the permissions."
|
||||||
|
not_found: "Not found."
|
||||||
|
not_allowed: "Method not allowed."
|
||||||
|
timeout: "Server timeout."
|
||||||
|
conflict: "Resource conflict."
|
||||||
|
bad_input: "Bad input."
|
||||||
|
server_error: "Server error."
|
||||||
|
unknown: "Unknown error."
|
||||||
|
|
||||||
|
resources:
|
||||||
|
your_sessions: "Your Sessions"
|
||||||
|
level: "Level"
|
||||||
|
social_network_apis: "Social Network APIs"
|
||||||
|
facebook_status: "Facebook Status"
|
||||||
|
facebook_friends: "Facebook Friends"
|
||||||
|
facebook_friend_sessions: "Facebook Friend Sessions"
|
||||||
|
gplus_friends: "G+ Friends"
|
||||||
|
gplus_friend_sessions: "G+ Friend Sessions"
|
||||||
|
leaderboard: 'leaderboard'
|
|
@ -167,7 +167,15 @@ a[data-toggle="modal"]
|
||||||
width: 50%
|
width: 50%
|
||||||
margin: 0 25%
|
margin: 0 25%
|
||||||
.progress-bar
|
.progress-bar
|
||||||
width: 100%
|
width: 0%
|
||||||
|
transition: width 0.1s ease
|
||||||
|
|
||||||
|
.errors .alert
|
||||||
|
padding: 5px
|
||||||
|
display: block
|
||||||
|
margin: 10px auto
|
||||||
|
.btn
|
||||||
|
margin-left: 10px
|
||||||
|
|
||||||
.modal
|
.modal
|
||||||
.wait
|
.wait
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.loading-screen
|
.loading-screen
|
||||||
h1(data-i18n="common.loading") Loading...
|
h1(data-i18n="common.loading") Loading...
|
||||||
.progress.progress-striped.active
|
.progress
|
||||||
.progress-bar
|
.progress-bar
|
||||||
|
|
||||||
|
.errors
|
31
app/templates/loading_error.jade
Normal file
31
app/templates/loading_error.jade
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
.alert.alert-danger.loading-error-alert
|
||||||
|
span(data-i18n="loading_error.could_not_load") Error loading from server
|
||||||
|
span (
|
||||||
|
span(data-i18n="resources.#{name}")
|
||||||
|
span )
|
||||||
|
if !responseText
|
||||||
|
strong(data-i18n="loading_error.connection_failure") Connection failed.
|
||||||
|
else if status === 401
|
||||||
|
strong(data-i18n="loading_error.unauthorized") You need to be signed in. Do you have cookies disabled?
|
||||||
|
else if status === 403
|
||||||
|
strong(data-i18n="loading_error.forbidden") You do not have the permissions.
|
||||||
|
else if status === 404
|
||||||
|
strong(data-i18n="loading_error.not_found") Not found.
|
||||||
|
else if status === 405
|
||||||
|
strong(data-i18n="loading_error.not_allowed") Method not allowed.
|
||||||
|
else if status === 408
|
||||||
|
strong(data-i18n="loading_error.timeout") Server timeout.
|
||||||
|
else if status === 409
|
||||||
|
strong(data-i18n="loading_error.conflict") Resource conflict.
|
||||||
|
else if status === 422
|
||||||
|
strong(data-i18n="loading_error.bad_input") Bad input.
|
||||||
|
else if status >= 500
|
||||||
|
strong(data-i18n="loading_error.server_error") Server error.
|
||||||
|
else
|
||||||
|
strong(data-i18n="loading_error.unknown") Unknown error.
|
||||||
|
|
||||||
|
if resourceIndex !== undefined
|
||||||
|
button.btn.btn-sm.retry-loading-resource(data-i18n="common.retry", data-resource-index=resourceIndex) Retry
|
||||||
|
if requestIndex !== undefined
|
||||||
|
button.btn.btn-sm.retry-loading-request(data-i18n="common.retry", data-request-index=requestIndex) Retry
|
||||||
|
|
|
@ -2,6 +2,7 @@ SuperModel = require 'models/SuperModel'
|
||||||
utils = require 'lib/utils'
|
utils = require 'lib/utils'
|
||||||
CocoClass = require 'lib/CocoClass'
|
CocoClass = require 'lib/CocoClass'
|
||||||
loadingScreenTemplate = require 'templates/loading'
|
loadingScreenTemplate = require 'templates/loading'
|
||||||
|
loadingErrorTemplate = require 'templates/loading_error'
|
||||||
|
|
||||||
visibleModal = null
|
visibleModal = null
|
||||||
waitingModal = null
|
waitingModal = null
|
||||||
|
@ -18,13 +19,26 @@ module.exports = class CocoView extends Backbone.View
|
||||||
'click a': 'toggleModal'
|
'click a': 'toggleModal'
|
||||||
'click button': 'toggleModal'
|
'click button': 'toggleModal'
|
||||||
'click li': 'toggleModal'
|
'click li': 'toggleModal'
|
||||||
|
'click .retry-loading-resource': 'onRetryResource'
|
||||||
|
'click .retry-loading-request': 'onRetryRequest'
|
||||||
|
|
||||||
subscriptions: {}
|
subscriptions: {}
|
||||||
shortcuts: {}
|
shortcuts: {}
|
||||||
|
|
||||||
|
# load progress properties
|
||||||
|
loadProgress:
|
||||||
|
num: 0
|
||||||
|
denom: 0
|
||||||
|
showing: false
|
||||||
|
resources: [] # models and collections
|
||||||
|
requests: [] # jqxhr's
|
||||||
|
somethings: [] # everything else
|
||||||
|
progress: 0
|
||||||
|
|
||||||
# Setup, Teardown
|
# Setup, Teardown
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
|
@loadProgress = _.cloneDeep @loadProgress
|
||||||
@supermodel ?= options?.supermodel or new SuperModel()
|
@supermodel ?= options?.supermodel or new SuperModel()
|
||||||
@options = options
|
@options = options
|
||||||
@subscriptions = utils.combineAncestralObject(@, 'subscriptions')
|
@subscriptions = utils.combineAncestralObject(@, 'subscriptions')
|
||||||
|
@ -33,6 +47,7 @@ module.exports = class CocoView extends Backbone.View
|
||||||
@shortcuts = utils.combineAncestralObject(@, 'shortcuts')
|
@shortcuts = utils.combineAncestralObject(@, 'shortcuts')
|
||||||
@subviews = {}
|
@subviews = {}
|
||||||
@listenToShortcuts()
|
@listenToShortcuts()
|
||||||
|
@updateProgressBar = _.debounce @updateProgressBar, 100
|
||||||
# Backbone.Mediator handles subscription setup/teardown automatically
|
# Backbone.Mediator handles subscription setup/teardown automatically
|
||||||
super options
|
super options
|
||||||
|
|
||||||
|
@ -74,7 +89,7 @@ module.exports = class CocoView extends Backbone.View
|
||||||
return @template if _.isString(@template)
|
return @template if _.isString(@template)
|
||||||
@$el.html @template(@getRenderData())
|
@$el.html @template(@getRenderData())
|
||||||
@afterRender()
|
@afterRender()
|
||||||
@showLoading() if @startsLoading
|
@showLoading() if @startsLoading or @loading() # TODO: Remove startsLoading entirely
|
||||||
@$el.i18n()
|
@$el.i18n()
|
||||||
@
|
@
|
||||||
|
|
||||||
|
@ -89,6 +104,101 @@ module.exports = class CocoView extends Backbone.View
|
||||||
context
|
context
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
|
||||||
|
# Resource and request loading management for any given view
|
||||||
|
|
||||||
|
addResourceToLoad: (modelOrCollection, name, value=1) ->
|
||||||
|
@loadProgress.resources.push {resource:modelOrCollection, value:value, name:name}
|
||||||
|
@listenToOnce modelOrCollection, 'sync', @updateProgress
|
||||||
|
@listenTo modelOrCollection, 'error', @onResourceLoadFailed
|
||||||
|
@updateProgress()
|
||||||
|
|
||||||
|
addRequestToLoad: (jqxhr, name, retryFunc, value=1) ->
|
||||||
|
@loadProgress.requests.push {request:jqxhr, value:value, name: name, retryFunc: retryFunc}
|
||||||
|
jqxhr.done @updateProgress
|
||||||
|
jqxhr.fail @onRequestLoadFailed
|
||||||
|
|
||||||
|
addSomethingToLoad: (name, value=1) ->
|
||||||
|
@loadProgress.somethings.push {loaded: false, name: name, value: value}
|
||||||
|
@updateProgress()
|
||||||
|
|
||||||
|
somethingLoaded: (name) ->
|
||||||
|
r = _.find @loadProgress.somethings, {name: name}
|
||||||
|
return console.error 'Could not find something called', name if not r
|
||||||
|
r.loaded = true
|
||||||
|
@updateProgress(name)
|
||||||
|
|
||||||
|
loading: ->
|
||||||
|
return false if @loaded
|
||||||
|
for r in @loadProgress.resources
|
||||||
|
return true if not r.resource.loaded
|
||||||
|
for r in @loadProgress.requests
|
||||||
|
return true if not r.request.status
|
||||||
|
for r in @loadProgress.somethings
|
||||||
|
return true if not r.loaded
|
||||||
|
return false
|
||||||
|
|
||||||
|
updateProgress: =>
|
||||||
|
console.debug 'Loaded', r.name if arguments[0] and r = _.find @loadProgress.resources, {resource:arguments[0]}
|
||||||
|
console.debug 'Loaded', r.name if arguments[2] and r = _.find @loadProgress.requests, {request:arguments[2]}
|
||||||
|
console.debug 'Loaded', r.name if arguments[0] and r = _.find @loadProgress.somethings, {name:arguments[0]}
|
||||||
|
|
||||||
|
denom = 0
|
||||||
|
denom += r.value for r in @loadProgress.resources
|
||||||
|
denom += r.value for r in @loadProgress.requests
|
||||||
|
denom += r.value for r in @loadProgress.somethings
|
||||||
|
num = @loadProgress.num
|
||||||
|
num += r.value for r in @loadProgress.resources when r.resource.loaded
|
||||||
|
num += r.value for r in @loadProgress.requests when r.request.status
|
||||||
|
num += r.value for r in @loadProgress.somethings when r.loaded
|
||||||
|
#console.log 'update progress', @, num, denom, arguments
|
||||||
|
|
||||||
|
progress = if denom then num / denom else 0
|
||||||
|
# sometimes the denominator isn't known from the outset, so make sure the overall progress only goes up
|
||||||
|
@loadProgress.progress = progress if progress > @loadProgress.progress
|
||||||
|
@updateProgressBar()
|
||||||
|
if num is denom and not @loaded
|
||||||
|
@loaded = true
|
||||||
|
@onLoaded()
|
||||||
|
|
||||||
|
updateProgressBar: =>
|
||||||
|
prog = "#{parseInt(@loadProgress.progress*100)}%"
|
||||||
|
@$el.find('.loading-screen .progress-bar').css('width', prog)
|
||||||
|
|
||||||
|
onLoaded: ->
|
||||||
|
@render()
|
||||||
|
|
||||||
|
# Error handling for loading
|
||||||
|
|
||||||
|
onResourceLoadFailed: (resource, jqxhr) ->
|
||||||
|
for r, index in @loadProgress.resources
|
||||||
|
break if r.resource is resource
|
||||||
|
@$el.find('.loading-screen .errors').append(loadingErrorTemplate({
|
||||||
|
status:jqxhr.status,
|
||||||
|
name: r.name
|
||||||
|
resourceIndex: index,
|
||||||
|
responseText: jqxhr.responseText
|
||||||
|
})).i18n()
|
||||||
|
|
||||||
|
onRetryResource: (e) ->
|
||||||
|
r = @loadProgress.resources[$(e.target).data('resource-index')]
|
||||||
|
r.resource.fetch()
|
||||||
|
$(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()
|
||||||
|
|
||||||
# Modals
|
# Modals
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
CocoView = require 'views/kinds/CocoView'
|
CocoView = require 'views/kinds/CocoView'
|
||||||
|
CocoClass = require 'lib/CocoClass'
|
||||||
Level = require 'models/Level'
|
Level = require 'models/Level'
|
||||||
LevelSession = require 'models/LevelSession'
|
LevelSession = require 'models/LevelSession'
|
||||||
CocoCollection = require 'models/CocoCollection'
|
CocoCollection = require 'models/CocoCollection'
|
||||||
|
@ -18,7 +19,6 @@ class LevelSessionsCollection extends CocoCollection
|
||||||
module.exports = class LadderTabView extends CocoView
|
module.exports = class LadderTabView extends CocoView
|
||||||
id: 'ladder-tab-view'
|
id: 'ladder-tab-view'
|
||||||
template: require 'templates/play/ladder/ladder_tab'
|
template: require 'templates/play/ladder/ladder_tab'
|
||||||
startsLoading: true
|
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click .connect-facebook': 'onConnectFacebook'
|
'click .connect-facebook': 'onConnectFacebook'
|
||||||
|
@ -32,6 +32,7 @@ module.exports = class LadderTabView extends CocoView
|
||||||
|
|
||||||
constructor: (options, @level, @sessions) ->
|
constructor: (options, @level, @sessions) ->
|
||||||
super(options)
|
super(options)
|
||||||
|
@addSomethingToLoad("social_network_apis")
|
||||||
@teams = teamDataFromLevel @level
|
@teams = teamDataFromLevel @level
|
||||||
@leaderboards = {}
|
@leaderboards = {}
|
||||||
@refreshLadder()
|
@refreshLadder()
|
||||||
|
@ -39,15 +40,16 @@ 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)
|
||||||
|
@somethingLoaded("social_network_apis")
|
||||||
@checked = true
|
@checked = true
|
||||||
|
|
||||||
@loadingFacebookFriends = true
|
@addSomethingToLoad("facebook_status")
|
||||||
FB.getLoginStatus (response) =>
|
FB.getLoginStatus (response) =>
|
||||||
@facebookStatus = response.status
|
@facebookStatus = response.status
|
||||||
if @facebookStatus is 'connected' then @loadFacebookFriendSessions() else @loadingFacebookFriends = false
|
@somethingLoaded("facebook_status")
|
||||||
|
@loadFacebookFriends() if @facebookStatus is 'connected'
|
||||||
|
|
||||||
if application.gplusHandler.loggedIn is undefined
|
if application.gplusHandler.loggedIn is undefined
|
||||||
@loadingGPlusFriends = true
|
|
||||||
@listenToOnce(application.gplusHandler, 'checked-state', @gplusSessionStateLoaded)
|
@listenToOnce(application.gplusHandler, 'checked-state', @gplusSessionStateLoaded)
|
||||||
else
|
else
|
||||||
@gplusSessionStateLoaded()
|
@gplusSessionStateLoaded()
|
||||||
|
@ -60,16 +62,24 @@ module.exports = class LadderTabView extends CocoView
|
||||||
|
|
||||||
onConnectedWithFacebook: -> location.reload() if @connecting
|
onConnectedWithFacebook: -> location.reload() if @connecting
|
||||||
|
|
||||||
|
loadFacebookFriends: ->
|
||||||
|
@addSomethingToLoad("facebook_friends")
|
||||||
|
FB.api '/me/friends', @onFacebookFriendsLoaded
|
||||||
|
|
||||||
|
onFacebookFriendsLoaded: (response) =>
|
||||||
|
@somethingLoaded("facebook_friends")
|
||||||
|
@facebookData = response.data
|
||||||
|
@loadFacebookFriendSessions()
|
||||||
|
|
||||||
loadFacebookFriendSessions: ->
|
loadFacebookFriendSessions: ->
|
||||||
FB.api '/me/friends', (response) =>
|
levelFrag = "#{@level.get('original')}.#{@level.get('version').major}"
|
||||||
@facebookData = response.data
|
url = "/db/level/#{levelFrag}/leaderboard_facebook_friends"
|
||||||
levelFrag = "#{@level.get('original')}.#{@level.get('version').major}"
|
jqxhr = $.ajax url, {
|
||||||
url = "/db/level/#{levelFrag}/leaderboard_facebook_friends"
|
data: { friendIDs: (f.id for f in @facebookData) }
|
||||||
$.ajax url, {
|
method: 'POST'
|
||||||
data: { friendIDs: (f.id for f in @facebookData) }
|
success: @onFacebookFriendSessionsLoaded
|
||||||
method: 'POST'
|
}
|
||||||
success: @onFacebookFriendSessionsLoaded
|
@addRequestToLoad(jqxhr, 'facebook_friend_sessions', 'loadFacebookFriendSessions')
|
||||||
}
|
|
||||||
|
|
||||||
onFacebookFriendSessionsLoaded: (result) =>
|
onFacebookFriendSessionsLoaded: (result) =>
|
||||||
friendsMap = {}
|
friendsMap = {}
|
||||||
|
@ -79,9 +89,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
|
||||||
@loadingFacebookFriends = false
|
|
||||||
@renderMaybe()
|
|
||||||
|
|
||||||
# GOOGLE PLUS
|
# GOOGLE PLUS
|
||||||
|
|
||||||
onConnectGPlus: ->
|
onConnectGPlus: ->
|
||||||
|
@ -93,21 +101,23 @@ module.exports = class LadderTabView extends CocoView
|
||||||
|
|
||||||
gplusSessionStateLoaded: ->
|
gplusSessionStateLoaded: ->
|
||||||
if application.gplusHandler.loggedIn
|
if application.gplusHandler.loggedIn
|
||||||
@loadingGPlusFriends = true
|
@addSomethingToLoad("gplus_friends")
|
||||||
application.gplusHandler.loadFriends @gplusFriendsLoaded
|
application.gplusHandler.loadFriends @gplusFriendsLoaded
|
||||||
else
|
|
||||||
@loadingGPlusFriends = false
|
|
||||||
@renderMaybe()
|
|
||||||
|
|
||||||
gplusFriendsLoaded: (friends) =>
|
gplusFriendsLoaded: (friends) =>
|
||||||
|
@somethingLoaded("gplus_friends")
|
||||||
@gplusData = friends.items
|
@gplusData = friends.items
|
||||||
|
@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"
|
||||||
$.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')
|
||||||
|
|
||||||
onGPlusFriendSessionsLoaded: (result) =>
|
onGPlusFriendSessionsLoaded: (result) =>
|
||||||
friendsMap = {}
|
friendsMap = {}
|
||||||
|
@ -117,29 +127,15 @@ 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
|
||||||
@loadingGPlusFriends = false
|
|
||||||
@renderMaybe()
|
|
||||||
|
|
||||||
# LADDER LOADING
|
# LADDER LOADING
|
||||||
|
|
||||||
refreshLadder: ->
|
refreshLadder: ->
|
||||||
promises = []
|
|
||||||
for team in @teams
|
for team in @teams
|
||||||
@leaderboards[team.id]?.off 'sync'
|
@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)
|
||||||
promises.push @leaderboards[team.id].promise
|
@addResourceToLoad @leaderboards[team.id], 'leaderboard', 3
|
||||||
@loadingLeaderboards = true
|
|
||||||
$.when(promises...).then(@leaderboardsLoaded)
|
|
||||||
|
|
||||||
leaderboardsLoaded: =>
|
|
||||||
@loadingLeaderboards = false
|
|
||||||
@renderMaybe()
|
|
||||||
|
|
||||||
renderMaybe: ->
|
|
||||||
return if @loadingFacebookFriends or @loadingLeaderboards or @loadingGPlusFriends
|
|
||||||
@startsLoading = false
|
|
||||||
@render()
|
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
ctx = super()
|
ctx = super()
|
||||||
|
@ -160,9 +156,16 @@ module.exports = class LadderTabView extends CocoView
|
||||||
sessions.reverse()
|
sessions.reverse()
|
||||||
sessions
|
sessions
|
||||||
|
|
||||||
class LeaderboardData
|
class LeaderboardData extends CocoClass
|
||||||
|
###
|
||||||
|
Consolidates what you need to load for a leaderboard into a single Backbone Model-like object.
|
||||||
|
###
|
||||||
|
|
||||||
constructor: (@level, @team, @session) ->
|
constructor: (@level, @team, @session) ->
|
||||||
_.extend @, Backbone.Events
|
super()
|
||||||
|
@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 = []
|
||||||
promises.push @topPlayers.fetch()
|
promises.push @topPlayers.fetch()
|
||||||
|
@ -173,18 +176,24 @@ class LeaderboardData
|
||||||
promises.push @playersAbove.fetch()
|
promises.push @playersAbove.fetch()
|
||||||
@playersBelow = new LeaderboardCollection(@level, {order:-1, scoreOffset: score, limit: 4, team: @team})
|
@playersBelow = new LeaderboardCollection(@level, {order:-1, scoreOffset: score, limit: 4, team: @team})
|
||||||
promises.push @playersBelow.fetch()
|
promises.push @playersBelow.fetch()
|
||||||
level = "#{level.get('original')}.#{level.get('version').major}"
|
level = "#{@level.get('original')}.#{@level.get('version').major}"
|
||||||
success = (@myRank) =>
|
success = (@myRank) =>
|
||||||
promises.push $.ajax "/db/level/#{level}/leaderboard_rank?scoreOffset=#{@session.get('totalScore')}&team=#{@team}", {success}
|
promises.push $.ajax "/db/level/#{level}/leaderboard_rank?scoreOffset=#{@session.get('totalScore')}&team=#{@team}", {success}
|
||||||
@promise = $.when(promises...)
|
@promise = $.when(promises...)
|
||||||
@promise.then @onLoad
|
@promise.then @onLoad
|
||||||
|
@promise.fail @onFail
|
||||||
@promise
|
@promise
|
||||||
|
|
||||||
onLoad: =>
|
onLoad: =>
|
||||||
|
return if @destroyed
|
||||||
@loaded = true
|
@loaded = true
|
||||||
@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) =>
|
||||||
|
return if @destroyed
|
||||||
|
@trigger 'error', @, jqxhr
|
||||||
|
|
||||||
inTopSessions: ->
|
inTopSessions: ->
|
||||||
return me.id in (session.attributes.creator for session in @topPlayers.models)
|
return me.id in (session.attributes.creator for session in @topPlayers.models)
|
||||||
|
@ -201,3 +210,7 @@ class LeaderboardData
|
||||||
startRank = @myRank - 4
|
startRank = @myRank - 4
|
||||||
session.rank = startRank + i for session, i in l
|
session.rank = startRank + i for session, i in l
|
||||||
l
|
l
|
||||||
|
|
||||||
|
allResources: ->
|
||||||
|
resources = [@topPlayers, @playersAbove, @playersBelow]
|
||||||
|
return (r for r in resources when r)
|
|
@ -24,7 +24,6 @@ class LevelSessionsCollection extends CocoCollection
|
||||||
module.exports = class LadderView extends RootView
|
module.exports = class LadderView extends RootView
|
||||||
id: 'ladder-view'
|
id: 'ladder-view'
|
||||||
template: require 'templates/play/ladder'
|
template: require 'templates/play/ladder'
|
||||||
startsLoading: true
|
|
||||||
|
|
||||||
subscriptions:
|
subscriptions:
|
||||||
'application:idle-changed': 'onIdleChanged'
|
'application:idle-changed': 'onIdleChanged'
|
||||||
|
@ -38,18 +37,18 @@ 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)
|
||||||
p1 = @level.fetch()
|
@level.fetch()
|
||||||
@sessions = new LevelSessionsCollection(levelID)
|
@sessions = new LevelSessionsCollection(levelID)
|
||||||
p2 = @sessions.fetch({})
|
@sessions.fetch({})
|
||||||
|
@addResourceToLoad(@sessions, 'your_sessions')
|
||||||
|
@addResourceToLoad(@level, 'level')
|
||||||
@simulator = new Simulator()
|
@simulator = new Simulator()
|
||||||
@listenTo(@simulator, 'statusUpdate', @updateSimulationStatus)
|
@listenTo(@simulator, 'statusUpdate', @updateSimulationStatus)
|
||||||
@teams = []
|
@teams = []
|
||||||
$.when(p1, p2).then @onLoaded
|
|
||||||
|
|
||||||
onLoaded: =>
|
onLoaded: ->
|
||||||
@teams = teamDataFromLevel @level
|
@teams = teamDataFromLevel @level
|
||||||
@startsLoading = false
|
super()
|
||||||
@render()
|
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
ctx = super()
|
ctx = super()
|
||||||
|
@ -63,7 +62,7 @@ module.exports = class LadderView extends RootView
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
return if @startsLoading
|
return if @loading()
|
||||||
@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)
|
||||||
|
@ -72,7 +71,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 @startsLoading
|
return if @destroyed or application.userIsIdle or @$el.find('#simulate.active').length or (new Date() - 2000 < @lastRefreshTime) or @loading()
|
||||||
@sessions.fetch({"success": @refreshViews})
|
@sessions.fetch({"success": @refreshViews})
|
||||||
|
|
||||||
refreshViews: =>
|
refreshViews: =>
|
||||||
|
|
|
@ -63,7 +63,7 @@ module.exports = class SpellView extends View
|
||||||
@createFirepad()
|
@createFirepad()
|
||||||
else
|
else
|
||||||
# needs to happen after the code generating this view is complete
|
# needs to happen after the code generating this view is complete
|
||||||
setTimeout @onLoaded, 1
|
setTimeout @onAllLoaded, 1
|
||||||
|
|
||||||
createACE: ->
|
createACE: ->
|
||||||
# Test themes and settings here: http://ace.ajax.org/build/kitchen-sink.html
|
# Test themes and settings here: http://ace.ajax.org/build/kitchen-sink.html
|
||||||
|
@ -178,9 +178,9 @@ module.exports = class SpellView extends View
|
||||||
else
|
else
|
||||||
@ace.setValue @previousSource
|
@ace.setValue @previousSource
|
||||||
@ace.clearSelection()
|
@ace.clearSelection()
|
||||||
@onLoaded()
|
@onAllLoaded()
|
||||||
|
|
||||||
onLoaded: =>
|
onAllLoaded: =>
|
||||||
@spell.transpile @spell.source
|
@spell.transpile @spell.source
|
||||||
@spell.loaded = true
|
@spell.loaded = true
|
||||||
Backbone.Mediator.publish 'tome:spell-loaded', spell: @spell
|
Backbone.Mediator.publish 'tome:spell-loaded', spell: @spell
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue