codecombat/app/views/courses/mock1/CourseDetailsView.coffee

210 lines
8 KiB
CoffeeScript
Raw Normal View History

app = require 'core/application'
RootView = require 'views/core/RootView'
template = require 'templates/courses/mock1/course-details'
CocoCollection = require 'collections/CocoCollection'
Campaign = require 'models/Campaign'
module.exports = class CourseDetailsView extends RootView
id: 'course-details-view'
template: template
events:
'change .expand-progress-checkbox': 'onExpandedProgressCheckbox'
'change .select-session': 'onChangeSession'
'change .student-mode-checkbox': 'onChangeStudent'
2015-07-10 20:10:46 -04:00
'click .btn-play-level': 'onClickPlayLevel'
2015-07-29 18:38:57 -04:00
'click .edit-description-save-btn': 'onEditDescriptionSave'
'click .edit-name-save-btn': 'onEditNameSave'
2015-07-10 20:10:46 -04:00
'click .member-header': 'onClickMemberHeader'
'click .progress-header': 'onClickProgressHeader'
'mouseenter .progress-level-cell': 'onMouseEnterPoint'
'mouseleave .progress-level-cell': 'onMouseLeavePoint'
2015-08-04 17:52:23 -04:00
constructor: (options, @courseID=0, @instanceID=0) ->
super options
@initData()
destroy: ->
@stopListening?()
getRenderData: ->
context = super()
context.conceptsProgression = @conceptsProgression ? []
context.course = @course ? {}
context.courseConcepts = @courseConcepts ? []
context.instance = @instances?[@currentInstanceIndex] ? {}
context.instances = @instances ? []
context.levelConceptsMap = @levelConceptsMap ? {}
context.maxLastStartedIndex = @maxLastStartedIndex ? 0
2015-07-10 20:10:46 -04:00
context.memberSort = @memberSort
context.userConceptsMap = @userConceptsMap ? {}
context.userLevelStateMap = @userLevelStateMap ? {}
context.showExpandedProgress = @course.levels.length <= 30 or @showExpandedProgress
context.studentMode = @options.studentMode ? false
conceptsCompleted = {}
for user of context.userConceptsMap
for concept of context.userConceptsMap[user]
conceptsCompleted[concept] ?= 0
conceptsCompleted[concept]++
context.conceptsCompleted = conceptsCompleted
context
initData: ->
2015-07-10 20:10:46 -04:00
@memberSort = 'nameAsc'
mockData = require 'views/courses/mock1/CoursesMockData'
@course = mockData.courses[@courseID]
2015-08-04 17:52:23 -04:00
@currentInstanceIndex = @instanceID
@instances = mockData.instances
@updateLevelMaps()
@campaigns = new CocoCollection([], { url: "/db/campaign", model: Campaign, comparator:'_id' })
@listenTo @campaigns, 'sync', @onCampaignSync
@supermodel.loadModel @campaigns, 'clan', cache: false
updateLevelMaps: ->
@levelMap = {}
@levelMap[level] = true for level in @course.levels
@userLevelStateMap = {}
@maxLastStartedIndex = -1
for student in @instances?[@currentInstanceIndex].students
@userLevelStateMap[student] = {}
lastCompletedIndex = _.random(-1, @course.levels.length)
for i in [0..lastCompletedIndex]
@userLevelStateMap[student][@course.levels[i]] = 'complete'
lastStartedIndex = lastCompletedIndex + 1
@userLevelStateMap[student][@course.levels[lastStartedIndex]] = 'started'
@maxLastStartedIndex = lastStartedIndex if lastStartedIndex > @maxLastStartedIndex
2015-07-10 20:10:46 -04:00
@sortMembers()
sortMembers: ->
# Progress sort precedence: most completed concepts, most started concepts, most levels, name sort
instance = @instances?[@currentInstanceIndex] ? {}
return if _.isEmpty(instance)
switch @memberSort
when "nameDesc"
instance.students.sort (a, b) -> b.localeCompare(a)
when "progressAsc"
instance.students.sort (a, b) =>
for level in @course.levels
if @userLevelStateMap[a][level] isnt 'complete' and @userLevelStateMap[b][level] is 'complete'
return -1
else if @userLevelStateMap[a][level] is 'complete' and @userLevelStateMap[b][level] isnt 'complete'
return 1
0
when "progressDesc"
instance.students.sort (a, b) =>
for level in @course.levels
if @userLevelStateMap[a][level] isnt 'complete' and @userLevelStateMap[b][level] is 'complete'
return 1
else if @userLevelStateMap[a][level] is 'complete' and @userLevelStateMap[b][level] isnt 'complete'
return -1
0
else
instance.students.sort (a, b) -> a.localeCompare(b)
onCampaignSync: ->
return unless @campaigns.loaded
@conceptsProgression = []
@courseConcepts = []
@levelConceptsMap = {}
@levelNameSlugMap = {}
@userConceptsMap = {}
# Update course levels if course has a specific campaign
for campaign in @campaigns.models when campaign.get('slug') is @course.campaign
@course.levels = []
for levelID, level of campaign.get('levels')
if campaign.get('slug') is @course.campaign
@course.levels.push level.name
@updateLevelMaps()
for campaign in @campaigns.models
continue if campaign.get('slug') is 'auditions'
for levelID, level of campaign.get('levels')
@levelNameSlugMap[level.name] = level.slug
if level.concepts?
for concept in level.concepts
@conceptsProgression.push concept unless concept in @conceptsProgression
continue unless @levelMap[level.name]
@courseConcepts.push concept unless concept in @courseConcepts
@levelConceptsMap[level.name] ?= {}
@levelConceptsMap[level.name][concept] = true
for student in @instances?[@currentInstanceIndex].students
@userConceptsMap[student] ?= {}
if @userLevelStateMap[student][level.name] is 'complete'
@userConceptsMap[student][concept] = 'complete'
else if @userLevelStateMap[student][level.name] is 'started'
@userConceptsMap[student][concept] ?= 'started'
@courseConcepts.sort (a, b) => if @conceptsProgression.indexOf(a) < @conceptsProgression.indexOf(b) then -1 else 1
@render?()
onChangeStudent: (e) ->
@options.studentMode = $('.student-mode-checkbox').prop('checked')
@render?()
$('.student-mode-checkbox').attr('checked', @options.studentMode)
onChangeSession: (e) ->
@showExpandedProgress = false
newSessionValue = $(e.target).val()
for val, index in @instances when val.name is newSessionValue
@currentInstanceIndex = index
@updateLevelMaps()
2015-07-10 20:10:46 -04:00
@onCampaignSync()
onExpandedProgressCheckbox: (e) ->
@showExpandedProgress = $('.expand-progress-checkbox').prop('checked')
# TODO: why does render reset the checkbox to be unchecked?
@render?()
$('.expand-progress-checkbox').attr('checked', @showExpandedProgress)
onClickEditClassName: (e) ->
alert 'TODO: Popup for editing name for this course session'
onClickEditClassDescription: (e) ->
alert 'TODO: Popup for editing description for this course session'
2015-07-10 20:10:46 -04:00
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) ->
levelName = $(e.target).data('level')
levelSlug = @levelNameSlugMap[levelName]
Backbone.Mediator.publish 'router:navigate', {
route: "/play/level/#{levelSlug}"
viewClass: 'views/play/level/PlayLevelView'
viewArgs: [{}, levelSlug]
}
2015-07-29 18:38:57 -04:00
onEditDescriptionSave: (e) ->
description = $('.edit-description-input').val()
@instances[@currentInstanceIndex].description = description
$('#editDescriptionModal').modal('hide')
@render?()
onEditNameSave: (e) ->
if name = $('.edit-name-input').val()
@instances[@currentInstanceIndex].name = name
$('#editNameModal').modal('hide')
@render?()
onMouseEnterPoint: (e) ->
$('.level-popup-container').hide()
container = $(e.target).find('.level-popup-container').show()
margin = 20
offset = $(e.target).offset()
scrollTop = $(e.target).offsetParent().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()