codecombat/app/views/courses/CourseDetailsView.coffee

202 lines
8 KiB
CoffeeScript
Raw Normal View History

2015-09-13 01:01:59 -04:00
Campaign = require 'models/Campaign'
CocoCollection = require 'collections/CocoCollection'
Course = require 'models/Course'
CourseInstance = require 'models/CourseInstance'
2015-09-13 01:01:59 -04:00
LevelSession = require 'models/LevelSession'
RootView = require 'views/core/RootView'
template = require 'templates/courses/course-details'
User = require 'models/User'
utils = require 'core/utils'
# TODO: logged out experience
# TODO: no course instances
# TODO: no course instance selected
module.exports = class CourseDetailsView extends RootView
id: 'course-details-view'
template: template
2015-09-13 01:01:59 -04:00
events:
'change .progress-expand-checkbox': 'onCheckExpandedProgress'
'click .btn-play-level': 'onClickPlayLevel'
'click .btn-save-settings': 'onClickSaveSettings'
'click .progress-member-header': 'onClickMemberHeader'
'click .progress-header': 'onClickProgressHeader'
'mouseenter .progress-level-cell': 'onMouseEnterPoint'
'mouseleave .progress-level-cell': 'onMouseLeavePoint'
constructor: (options, @courseID) ->
super options
2015-09-13 01:01:59 -04:00
@courseInstanceID = utils.getQueryVariable('ciid', false) or options.courseInstanceID
@adminMode = me.isAdmin()
@memberSort = 'nameAsc'
unless me.isAnonymous()
@course = new Course _id: @courseID
@listenTo @course, 'sync', @onCourseSync
@supermodel.loadModel @course, 'course', cache: false
getRenderData: ->
context = super()
context.adminMode = @adminMode ? false
context.campaign = @campaign
context.conceptsCompleted = @conceptsCompleted ? {}
context.course = @course if @course?.loaded
context.courseInstance = @courseInstance if @courseInstance?.loaded
context.levelConceptMap = @levelConceptMap ? {}
context.memberSort = @memberSort
context.memberUserMap = @memberUserMap ? {}
context.showExpandedProgress = @showExpandedProgress
context.sortedMembers = @sortedMembers ? []
context.userConceptStateMap = @userConceptStateMap ? {}
context.userLevelStateMap = @userLevelStateMap ? {}
context
onCourseSync: ->
# console.log 'onCourseSync'
return if @campaign?
@campaign = new Campaign _id: @course.get('campaignID')
@listenTo @campaign, 'sync', @onCampaignSync
@supermodel.loadModel @campaign, 'campaign', cache: false
@render?()
onCampaignSync: ->
# console.log 'onCampaignSync'
if @courseInstanceID
2015-09-13 01:01:59 -04:00
@loadCourseInstance(@courseInstanceID)
else if !me.isAnonymous()
@courseInstances = new CocoCollection([], { url: "/db/user/#{me.id}/course_instances", model: CourseInstance})
2015-09-13 01:01:59 -04:00
@listenToOnce @courseInstances, 'sync', @onCourseInstancesSync
@supermodel.loadCollection(@courseInstances, 'course_instances')
2015-09-13 01:01:59 -04:00
@levelConceptMap = {}
for levelID, level of @campaign.get('levels')
@levelConceptMap[levelID] ?= {}
for concept in level.concepts
@levelConceptMap[levelID][concept] = true
@render?()
2015-09-13 01:01:59 -04:00
loadCourseInstance: (courseInstanceID) ->
# console.log 'loadCourseInstance'
return if @courseInstance?
@courseInstance = new CourseInstance _id: courseInstanceID
@listenTo @courseInstance, 'sync', @onCourseInstanceSync
@supermodel.loadModel @courseInstance, 'course_instance', cache: false
2015-09-13 01:01:59 -04:00
onCourseInstancesSync: ->
# console.log 'onCourseInstancesSync'
if @courseInstances.models.length is 1
2015-09-13 01:01:59 -04:00
@loadCourseInstance(@courseInstances.models[0].id)
else if @courseInstances.models.length > 0
2015-09-13 01:01:59 -04:00
@loadCourseInstance(@courseInstances.models[0].id)
onCourseInstanceSync: ->
console.log 'onCourseInstanceSync', @courseInstance.get('description')
@adminMode = true if @courseInstance.get('ownerID') is me.id
@levelSessions = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/level_sessions", model: LevelSession, comparator:'_id' })
@listenToOnce @levelSessions, 'sync', @onLevelSessionsSync
@supermodel.loadCollection @levelSessions, 'level_sessions', cache: false
@members = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/members", model: User, comparator: 'nameLower' })
@listenToOnce @members, 'sync', @onMembersSync
@supermodel.loadCollection @members, 'members', cache: false
@render?()
onLevelSessionsSync: ->
# console.log 'onLevelSessionsSync'
@userConceptStateMap = {}
@userLevelStateMap = {}
for levelSession in @levelSessions.models
userID = levelSession.get('creator')
levelID = levelSession.get('level').original
@userConceptStateMap[userID] ?= {}
@userLevelStateMap[userID] ?= {}
state = if levelSession.get('state')?.complete then 'complete' else 'started'
@userLevelStateMap[userID][levelID] = state
for concept of @levelConceptMap[levelID]
@userConceptStateMap[userID][concept] = state
@conceptsCompleted = {}
for userID, conceptStateMap of @userConceptStateMap
for concept, state of conceptStateMap
@conceptsCompleted[concept] ?= 0
@conceptsCompleted[concept]++
@render?()
onMembersSync: ->
# console.log 'onMembersSync'
@memberUserMap = {}
for user in @members.models
@memberUserMap[user.id] = user
@sortMembers()
@render?()
onCheckExpandedProgress: (e) ->
@showExpandedProgress = $('.progress-expand-checkbox').prop('checked')
# TODO: why does render reset the checkbox to be unchecked?
@render?()
$('.progress-expand-checkbox').attr('checked', @showExpandedProgress)
onClickMemberHeader: (e) ->
@memberSort = if @memberSort is 'nameAsc' then 'nameDesc' else 'nameAsc'
@sortMembers()
@render?()
onClickProgressHeader: (e) ->
@memberSort = if @memberSort is 'progressAsc' then 'progressDesc' else 'progressAsc'
@sortMembers()
@render?()
onClickPlayLevel: (e) ->
levelSlug = $(e.target).data('level-slug')
Backbone.Mediator.publish 'router:navigate', {
route: "/play/level/#{levelSlug}"
viewClass: 'views/play/level/PlayLevelView'
viewArgs: [{}, levelSlug]
}
onClickSaveSettings: (e) ->
return unless @courseInstance
if name = $('.settings-name-input').val()
@courseInstance.set('name', name)
description = $('.settings-description-input').val()
console.log 'onClickSaveSettings', description
@courseInstance.set('description', description)
@courseInstance.patch()
$('#settingsModal').modal('hide')
onMouseEnterPoint: (e) ->
$('.level-popup-container').hide()
container = $(e.target).find('.level-popup-container').show()
margin = 20
offset = $(e.target).offset()
scrollTop = $('#page-container').scrollTop()
height = container.outerHeight()
container.css('left', offset.left + e.offsetX)
container.css('top', offset.top + scrollTop - height - margin)
onMouseLeavePoint: (e) ->
$(e.target).find('.level-popup-container').hide()
sortMembers: ->
# Progress sort precedence: most completed concepts, most started concepts, most levels, name sort
return unless @campaign and @courseInstance and @memberUserMap
@sortedMembers = @courseInstance.get('members')
switch @memberSort
when "nameDesc"
@sortedMembers.sort (a, b) => @memberUserMap[b]?.get('name').localeCompare(@memberUserMap[a]?.get('name'))
when "progressAsc"
@sortedMembers.sort (a, b) =>
for levelID, level of @campaign.get('levels')
if @userLevelStateMap[a][levelID] isnt 'complete' and @userLevelStateMap[b][levelID] is 'complete'
return -1
else if @userLevelStateMap[a][levelID] is 'complete' and @userLevelStateMap[b][levelID] isnt 'complete'
return 1
0
when "progressDesc"
@sortedMembers.sort (a, b) =>
for levelID, level of @campaign.get('levels')
if @userLevelStateMap[a][levelID] isnt 'complete' and @userLevelStateMap[b][levelID] is 'complete'
return 1
else if @userLevelStateMap[a][levelID] is 'complete' and @userLevelStateMap[b][levelID] isnt 'complete'
return -1
0
else
@sortedMembers.sort (a, b) => @memberUserMap[a]?.get('name').localeCompare(@memberUserMap[b]?.get('name'))