Decaffeinate ui/features/grade_summary
Refs FOO-3200 flag=none Remove all CoffeeScript from this feature bundle. Test plan: * all tests pass Change-Id: I2d0e495699931a9963c49816d2adcffec5e92142 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/304696 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Cameron Ray <cameron.ray@instructure.com> QA-Review: Cameron Ray <cameron.ray@instructure.com> Product-Review: Charley Kline <ckline@instructure.com>
This commit is contained in:
parent
03ffd9d120
commit
c08fe4afdc
|
@ -18,7 +18,7 @@
|
|||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection.coffee'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection'
|
||||
import fakeENV from 'helpers/fakeENV'
|
||||
import tz from '@canvas/timezone'
|
||||
|
||||
|
@ -96,6 +96,7 @@ QUnit.module('OutcomeResultCollectionSpec', {
|
|||
})
|
||||
|
||||
test('default params reflect aligned outcome', function () {
|
||||
// eslint-disable-next-line new-cap
|
||||
const collectionModel = new this.outcomeResultCollection.model()
|
||||
deepEqual(collectionModel.get('mastery_points'), 8)
|
||||
deepEqual(collectionModel.get('points_possible'), 10)
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import CollectionView from '@canvas/backbone-collection-view'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection.coffee'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import Group from 'ui/features/grade_summary/backbone/models/Group.coffee'
|
||||
import Group from 'ui/features/grade_summary/backbone/models/Group'
|
||||
import OutcomeDetailView from 'ui/features/grade_summary/backbone/views/OutcomeDetailView'
|
||||
import fakeENV from 'helpers/fakeENV'
|
||||
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import _ from 'underscore'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import OutcomeDialogView from 'ui/features/grade_summary/backbone/views/OutcomeDialogView.coffee'
|
||||
import OutcomeLineGraphView from 'ui/features/grade_summary/backbone/views/OutcomeLineGraphView.coffee'
|
||||
import OutcomeDialogView from 'ui/features/grade_summary/backbone/views/OutcomeDialogView'
|
||||
import OutcomeLineGraphView from 'ui/features/grade_summary/backbone/views/OutcomeLineGraphView'
|
||||
|
||||
QUnit.module('OutcomeDialogViewSpec', {
|
||||
setup() {
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import {isUndefined} from 'lodash'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection.coffee'
|
||||
import OutcomeLineGraphView from 'ui/features/grade_summary/backbone/views/OutcomeLineGraphView.coffee'
|
||||
import OutcomeResultCollection from 'ui/features/grade_summary/backbone/collections/OutcomeResultCollection'
|
||||
import OutcomeLineGraphView from 'ui/features/grade_summary/backbone/views/OutcomeLineGraphView'
|
||||
import tz from '@canvas/timezone'
|
||||
import fakeENV from 'helpers/fakeENV'
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import $ from 'jquery'
|
|||
import {isUndefined} from 'lodash'
|
||||
import Popover from 'jquery-popover'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import OutcomePopoverView from 'ui/features/grade_summary/backbone/views/OutcomePopoverView.coffee'
|
||||
import OutcomePopoverView from 'ui/features/grade_summary/backbone/views/OutcomePopoverView'
|
||||
import template from '@canvas/outcomes/jst/outcomePopover.handlebars'
|
||||
|
||||
QUnit.module('OutcomePopoverViewSpec', {
|
||||
|
@ -42,7 +42,7 @@ QUnit.module('OutcomePopoverViewSpec', {
|
|||
})
|
||||
|
||||
test('closePopover', function () {
|
||||
ok(isUndefined(this.popoverView.popover, 'precondition'))
|
||||
ok(isUndefined(this.popoverView.popover), 'precondition')
|
||||
ok(this.popoverView.closePopover())
|
||||
this.popoverView.popover = new Popover(this.e('mouseleave'), this.popoverView.render(), {
|
||||
verticalSide: 'bottom',
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import {isUndefined} from 'lodash'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import OutcomePopoverView from 'ui/features/grade_summary/backbone/views/OutcomePopoverView.coffee'
|
||||
import OutcomeDialogView from 'ui/features/grade_summary/backbone/views/OutcomeDialogView.coffee'
|
||||
import OutcomeView from 'ui/features/grade_summary/backbone/views/OutcomeView.coffee'
|
||||
import ProgressBarView from 'ui/features/grade_summary/backbone/views/ProgressBarView.coffee'
|
||||
import OutcomePopoverView from 'ui/features/grade_summary/backbone/views/OutcomePopoverView'
|
||||
import OutcomeDialogView from 'ui/features/grade_summary/backbone/views/OutcomeDialogView'
|
||||
import OutcomeView from 'ui/features/grade_summary/backbone/views/OutcomeView'
|
||||
import ProgressBarView from 'ui/features/grade_summary/backbone/views/ProgressBarView'
|
||||
import assertions from 'helpers/assertions'
|
||||
|
||||
QUnit.module('OutcomeViewSpec', {
|
||||
|
@ -36,6 +37,7 @@ QUnit.module('OutcomeViewSpec', {
|
|||
},
|
||||
})
|
||||
|
||||
// eslint-disable-next-line qunit/resolve-async
|
||||
test('should be accessible', function (assert) {
|
||||
const done = assert.async()
|
||||
assertions.isAccessible(this.outcomeView, done, {a11yReport: true})
|
||||
|
@ -46,7 +48,7 @@ test('assign instance of ProgressBarView on init', function () {
|
|||
})
|
||||
|
||||
test('have after render behavior', function () {
|
||||
ok(isUndefined(this.outcomeView.popover, 'precondition'))
|
||||
ok(isUndefined(this.outcomeView.popover), 'precondition')
|
||||
this.outcomeView.render()
|
||||
ok(this.outcomeView.popover instanceof OutcomePopoverView)
|
||||
ok(this.outcomeView.dialog instanceof OutcomeDialogView)
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import WrappedCollection from './WrappedCollection.coffee'
|
||||
|
||||
export default class OutcomeResultCollection extends WrappedCollection
|
||||
key: 'outcome_results'
|
||||
model: Outcome
|
||||
@optionProperty 'outcome'
|
||||
url: -> "/api/v1/courses/#{@course_id}/outcome_results?user_ids[]=#{@user_id}&outcome_ids[]=#{@outcome.id}&include[]=alignments&per_page=100"
|
||||
loadAll: true
|
||||
|
||||
comparator: (model) ->
|
||||
return -1 * model.get('submitted_or_assessed_at').getTime()
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@model = Outcome.extend defaults: {
|
||||
points_possible: @outcome.get('points_possible'),
|
||||
mastery_points: @outcome.get('mastery_points')
|
||||
}
|
||||
@course_id = ENV.context_asset_string?.replace('course_', '')
|
||||
@user_id = ENV.student_id
|
||||
@on('reset', @handleReset)
|
||||
@on('add', @handleAdd)
|
||||
|
||||
handleReset: =>
|
||||
@each @handleAdd
|
||||
|
||||
handleAdd: (model) =>
|
||||
alignment_id = model.get('links').alignment
|
||||
model.set('alignment_name', @alignments.get(alignment_id)?.get('name'))
|
||||
if model.get('points_possible') > 0
|
||||
model.set('score', model.get('points_possible') * model.get('percent'))
|
||||
else
|
||||
model.set('score', model.get('mastery_points') * model.get('percent'))
|
||||
|
||||
parse: (response) ->
|
||||
@alignments ?= new Backbone.Collection([])
|
||||
@alignments.add(response?.linked?.alignments || [])
|
||||
response[@key]
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Copyright (C) 2015 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import WrappedCollection from './WrappedCollection'
|
||||
|
||||
class OutcomeResultCollection extends WrappedCollection {
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.handleReset = this.handleReset.bind(this)
|
||||
this.handleAdd = this.handleAdd.bind(this)
|
||||
}
|
||||
|
||||
url = () =>
|
||||
`/api/v1/courses/${this.course_id}/outcome_results?user_ids[]=${this.user_id}&outcome_ids[]=${this.outcome.id}&include[]=alignments&per_page=100`
|
||||
|
||||
comparator = model => -1 * model.get('submitted_or_assessed_at').getTime()
|
||||
|
||||
initialize() {
|
||||
super.initialize(...arguments)
|
||||
this.model = Outcome.extend({
|
||||
defaults: {
|
||||
points_possible: this.outcome.get('points_possible'),
|
||||
mastery_points: this.outcome.get('mastery_points'),
|
||||
},
|
||||
})
|
||||
this.course_id = ENV.context_asset_string?.replace('course_', '')
|
||||
this.user_id = ENV.student_id
|
||||
this.on('reset', this.handleReset)
|
||||
this.on('add', this.handleAdd)
|
||||
}
|
||||
|
||||
handleReset = () => this.each(this.handleAdd)
|
||||
|
||||
handleAdd(model) {
|
||||
const alignment_id = model.get('links').alignment
|
||||
model.set('alignment_name', this.alignments.get(alignment_id)?.get('name'))
|
||||
if (model.get('points_possible') > 0) {
|
||||
model.set('score', model.get('points_possible') * model.get('percent'))
|
||||
} else {
|
||||
model.set('score', model.get('mastery_points') * model.get('percent'))
|
||||
}
|
||||
}
|
||||
|
||||
parse(response) {
|
||||
if (this.alignments === null || typeof this.alignments === 'undefined') {
|
||||
this.alignments = new Backbone.Collection([])
|
||||
}
|
||||
this.alignments.add(response?.linked?.alignments || [])
|
||||
return response[this.key]
|
||||
}
|
||||
}
|
||||
|
||||
OutcomeResultCollection.prototype.key = 'outcome_results'
|
||||
OutcomeResultCollection.prototype.model = Outcome
|
||||
OutcomeResultCollection.optionProperty('outcome')
|
||||
OutcomeResultCollection.prototype.loadAll = true
|
||||
|
||||
export default OutcomeResultCollection
|
|
@ -17,13 +17,12 @@
|
|||
|
||||
import $ from 'jquery'
|
||||
|
||||
import _ from 'underscore'
|
||||
import {Collection} from '@canvas/backbone'
|
||||
import Section from '../models/Section.coffee'
|
||||
import Group from '../models/Group.coffee'
|
||||
import Section from '../models/Section'
|
||||
import Group from '../models/Group'
|
||||
import Outcome from '@canvas/grade-summary/backbone/models/Outcome.coffee'
|
||||
import PaginatedCollection from '@canvas/pagination/backbone/collections/PaginatedCollection.coffee'
|
||||
import WrappedCollection from './WrappedCollection.coffee'
|
||||
import WrappedCollection from './WrappedCollection'
|
||||
import natcompare from '@canvas/util/natcompare'
|
||||
|
||||
class GroupCollection extends PaginatedCollection {
|
||||
|
@ -63,7 +62,7 @@ export default class OutcomeSummaryCollection extends Collection {
|
|||
|
||||
fetch = () => {
|
||||
const dfd = $.Deferred()
|
||||
const requests = _.values(this.rawCollections).map(collection => {
|
||||
const requests = Object.values(this.rawCollections).map(collection => {
|
||||
collection.loadAll = true
|
||||
return collection.fetch()
|
||||
})
|
||||
|
@ -73,8 +72,7 @@ export default class OutcomeSummaryCollection extends Collection {
|
|||
|
||||
rollups() {
|
||||
const studentRollups = this.rawCollections.rollups.at(0).get('scores')
|
||||
const pairs = studentRollups.map(x => [x.links.outcome, x])
|
||||
return _.object(pairs)
|
||||
return Object.fromEntries(studentRollups.map(x => [x.links.outcome, x]))
|
||||
}
|
||||
|
||||
populateGroupOutcomes() {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import PaginatedCollection from '@canvas/pagination/backbone/collections/PaginatedCollection.coffee'
|
||||
|
||||
export default class WrappedCollection extends PaginatedCollection
|
||||
@optionProperty 'key'
|
||||
|
||||
parse: (response) ->
|
||||
@linked = response.linked
|
||||
response[@key]
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (C) 2015 - present Instructure, Inc.
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
|
@ -15,19 +15,15 @@
|
|||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Adds _.sum method.
|
||||
//
|
||||
// Use like:
|
||||
//
|
||||
// _.sum([2,3,4]) #=> 9
|
||||
//
|
||||
// or with a custom accessor:
|
||||
//
|
||||
// _.sum([[2,3], [3,4]], (a) -> a[0]) #=> 5
|
||||
import _ from 'underscore'
|
||||
import PaginatedCollection from '@canvas/pagination/backbone/collections/PaginatedCollection.coffee'
|
||||
|
||||
export default _.mixin({
|
||||
sum(array, accessor = null, start = 0) {
|
||||
return _.reduce(array, (memo, el) => (accessor != null ? accessor(el) : el) + memo, start)
|
||||
},
|
||||
})
|
||||
class WrappedCollection extends PaginatedCollection {
|
||||
parse(response) {
|
||||
this.linked = response.linked
|
||||
return response[this.key]
|
||||
}
|
||||
}
|
||||
|
||||
WrappedCollection.optionProperty('key')
|
||||
|
||||
export default WrappedCollection
|
|
@ -1,62 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import _ from 'underscore'
|
||||
import {Model, Collection} from '@canvas/backbone'
|
||||
import natcompare from '@canvas/util/natcompare'
|
||||
|
||||
export default class Group extends Model
|
||||
initialize: ->
|
||||
@set('outcomes', new Collection([], comparator: natcompare.byGet('friendly_name')))
|
||||
|
||||
count: -> @get('outcomes').length
|
||||
|
||||
|
||||
statusCount: (status) ->
|
||||
@get('outcomes').filter((x) ->
|
||||
x.status() == status
|
||||
).length
|
||||
|
||||
mastery_count: ->
|
||||
@statusCount('mastery') + @statusCount('exceeds')
|
||||
|
||||
remedialCount: ->
|
||||
@statusCount('remedial')
|
||||
|
||||
undefinedCount: ->
|
||||
@statusCount('undefined')
|
||||
|
||||
status: ->
|
||||
if @remedialCount() > 0
|
||||
"remedial"
|
||||
else
|
||||
if @mastery_count() == @count()
|
||||
"mastery"
|
||||
else if @undefinedCount() == @count()
|
||||
"undefined"
|
||||
else
|
||||
"near"
|
||||
|
||||
started: ->
|
||||
true
|
||||
|
||||
toJSON: ->
|
||||
_.extend super,
|
||||
count: @count()
|
||||
mastery_count: @mastery_count()
|
||||
started: @started()
|
||||
status: @status()
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {Model, Collection} from '@canvas/backbone'
|
||||
import natcompare from '@canvas/util/natcompare'
|
||||
|
||||
export default class Group extends Model {
|
||||
initialize() {
|
||||
return this.set('outcomes', new Collection([], {comparator: natcompare.byGet('friendly_name')}))
|
||||
}
|
||||
|
||||
count() {
|
||||
return this.get('outcomes').length
|
||||
}
|
||||
|
||||
statusCount(status) {
|
||||
return this.get('outcomes').filter(x => x.status() === status).length
|
||||
}
|
||||
|
||||
mastery_count() {
|
||||
return this.statusCount('mastery') + this.statusCount('exceeds')
|
||||
}
|
||||
|
||||
remedialCount() {
|
||||
return this.statusCount('remedial')
|
||||
}
|
||||
|
||||
undefinedCount() {
|
||||
return this.statusCount('undefined')
|
||||
}
|
||||
|
||||
status() {
|
||||
if (this.remedialCount() > 0) {
|
||||
return 'remedial'
|
||||
} else if (this.mastery_count() === this.count()) {
|
||||
return 'mastery'
|
||||
} else if (this.undefinedCount() === this.count()) {
|
||||
return 'undefined'
|
||||
} else {
|
||||
return 'near'
|
||||
}
|
||||
}
|
||||
|
||||
started() {
|
||||
return true
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...super.toJSON(...arguments),
|
||||
count: this.count(),
|
||||
mastery_count: this.mastery_count(),
|
||||
started: this.started(),
|
||||
status: this.status(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {Model, Collection} from '@canvas/backbone'
|
||||
import natcompare from '@canvas/util/natcompare'
|
||||
|
||||
export default class Section extends Model
|
||||
initialize: ->
|
||||
@set('groups', new Collection([], comparator: natcompare.byGet('title')))
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {Model, Collection} from '@canvas/backbone'
|
||||
import natcompare from '@canvas/util/natcompare'
|
||||
|
||||
export default class Section extends Model {
|
||||
initialize() {
|
||||
return this.set('groups', new Collection([], {comparator: natcompare.byGet('title')}))
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import ProgressBarView from './ProgressBarView.coffee'
|
||||
import ProgressBarView from './ProgressBarView'
|
||||
import template from '../../jst/alignment.handlebars'
|
||||
|
||||
export default class AlignmentView extends Backbone.View {
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import {View, Collection} from '@canvas/backbone'
|
||||
import _ from 'underscore'
|
||||
import CollectionView from '@canvas/backbone-collection-view'
|
||||
import OutcomeView from './OutcomeView.coffee'
|
||||
import template from '../../jst/group.handlebars'
|
||||
|
||||
I18n = useI18nScope('grade_summaryGroupView')
|
||||
|
||||
export default class GroupView extends View
|
||||
tagName: 'li'
|
||||
className: 'group'
|
||||
|
||||
els:
|
||||
'.outcomes': '$outcomes'
|
||||
|
||||
events:
|
||||
'click .group-description': 'expand'
|
||||
'keyclick .group-description': 'expand'
|
||||
|
||||
template: template
|
||||
|
||||
render: ->
|
||||
super
|
||||
outcomesView = new CollectionView
|
||||
el: @$outcomes
|
||||
collection: @model.get('outcomes')
|
||||
itemView: OutcomeView
|
||||
outcomesView.render()
|
||||
|
||||
expand: ->
|
||||
@$el.toggleClass('expanded')
|
||||
if @$el.hasClass("expanded")
|
||||
@$el.children("div.group-description").attr("aria-expanded", "true")
|
||||
else
|
||||
@$el.children("div.group-description").attr("aria-expanded", "false")
|
||||
|
||||
$collapseToggle = $('div.outcome-toggles a.icon-collapse')
|
||||
if $('li.group.expanded').length == 0
|
||||
$collapseToggle.attr('disabled', 'disabled')
|
||||
$collapseToggle.attr('aria-disabled', 'true')
|
||||
else
|
||||
$collapseToggle.removeAttr('disabled')
|
||||
$collapseToggle.attr('aria-disabled', 'false')
|
||||
|
||||
$expandToggle = $('div.outcome-toggles a.icon-expand')
|
||||
if $('li.group:not(.expanded)').length == 0
|
||||
$expandToggle.attr('disabled', 'disabled')
|
||||
$expandToggle.attr('aria-disabled', 'true')
|
||||
else
|
||||
$expandToggle.removeAttr('disabled')
|
||||
$expandToggle.attr('aria-disabled', 'false')
|
||||
|
||||
statusTooltip: ->
|
||||
switch @model.status()
|
||||
when 'undefined' then I18n.t('Unstarted')
|
||||
when 'remedial' then I18n.t('Well Below Mastery')
|
||||
when 'near' then I18n.t('Near Mastery')
|
||||
when 'mastery' then I18n.t('Meets Mastery')
|
||||
when 'exceeds' then I18n.t('Exceeds Mastery')
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
_.extend json,
|
||||
statusTooltip: @statusTooltip()
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import $ from 'jquery'
|
||||
import {View} from '@canvas/backbone'
|
||||
import CollectionView from '@canvas/backbone-collection-view'
|
||||
import OutcomeView from './OutcomeView'
|
||||
import template from '../../jst/group.handlebars'
|
||||
|
||||
const I18n = useI18nScope('grade_summaryGroupView')
|
||||
|
||||
class GroupView extends View {
|
||||
render() {
|
||||
super.render(...arguments)
|
||||
const outcomesView = new CollectionView({
|
||||
el: this.$outcomes,
|
||||
collection: this.model.get('outcomes'),
|
||||
itemView: OutcomeView,
|
||||
})
|
||||
return outcomesView.render()
|
||||
}
|
||||
|
||||
expand() {
|
||||
this.$el.toggleClass('expanded')
|
||||
if (this.$el.hasClass('expanded')) {
|
||||
this.$el.children('div.group-description').attr('aria-expanded', 'true')
|
||||
} else {
|
||||
this.$el.children('div.group-description').attr('aria-expanded', 'false')
|
||||
}
|
||||
|
||||
const $collapseToggle = $('div.outcome-toggles a.icon-collapse')
|
||||
if ($('li.group.expanded').length === 0) {
|
||||
$collapseToggle.attr('disabled', 'disabled')
|
||||
$collapseToggle.attr('aria-disabled', 'true')
|
||||
} else {
|
||||
$collapseToggle.removeAttr('disabled')
|
||||
$collapseToggle.attr('aria-disabled', 'false')
|
||||
}
|
||||
|
||||
const $expandToggle = $('div.outcome-toggles a.icon-expand')
|
||||
if ($('li.group:not(.expanded)').length === 0) {
|
||||
$expandToggle.attr('disabled', 'disabled')
|
||||
return $expandToggle.attr('aria-disabled', 'true')
|
||||
} else {
|
||||
$expandToggle.removeAttr('disabled')
|
||||
return $expandToggle.attr('aria-disabled', 'false')
|
||||
}
|
||||
}
|
||||
|
||||
statusTooltip() {
|
||||
switch (this.model.status()) {
|
||||
case 'undefined':
|
||||
return I18n.t('Unstarted')
|
||||
case 'remedial':
|
||||
return I18n.t('Well Below Mastery')
|
||||
case 'near':
|
||||
return I18n.t('Near Mastery')
|
||||
case 'mastery':
|
||||
return I18n.t('Meets Mastery')
|
||||
case 'exceeds':
|
||||
return I18n.t('Exceeds Mastery')
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...super.toJSON(...arguments),
|
||||
statusTooltip: this.statusTooltip(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupView.prototype.template = template
|
||||
GroupView.prototype.tagName = 'li'
|
||||
GroupView.prototype.className = 'group'
|
||||
GroupView.prototype.els = {'.outcomes': '$outcomes'}
|
||||
GroupView.prototype.events = {
|
||||
'click .group-description': 'expand',
|
||||
'keyclick .group-description': 'expand',
|
||||
}
|
||||
|
||||
export default GroupView
|
|
@ -16,18 +16,14 @@
|
|||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import OutcomeResultCollection from '../collections/OutcomeResultCollection.coffee'
|
||||
import OutcomeResultCollection from '../collections/OutcomeResultCollection'
|
||||
import DialogBaseView from '@canvas/dialog-base-view'
|
||||
import CollectionView from '@canvas/backbone-collection-view'
|
||||
import AlignmentView from './AlignmentView'
|
||||
import ProgressBarView from './ProgressBarView.coffee'
|
||||
import ProgressBarView from './ProgressBarView'
|
||||
import template from '../../jst/outcome_detail.handlebars'
|
||||
|
||||
export default class OutcomeDetailView extends DialogBaseView {
|
||||
static initClass() {
|
||||
this.prototype.template = template
|
||||
}
|
||||
|
||||
class OutcomeDetailView extends DialogBaseView {
|
||||
dialogOptions() {
|
||||
return {
|
||||
containerId: 'outcome_detail',
|
||||
|
@ -77,4 +73,7 @@ export default class OutcomeDetailView extends DialogBaseView {
|
|||
return {...json, progress: this.progress}
|
||||
}
|
||||
}
|
||||
OutcomeDetailView.initClass()
|
||||
|
||||
OutcomeDetailView.prototype.template = template
|
||||
|
||||
export default OutcomeDetailView
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import $ from 'jquery'
|
||||
import _ from 'underscore'
|
||||
import DialogBaseView from '@canvas/dialog-base-view'
|
||||
import OutcomeLineGraphView from './OutcomeLineGraphView.coffee'
|
||||
import template from '@canvas/outcomes/jst/outcomePopover.handlebars'
|
||||
|
||||
export default class OutcomeResultsDialogView extends DialogBaseView
|
||||
@optionProperty 'model'
|
||||
$target: null
|
||||
template: template
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@outcomeLineGraphView = new OutcomeLineGraphView({
|
||||
model: @model
|
||||
})
|
||||
|
||||
afterRender: ->
|
||||
@outcomeLineGraphView.setElement(@$("div.line-graph"))
|
||||
@outcomeLineGraphView.render()
|
||||
|
||||
dialogOptions: ->
|
||||
containerId: "outcome_results_dialog"
|
||||
close: @onClose
|
||||
buttons: []
|
||||
width: 460
|
||||
|
||||
show: (e) ->
|
||||
return unless (e.type == "click" || @_getKey(e.keyCode))
|
||||
@$target = $(e.target)
|
||||
e.preventDefault()
|
||||
@$el.dialog('option', 'title', @model.get('title'))
|
||||
super
|
||||
@render()
|
||||
|
||||
onClose: =>
|
||||
@$target.focus()
|
||||
delete @$target
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
_.extend json,
|
||||
dialog: true
|
||||
|
||||
# Private
|
||||
_getKey: (keycode) =>
|
||||
keys = {
|
||||
13 : "enter"
|
||||
32 : "spacebar"
|
||||
}
|
||||
keys[keycode]
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Copyright (C) 2015 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import $ from 'jquery'
|
||||
import DialogBaseView from '@canvas/dialog-base-view'
|
||||
import OutcomeLineGraphView from './OutcomeLineGraphView'
|
||||
import template from '@canvas/outcomes/jst/outcomePopover.handlebars'
|
||||
|
||||
class OutcomeResultsDialogView extends DialogBaseView {
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.onClose = this.onClose.bind(this)
|
||||
this._getKey = this._getKey.bind(this)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
super.initialize(...arguments)
|
||||
return (this.outcomeLineGraphView = new OutcomeLineGraphView({
|
||||
model: this.model,
|
||||
}))
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
this.outcomeLineGraphView.setElement(this.$('div.line-graph'))
|
||||
return this.outcomeLineGraphView.render()
|
||||
}
|
||||
|
||||
dialogOptions() {
|
||||
return {
|
||||
containerId: 'outcome_results_dialog',
|
||||
close: this.onClose,
|
||||
buttons: [],
|
||||
width: 460,
|
||||
}
|
||||
}
|
||||
|
||||
show(e) {
|
||||
if (e.type !== 'click' && !this._getKey(e.keyCode)) return
|
||||
this.$target = $(e.target)
|
||||
e.preventDefault()
|
||||
this.$el.dialog('option', 'title', this.model.get('title'))
|
||||
super.show(...arguments)
|
||||
return this.render()
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.$target.focus()
|
||||
delete this.$target
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...super.toJSON(...arguments),
|
||||
dialog: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Private
|
||||
_getKey(keycode) {
|
||||
const keys = {
|
||||
13: 'enter',
|
||||
32: 'spacebar',
|
||||
}
|
||||
return keys[keycode]
|
||||
}
|
||||
}
|
||||
|
||||
OutcomeResultsDialogView.optionProperty('model')
|
||||
OutcomeResultsDialogView.prototype.$target = null
|
||||
OutcomeResultsDialogView.prototype.template = template
|
||||
|
||||
export default OutcomeResultsDialogView
|
|
@ -1,285 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import _ from 'underscore'
|
||||
import Backbone from '@canvas/backbone'
|
||||
import I18n from '@canvas/i18n'
|
||||
import OutcomeResultCollection from '../collections/OutcomeResultCollection.coffee'
|
||||
import d3 from 'd3/d3'
|
||||
import accessibleTemplate from '../../jst/accessibleLineGraph.handlebars'
|
||||
import '../../sum'
|
||||
|
||||
# Trend class based on formulae found here:
|
||||
# http://classroom.synonym.com/calculate-trendline-2709.html
|
||||
class Trend
|
||||
constructor: (@rawData) ->
|
||||
|
||||
# Returns: [[x1, y1], [x2, y2]]
|
||||
data: ->
|
||||
[[
|
||||
@xValue(@rawData[0])
|
||||
@yIntercept()
|
||||
@xValue(_.last(@rawData))
|
||||
(@slope() * @xValue(_.last(@rawData))) + @yIntercept()
|
||||
]]
|
||||
|
||||
slope: ->
|
||||
(@a() - @b()) / (@c() - @d())
|
||||
|
||||
yIntercept: ->
|
||||
(@e() - @f()) / @n()
|
||||
|
||||
# The number of points of data.
|
||||
n: ->
|
||||
@rawData.length
|
||||
|
||||
# `n` times the sum of the products of each x & y pair.
|
||||
a: ->
|
||||
@n() * _.sum(@rawData, (point) => (@xValue(point) * @yValue(point)))
|
||||
|
||||
# The product of the sum of all x values and all y values.
|
||||
b: ->
|
||||
_.sum(@rawData, @xValue) * _.sum(@rawData, @yValue)
|
||||
|
||||
# `n` times the sum of all x values individually squared.
|
||||
c: ->
|
||||
@n() * _.sum(@rawData, (point) => Math.pow(@xValue(point), 2))
|
||||
|
||||
# The sum of all x values squared.
|
||||
d: ->
|
||||
Math.pow(_.sum(@rawData, @xValue), 2)
|
||||
|
||||
# The sum of all y values.
|
||||
e: ->
|
||||
_.sum(@rawData, @yValue)
|
||||
|
||||
# The slope times the sum of all x values.
|
||||
f: ->
|
||||
@slope() * _.sum(@rawData, @xValue)
|
||||
|
||||
xValue: (point) ->
|
||||
point.x
|
||||
|
||||
yValue: (point) ->
|
||||
point.y
|
||||
|
||||
export default class OutcomeLineGraphView extends Backbone.View
|
||||
@optionProperty 'el'
|
||||
@optionProperty 'height'
|
||||
@optionProperty 'limit'
|
||||
@optionProperty 'margin'
|
||||
@optionProperty 'model'
|
||||
@optionProperty 'timeFormat'
|
||||
defaults:
|
||||
height: 200
|
||||
limit: 8
|
||||
margin: {top: 20, right: 20, bottom: 30, left: 40}
|
||||
# 2015-02-06T17:49:08Z
|
||||
timeFormat: "%Y-%m-%dT%XZ"
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@deferred = $.Deferred()
|
||||
@collection = new OutcomeResultCollection([], {
|
||||
outcome: @model
|
||||
})
|
||||
@collection.on 'fetched:last', =>
|
||||
@deferred.resolve()
|
||||
@collection.fetch()
|
||||
|
||||
render: ->
|
||||
if @deferred.isResolved()
|
||||
return @ if @collection.isEmpty()
|
||||
|
||||
@_prepareScales()
|
||||
@_prepareAxes()
|
||||
@_prepareLines()
|
||||
|
||||
@svg = d3.select(@el)
|
||||
.append("svg")
|
||||
.attr("width", @width() + @margin.left + @margin.right)
|
||||
.attr("height", @height + @margin.top + @margin.bottom)
|
||||
.attr("aria-hidden", true)
|
||||
.append("g")
|
||||
.attr("transform", "translate(#{@margin.left}, #{@margin.top})")
|
||||
|
||||
@_appendAxes()
|
||||
@_appendLines()
|
||||
|
||||
@$('.screenreader-only').append(accessibleTemplate(@toJSON()))
|
||||
else
|
||||
@deferred.done(@render)
|
||||
|
||||
|
||||
@
|
||||
|
||||
toJSON: ->
|
||||
current_user_name: ENV.current_user.display_name
|
||||
data: @data()
|
||||
outcome_name: @model.get('friendly_name')
|
||||
|
||||
# Data helpers
|
||||
data: ->
|
||||
@_data ?= @collection.chain()
|
||||
.last(@limit)
|
||||
.map((outcomeResult, i) =>
|
||||
x: i
|
||||
y: @percentageFor(outcomeResult.get('score'))
|
||||
date: outcomeResult.get('submitted_or_assessed_at')
|
||||
).value()
|
||||
|
||||
masteryPercentage: ->
|
||||
if @model.get('points_possible') > 0
|
||||
(@model.get('mastery_points') / @model.get('points_possible')) * 100
|
||||
else
|
||||
100
|
||||
|
||||
percentageFor: (score) ->
|
||||
if @model.get('points_possible') > 0
|
||||
((score / @model.get('points_possible')) * 100)
|
||||
else
|
||||
((score / @model.get('mastery_points')) * 100)
|
||||
|
||||
xValue: (point) =>
|
||||
@x(point.x)
|
||||
|
||||
yValue: (point) =>
|
||||
@y(point.y)
|
||||
|
||||
# View helpers
|
||||
_appendAxes: ->
|
||||
@svg.append("g")
|
||||
.attr("class", "x axis")
|
||||
.attr("transform", "translate(0,#{@height})")
|
||||
.call(@xAxis)
|
||||
|
||||
@svg.append("g")
|
||||
.attr("class", "date-guides")
|
||||
.attr("transform", "translate(0,#{@height})")
|
||||
.call(@dateGuides)
|
||||
|
||||
@svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.call(@yAxis)
|
||||
|
||||
@svg.append("g")
|
||||
.attr("class", "guides")
|
||||
.call(@yGuides)
|
||||
|
||||
@svg.append("g")
|
||||
.attr("class", "mastery-percentage-guide")
|
||||
.style("stroke-dasharray", ("3, 3"))
|
||||
.call(@masteryPercentageGuide)
|
||||
|
||||
_appendLines: ->
|
||||
@svg.selectAll("circle")
|
||||
.data(@data())
|
||||
.enter().append("circle")
|
||||
.attr("fill", "black")
|
||||
.attr("r", 3)
|
||||
.attr("cx", @xValue)
|
||||
.attr("cy", @yValue)
|
||||
|
||||
@svg.append("path")
|
||||
.datum(@data())
|
||||
.attr("d", @line)
|
||||
.attr("class", "line")
|
||||
.attr("stroke", "black")
|
||||
.attr("stroke-width", 1)
|
||||
.attr("fill", "none")
|
||||
|
||||
if @trend?
|
||||
@svg.selectAll(".trendline")
|
||||
.data(@trend.data())
|
||||
.enter()
|
||||
.append("line")
|
||||
.attr("class", "trendline")
|
||||
.attr("x1", (d) => @x(d[0]))
|
||||
.attr("y1", (d) => @y(d[1]))
|
||||
.attr("x2", (d) => @x(d[2]))
|
||||
.attr("y2", (d) => @y(d[3]))
|
||||
.attr("stroke-width", 1)
|
||||
|
||||
@svg
|
||||
|
||||
|
||||
_prepareAxes: ->
|
||||
@xAxis = d3.svg.axis()
|
||||
.scale(@x)
|
||||
.tickFormat('')
|
||||
@dateGuides = d3.svg.axis()
|
||||
.scale(@xTimeScale)
|
||||
.tickValues([
|
||||
_.first(@data()).date
|
||||
_.last(@data()).date
|
||||
])
|
||||
.tickFormat((d) -> Intl.DateTimeFormat(I18n.currentLocale(), { day: 'numeric', month: 'numeric'}).format(d))
|
||||
@yAxis = d3.svg.axis()
|
||||
.scale(@y)
|
||||
.orient("left")
|
||||
.tickFormat((d) -> I18n.n(d, { percentage: true }))
|
||||
.tickValues([0, 50, 100])
|
||||
@yGuides = d3.svg.axis()
|
||||
.scale(@y)
|
||||
.orient("left")
|
||||
.tickValues([50, 100])
|
||||
.tickSize(-@width(), 0, 0)
|
||||
.tickFormat("")
|
||||
@masteryPercentageGuide = d3.svg.axis()
|
||||
.scale(@y)
|
||||
.orient("left")
|
||||
.tickValues([@masteryPercentage()])
|
||||
.tickSize(-@width(), 0, 0)
|
||||
.tickFormat("")
|
||||
|
||||
_prepareLines: ->
|
||||
if @data().length >=3
|
||||
@trend = new Trend(@data())
|
||||
|
||||
@line = d3.svg.line()
|
||||
.x(@xValue)
|
||||
.y(@yValue)
|
||||
.interpolate('linear')
|
||||
|
||||
_prepareScales: ->
|
||||
@x = d3.scale.linear()
|
||||
.range([0, @width()])
|
||||
.domain([0, @limit - 1])
|
||||
@xTimeScale = d3.time.scale()
|
||||
.range([0, @xTimeScaleWidth()])
|
||||
.domain([
|
||||
_.first(@data()).date
|
||||
_.last(@data()).date
|
||||
])
|
||||
@y = d3.scale.linear()
|
||||
.range([@height, @margin.bottom])
|
||||
.domain([0, 100])
|
||||
|
||||
width: ->
|
||||
@$el.width() - @margin.left - @margin.right - 10
|
||||
|
||||
# The width of the axis used to display the first and last date of scores
|
||||
# displayed has to be different than the full width, in case the number
|
||||
# of points is fewer than the limit (8). What we want is the width of the
|
||||
# element reduced by the difference between the limit and the number of
|
||||
# points we actually have, multiplied by the width each point represents,
|
||||
# based on the element's width and the limit.
|
||||
xTimeScaleWidth: ->
|
||||
(@width() - (
|
||||
(@width() / (@limit - 1)) *
|
||||
(@limit - @data().length)
|
||||
))
|
|
@ -0,0 +1,340 @@
|
|||
//
|
||||
// Copyright (C) 2015 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import {sumBy} from 'lodash'
|
||||
import Backbone from '@canvas/backbone'
|
||||
import I18n from '@canvas/i18n'
|
||||
import OutcomeResultCollection from '../collections/OutcomeResultCollection'
|
||||
import d3 from 'd3/d3'
|
||||
import accessibleTemplate from '../../jst/accessibleLineGraph.handlebars'
|
||||
|
||||
const first = array => array.at(0)
|
||||
const last = array => array.at(-1)
|
||||
|
||||
// Trend class based on formulae found here:
|
||||
// http://classroom.synonym.com/calculate-trendline-2709.html
|
||||
class Trend {
|
||||
constructor(rawData) {
|
||||
this.rawData = rawData
|
||||
}
|
||||
|
||||
// Returns: [[x1, y1], [x2, y2]]
|
||||
data() {
|
||||
return [
|
||||
[
|
||||
this.rawData[0].x,
|
||||
this.yIntercept(),
|
||||
last(this.rawData).x,
|
||||
this.slope() * last(this.rawData).x + this.yIntercept(),
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
slope() {
|
||||
return (this.a() - this.b()) / (this.c() - this.d())
|
||||
}
|
||||
|
||||
yIntercept() {
|
||||
return (this.e() - this.f()) / this.n()
|
||||
}
|
||||
|
||||
// The number of points of data.
|
||||
n() {
|
||||
return this.rawData.length
|
||||
}
|
||||
|
||||
// `n` times the sum of the products of each x & y pair.
|
||||
a() {
|
||||
return this.n() * sumBy(this.rawData, p => p.x * p.y)
|
||||
}
|
||||
|
||||
// The product of the sum of all x values and all y values.
|
||||
b() {
|
||||
return sumBy(this.rawData, p => p.x) * sumBy(this.rawData, p => p.y)
|
||||
}
|
||||
|
||||
// `n` times the sum of all x values individually squared.
|
||||
c() {
|
||||
return this.n() * sumBy(this.rawData, p => p.x * p.x)
|
||||
}
|
||||
|
||||
// The sum of all x values squared.
|
||||
d() {
|
||||
return Math.pow(
|
||||
sumBy(this.rawData, p => p.x),
|
||||
2
|
||||
)
|
||||
}
|
||||
|
||||
// The sum of all y values.
|
||||
e() {
|
||||
return sumBy(this.rawData, p => p.y)
|
||||
}
|
||||
|
||||
// The slope times the sum of all x values.
|
||||
f() {
|
||||
return this.slope() * sumBy(this.rawData, p => p.x)
|
||||
}
|
||||
}
|
||||
|
||||
class OutcomeLineGraphView extends Backbone.View {
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.xValue = this.xValue.bind(this)
|
||||
this.yValue = this.yValue.bind(this)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
super.initialize(...arguments)
|
||||
this.deferred = $.Deferred()
|
||||
this.collection = new OutcomeResultCollection([], {
|
||||
outcome: this.model,
|
||||
})
|
||||
this.collection.on('fetched:last', () => {
|
||||
return this.deferred.resolve()
|
||||
})
|
||||
return this.collection.fetch()
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.deferred.isResolved()) {
|
||||
if (this.collection.isEmpty()) {
|
||||
return this
|
||||
}
|
||||
|
||||
this._prepareScales()
|
||||
this._prepareAxes()
|
||||
this._prepareLines()
|
||||
|
||||
this.svg = d3
|
||||
.select(this.el)
|
||||
.append('svg')
|
||||
.attr('width', this.width() + this.margin.left + this.margin.right)
|
||||
.attr('height', this.height + this.margin.top + this.margin.bottom)
|
||||
.attr('aria-hidden', true)
|
||||
.append('g')
|
||||
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`)
|
||||
|
||||
this._appendAxes()
|
||||
this._appendLines()
|
||||
|
||||
this.$('.screenreader-only').append(accessibleTemplate(this.toJSON()))
|
||||
} else {
|
||||
this.deferred.done(this.render)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
current_user_name: ENV.current_user.display_name,
|
||||
data: this.data(),
|
||||
outcome_name: this.model.get('friendly_name'),
|
||||
}
|
||||
}
|
||||
|
||||
// Data helpers
|
||||
data() {
|
||||
if (this._data === null || typeof this._data === 'undefined') {
|
||||
this._data = this.collection
|
||||
.chain()
|
||||
.last(this.limit)
|
||||
.map((outcomeResult, i) => ({
|
||||
x: i,
|
||||
y: this.percentageFor(outcomeResult.get('score')),
|
||||
date: outcomeResult.get('submitted_or_assessed_at'),
|
||||
}))
|
||||
.value()
|
||||
}
|
||||
return this._data
|
||||
}
|
||||
|
||||
masteryPercentage() {
|
||||
if (this.model.get('points_possible') > 0) {
|
||||
return (this.model.get('mastery_points') / this.model.get('points_possible')) * 100
|
||||
} else {
|
||||
return 100
|
||||
}
|
||||
}
|
||||
|
||||
percentageFor(score) {
|
||||
if (this.model.get('points_possible') > 0) {
|
||||
return (score / this.model.get('points_possible')) * 100
|
||||
} else {
|
||||
return (score / this.model.get('mastery_points')) * 100
|
||||
}
|
||||
}
|
||||
|
||||
xValue(point) {
|
||||
return this.x(point.x)
|
||||
}
|
||||
|
||||
yValue(point) {
|
||||
return this.y(point.y)
|
||||
}
|
||||
|
||||
// View helpers
|
||||
_appendAxes() {
|
||||
this.svg
|
||||
.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0,${this.height})`)
|
||||
.call(this.xAxis)
|
||||
|
||||
this.svg
|
||||
.append('g')
|
||||
.attr('class', 'date-guides')
|
||||
.attr('transform', `translate(0,${this.height})`)
|
||||
.call(this.dateGuides)
|
||||
|
||||
this.svg.append('g').attr('class', 'y axis').call(this.yAxis)
|
||||
|
||||
this.svg.append('g').attr('class', 'guides').call(this.yGuides)
|
||||
|
||||
return this.svg
|
||||
.append('g')
|
||||
.attr('class', 'mastery-percentage-guide')
|
||||
.style('stroke-dasharray', '3, 3')
|
||||
.call(this.masteryPercentageGuide)
|
||||
}
|
||||
|
||||
_appendLines() {
|
||||
this.svg
|
||||
.selectAll('circle')
|
||||
.data(this.data())
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('fill', 'black')
|
||||
.attr('r', 3)
|
||||
.attr('cx', this.xValue)
|
||||
.attr('cy', this.yValue)
|
||||
|
||||
this.svg
|
||||
.append('path')
|
||||
.datum(this.data())
|
||||
.attr('d', this.line)
|
||||
.attr('class', 'line')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 1)
|
||||
.attr('fill', 'none')
|
||||
|
||||
if (this.trend != null) {
|
||||
this.svg
|
||||
.selectAll('.trendline')
|
||||
.data(this.trend.data())
|
||||
.enter()
|
||||
.append('line')
|
||||
.attr('class', 'trendline')
|
||||
.attr('x1', d => this.x(d[0]))
|
||||
.attr('y1', d => this.y(d[1]))
|
||||
.attr('x2', d => this.x(d[2]))
|
||||
.attr('y2', d => this.y(d[3]))
|
||||
.attr('stroke-width', 1)
|
||||
}
|
||||
|
||||
return this.svg
|
||||
}
|
||||
|
||||
_prepareAxes() {
|
||||
this.xAxis = d3.svg.axis().scale(this.x).tickFormat('')
|
||||
this.dateGuides = d3.svg
|
||||
.axis()
|
||||
.scale(this.xTimeScale)
|
||||
.tickValues([first(this.data()).date, last(this.data()).date])
|
||||
.tickFormat(d =>
|
||||
Intl.DateTimeFormat(I18n.currentLocale(), {day: 'numeric', month: 'numeric'}).format(d)
|
||||
)
|
||||
this.yAxis = d3.svg
|
||||
.axis()
|
||||
.scale(this.y)
|
||||
.orient('left')
|
||||
.tickFormat(d => I18n.n(d, {percentage: true}))
|
||||
.tickValues([0, 50, 100])
|
||||
this.yGuides = d3.svg
|
||||
.axis()
|
||||
.scale(this.y)
|
||||
.orient('left')
|
||||
.tickValues([50, 100])
|
||||
.tickSize(-this.width(), 0, 0)
|
||||
.tickFormat('')
|
||||
return (this.masteryPercentageGuide = d3.svg
|
||||
.axis()
|
||||
.scale(this.y)
|
||||
.orient('left')
|
||||
.tickValues([this.masteryPercentage()])
|
||||
.tickSize(-this.width(), 0, 0)
|
||||
.tickFormat(''))
|
||||
}
|
||||
|
||||
_prepareLines() {
|
||||
if (this.data().length >= 3) {
|
||||
this.trend = new Trend(this.data())
|
||||
}
|
||||
|
||||
return (this.line = d3.svg.line().x(this.xValue).y(this.yValue).interpolate('linear'))
|
||||
}
|
||||
|
||||
_prepareScales() {
|
||||
this.x = d3.scale
|
||||
.linear()
|
||||
.range([0, this.width()])
|
||||
.domain([0, this.limit - 1])
|
||||
this.xTimeScale = d3.time
|
||||
.scale()
|
||||
.range([0, this.xTimeScaleWidth()])
|
||||
.domain([first(this.data()).date, last(this.data()).date])
|
||||
return (this.y = d3.scale.linear().range([this.height, this.margin.bottom]).domain([0, 100]))
|
||||
}
|
||||
|
||||
width() {
|
||||
return this.$el.width() - this.margin.left - this.margin.right - 10
|
||||
}
|
||||
|
||||
// The width of the axis used to display the first and last date of scores
|
||||
// displayed has to be different than the full width, in case the number
|
||||
// of points is fewer than the limit (8). What we want is the width of the
|
||||
// element reduced by the difference between the limit and the number of
|
||||
// points we actually have, multiplied by the width each point represents,
|
||||
// based on the element's width and the limit.
|
||||
xTimeScaleWidth() {
|
||||
return this.width() - (this.width() / (this.limit - 1)) * (this.limit - this.data().length)
|
||||
}
|
||||
}
|
||||
|
||||
OutcomeLineGraphView.optionProperty('el')
|
||||
OutcomeLineGraphView.optionProperty('height')
|
||||
OutcomeLineGraphView.optionProperty('limit')
|
||||
OutcomeLineGraphView.optionProperty('margin')
|
||||
OutcomeLineGraphView.optionProperty('model')
|
||||
OutcomeLineGraphView.optionProperty('timeFormat')
|
||||
OutcomeLineGraphView.prototype.defaults = {
|
||||
height: 200,
|
||||
limit: 8,
|
||||
margin: {top: 20, right: 20, bottom: 30, left: 40},
|
||||
// 2015-02-06T17:49:08Z
|
||||
timeFormat: '%Y-%m-%dT%XZ',
|
||||
}
|
||||
|
||||
export default OutcomeLineGraphView
|
|
@ -1,71 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import Popover from 'jquery-popover'
|
||||
import OutcomeLineGraphView from './OutcomeLineGraphView.coffee'
|
||||
import template from '@canvas/outcomes/jst/outcomePopover.handlebars'
|
||||
|
||||
export default class OutcomePopoverView extends Backbone.View
|
||||
TIMEOUT_LENGTH: 50
|
||||
|
||||
@optionProperty 'el'
|
||||
@optionProperty 'model'
|
||||
|
||||
events:
|
||||
'click i': 'mouseleave'
|
||||
'mouseenter i': 'mouseenter'
|
||||
'mouseleave i': 'mouseleave'
|
||||
inside: false
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@outcomeLineGraphView = new OutcomeLineGraphView({
|
||||
model: @model
|
||||
})
|
||||
|
||||
# Overrides
|
||||
render: ->
|
||||
template(@toJSON())
|
||||
|
||||
# Instance methods
|
||||
closePopover: (e) ->
|
||||
e?.preventDefault()
|
||||
return true unless @popover?
|
||||
@popover.hide()
|
||||
delete @popover
|
||||
|
||||
mouseenter: (e) =>
|
||||
@openPopover(e)
|
||||
@inside = true
|
||||
|
||||
mouseleave: (e) =>
|
||||
@inside = false
|
||||
setTimeout =>
|
||||
return if @inside || !@popover
|
||||
@closePopover()
|
||||
, @TIMEOUT_LENGTH
|
||||
|
||||
openPopover: (e) ->
|
||||
if @closePopover()
|
||||
@popover = new Popover(e, @render(), {
|
||||
verticalSide: 'bottom'
|
||||
manualOffset: 14
|
||||
})
|
||||
@outcomeLineGraphView.setElement(@popover.el.find("div.line-graph"))
|
||||
@outcomeLineGraphView.render()
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// Copyright (C) 2015 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS206: Consider reworking classes to avoid initClass
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import Popover from 'jquery-popover'
|
||||
import OutcomeLineGraphView from './OutcomeLineGraphView'
|
||||
import template from '@canvas/outcomes/jst/outcomePopover.handlebars'
|
||||
|
||||
const TIMEOUT_LENGTH = 50
|
||||
|
||||
class OutcomePopoverView extends Backbone.View {
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.mouseenter = this.mouseenter.bind(this)
|
||||
this.mouseleave = this.mouseleave.bind(this)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
super.initialize(...arguments)
|
||||
return (this.outcomeLineGraphView = new OutcomeLineGraphView({
|
||||
model: this.model,
|
||||
}))
|
||||
}
|
||||
|
||||
// Overrides
|
||||
render() {
|
||||
return template(this.toJSON())
|
||||
}
|
||||
|
||||
// Instance methods
|
||||
closePopover(e) {
|
||||
e?.preventDefault()
|
||||
if (this.popover === null || typeof this.popover === 'undefined') return true
|
||||
this.popover.hide()
|
||||
return delete this.popover
|
||||
}
|
||||
|
||||
mouseenter(e) {
|
||||
this.openPopover(e)
|
||||
this.inside = true
|
||||
return true
|
||||
}
|
||||
|
||||
mouseleave(_e) {
|
||||
this.inside = false
|
||||
setTimeout(() => {
|
||||
if (!this.inside && this.popover) this.closePopover()
|
||||
}, TIMEOUT_LENGTH)
|
||||
}
|
||||
|
||||
openPopover(e) {
|
||||
if (this.closePopover()) {
|
||||
this.popover = new Popover(e, this.render(), {
|
||||
verticalSide: 'bottom',
|
||||
manualOffset: 14,
|
||||
})
|
||||
}
|
||||
this.outcomeLineGraphView.setElement(this.popover.el.find('div.line-graph'))
|
||||
return this.outcomeLineGraphView.render()
|
||||
}
|
||||
}
|
||||
|
||||
OutcomePopoverView.prototype.events = {
|
||||
'click i': 'mouseleave',
|
||||
'mouseenter i': 'mouseenter',
|
||||
'mouseleave i': 'mouseleave',
|
||||
}
|
||||
OutcomePopoverView.prototype.inside = false
|
||||
OutcomePopoverView.prototype.TIMEOUT_LENGTH = TIMEOUT_LENGTH
|
||||
|
||||
OutcomePopoverView.optionProperty('el')
|
||||
OutcomePopoverView.optionProperty('model')
|
||||
|
||||
export default OutcomePopoverView
|
|
@ -1,53 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import _ from 'underscore'
|
||||
import Backbone from '@canvas/backbone'
|
||||
import ProgressBarView from './ProgressBarView.coffee'
|
||||
import OutcomePopoverView from './OutcomePopoverView.coffee'
|
||||
import OutcomeDialogView from './OutcomeDialogView.coffee'
|
||||
import template from '../../jst/outcome.handlebars'
|
||||
|
||||
export default class OutcomeView extends Backbone.View
|
||||
className: 'outcome'
|
||||
events:
|
||||
'click .more-details' : 'show'
|
||||
'keydown .more-details' : 'show'
|
||||
tagName: 'li'
|
||||
template: template
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@progress = new ProgressBarView(model: @model)
|
||||
|
||||
afterRender: ->
|
||||
@popover = new OutcomePopoverView({
|
||||
el: @$('.more-details')
|
||||
model: @model
|
||||
})
|
||||
@dialog = new OutcomeDialogView({
|
||||
model: @model
|
||||
})
|
||||
|
||||
show: (e) ->
|
||||
@dialog.show e
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
_.extend json,
|
||||
progress: @progress
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import ProgressBarView from './ProgressBarView'
|
||||
import OutcomePopoverView from './OutcomePopoverView'
|
||||
import OutcomeDialogView from './OutcomeDialogView'
|
||||
import template from '../../jst/outcome.handlebars'
|
||||
|
||||
class OutcomeView extends Backbone.View {
|
||||
initialize() {
|
||||
super.initialize(...arguments)
|
||||
return (this.progress = new ProgressBarView({model: this.model}))
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
this.popover = new OutcomePopoverView({
|
||||
el: this.$('.more-details'),
|
||||
model: this.model,
|
||||
})
|
||||
return (this.dialog = new OutcomeDialogView({
|
||||
model: this.model,
|
||||
}))
|
||||
}
|
||||
|
||||
show(e) {
|
||||
return this.dialog.show(e)
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...super.toJSON(...arguments),
|
||||
progress: this.progress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutcomeView.prototype.className = 'outcome'
|
||||
OutcomeView.prototype.tagName = 'li'
|
||||
OutcomeView.prototype.template = template
|
||||
OutcomeView.prototype.events = {
|
||||
'click .more-details': 'show',
|
||||
'keydown .more-details': 'show',
|
||||
}
|
||||
|
||||
export default OutcomeView
|
|
@ -1,23 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import template from '../../jst/progress_bar.handlebars'
|
||||
|
||||
export default class ProgressBarView extends Backbone.View
|
||||
className: 'bar'
|
||||
template: template
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Copyright (C) 2014 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Backbone from '@canvas/backbone'
|
||||
import template from '../../jst/progress_bar.handlebars'
|
||||
|
||||
class ProgressBarView extends Backbone.View {}
|
||||
|
||||
ProgressBarView.prototype.className = 'bar'
|
||||
ProgressBarView.prototype.template = template
|
||||
|
||||
export default ProgressBarView
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import {View} from '@canvas/backbone'
|
||||
import CollectionView from '@canvas/backbone-collection-view'
|
||||
import GroupView from './GroupView.coffee'
|
||||
import GroupView from './GroupView'
|
||||
import template from '../../jst/section.handlebars'
|
||||
|
||||
export default class SectionView extends View {
|
||||
|
|
Loading…
Reference in New Issue