remove prior screenreader gradebook
Change-Id: I931fef060ecc64263fc1a8768deda505fef09fd6 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/354831 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Cameron Ray <cameron.ray@instructure.com> QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com> Product-Review: Aaron Shafovaloff <ashafovaloff@instructure.com>
This commit is contained in:
parent
f0348ada41
commit
775df8e396
|
@ -310,8 +310,7 @@ class GradebooksController < ApplicationController
|
|||
# within the "gradebook" version there are two "views":
|
||||
# "default"
|
||||
# "learning_mastery"
|
||||
# "individual" (also "srgb")
|
||||
# "individual_enhanced"
|
||||
# "individual"
|
||||
|
||||
if requested_gradebook_view.present?
|
||||
if requested_gradebook_view != preferred_gradebook_view
|
||||
|
@ -321,11 +320,8 @@ class GradebooksController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
individual_enhanced_enabled = @context.root_account.feature_enabled?(:individual_gradebook_enhancements)
|
||||
if %w[srgb individual individual_enhanced].include?(gradebook_version) && individual_enhanced_enabled
|
||||
if %w[srgb individual individual_enhanced].include?(gradebook_version)
|
||||
show_enhanced_individual_gradebook
|
||||
elsif ["srgb", "individual"].include?(gradebook_version)
|
||||
show_individual_gradebook
|
||||
elsif preferred_gradebook_view == "learning_mastery" && outcome_gradebook_enabled?
|
||||
show_learning_mastery
|
||||
else
|
||||
|
@ -547,7 +543,6 @@ class GradebooksController < ApplicationController
|
|||
grading_standard_scaling_factor: active_grading_standard_scaling_factor(grading_standard),
|
||||
group_weighting_scheme: @context.group_weighting_scheme,
|
||||
has_modules: @context.has_modules?,
|
||||
individual_gradebook_enhancements: root_account.feature_enabled?(:individual_gradebook_enhancements),
|
||||
late_policy: @context.late_policy.as_json(include_root: false),
|
||||
login_handle_name: root_account.settings[:login_handle_name],
|
||||
message_attachment_upload_folder_id: @current_user.conversation_attachments_folder.id.to_s,
|
||||
|
@ -624,7 +619,6 @@ class GradebooksController < ApplicationController
|
|||
grading_standard_points_based: active_grading_standard_points_based(grading_standard),
|
||||
grading_standard_scaling_factor: active_grading_standard_scaling_factor(grading_standard),
|
||||
group_weighting_scheme: @context.group_weighting_scheme,
|
||||
individual_gradebook_enhancements: true,
|
||||
outcome_gradebook_enabled: outcome_gradebook_enabled?,
|
||||
outcome_rollups_url: api_v1_course_outcome_rollups_url(@context, per_page: 100),
|
||||
proxy_submissions_allowed: Account.site_admin.feature_enabled?(:proxy_file_uploads) && @context.grants_right?(@current_user, session, :proxy_assignment_submission),
|
||||
|
@ -723,7 +717,6 @@ class GradebooksController < ApplicationController
|
|||
late_policy: @context.late_policy.as_json(include_root: false),
|
||||
login_handle_name: root_account.settings[:login_handle_name],
|
||||
has_modules: @context.has_modules?,
|
||||
individual_gradebook_enhancements: root_account.feature_enabled?(:individual_gradebook_enhancements),
|
||||
message_attachment_upload_folder_id: @current_user.conversation_attachments_folder.id.to_s,
|
||||
outcome_gradebook_enabled: outcome_gradebook_enabled?,
|
||||
outcome_links_url: api_v1_course_outcome_group_links_url(@context, outcome_style: :full),
|
||||
|
@ -783,7 +776,6 @@ class GradebooksController < ApplicationController
|
|||
settings: gradebook_settings(@context.global_id),
|
||||
settings_update_url: api_v1_course_gradebook_settings_update_url(@context),
|
||||
IMPROVED_LMGB: root_account.feature_enabled?(:improved_lmgb),
|
||||
individual_gradebook_enhancements: root_account.feature_enabled?(:individual_gradebook_enhancements),
|
||||
},
|
||||
OUTCOME_AVERAGE_CALCULATION: root_account.feature_enabled?(:outcome_average_calculation),
|
||||
outcome_service_results_to_canvas: outcome_service_results_to_canvas_enabled?,
|
||||
|
@ -813,8 +805,7 @@ class GradebooksController < ApplicationController
|
|||
COURSE_URL: named_context_url(@context, :context_url),
|
||||
COURSE_IS_CONCLUDED: @context.is_a?(Course) && @context.completed?,
|
||||
OUTCOME_GRADEBOOK_ENABLED: outcome_gradebook_enabled?,
|
||||
OVERRIDE_GRADES_ENABLED: @context.try(:allow_final_grade_override?),
|
||||
individual_gradebook_enhancements: @context.root_account.feature_enabled?(:individual_gradebook_enhancements)
|
||||
OVERRIDE_GRADES_ENABLED: @context.try(:allow_final_grade_override?)
|
||||
)
|
||||
|
||||
render html: "", layout: true
|
||||
|
|
|
@ -1,21 +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 "base/environment";
|
||||
@import "pages/shared/message_students";
|
||||
@import "pages/screenreader_gradebook/screenreader_gradebook";
|
|
@ -1,33 +0,0 @@
|
|||
<%
|
||||
# Copyright (C) 2011 - 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/>.
|
||||
%>
|
||||
|
||||
<%
|
||||
css_bundle :screenreader_gradebook
|
||||
deferred_js_bundle :screenreader_gradebook
|
||||
%>
|
||||
<% provide :page_title, t("Gradebook: Individual View") %>
|
||||
<div>
|
||||
<span data-component="GradebookSelector"></span>
|
||||
<span data-component="IndividualProxyUploader" data-variant="IndividualGradebook"></span>
|
||||
</div>
|
||||
<div style="display:none;">
|
||||
<%= render :partial => "shared/message_students" %>
|
||||
</div>
|
||||
<% if show_message_students_with_observers_dialog? %>
|
||||
<span data-component="MessageStudentsWithObserversModal"></span>
|
||||
<% end %>
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "canvas-lms",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": "These are all things that there is not an npm version of, so they have to stay here, even when using webpack",
|
||||
"dependencies": {
|
||||
"ember": "1.4.0"
|
||||
}
|
||||
}
|
|
@ -125,7 +125,7 @@ it can work against the es6 source and not the compiled output.
|
|||
|
||||
[X] load up canvas w/ optimized js and RAILS_LOAD_ALL_LOCALES=1, switch your locale and ensure you see translations
|
||||
|
||||
[ ] extract duplicated loader code from i18nLinerHandlebars and emberHandlebars
|
||||
[ ] extract duplicated loader code from i18nLinerHandlebars
|
||||
|
||||
[ ] in a separate commit extract i18nLinerHandlebars loader function and what
|
||||
it duplicates from prepare_hbs to a function both can use.
|
||||
|
|
|
@ -286,7 +286,6 @@
|
|||
"core-js-builder": "^3",
|
||||
"css-loader": "^3",
|
||||
"dependency-cruiser": "^16.3.1",
|
||||
"ember-template-compiler": "^1.8.0",
|
||||
"enzyme": "^3",
|
||||
"enzyme-adapter-react-16": "^1.15.7",
|
||||
"enzyme-to-json": "^3.3.4",
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "ember",
|
||||
"version": "1.4.0",
|
||||
"main": [
|
||||
"./ember.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">= 1.7 <= 2.1",
|
||||
"handlebars": ">= 1.0.0 < 2.0.0"
|
||||
},
|
||||
"homepage": "https://github.com/components/ember",
|
||||
"_release": "1.4.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.4.0",
|
||||
"commit": "3d9e0e9401d60ddf8e703ccc7698916eb7d2c2cc"
|
||||
},
|
||||
"_source": "git://github.com/components/ember.git",
|
||||
"_target": "1.4.0",
|
||||
"_originalSource": "ember"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
**/*
|
|
@ -1,5 +0,0 @@
|
|||
vendor
|
||||
composer.lock
|
||||
components
|
||||
node_modules
|
||||
emberjs
|
|
@ -1 +0,0 @@
|
|||
**/*
|
|
@ -1,9 +0,0 @@
|
|||
VERSION=v1.4.0
|
||||
|
||||
default:
|
||||
@curl -O http://builds.emberjs.com/tags/$(VERSION)/ember.js
|
||||
@curl -O http://builds.emberjs.com/tags/$(VERSION)/ember.min.js
|
||||
@curl -O http://builds.emberjs.com/tags/$(VERSION)/ember.prod.js
|
||||
@curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-template-compiler.js
|
||||
|
||||
.PHONY: default
|
|
@ -1,12 +0,0 @@
|
|||
Ember.js
|
||||
========
|
||||
|
||||
Shim repository for [Ember Application Framework](http://emberjs.com/).
|
||||
|
||||
This package provides the core of the ember.js framework.
|
||||
|
||||
Package Managers
|
||||
----------------
|
||||
|
||||
* [Bower](http://bower.io): `ember`
|
||||
* [Composer](http://packagist.org/packages/components/ember): `components/ember`
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"name": "ember",
|
||||
"version": "1.4.0",
|
||||
"main": [
|
||||
"./ember.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">= 1.7 <= 2.1",
|
||||
"handlebars": ">= 1.0.0 < 2.0.0"
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"name": "ember",
|
||||
"repo": "components/ember",
|
||||
"version": "1.4.0",
|
||||
"main": "ember.js",
|
||||
"scripts": [
|
||||
"ember.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"component/jquery": ">= 1.7 <= 2.1",
|
||||
"components/handlebars.js": ">= 1.0.0 < 2.0.0"
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"name": "components/ember",
|
||||
"description": "A framework for creating ambitious web applications.",
|
||||
"type": "component",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"components/jquery": ">=1.7 <= 2.1",
|
||||
"components/handlebars.js": "1.*"
|
||||
},
|
||||
"extra": {
|
||||
"component": {
|
||||
"scripts": [
|
||||
"ember.js"
|
||||
],
|
||||
"files": [
|
||||
"ember.min.js"
|
||||
],
|
||||
"shim": {
|
||||
"exports": "Ember",
|
||||
"deps": [
|
||||
"jquery",
|
||||
"handlebars"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,324 +0,0 @@
|
|||
(function() {
|
||||
var Ember = { assert: function() {}, FEATURES: { isEnabled: function() {} } };
|
||||
/*!
|
||||
* @overview Ember - JavaScript Application Framework
|
||||
* @copyright Copyright 2011-2014 Tilde Inc. and contributors
|
||||
* Portions Copyright 2006-2011 Strobe Inc.
|
||||
* Portions Copyright 2008-2011 Apple Inc. All rights reserved.
|
||||
* @license Licensed under MIT license
|
||||
* See https://raw.github.com/emberjs/ember.js/master/LICENSE
|
||||
* @version 1.4.0
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
/**
|
||||
@module ember
|
||||
@submodule ember-handlebars-compiler
|
||||
*/
|
||||
|
||||
// Eliminate dependency on any Ember to simplify precompilation workflow
|
||||
var objectCreate = Object.create || function(parent) {
|
||||
function F() {}
|
||||
F.prototype = parent;
|
||||
return new F();
|
||||
};
|
||||
|
||||
var Handlebars = require('handlebars')
|
||||
|
||||
Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " +
|
||||
"a SCRIPT tag in the HTML HEAD linking to the Handlebars file " +
|
||||
"before you link to Ember.", Handlebars);
|
||||
|
||||
Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " +
|
||||
"COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION +
|
||||
" - Please note: Builds of master may have other COMPILER_REVISION values.",
|
||||
Handlebars.COMPILER_REVISION === 4);
|
||||
|
||||
/**
|
||||
Prepares the Handlebars templating library for use inside Ember's view
|
||||
system.
|
||||
|
||||
The `Ember.Handlebars` object is the standard Handlebars library, extended to
|
||||
use Ember's `get()` method instead of direct property access, which allows
|
||||
computed properties to be used inside templates.
|
||||
|
||||
To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`.
|
||||
This will return a function that can be used by `Ember.View` for rendering.
|
||||
|
||||
@class Handlebars
|
||||
@namespace Ember
|
||||
*/
|
||||
Ember.Handlebars = objectCreate(Handlebars);
|
||||
|
||||
/**
|
||||
Register a bound helper or custom view helper.
|
||||
|
||||
## Simple bound helper example
|
||||
|
||||
```javascript
|
||||
Ember.Handlebars.helper('capitalize', function(value) {
|
||||
return value.toUpperCase();
|
||||
});
|
||||
```
|
||||
|
||||
The above bound helper can be used inside of templates as follows:
|
||||
|
||||
```handlebars
|
||||
{{capitalize name}}
|
||||
```
|
||||
|
||||
In this case, when the `name` property of the template's context changes,
|
||||
the rendered value of the helper will update to reflect this change.
|
||||
|
||||
For more examples of bound helpers, see documentation for
|
||||
`Ember.Handlebars.registerBoundHelper`.
|
||||
|
||||
## Custom view helper example
|
||||
|
||||
Assuming a view subclass named `App.CalendarView` were defined, a helper
|
||||
for rendering instances of this view could be registered as follows:
|
||||
|
||||
```javascript
|
||||
Ember.Handlebars.helper('calendar', App.CalendarView):
|
||||
```
|
||||
|
||||
The above bound helper can be used inside of templates as follows:
|
||||
|
||||
```handlebars
|
||||
{{calendar}}
|
||||
```
|
||||
|
||||
Which is functionally equivalent to:
|
||||
|
||||
```handlebars
|
||||
{{view App.CalendarView}}
|
||||
```
|
||||
|
||||
Options in the helper will be passed to the view in exactly the same
|
||||
manner as with the `view` helper.
|
||||
|
||||
@method helper
|
||||
@for Ember.Handlebars
|
||||
@param {String} name
|
||||
@param {Function|Ember.View} function or view class constructor
|
||||
@param {String} dependentKeys*
|
||||
*/
|
||||
Ember.Handlebars.helper = function(name, value) {
|
||||
Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Ember.Component.detect(value) || name.match(/-/));
|
||||
|
||||
if (Ember.View.detect(value)) {
|
||||
Ember.Handlebars.registerHelper(name, Ember.Handlebars.makeViewHelper(value));
|
||||
} else {
|
||||
Ember.Handlebars.registerBoundHelper.apply(null, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Returns a helper function that renders the provided ViewClass.
|
||||
|
||||
Used internally by Ember.Handlebars.helper and other methods
|
||||
involving helper/component registration.
|
||||
|
||||
@private
|
||||
@method helper
|
||||
@for Ember.Handlebars
|
||||
@param {Function} ViewClass view class constructor
|
||||
*/
|
||||
Ember.Handlebars.makeViewHelper = function(ViewClass) {
|
||||
return function(options) {
|
||||
Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2);
|
||||
return Ember.Handlebars.helpers.view.call(this, ViewClass, options);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@class helpers
|
||||
@namespace Ember.Handlebars
|
||||
*/
|
||||
Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);
|
||||
|
||||
/**
|
||||
Override the the opcode compiler and JavaScript compiler for Handlebars.
|
||||
|
||||
@class Compiler
|
||||
@namespace Ember.Handlebars
|
||||
@private
|
||||
@constructor
|
||||
*/
|
||||
Ember.Handlebars.Compiler = function() {};
|
||||
|
||||
// Handlebars.Compiler doesn't exist in runtime-only
|
||||
if (Handlebars.Compiler) {
|
||||
Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
|
||||
}
|
||||
|
||||
Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;
|
||||
|
||||
/**
|
||||
@class JavaScriptCompiler
|
||||
@namespace Ember.Handlebars
|
||||
@private
|
||||
@constructor
|
||||
*/
|
||||
Ember.Handlebars.JavaScriptCompiler = function() {};
|
||||
|
||||
// Handlebars.JavaScriptCompiler doesn't exist in runtime-only
|
||||
if (Handlebars.JavaScriptCompiler) {
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
|
||||
}
|
||||
|
||||
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";
|
||||
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
|
||||
return "''";
|
||||
};
|
||||
|
||||
/**
|
||||
Override the default buffer for Ember Handlebars. By default, Handlebars
|
||||
creates an empty String at the beginning of each invocation and appends to
|
||||
it. Ember's Handlebars overrides this to append to a single shared buffer.
|
||||
|
||||
@private
|
||||
@method appendToBuffer
|
||||
@param string {String}
|
||||
*/
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
|
||||
return "data.buffer.push("+string+");";
|
||||
};
|
||||
|
||||
// Hacks ahead:
|
||||
// Handlebars presently has a bug where the `blockHelperMissing` hook
|
||||
// doesn't get passed the name of the missing helper name, but rather
|
||||
// gets passed the value of that missing helper evaluated on the current
|
||||
// context, which is most likely `undefined` and totally useless.
|
||||
//
|
||||
// So we alter the compiled template function to pass the name of the helper
|
||||
// instead, as expected.
|
||||
//
|
||||
// This can go away once the following is closed:
|
||||
// https://github.com/wycats/handlebars.js/issues/634
|
||||
|
||||
var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/,
|
||||
BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/,
|
||||
INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/;
|
||||
|
||||
Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) {
|
||||
var helperInvocation = source[source.length - 1],
|
||||
helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1],
|
||||
matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation);
|
||||
|
||||
source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3];
|
||||
}
|
||||
var stringifyBlockHelperMissing = Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation;
|
||||
|
||||
var originalBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.blockValue;
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.blockValue = function() {
|
||||
originalBlockValue.apply(this, arguments);
|
||||
stringifyBlockHelperMissing(this.source);
|
||||
};
|
||||
|
||||
var originalAmbiguousBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue;
|
||||
Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() {
|
||||
originalAmbiguousBlockValue.apply(this, arguments);
|
||||
stringifyBlockHelperMissing(this.source);
|
||||
};
|
||||
|
||||
var prefix = "ember" + (+new Date()), incr = 1;
|
||||
|
||||
/**
|
||||
Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that
|
||||
all simple mustaches in Ember's Handlebars will also set up an observer to
|
||||
keep the DOM up to date when the underlying property changes.
|
||||
|
||||
@private
|
||||
@method mustache
|
||||
@for Ember.Handlebars.Compiler
|
||||
@param mustache
|
||||
*/
|
||||
Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
|
||||
if (mustache.isHelper && mustache.id.string === 'control') {
|
||||
mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
|
||||
mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
|
||||
} else if (mustache.params.length || mustache.hash) {
|
||||
// no changes required
|
||||
} else {
|
||||
var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]);
|
||||
|
||||
// Update the mustache node to include a hash value indicating whether the original node
|
||||
// was escaped. This will allow us to properly escape values when the underlying value
|
||||
// changes and we need to re-render the value.
|
||||
if (!mustache.escaped) {
|
||||
mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
|
||||
mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
|
||||
}
|
||||
mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
|
||||
}
|
||||
|
||||
return Handlebars.Compiler.prototype.mustache.call(this, mustache);
|
||||
};
|
||||
|
||||
/**
|
||||
Used for precompilation of Ember Handlebars templates. This will not be used
|
||||
during normal app execution.
|
||||
|
||||
@method precompile
|
||||
@for Ember.Handlebars
|
||||
@static
|
||||
@param {String} string The template to precompile
|
||||
*/
|
||||
Ember.Handlebars.precompile = function(string) {
|
||||
var ast = Handlebars.parse(string);
|
||||
|
||||
var options = {
|
||||
knownHelpers: {
|
||||
action: true,
|
||||
unbound: true,
|
||||
'bind-attr': true,
|
||||
template: true,
|
||||
view: true,
|
||||
_triageMustache: true
|
||||
},
|
||||
data: true,
|
||||
stringParams: true
|
||||
};
|
||||
|
||||
var environment = new Ember.Handlebars.Compiler().compile(ast, options);
|
||||
return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
};
|
||||
|
||||
// We don't support this for Handlebars runtime-only
|
||||
if (Handlebars.compile) {
|
||||
/**
|
||||
The entry point for Ember Handlebars. This replaces the default
|
||||
`Handlebars.compile` and turns on template-local data and String
|
||||
parameters.
|
||||
|
||||
@method compile
|
||||
@for Ember.Handlebars
|
||||
@static
|
||||
@param {String} string The template to compile
|
||||
@return {Function}
|
||||
*/
|
||||
Ember.Handlebars.compile = function(string) {
|
||||
var ast = Handlebars.parse(string);
|
||||
var options = { data: true, stringParams: true };
|
||||
var environment = new Ember.Handlebars.Compiler().compile(ast, options);
|
||||
var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
|
||||
var template = Ember.Handlebars.template(templateSpec);
|
||||
template.isMethod = false; //Make sure we don't wrap templates with ._super
|
||||
|
||||
return template;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
|
||||
|
||||
exports.precompile = Ember.Handlebars.precompile;
|
||||
exports.EmberHandlebars = Ember.Handlebars;
|
||||
})();
|
File diff suppressed because one or more lines are too long
41801
packages/ember/ember.mjs
41801
packages/ember/ember.mjs
File diff suppressed because it is too large
Load Diff
|
@ -1,218 +0,0 @@
|
|||
import Ember from './ember.mjs'
|
||||
|
||||
export default Ember
|
||||
export const $ = Ember.$
|
||||
export const A = Ember.A
|
||||
export const ActionHandler = Ember.ActionHandler
|
||||
export const addBeforeObserver = Ember.addBeforeObserver
|
||||
export const addListener = Ember.addListener
|
||||
export const addObserver = Ember.addObserver
|
||||
export const aliasMethod = Ember.aliasMethod
|
||||
export const anyUnprocessedMixins = Ember.anyUnprocessedMixins
|
||||
export const Application = Ember.Application
|
||||
export const Array = Ember.Array
|
||||
export const arrayComputed = Ember.arrayComputed
|
||||
export const ArrayComputedProperty = Ember.ArrayComputedProperty
|
||||
export const ArrayController = Ember.ArrayController
|
||||
export const ArrayPolyfills = Ember.ArrayPolyfills
|
||||
export const ArrayProxy = Ember.ArrayProxy
|
||||
export const assert = Ember.assert
|
||||
export const beforeObserver = Ember.beforeObserver
|
||||
export const beforeObserversFor = Ember.beforeObserversFor
|
||||
export const beginPropertyChanges = Ember.beginPropertyChanges
|
||||
export const bind = Ember.bind
|
||||
export const Binding = Ember.Binding
|
||||
export const BOOTED = Ember.BOOTED
|
||||
export const cacheFor = Ember.cacheFor
|
||||
export const canInvoke = Ember.canInvoke
|
||||
export const changeProperties = Ember.changeProperties
|
||||
export const Checkbox = Ember.Checkbox
|
||||
export const CollectionView = Ember.CollectionView
|
||||
export const Comparable = Ember.Comparable
|
||||
export const compare = Ember.compare
|
||||
export const Component = Ember.Component
|
||||
export const ComponentLookup = Ember.ComponentLookup
|
||||
export const ComponentTemplateDeprecation = Ember.ComponentTemplateDeprecation
|
||||
export const computed = Ember.computed
|
||||
export const ComputedProperty = Ember.ComputedProperty
|
||||
export const config = Ember.config
|
||||
export const Container = Ember.Container
|
||||
export const ContainerView = Ember.ContainerView
|
||||
export const Controller = Ember.Controller
|
||||
export const controllerFor = Ember.controllerFor
|
||||
export const ControllerMixin = Ember.ControllerMixin
|
||||
export const copy = Ember.copy
|
||||
export const Copyable = Ember.Copyable
|
||||
export const CoreObject = Ember.CoreObject
|
||||
export const CoreView = Ember.CoreView
|
||||
export const create = Ember.create
|
||||
export const DAG = Ember.DAG
|
||||
export const DataAdapter = Ember.DataAdapter
|
||||
export const debug = Ember.debug
|
||||
export const DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION
|
||||
export const DefaultResolver = Ember.DefaultResolver
|
||||
export const Deferred = Ember.Deferred
|
||||
export const DeferredMixin = Ember.DeferredMixin
|
||||
export const defineProperty = Ember.defineProperty
|
||||
export const deprecate = Ember.deprecate
|
||||
export const deprecateFunc = Ember.deprecateFunc
|
||||
export const Descriptor = Ember.Descriptor
|
||||
export const destroy = Ember.destroy
|
||||
export const EachProxy = Ember.EachProxy
|
||||
export const Em = Ember
|
||||
export const empty = Ember.empty
|
||||
export const EMPTY_META = Ember.EMPTY_META
|
||||
export const endPropertyChanges = Ember.endPropertyChanges
|
||||
export const Enumerable = Ember.Enumerable
|
||||
export const EnumerableUtils = Ember.EnumerableUtils
|
||||
export const ENV = Ember.ENV
|
||||
export const Error = Ember.Error
|
||||
export const EventDispatcher = Ember.EventDispatcher
|
||||
export const Evented = Ember.Evented
|
||||
export const expandProperties = Ember.expandProperties
|
||||
export const EXTEND_PROTOTYPES = Ember.EXTEND_PROTOTYPES
|
||||
export const FEATURES = Ember.FEATURES
|
||||
export const finishChains = Ember.finishChains
|
||||
export const flushPendingChains = Ember.flushPendingChains
|
||||
export const Freezable = Ember.Freezable
|
||||
export const FROZEN_ERROR = Ember.FROZEN_ERROR
|
||||
export const generateController = Ember.generateController
|
||||
export const generateControllerFactory = Ember.generateControllerFactory
|
||||
export const generateGuid = Ember.generateGuid
|
||||
export const get = Ember.get
|
||||
export const getMeta = Ember.getMeta
|
||||
export const getProperties = Ember.getProperties
|
||||
export const getWithDefault = Ember.getWithDefault
|
||||
export const GUID_KEY = Ember.GUID_KEY
|
||||
export const GUID_PREFIX = Ember.GUID_PREFIX
|
||||
export const guidFor = Ember.guidFor
|
||||
export const Handlebars = Ember.Handlebars
|
||||
export const handleErrors = Ember.handleErrors
|
||||
export const HashLocation = Ember.HashLocation
|
||||
export const hasListeners = Ember.hasListeners
|
||||
export const HistoryLocation = Ember.HistoryLocation
|
||||
export const immediateObserver = Ember.immediateObserver
|
||||
export const inspect = Ember.inspect
|
||||
export const instrument = Ember.instrument
|
||||
export const Instrumentation = Ember.Instrumentation
|
||||
export const IS_BINDING = Ember.IS_BINDING
|
||||
export const isArray = Ember.isArray
|
||||
export const isEmpty = Ember.isEmpty
|
||||
export const isEqual = Ember.isEqual
|
||||
export const isGlobalPath = Ember.isGlobalPath
|
||||
export const isNamespace = Ember.isNamespace
|
||||
export const isNone = Ember.isNone
|
||||
export const isWatching = Ember.isWatching
|
||||
export const K = Ember.K
|
||||
export const keys = Ember.keys
|
||||
export const libraries = Ember.libraries
|
||||
export const LinkView = Ember.LinkView
|
||||
export const listenersDiff = Ember.listenersDiff
|
||||
export const listenersFor = Ember.listenersFor
|
||||
export const listenersUnion = Ember.listenersUnion
|
||||
export const Location = Ember.Location
|
||||
export const LOG_BINDINGS = Ember.LOG_BINDINGS
|
||||
export const LOG_STACKTRACE_ON_DEPRECATION = Ember.LOG_STACKTRACE_ON_DEPRECATION
|
||||
export const LOG_VERSION = Ember.LOG_VERSION
|
||||
export const Logger = Ember.Logger
|
||||
export const lookup = Ember.lookup
|
||||
export const makeArray = Ember.makeArray
|
||||
export const MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION
|
||||
export const Map = Ember.Map
|
||||
export const MapWithDefault = Ember.MapWithDefault
|
||||
export const merge = Ember.merge
|
||||
export const meta = Ember.meta
|
||||
export const META_DESC = Ember.META_DESC
|
||||
export const META_KEY = Ember.META_KEY
|
||||
export const MetamorphENV = Ember.MetamorphENV
|
||||
export const metaPath = Ember.metaPath
|
||||
export const mixin = Ember.mixin
|
||||
export const Mixin = Ember.Mixin
|
||||
export const MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS
|
||||
export const MutableArray = Ember.MutableArray
|
||||
export const MutableEnumerable = Ember.MutableEnumerable
|
||||
export const NAME_KEY = Ember.NAME_KEY
|
||||
export const Namespace = Ember.Namespace
|
||||
export const NativeArray = Ember.NativeArray
|
||||
export const none = Ember.none
|
||||
export const NoneLocation = Ember.NoneLocation
|
||||
export const normalizeTuple = Ember.normalizeTuple
|
||||
export const Object = Ember.Object
|
||||
export const ObjectController = Ember.ObjectController
|
||||
export const ObjectProxy = Ember.ObjectProxy
|
||||
export const Observable = Ember.Observable
|
||||
export const observer = Ember.observer
|
||||
export const observersFor = Ember.observersFor
|
||||
export const on = Ember.on
|
||||
export const onerror = Ember.onerror
|
||||
export const oneWay = Ember.oneWay
|
||||
export const onLoad = Ember.onLoad
|
||||
export const ORDER_DEFINITION = Ember.ORDER_DEFINITION
|
||||
export const ORDER_DEFINITION_MAPPING = Ember.ORDER_DEFINITION_MAPPING
|
||||
export const OrderedSet = Ember.OrderedSet
|
||||
export const overrideChains = Ember.overrideChains
|
||||
export const platform = Ember.platform
|
||||
export const PromiseProxyMixin = Ember.PromiseProxyMixin
|
||||
export const propertyDidChange = Ember.propertyDidChange
|
||||
export const propertyWillChange = Ember.propertyWillChange
|
||||
export const reduceComputed = Ember.reduceComputed
|
||||
export const ReduceComputedProperty = Ember.ReduceComputedProperty
|
||||
export const removeBeforeObserver = Ember.removeBeforeObserver
|
||||
export const removeChainWatcher = Ember.removeChainWatcher
|
||||
export const removeListener = Ember.removeListener
|
||||
export const removeObserver = Ember.removeObserver
|
||||
export const RenderBuffer = Ember.RenderBuffer
|
||||
export const required = Ember.required
|
||||
export const rewatch = Ember.rewatch
|
||||
export const Route = Ember.Route
|
||||
export const Router = Ember.Router
|
||||
export const RouterDSL = Ember.RouterDSL
|
||||
export const RSVP = Ember.RSVP
|
||||
export const run = Ember.run
|
||||
export const runLoadHooks = Ember.runLoadHooks
|
||||
export const Select = Ember.Select
|
||||
export const SelectOptgroup = Ember.SelectOptgroup
|
||||
export const SelectOption = Ember.SelectOption
|
||||
export const sendEvent = Ember.sendEvent
|
||||
export const set = Ember.set
|
||||
export const Set = Ember.Set
|
||||
export const setMeta = Ember.setMeta
|
||||
export const setProperties = Ember.setProperties
|
||||
export const SHIM_ES5 = Ember.SHIM_ES5
|
||||
export const SortableMixin = Ember.SortableMixin
|
||||
export const State = Ember.State
|
||||
export const StateManager = Ember.StateManager
|
||||
export const String = Ember.String
|
||||
export const STRINGS = Ember.STRINGS
|
||||
export const STRUCTURED_PROFILE = Ember.STRUCTURED_PROFILE
|
||||
export const SubArray = Ember.SubArray
|
||||
export const subscribe = Ember.subscribe
|
||||
export const TargetActionSupport = Ember.TargetActionSupport
|
||||
export const TEMPLATES = Ember.TEMPLATES
|
||||
export const Test = Ember.Test
|
||||
export const testing = Ember.testing
|
||||
export const TESTING_DEPRECATION = Ember.TESTING_DEPRECATION
|
||||
export const TextArea = Ember.TextArea
|
||||
export const TextField = Ember.TextField
|
||||
export const TextSupport = Ember.TextSupport
|
||||
export const toString = Ember.toString
|
||||
export const TrackedArray = Ember.TrackedArray
|
||||
export const tryCatchFinally = Ember.tryCatchFinally
|
||||
export const tryFinally = Ember.tryFinally
|
||||
export const tryInvoke = Ember.tryInvoke
|
||||
export const trySet = Ember.trySet
|
||||
export const typeOf = Ember.typeOf
|
||||
export const unwatch = Ember.unwatch
|
||||
export const unwatchKey = Ember.unwatchKey
|
||||
export const unwatchPath = Ember.unwatchPath
|
||||
export const uuid = Ember.uuid
|
||||
export const VERSION = Ember.VERSION
|
||||
export const View = Ember.View
|
||||
export const ViewTargetActionSupport = Ember.ViewTargetActionSupport
|
||||
export const ViewUtils = Ember.ViewUtils
|
||||
export const warn = Ember.warn
|
||||
export const watch = Ember.watch
|
||||
export const watchedEvents = Ember.watchedEvents
|
||||
export const watchKey = Ember.watchKey
|
||||
export const watchPath = Ember.watchPath
|
||||
export const wrap = Ember.wrap
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"name": "ember",
|
||||
"version": "1.4.0",
|
||||
"main": "./index.mjs",
|
||||
"owner": "EVAL"
|
||||
}
|
|
@ -986,21 +986,6 @@ describe GradebooksController do
|
|||
expect(response).to render_template("gradebooks/gradebook")
|
||||
end
|
||||
|
||||
it "renders screenreader gradebook when preferred with 'individual'" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
@admin.set_preference(:gradebook_version, "individual")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
|
||||
it "renders screenreader gradebook when preferred with 'srgb'" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
# most a11y users will have this set from before New Gradebook existed
|
||||
@admin.set_preference(:gradebook_version, "srgb")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
|
||||
it "renders default gradebook when user has no preference" do
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/gradebook")
|
||||
|
@ -1013,34 +998,6 @@ describe GradebooksController do
|
|||
expect(response).to render_template("gradebooks/gradebook")
|
||||
end
|
||||
|
||||
it "renders enhanced individual gradebook when individual_enhanced & individual_gradebook_enhancements is enabled" do
|
||||
@course.root_account.enable_feature!(:individual_gradebook_enhancements)
|
||||
@admin.set_preference(:gradebook_version, "individual_enhanced")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("layouts/application")
|
||||
end
|
||||
|
||||
it "renders enhanced individual gradebook when individual & individual_gradebook_enhancements is enabled" do
|
||||
@course.root_account.enable_feature!(:individual_gradebook_enhancements)
|
||||
@admin.set_preference(:gradebook_version, "individual")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("layouts/application")
|
||||
end
|
||||
|
||||
it "renders enhanced individual gradebook when srgb & individual_gradebook_enhancements is enabled" do
|
||||
@course.root_account.enable_feature!(:individual_gradebook_enhancements)
|
||||
@admin.set_preference(:gradebook_version, "srgb")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("layouts/application")
|
||||
end
|
||||
|
||||
it "renders traditional gradebook when individual_gradebook_enhancements is disabled" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
@admin.set_preference(:gradebook_version, "individual_enhanced")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/gradebook")
|
||||
end
|
||||
|
||||
describe "score to ungraded" do
|
||||
before do
|
||||
options = Gradebook::ApplyScoreToUngradedSubmissions::Options.new(
|
||||
|
@ -1118,21 +1075,6 @@ describe GradebooksController do
|
|||
end
|
||||
end
|
||||
|
||||
context "in development and requested version is 'individual'" do
|
||||
before do
|
||||
account_admin_user(account: @course.root_account)
|
||||
user_session(@admin)
|
||||
@admin.set_preference(:gradebook_version, "default")
|
||||
allow(Rails.env).to receive(:development?).and_return(true)
|
||||
end
|
||||
|
||||
it "renders screenreader gradebook" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
get "show", params: { course_id: @course.id, version: "individual" }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
end
|
||||
|
||||
describe "prefetching" do
|
||||
render_views
|
||||
|
||||
|
@ -1269,33 +1211,6 @@ describe GradebooksController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "show_message_students_with_observers_dialog" do
|
||||
shared_examples_for "environment variable" do
|
||||
it "is true when the feature is enabled" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
Account.site_admin.enable_feature!(:message_observers_of_students_who)
|
||||
get :show, params: { course_id: @course.id }
|
||||
expect(gradebook_options[:show_message_students_with_observers_dialog]).to be true
|
||||
end
|
||||
|
||||
it "is false when the feature is not enabled" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
get :show, params: { course_id: @course.id }
|
||||
expect(gradebook_options[:show_message_students_with_observers_dialog]).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context "when individual gradebook is enabled" do
|
||||
before { @teacher.set_preference(:gradebook_version, "srgb") }
|
||||
|
||||
include_examples "environment variable"
|
||||
end
|
||||
|
||||
context "when default gradebook is enabled" do
|
||||
include_examples "environment variable"
|
||||
end
|
||||
end
|
||||
|
||||
describe "grading_standard" do
|
||||
it "uses the Canvas default grading standard if the course does not have one" do
|
||||
get :show, params: { course_id: @course.id }
|
||||
|
@ -1691,13 +1606,6 @@ describe GradebooksController do
|
|||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebook")
|
||||
end
|
||||
|
||||
it "redirects to Individual View with a friendly URL" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
@teacher.set_preference(:gradebook_version, "srgb")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
end
|
||||
|
||||
it "renders the unauthorized page without gradebook authorization" do
|
||||
|
@ -1830,13 +1738,6 @@ describe GradebooksController do
|
|||
expect(response).to render_template("gradebooks/gradebook")
|
||||
end
|
||||
|
||||
it "renders 'individual' when the user uses individual view" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
update_preferred_gradebook_version!("individual")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
|
||||
it "updates the user's preference when the requested view is 'gradebook'" do
|
||||
get "show", params: { course_id: @course.id, view: "gradebook" }
|
||||
@teacher.reload
|
||||
|
@ -1889,13 +1790,6 @@ describe GradebooksController do
|
|||
expect(response).to render_template("gradebooks/gradebook")
|
||||
end
|
||||
|
||||
it "renders 'individual' when the user uses individual view" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
update_preferred_gradebook_version!("individual")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
|
||||
it "redirects to the gradebook when requesting the preferred view" do
|
||||
get "show", params: { course_id: @course.id, view: "gradebook" }
|
||||
expect(response).to redirect_to(action: "show")
|
||||
|
@ -1929,13 +1823,6 @@ describe GradebooksController do
|
|||
expect(response).to render_template("gradebooks/learning_mastery")
|
||||
end
|
||||
|
||||
it "renders 'individual' when the user uses individual view" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
update_preferred_gradebook_version!("individual")
|
||||
get "show", params: { course_id: @course.id }
|
||||
expect(response).to render_template("gradebooks/individual")
|
||||
end
|
||||
|
||||
it "redirects to the gradebook when requesting the preferred view" do
|
||||
get "show", params: { course_id: @course.id, view: "learning_mastery" }
|
||||
expect(response).to redirect_to(action: "show")
|
||||
|
|
|
@ -51,32 +51,6 @@ describe "Final Grade Override" do
|
|||
end
|
||||
end
|
||||
|
||||
context "Individual Gradebook" do
|
||||
before do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
@student = @students.first
|
||||
@enrollment = @course.enrollments.find_by(user: @student)
|
||||
@enrollment.scores.find_by(course_score: true).update!(override_score: 97.1)
|
||||
user_session(@teacher)
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.allow_final_grade_override_option.click
|
||||
SRGB.select_student(@student)
|
||||
end
|
||||
|
||||
it "display override percent in individual gradebook", priority: "1" do
|
||||
expect(SRGB.final_grade_override.text).to include "97.1%"
|
||||
end
|
||||
|
||||
it "display override grade in individual gradebook", priority: "1" do
|
||||
expect(SRGB.final_grade_override_input).to have_value "A"
|
||||
end
|
||||
|
||||
it "saves overridden grade in SRGB", priority: "1" do
|
||||
SRGB.enter_override_grade("D-")
|
||||
expect(@enrollment.scores.find_by(course_score: true).override_score).to be 61.0
|
||||
end
|
||||
end
|
||||
|
||||
it "displays the override column", priority: "1" do
|
||||
user_session(@teacher)
|
||||
Gradebook.visit(@course)
|
||||
|
|
|
@ -155,86 +155,6 @@ describe "Excuse an Assignment" do
|
|||
end
|
||||
|
||||
shared_examples "Basic Behavior" do |view|
|
||||
context "Group Assignments", :group do
|
||||
it "preserves assignment excused status", priority: "1" do
|
||||
course_with_teacher_logged_in
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
group_test_setup 4, 1, 1
|
||||
|
||||
@students.each { |student| @testgroup[0].add_user student }
|
||||
@testgroup[0].save!
|
||||
|
||||
assignment = @course.assignments.create!(
|
||||
title: "Group Assignment",
|
||||
group_category_id: @group_category[0].id,
|
||||
grade_group_students_individually: false,
|
||||
points_possible: 20
|
||||
)
|
||||
|
||||
assignment.grade_student @students[1], excuse: true, grader: @teacher
|
||||
assignment.grade_student @students[0], grade: 15, grader: @teacher
|
||||
|
||||
score_values = []
|
||||
|
||||
if view == "srgb"
|
||||
get "/courses/#{@course.id}/gradebook/change_gradebook_version?version=srgb"
|
||||
click_option f("#assignment_select"), assignment.title
|
||||
next_student = f(".student_navigation button.next_object")
|
||||
4.times do
|
||||
next_student.click
|
||||
wait_for_ajaximations
|
||||
score_values << f("#student_and_assignment_grade").attribute("value")
|
||||
end
|
||||
else
|
||||
get "/courses/#{@course.id}/gradebook/"
|
||||
wait_for_ajaximations
|
||||
score_values = ff(".canvas_1 .slick-row .slick-cell:first-child").map(& :text)
|
||||
end
|
||||
expect(score_values).to eq %w[15 Excused 15 15]
|
||||
end
|
||||
|
||||
it "excuses assignments on individual basis", priority: "1" do
|
||||
course_with_teacher_logged_in
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
group_test_setup 2, 1, 1
|
||||
|
||||
@students.each { |student| @testgroup[0].add_user student }
|
||||
@testgroup[0].save!
|
||||
|
||||
a1 = @course.assignments.create!(
|
||||
title: "Group Assignment",
|
||||
group_category_id: @group_category[0].id,
|
||||
grade_group_students_individually: false,
|
||||
points_possible: 10
|
||||
)
|
||||
a2 = @course.assignments.create! title: "Assignment", points_possible: 20
|
||||
|
||||
@students.each do |student|
|
||||
a1.grade_student student, grade: 5, grader: @teacher
|
||||
a2.grade_student student, grade: 20, grader: @teacher
|
||||
end
|
||||
|
||||
a1.grade_student @students[1], excuse: true, grader: @teacher
|
||||
|
||||
totals = []
|
||||
if view == "srgb"
|
||||
get "/courses/#{@course.id}/gradebook/change_gradebook_version?version=srgb"
|
||||
next_student = f(".student_navigation button.next_object")
|
||||
2.times do
|
||||
next_student.click
|
||||
wait_for_ajaximations
|
||||
totals << f("span.total-grade").text[/\d+(\.\d+)?%/]
|
||||
end
|
||||
else
|
||||
get "/courses/#{@course.id}/gradebook/"
|
||||
wait_for_ajaximations
|
||||
totals = ff(".canvas_1 .slick-row .slick-cell:last-child").map(& :text)
|
||||
end
|
||||
|
||||
expect(totals).to eq(["83.33%", "100%"]).or eq ["83.3%", "100%"]
|
||||
end
|
||||
end
|
||||
|
||||
it "formats excused grade like dropped assignment", priority: "1" do
|
||||
assignment = @course.assignments.create! title: "Excuse Me", points_possible: 20
|
||||
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2017 - 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/>.
|
||||
|
||||
require_relative "../pages/gradebook_individual_view_page"
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
|
||||
describe "Late Policies:" do
|
||||
include_context "in-process server selenium tests"
|
||||
include GradebookCommon
|
||||
|
||||
include_context "late_policy_course_setup"
|
||||
|
||||
before(:once) do
|
||||
# create course with students, assignments, submissions and grades
|
||||
init_course_with_students(1)
|
||||
create_course_late_policy
|
||||
create_assignments
|
||||
make_submissions
|
||||
grade_assignments
|
||||
end
|
||||
|
||||
context "grade detail tray other" do
|
||||
before do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session(@teacher)
|
||||
GradebookIndividualViewPage.visit(@course.id)
|
||||
end
|
||||
|
||||
it "missing submission has missing pill removed after being graded" do
|
||||
GradebookIndividualViewPage.select_assignment(@a2)
|
||||
GradebookIndividualViewPage.select_student(@course.students.first)
|
||||
|
||||
expect(find_all_with_jquery(".missing-pill:contains('missing')").length).to eq 0
|
||||
end
|
||||
|
||||
it "late submission has late pill" do
|
||||
GradebookIndividualViewPage.select_assignment(@a1)
|
||||
GradebookIndividualViewPage.select_student(@course.students.first)
|
||||
|
||||
expect(GradebookIndividualViewPage.status_pill("late")).to be_displayed
|
||||
end
|
||||
|
||||
it "late submission has late penalty" do
|
||||
GradebookIndividualViewPage.select_assignment(@a1)
|
||||
GradebookIndividualViewPage.select_student(@course.students.first)
|
||||
|
||||
late_penalty_value = "-" + @course.students.first.submissions.find_by(assignment_id: @a1.id).points_deducted.to_s
|
||||
|
||||
# the data from rails and data from ui are not in the same format
|
||||
expect(GradebookIndividualViewPage.late_penalty_text.to_f.to_s).to eq late_penalty_value
|
||||
end
|
||||
|
||||
it "late submission has final grade" do
|
||||
GradebookIndividualViewPage.select_assignment(@a1)
|
||||
GradebookIndividualViewPage.select_student(@course.students.first)
|
||||
|
||||
final_grade_value = @course.students.first.submissions.find_by(assignment_id: @a1.id).published_grade
|
||||
expect(GradebookIndividualViewPage.late_policy_final_grade_text).to eq final_grade_value
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2017 - 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/>.
|
||||
|
||||
require_relative "../pages/srgb_page"
|
||||
require_relative "weighting_setup"
|
||||
require_relative "a_gradebook_shared_example"
|
||||
|
||||
describe.skip "individual view EVAL-4360 remove test file with FF individual_gradebook_enhancements" do
|
||||
include_context "in-process server selenium tests"
|
||||
include WeightingSetup
|
||||
|
||||
let(:total_grade) do
|
||||
user_session(@teacher)
|
||||
grading_period_titles = ["All Grading Periods", @gp1.title, @gp2.title]
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
if @grading_period_index
|
||||
SRGB.select_grading_period(grading_period_titles[@grading_period_index])
|
||||
refresh_page
|
||||
end
|
||||
SRGB.select_student(@student)
|
||||
SRGB.total_score
|
||||
end
|
||||
|
||||
let(:individual_view) { true }
|
||||
|
||||
before(:once) do
|
||||
weighted_grading_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
end
|
||||
|
||||
after do
|
||||
clear_local_storage
|
||||
end
|
||||
|
||||
it_behaves_like "a gradebook"
|
||||
end
|
|
@ -301,7 +301,7 @@ class EnhancedSRGB
|
|||
end
|
||||
|
||||
def visit(course_id)
|
||||
get "/courses/#{course_id}/gradebook/change_gradebook_version?version=individual_enhanced"
|
||||
get "/courses/#{course_id}/gradebook/change_gradebook_version?version=individual"
|
||||
end
|
||||
|
||||
def sort_assignments_by(sort_order)
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2018 - 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/>.
|
||||
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
require_relative "../pages/srgb_page"
|
||||
require_relative "../pages/speedgrader_page"
|
||||
|
||||
describe "Individual View Gradebook" do
|
||||
include_context "in-process server selenium tests"
|
||||
include GradebookCommon
|
||||
|
||||
before(:once) do
|
||||
# create a course with a teacher
|
||||
@teacher1 = course_with_teacher(course_name: "Course1", active_all: true).user
|
||||
|
||||
# enroll a second teacher
|
||||
@teacher2 = course_with_teacher(course: @course, name: "Teacher2", active_all: true).user
|
||||
|
||||
# enroll two students
|
||||
@student1 = course_with_student(course: @course, name: "Student1", active_all: true).user
|
||||
@student2 = course_with_student(course: @course, name: "Student2", active_all: true).user
|
||||
end
|
||||
|
||||
context "with a moderated assignment" do
|
||||
before(:once) do
|
||||
# create moderated assignment
|
||||
@moderated_assignment = @course.assignments.create!(
|
||||
title: "Moderated Assignment1",
|
||||
grader_count: 2,
|
||||
final_grader_id: @teacher1.id,
|
||||
grading_type: "points",
|
||||
points_possible: 15,
|
||||
submission_types: "online_text_entry",
|
||||
moderated_grading: true
|
||||
)
|
||||
|
||||
# give a grade as non-final grader
|
||||
@student1_submission = @moderated_assignment.grade_student(@student1, grade: 13, grader: @teacher2, provisional: true).first
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
end
|
||||
|
||||
before do
|
||||
# switch session to non-final-grader
|
||||
user_session(@teacher2)
|
||||
end
|
||||
|
||||
it "prevents unmuting the assignment before grades are posted", priority: "2" do
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_assignment(@moderated_assignment)
|
||||
wait_for_ajaximations
|
||||
scroll_into_view("#assignment_muted_check")
|
||||
|
||||
expect(SRGB.assignment_muted_checkbox.attribute("checked")).to eq "true"
|
||||
expect(SRGB.assignment_muted_checkbox.attribute("disabled")).to eq "true"
|
||||
end
|
||||
|
||||
it "prevents grading for the assignment before grades are posted", priority: "2" do
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_student(@student1)
|
||||
SRGB.select_assignment(@moderated_assignment)
|
||||
scroll_into_view("#student_and_assignment_grade")
|
||||
|
||||
expect(SRGB.main_grade_input.attribute("disabled")).to eq "true"
|
||||
end
|
||||
|
||||
context "when grades are posted" do
|
||||
before(:once) do
|
||||
@moderated_assignment.update!(grades_published_at: Time.zone.now)
|
||||
end
|
||||
|
||||
before do
|
||||
SRGB.visit(@course.id)
|
||||
end
|
||||
|
||||
it "allows grading for the assignment", priority: "2" do
|
||||
SRGB.select_student(@student1)
|
||||
SRGB.select_assignment(@moderated_assignment)
|
||||
|
||||
SRGB.enter_grade("15")
|
||||
expect(SRGB.current_grade).to eq "15"
|
||||
end
|
||||
|
||||
it "allows unmuting the assignment", priority: "2" do
|
||||
SRGB.select_assignment(@moderated_assignment)
|
||||
wait_for_ajaximations
|
||||
scroll_into_view("#assignment_muted_check")
|
||||
|
||||
expect(SRGB.assignment_muted_checkbox.attribute("disabled")).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with an anonymous assignment" do
|
||||
before(:once) do
|
||||
# create a new anonymous assignment
|
||||
@anonymous_assignment = @course.assignments.create!(
|
||||
title: "Anonymous Assignment",
|
||||
submission_types: "online_text_entry",
|
||||
anonymous_grading: true,
|
||||
points_possible: 10
|
||||
)
|
||||
|
||||
# create an unmuted anonymous assignment
|
||||
@unmuted_anonymous_assignment = @course.assignments.create!(
|
||||
title: "Unmuted Anon Assignment",
|
||||
submission_types: "online_text_entry",
|
||||
anonymous_grading: true,
|
||||
points_possible: 10
|
||||
)
|
||||
@unmuted_anonymous_assignment.unmute!
|
||||
end
|
||||
|
||||
before do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session(@teacher1)
|
||||
SRGB.visit(@course.id)
|
||||
end
|
||||
|
||||
it "excludes the muted assignment from the assignment list", priority: "1" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.select_student(@student1)
|
||||
SRGB.assignment_dropdown.click
|
||||
|
||||
# muted anonymous assignment is not displayed
|
||||
expect(SRGB.assignment_dropdown).not_to include_text "Anonymous Assignment"
|
||||
# unmuted anonymous assignment is displayed
|
||||
expect(SRGB.assignment_dropdown).to include_text "Unmuted Anon Assignment"
|
||||
end
|
||||
|
||||
it "hides student names in speedgrader", priority: "2" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
# Open speedgrader for the anonymous assignment
|
||||
SRGB.select_assignment(@anonymous_assignment)
|
||||
scroll_into_view("#assignment-speedgrader-link")
|
||||
wait_for_new_page_load(SRGB.speedgrader_link.click)
|
||||
|
||||
# open the student list dropdown
|
||||
Speedgrader.students_dropdown_button.click
|
||||
|
||||
# ensure the student names are anonymized
|
||||
student_names = Speedgrader.students_select_menu_list.map(&:text)
|
||||
expect(student_names).to match_array ["Student 1", "Student 2"]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2016 - 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/>.
|
||||
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
require_relative "../pages/srgb_page"
|
||||
|
||||
describe.skip "Screenreader Gradebook EVAL-4360 remove test file with FF individual_gradebook_enhancements" do
|
||||
include_context "in-process server selenium tests"
|
||||
include_context "reusable_gradebook_course"
|
||||
include GradebookCommon
|
||||
|
||||
let(:srgb_page) { SRGB }
|
||||
|
||||
let(:course_setup) do
|
||||
enroll_teacher_and_students
|
||||
assignment_1
|
||||
assignment_2
|
||||
student_submission
|
||||
assignment_1.grade_student(student, grade: 10, grader: teacher)
|
||||
end
|
||||
|
||||
before do
|
||||
course_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session(teacher)
|
||||
srgb_page.visit(test_course.id)
|
||||
srgb_page.select_student(student)
|
||||
end
|
||||
|
||||
it "toggles ungraded as 0 with correct grades", priority: "2" do
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
srgb_page.ungraded_as_zero.click
|
||||
expect(srgb_page.final_grade).to include_text("50%")
|
||||
|
||||
srgb_page.ungraded_as_zero.click
|
||||
expect(srgb_page.final_grade).to include_text("100%")
|
||||
end
|
||||
|
||||
it "hides student names", priority: "2" do
|
||||
srgb_page.hide_student_names.click
|
||||
expect(srgb_page.secondary_id_label).to include_text("hidden")
|
||||
end
|
||||
|
||||
it "shows conluded enrollments", priority: "2" do
|
||||
srgb_page.concluded_enrollments.click
|
||||
wait_for_ajaximations
|
||||
expect(srgb_page.student_dropdown).to include_text("Student, Concluded")
|
||||
end
|
||||
|
||||
it "shows notes in student info", priority: "2" do
|
||||
srgb_page.show_notes_option.click
|
||||
expect(srgb_page.notes_field).to be_present
|
||||
end
|
||||
end
|
|
@ -1,292 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2016 - 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/>.
|
||||
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
require_relative "../pages/srgb_page"
|
||||
require_relative "../setup/gradebook_setup"
|
||||
require_relative "../pages/gradebook_grade_detail_tray_page"
|
||||
|
||||
describe.skip "Screenreader Gradebook grading EVAL-4360 remove test file with FF individual_gradebook_enhancements" do
|
||||
include_context "in-process server selenium tests"
|
||||
include_context "reusable_gradebook_course"
|
||||
include GradebookCommon
|
||||
include GradebookSetup
|
||||
|
||||
let(:srgb_page) { SRGB }
|
||||
|
||||
let(:course_setup) do
|
||||
enroll_teacher_and_students
|
||||
assignment_1
|
||||
assignment_2
|
||||
assignment_2.update!(due_at: 2.days.ago, submission_types: "online_text_entry")
|
||||
assignment_3
|
||||
assignment_4
|
||||
student_submission
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
end
|
||||
|
||||
let(:login_to_srgb) do
|
||||
user_session(teacher)
|
||||
srgb_page.visit(test_course.id)
|
||||
srgb_page.select_student(student)
|
||||
end
|
||||
|
||||
let(:proxy_submit) do
|
||||
assignment_1.update!(submission_types: "online_upload")
|
||||
file_attachment = attachment_model(content_type: "application/pdf", context: student)
|
||||
submission = assignment_1.submit_homework(student, submission_type: "online_upload", attachments: [file_attachment])
|
||||
teacher.update!(short_name: "Test Teacher")
|
||||
submission.update!(proxy_submitter: teacher)
|
||||
end
|
||||
|
||||
let(:proxy_permission) do
|
||||
Account.site_admin.enable_feature!(:proxy_file_uploads)
|
||||
teacher_role = Role.get_built_in_role("TeacherEnrollment", root_account_id: Account.default.id)
|
||||
RoleOverride.create!(
|
||||
permission: "proxy_assignment_submission",
|
||||
enabled: true,
|
||||
role: teacher_role,
|
||||
account: @course.root_account
|
||||
)
|
||||
end
|
||||
|
||||
context "in Grades section" do
|
||||
before do
|
||||
course_setup
|
||||
login_to_srgb
|
||||
end
|
||||
|
||||
it "displays correct Grade for label on assignments" do
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
|
||||
expect(srgb_page.grade_for_label).to include_text("Grade for User - Points Assignment")
|
||||
end
|
||||
|
||||
it "displays correct Grade for: label on next assignment" do
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
srgb_page.next_assignment_button.click
|
||||
|
||||
expect(srgb_page.grade_for_label).to include_text("Grade for User - Percent Assignment")
|
||||
end
|
||||
|
||||
it "displays correct points for graded by Points" do
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, 8)
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(srgb_page.main_grade_input).to have_value("8")
|
||||
end
|
||||
|
||||
it "displays a flash message when an invalid grade is given and preserves the missing tag" do
|
||||
srgb_page.select_assignment(assignment_2)
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, "Invalid Grade")
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(f(".missing-pill")).to be_displayed
|
||||
expect_flash_message :error, "Invalid Grade"
|
||||
end
|
||||
|
||||
it "does not grade student when tabing over the grade input without editing" do
|
||||
srgb_page.select_assignment(assignment_2)
|
||||
srgb_page.main_grade_input.click
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(f(".missing-pill")).to be_displayed
|
||||
expect(srgb_page.main_grade_input).to have_value("-")
|
||||
end
|
||||
|
||||
it "excuses student when grade input is 'Excused'" do
|
||||
srgb_page.select_assignment(assignment_2)
|
||||
srgb_page.main_grade_input.clear
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, "Excused")
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(srgb_page.excuse_checkbox.attribute("checked")).to be_truthy
|
||||
expect(srgb_page.main_grade_input).to have_value("Excused")
|
||||
end
|
||||
|
||||
it "displays correct points for graded by Percent" do
|
||||
srgb_page.select_assignment(assignment_2)
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, 8)
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(srgb_page.main_grade_input).to have_value("80%")
|
||||
end
|
||||
|
||||
it "displays correct points for graded by Complete/Incomplete" do
|
||||
srgb_page.select_assignment(assignment_3)
|
||||
click_option("#student_and_assignment_grade", "Complete")
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(f("#grading div.ember-view")).to include_text("10 out of 10")
|
||||
end
|
||||
|
||||
it "displays correct points for graded by Letter Grade" do
|
||||
srgb_page.select_assignment(assignment_4)
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, 8)
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
expect(srgb_page.main_grade_input).to have_value("B-")
|
||||
end
|
||||
|
||||
it "displays submission details modal with correct grade" do
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, 8)
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
srgb_page.submission_details_button.click
|
||||
|
||||
expect(f(".submission_details_dialog .assignment-name")).to include_text(assignment_1.name)
|
||||
expect(fj(".submission_details_grade_form input:visible")).to have_value("8")
|
||||
end
|
||||
|
||||
it "updates grade in submission details modal" do
|
||||
skip("fragile")
|
||||
srgb_page.select_assignment(assignment_2)
|
||||
replace_content(srgb_page.main_grade_input, 8)
|
||||
srgb_page.submission_details_button.click
|
||||
|
||||
# change grade from 8 to 10 in the assignment details modal
|
||||
details_modal_grade_input = f(".submission_details_grade_form input")
|
||||
details_modal_grade_input.clear
|
||||
replace_content(details_modal_grade_input, 10)
|
||||
f("form.submission_details_grade_form button").click
|
||||
|
||||
expect(srgb_page.main_grade_input).to have_value("100%")
|
||||
end
|
||||
end
|
||||
|
||||
context "displays warning" do
|
||||
before do
|
||||
course_setup
|
||||
end
|
||||
|
||||
it "on late submissions" do
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
expect(f(".late-pill")).to include_text("LATE")
|
||||
expect(f(".submission_late_penalty")).to include_text("Late Penalty")
|
||||
expect(f(".submission_final_grade")).to include_text("Final Grade")
|
||||
end
|
||||
|
||||
it "on missing submissions" do
|
||||
assignment_1.submissions.find_by(user: student).update!(late_policy_status: "missing")
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
expect(f(".missing-pill")).to include_text("MISSING")
|
||||
end
|
||||
|
||||
it "on dropped assignments" do
|
||||
# create an assignment group with drop lowest 1 score rule
|
||||
srgb_page.drop_lowest(test_course, 1)
|
||||
|
||||
# grade a few assignments with one really low grade
|
||||
assignment_1.grade_student(student, grade: 3, grader: teacher)
|
||||
assignment_2.grade_student(student, grade: 10, grader: teacher)
|
||||
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
|
||||
# indicates assignment_1 was dropped
|
||||
expect(f(".dropped.muted")).to include_text("This grade is currently dropped for this student.")
|
||||
end
|
||||
|
||||
it "on resubmitted assignments" do
|
||||
# grade assignment
|
||||
assignment_1.grade_student(student, grade: 8, grader: teacher)
|
||||
|
||||
# resubmit as student
|
||||
Timecop.travel(1.hour.from_now) do
|
||||
assignment_1.submit_homework(
|
||||
student,
|
||||
submission_type: "online_text_entry",
|
||||
body: "re-submitting!"
|
||||
)
|
||||
end
|
||||
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
|
||||
# indicates assignment_1 was resubmitted
|
||||
expect(f(".resubmitted.muted")).to include_text("This assignment has been resubmitted")
|
||||
|
||||
# grade the assignment again
|
||||
srgb_page.grade_srgb_assignment(srgb_page.main_grade_input, 10)
|
||||
srgb_page.tab_out_of_input(srgb_page.main_grade_input)
|
||||
|
||||
# warning should be removed
|
||||
expect(f("#content")).not_to contain_css(".resubmitted.muted em")
|
||||
end
|
||||
end
|
||||
|
||||
context "with grading periods" do
|
||||
before do
|
||||
term_name = "First Term"
|
||||
create_grading_periods(term_name)
|
||||
add_teacher_and_student
|
||||
associate_course_to_term(term_name)
|
||||
user_session(@teacher)
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
end
|
||||
|
||||
it "assignment in ended gp should be gradable" do
|
||||
assignment = @course.assignments.create!(due_at: 13.days.ago, title: "assign in ended")
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_grading_period(@gp_ended.title)
|
||||
SRGB.select_student(@student)
|
||||
SRGB.select_assignment(assignment)
|
||||
SRGB.enter_grade(8)
|
||||
|
||||
expect(SRGB.current_grade).to eq "8"
|
||||
expect(Submission.where(assignment_id: assignment.id, user_id: @student.id).first.grade).to eq "8"
|
||||
end
|
||||
|
||||
it "assignment in closed gp should not be gradable" do
|
||||
assignment = @course.assignments.create!(due_at: 18.days.ago, title: "assign in closed")
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_grading_period(@gp_closed.title)
|
||||
SRGB.select_student(@student)
|
||||
SRGB.select_assignment(assignment)
|
||||
|
||||
expect(SRGB.grading_enabled?).to be false
|
||||
expect(Submission.not_placeholder.where(assignment_id: assignment.id, user_id: @student.id).first).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "submit for student" do
|
||||
before do
|
||||
enroll_teacher_and_students
|
||||
proxy_permission
|
||||
assignment_1.update!(submission_types: "online_upload")
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
end
|
||||
|
||||
it "displays submit for student button for file upload assignments" do
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
expect(srgb_page.submit_for_student_button).to include_text("Submit for Student")
|
||||
end
|
||||
|
||||
it "displays the submitter's identity for proxy submissions" do
|
||||
proxy_submit
|
||||
login_to_srgb
|
||||
srgb_page.select_assignment(assignment_1)
|
||||
expect(srgb_page.proxy_submitter_label).to include_text("Submitted by Test Teacher")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,468 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
require_relative "../pages/gradebook_cells_page"
|
||||
require_relative "../pages/srgb_page"
|
||||
require_relative "../pages/grading_curve_page"
|
||||
|
||||
describe "Screenreader Gradebook" do
|
||||
include_context "in-process server selenium tests"
|
||||
include_context "reusable_gradebook_course"
|
||||
include GradebookCommon
|
||||
|
||||
let(:default_gradebook) { "/courses/#{@course.id}/gradebook/change_gradebook_version?version=2" }
|
||||
let(:button_type_submit) { f(".button_type_submit") }
|
||||
let(:arrange_assignments) { f("#arrange_assignments") }
|
||||
|
||||
let(:assign1_default_points) { 1 }
|
||||
let(:assignment_default_points) { 20 }
|
||||
let(:grading_value) { f(".grading_value") }
|
||||
let(:gradebook_cell_css) { ".gradebook-cell" }
|
||||
let(:view_grading_history) { f("a[href='/courses/#{@course.id}/gradebook/history']") }
|
||||
|
||||
def active_element
|
||||
driver.switch_to.active_element
|
||||
end
|
||||
|
||||
def basic_percent_setup(num = 1)
|
||||
init_course_with_students num
|
||||
user_session(@teacher)
|
||||
@course.assignments.create!(
|
||||
title: "Test 1",
|
||||
submission_types: "online_text_entry",
|
||||
points_possible: 20,
|
||||
grading_type: "percent"
|
||||
)
|
||||
end
|
||||
|
||||
def basic_point_setup(num = 1)
|
||||
init_course_with_students num
|
||||
user_session(@teacher)
|
||||
@curve_assignment = @course.assignments.create!(
|
||||
title: "Test 1",
|
||||
submission_types: "online_text_entry",
|
||||
points_possible: 20,
|
||||
grading_type: "points"
|
||||
)
|
||||
end
|
||||
|
||||
def simple_setup(student_number = 2)
|
||||
init_course_with_students student_number
|
||||
user_session(@teacher)
|
||||
@course.assignment_groups.create! name: "Group 1"
|
||||
@course.assignment_groups.create! name: "Group 2"
|
||||
@assign1 = @course.assignments.create!(
|
||||
title: "Test 1",
|
||||
points_possible: assignment_default_points,
|
||||
assignment_group: @course.assignment_groups[0]
|
||||
)
|
||||
@assign2 = @course.assignments.create!(
|
||||
title: "Test 2",
|
||||
points_possible: assignment_default_points,
|
||||
assignment_group: @course.assignment_groups[1]
|
||||
)
|
||||
|
||||
@grade_array = %w[15 12 11 3]
|
||||
end
|
||||
|
||||
def simple_grade
|
||||
@assign1.grade_student(@students[0], grade: @grade_array[0], grader: @teacher)
|
||||
@assign1.grade_student(@students[1], grade: @grade_array[1], grader: @teacher)
|
||||
@assign2.grade_student(@students[0], grade: @grade_array[2], grader: @teacher)
|
||||
@assign2.grade_student(@students[1], grade: @grade_array[3], grader: @teacher)
|
||||
end
|
||||
|
||||
it "can select a student", priority: "1" do
|
||||
simple_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
simple_grade
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
student_dropdown_options = ["No Student Selected", @students[0].sortable_name, @students[1].sortable_name]
|
||||
expect(get_options("#student_select").map(&:text)).to eq student_dropdown_options
|
||||
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
assignment_points = ["(#{@grade_array[0]} / 20)", "(#{@grade_array[2]} / 20)"]
|
||||
expect(ff("#student_information .assignment-subtotal-grade .points").map(&:text)).to eq assignment_points
|
||||
|
||||
click_option "#student_select", @students[1].sortable_name
|
||||
assignment_points = ["(#{@grade_array[1]} / 20)", "(#{@grade_array[3]} / 20)"]
|
||||
expect(ff("#student_information .assignment-subtotal-grade .points").map(&:text)).to eq assignment_points
|
||||
end
|
||||
|
||||
it "can select a student using buttons", priority: "1" do
|
||||
init_course_with_students 3
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session(@teacher)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
# first student
|
||||
expect(SRGB.previous_student.attribute("disabled")).to be_truthy
|
||||
SRGB.next_student.click
|
||||
expect(f("#student_information .student_selection")).to include_text @students[0].name
|
||||
|
||||
# second student
|
||||
SRGB.next_student.click
|
||||
expect(f("#student_information .student_selection")).to include_text @students[1].name
|
||||
|
||||
# third student
|
||||
SRGB.next_student.click
|
||||
expect(SRGB.next_student.attribute("disabled")).to be_truthy
|
||||
expect(f("#student_information .student_selection")).to include_text @students[2].name
|
||||
expect(SRGB.previous_student).to eq driver.switch_to.active_element
|
||||
|
||||
# click twice to go back to first student
|
||||
SRGB.previous_student.click
|
||||
SRGB.previous_student.click
|
||||
expect(f("#student_information .student_selection")).to include_text @students[0].name
|
||||
expect(SRGB.next_student).to eq driver.switch_to.active_element
|
||||
end
|
||||
|
||||
it "can select an assignment using buttons", priority: "2" do
|
||||
simple_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_student(@students[0])
|
||||
SRGB.select_assignment(@assign1)
|
||||
|
||||
expect(SRGB.previous_assignment.attribute("disabled")).to be_truthy
|
||||
expect(SRGB.next_assignment.attribute("disabled")).not_to be_truthy
|
||||
|
||||
SRGB.next_assignment.click
|
||||
expect(SRGB.previous_assignment.attribute("disabled")).not_to be_truthy
|
||||
expect(SRGB.next_assignment.attribute("disabled")).to be_truthy
|
||||
|
||||
SRGB.previous_assignment.click
|
||||
expect(SRGB.previous_assignment.attribute("disabled")).to be_truthy
|
||||
end
|
||||
|
||||
it "links to assignment show page", priority: "2" do
|
||||
simple_setup
|
||||
simple_grade
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
@submission = @assign1.submit_homework(@students[0], body: "student submission")
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_student(@students[0])
|
||||
SRGB.select_assignment(@assign1)
|
||||
SRGB.assignment_link.click
|
||||
|
||||
expect(driver.current_url).to include("/courses/#{@course.id}/assignments/#{@assign1.id}")
|
||||
end
|
||||
|
||||
it "sets default grade", priority: "2" do
|
||||
skip_if_safari(:alert)
|
||||
num_of_students = 2
|
||||
simple_setup(num_of_students)
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_student(@students[0])
|
||||
SRGB.select_assignment(@assign1)
|
||||
|
||||
SRGB.default_grade.click
|
||||
replace_content(grading_value, assign1_default_points)
|
||||
button_type_submit.click
|
||||
accept_alert
|
||||
|
||||
get default_gradebook
|
||||
expect(Gradebook::Cells.get_grade(@students[0], @assign1)).to eq("1")
|
||||
expect(Gradebook::Cells.get_grade(@students[1], @assign1)).to eq("1")
|
||||
end
|
||||
|
||||
it "can select an assignment", priority: "1" do
|
||||
a1 = basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
a2 = @course.assignments.create!(
|
||||
title: "Test 2",
|
||||
points_possible: 20
|
||||
)
|
||||
|
||||
a1.grade_student(@students[0], grade: 14, grader: @teacher)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
expect(get_options("#assignment_select").map(&:text)).to eq ["No Assignment Selected", a1.name, a2.name]
|
||||
click_option "#assignment_select", a1.name
|
||||
expect(f("#assignment_information .assignment_selection")).to include_text a1.name
|
||||
expect(f("#assignment_information")).to include_text "Online text entry"
|
||||
end
|
||||
|
||||
it "displays/removes warning message for resubmitted assignments", priority: "1" do
|
||||
skip "Skipped because this spec fails if not run in foreground\n" \
|
||||
"This is believed to be the issue: https://code.google.com/p/selenium/issues/detail?id=7346"
|
||||
assignment = basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session @students[0]
|
||||
assignment.submit_homework @students[0], submission_type: "online_text_entry", body: "Hello!"
|
||||
|
||||
user_session @teacher
|
||||
assignment.grade_student(@students[0], grade: 12, grader: @teacher)
|
||||
|
||||
user_session @students[0]
|
||||
assignment.submit_homework @students[0], submission_type: "online_text_entry", body: "Hello again!"
|
||||
|
||||
user_session @teacher
|
||||
SRGB.visit(@course.id)
|
||||
click_option "#assignment_select", assignment.name
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
expect(f("p.resubmitted")).to be_displayed
|
||||
|
||||
replace_content f("#student_and_assignment_grade"), "15\t"
|
||||
expect(f("#content")).not_to contain_css("p.resubmitted")
|
||||
end
|
||||
|
||||
it "grades match default gradebook grades", priority: "1" do
|
||||
skip "Skipped because this spec fails if not run in foreground\n" \
|
||||
"This is believed to be the issue: https://code.google.com/p/selenium/issues/detail?id=7346"
|
||||
a1 = basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
a2 = @course.assignments.create!(
|
||||
title: "Test 2",
|
||||
points_possible: 20
|
||||
)
|
||||
|
||||
grades = [15, 12]
|
||||
|
||||
get "/courses/#{@course.id}/gradebook"
|
||||
f(".canvas_1 .slick-row .slick-cell").click
|
||||
f(".canvas_1 .slick-row .slick-cell .grade").send_keys grades[0], :return
|
||||
|
||||
SRGB.visit(@course.id)
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
click_option "#assignment_select", a1.name
|
||||
expect(f("#student_and_assignment_grade")).to have_value grades[0]
|
||||
expect(f("#student_information .total-grade")).to include_text "75% (#{grades[0]} / 20 points)"
|
||||
|
||||
click_option "#assignment_select", a2.name
|
||||
f("#student_and_assignment_grade").clear
|
||||
f("#student_and_assignment_grade").send_keys grades[1], :return
|
||||
get default_gradebook
|
||||
expect(f(".canvas_1 .slick-row .slick-cell:nth-of-type(2)")).to include_text grades[1]
|
||||
end
|
||||
|
||||
it "can mute assignments", priority: "1" do
|
||||
assignment = basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
assignment.unmute!
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
click_option "#assignment_select", assignment.name
|
||||
f("#assignment_muted_check").click
|
||||
fj('.ui-dialog:visible [data-action="mute"]').click
|
||||
wait_for_ajax_requests
|
||||
|
||||
get "/courses/#{@course.id}/grades/#{@students[0].id}"
|
||||
expect(f(".student_assignment.editable")).to have_attribute("data-muted", "true")
|
||||
end
|
||||
|
||||
it "can unmute assignments", priority: "1" do
|
||||
assignment = basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
assignment.mute!
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
click_option "#assignment_select", assignment.name
|
||||
f("#assignment_muted_check").click
|
||||
fj('.ui-dialog:visible [data-action="unmute"]').click
|
||||
wait_for_ajax_requests
|
||||
|
||||
get "/courses/#{@course.id}/grades/#{@students[0].id}"
|
||||
expect(f(".student_assignment.editable")).to have_attribute("data-muted", "false")
|
||||
end
|
||||
|
||||
it "can message students who...", priority: "1" do
|
||||
basic_percent_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
click_option "#assignment_select", "Test 1"
|
||||
f("#message_students").click
|
||||
expect(f("#message_students_dialog")).to be_displayed
|
||||
|
||||
f("#body").send_keys("Hello!")
|
||||
driver.action.send_keys(:tab).perform
|
||||
driver.action.send_keys(:enter).perform
|
||||
expect(f("#message_students_dialog")).not_to be_displayed
|
||||
end
|
||||
|
||||
it "has total graded submission", priority: "1" do
|
||||
assignment = basic_percent_setup 2
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
|
||||
assignment.grade_student(@students[0], grade: 15, grader: @teacher)
|
||||
assignment.grade_student(@students[1], grade: 5, grader: @teacher)
|
||||
|
||||
SRGB.visit(@course.id)
|
||||
click_option "#student_select", @students[0].sortable_name
|
||||
click_option "#assignment_select", assignment.name
|
||||
expect(f("#assignment_information p:nth-of-type(2)")).to include_text "Graded submissions: 2"
|
||||
expect(ff("#assignment_information table td").map(&:text)).to eq %w[20 10 15 5]
|
||||
end
|
||||
|
||||
context "as a teacher" do
|
||||
before(:once) do
|
||||
gradebook_data_setup
|
||||
end
|
||||
|
||||
before do
|
||||
user_session(@teacher)
|
||||
end
|
||||
|
||||
it "shows sections in drop-down", priority: "1" do
|
||||
sections = []
|
||||
2.times do |i|
|
||||
sections << @course.course_sections.create!(name: "other section #{i}")
|
||||
end
|
||||
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
ui_options = Selenium::WebDriver::Support::Select.new(f("#section_select")).options.map(&:text)
|
||||
sections.each do |section|
|
||||
expect(ui_options.include?(section[:name])).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it "shows history", priority: "2" do
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
view_grading_history.click
|
||||
expect(driver.page_source).to include("Gradebook History")
|
||||
expect(driver.current_url).to include("gradebook/history")
|
||||
end
|
||||
|
||||
it "shows all drop down options", priority: "2" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
arrange_assignments.click
|
||||
expect(arrange_assignments).to include_text("By Assignment Group and Position\nAlphabetically\nBy Due Date")
|
||||
end
|
||||
|
||||
it "keeps the assignment arrangement choice between reloads" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
%w[assignment_group alpha due_date].each do |assignment_order|
|
||||
SRGB.sort_assignments_by(assignment_order)
|
||||
refresh_page
|
||||
|
||||
expect(SRGB.assignment_sort_order).to eq(assignment_order)
|
||||
end
|
||||
end
|
||||
|
||||
it "focuses on accessible elements when setting default grades", priority: "1" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
skip_if_safari(:alert)
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_assignment(@second_assignment)
|
||||
|
||||
# When the modal opens the close button should have focus
|
||||
SRGB.default_grade.click
|
||||
focused_classes = active_element[:class].split
|
||||
expect(focused_classes).to include("ui-dialog-titlebar-close")
|
||||
|
||||
# When the modal closes by setting a grade
|
||||
# the "set default grade" button should have focus
|
||||
button_type_submit.click
|
||||
accept_alert
|
||||
check_element_has_focus(SRGB.default_grade)
|
||||
|
||||
# When the modal closes by the close button
|
||||
# the "set default grade" button should have focus
|
||||
driver.action.send_keys(:enter).perform # to open the modal
|
||||
driver.action.send_keys(:enter).perform # to close the modal
|
||||
check_element_has_focus(SRGB.default_grade)
|
||||
end
|
||||
|
||||
describe "Download Submissions Button" do
|
||||
let!(:change_first_assignment_to_media_recording) do
|
||||
@first_assignment.submission_types = "media_recording"
|
||||
@first_assignment.save
|
||||
end
|
||||
|
||||
let!(:change_third_assignment_to_include_media_and_have_submission) do
|
||||
@third_assignment.submission_types = "online_text_entry,media_recording"
|
||||
@third_assignment.save
|
||||
|
||||
submission = @third_assignment.submit_homework(@student_1, body: "Can you click?")
|
||||
submission.save!
|
||||
end
|
||||
|
||||
# The Download Submission button should be displayed for online_upload,
|
||||
# online_text_entry, online_url, and online_quiz assignments. It should
|
||||
# not be displayed for any other types.
|
||||
it "is displayed for online assignments" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
click_option "#assignment_select", "second assignment"
|
||||
|
||||
expect(f("#submissions_download_button")).to be_present
|
||||
end
|
||||
|
||||
it "is not displayed for assignments which are not submitted online" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
|
||||
click_option "#assignment_select", @assignment.name
|
||||
|
||||
expect(f("#content")).not_to contain_css("#submissions_download_button")
|
||||
end
|
||||
|
||||
it "is displayed for assignments which allow both online and non-online submittion" do
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
SRGB.visit(@course.id)
|
||||
click_option "#assignment_select", "assignment three"
|
||||
|
||||
expect(f("#submissions_download_button")).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "curving grades" do
|
||||
it "curves grades", priority: "1" do
|
||||
skip_if_safari(:alert)
|
||||
basic_point_setup 3
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
|
||||
grades = [12, 10, 11]
|
||||
3.times { |num| @curve_assignment.grade_student(@students[num], grade: grades[num], grader: @teacher) }
|
||||
|
||||
SRGB.visit(@course.id)
|
||||
SRGB.select_assignment(@curve_assignment)
|
||||
|
||||
SRGB.curve_grade_button.click
|
||||
assignment_name = @curve_assignment.name
|
||||
# verify that the modal pops up
|
||||
curve_form = GradingCurvePage.new
|
||||
expect(curve_form.grading_curve_dialog_title.text).to eq "Curve Grade for #{assignment_name}"
|
||||
|
||||
curve_value = "10"
|
||||
curve_form.edit_grade_curve(curve_value)
|
||||
curve_form.curve_grade_submit
|
||||
accept_alert
|
||||
|
||||
assignment_score = SRGB.assignment_scores.text.split
|
||||
# assignment avg score, high score, low score
|
||||
scores_as_string = %w[13 20 8]
|
||||
3.times { |num| expect(assignment_score[num + 1]).to eq(scores_as_string[num]) }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,86 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2016 - 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/>.
|
||||
|
||||
require_relative "../../helpers/gradebook_common"
|
||||
require_relative "../pages/srgb_page"
|
||||
require_relative "../pages/gradebook_cells_page"
|
||||
|
||||
describe "Screenreader Gradebook Student Information" do
|
||||
include_context "in-process server selenium tests"
|
||||
include_context "reusable_gradebook_course"
|
||||
include GradebookCommon
|
||||
|
||||
let(:srgb_page) { SRGB }
|
||||
let(:course_setup) do
|
||||
enroll_teacher_and_students
|
||||
assignment_1
|
||||
assignment_5
|
||||
student_submission
|
||||
assignment_1.grade_student(student, grade: 3, grader: teacher)
|
||||
end
|
||||
|
||||
context "in Student Information section" do
|
||||
before do
|
||||
course_setup
|
||||
@course.root_account.disable_feature!(:individual_gradebook_enhancements)
|
||||
user_session(teacher)
|
||||
srgb_page.visit(test_course.id)
|
||||
end
|
||||
|
||||
it "allows comments in Notes field", priority: "2" do
|
||||
skip_if_chrome("fails in chrome - due to replace content")
|
||||
srgb_page.select_student(student)
|
||||
srgb_page.show_notes_option.click
|
||||
replace_content(srgb_page.notes_field, "Good job!")
|
||||
srgb_page.tab_out_of_input(srgb_page.notes_field)
|
||||
|
||||
expect(srgb_page.notes_field).to have_value("Good job!")
|
||||
end
|
||||
|
||||
it "displays student's grades", priority: "2" do
|
||||
srgb_page.select_student(student)
|
||||
expect(srgb_page.final_grade.text).to eq("30% (3 / 10 points)")
|
||||
expect(srgb_page.assign_subtotal_grade.text).to eq("30% (3 / 10)")
|
||||
expect_new_page_load { srgb_page.switch_to_default_gradebook }
|
||||
expect(Gradebook::Cells.get_total_grade(student)).to eq("30%")
|
||||
end
|
||||
|
||||
context "displays no points possible warning" do
|
||||
before do
|
||||
@course.apply_assignment_group_weights = true
|
||||
@course.save!
|
||||
srgb_page.visit(test_course.id)
|
||||
end
|
||||
|
||||
it "with only a student selected", priority: "2" do
|
||||
srgb_page.select_student(student)
|
||||
|
||||
expect(f("span.text-error > i.icon-warning")).to be_displayed
|
||||
expect(f("#student_information > div.row-fluid")).to include_text("Score does not include assignments from the group")
|
||||
end
|
||||
|
||||
it "with only an assignment is selected", priority: "2" do
|
||||
srgb_page.select_assignment(assignment_5)
|
||||
|
||||
expect(f("a > i.icon-warning")).to be_displayed
|
||||
expect(f("#assignment_information > div.row-fluid")).to include_text("Assignments in this group have no points")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"imports": {
|
||||
"#params": "./params.js",
|
||||
"#webpack-ember-handlebars-loader": "./webpack/emberHandlebars.js",
|
||||
"#webpack-i18nliner-handlebars-loader": "./webpack/i18nLinerHandlebars.js"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,11 +88,6 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.hbs$/,
|
||||
include: [path.join(canvasDir, 'ui/features/screenreader_gradebook/jst')],
|
||||
use: [require.resolve('#webpack-ember-handlebars-loader')],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
/* eslint-disable import/no-unresolved */
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// This is basically one big port of what we do in ruby-land in the
|
||||
// handlebars-tasks gem. We need to run handlebars source through basic
|
||||
// compilation to extract i18nliner scopes, and then we wrap the resulting
|
||||
// template in an AMD module, giving it dependencies on handlebars, it's scoped
|
||||
// i18n object if it needs one, and any brandableCss variant stuff it needs.
|
||||
|
||||
const path = require('path')
|
||||
const Handlebars = require('handlebars')
|
||||
const EmberHandlebars = require('ember-template-compiler').EmberHandlebars
|
||||
const {readI18nScopeFromJSONFile} = require('@instructure/i18nliner-canvas/scoped_hbs_resolver')
|
||||
const ScopedHbsExtractor = require('@instructure/i18nliner-canvas/scoped_hbs_extractor')
|
||||
const ScopedHbsPreProcessor = require('@instructure/i18nliner-canvas/scoped_hbs_pre_processor')
|
||||
const {canvasDir} = require('../params')
|
||||
|
||||
function compileHandlebars(data) {
|
||||
const {path, source} = data
|
||||
try {
|
||||
let translationCount = 0
|
||||
const ast = Handlebars.parse(source)
|
||||
const scope = readI18nScopeFromJSONFile(path)
|
||||
const extractor = new ScopedHbsExtractor(ast, {path, scope})
|
||||
ScopedHbsPreProcessor.processWithScope(scope, ast)
|
||||
extractor.forEach(() => translationCount++)
|
||||
|
||||
const precompiler = data.ember ? EmberHandlebars : Handlebars
|
||||
const template = precompiler.precompile(ast).toString()
|
||||
const payload = {template, scope, translationCount}
|
||||
return payload
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-ex-assign
|
||||
e = e.message || e
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e)
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {error: e}
|
||||
}
|
||||
}
|
||||
|
||||
function emitTemplate({name, template, dependencies}) {
|
||||
return `
|
||||
import Ember from 'ember';
|
||||
${dependencies.map(d => `import ${JSON.stringify(d)};`).join('\n')}
|
||||
|
||||
const template = Ember.Handlebars.template(${template});
|
||||
Ember.TEMPLATES['${name}'] = template;
|
||||
export default template;
|
||||
`
|
||||
}
|
||||
|
||||
const withLeadingDotSlash = x => (x.startsWith('.') ? x : `./${x}`)
|
||||
const emberHelpers = path.resolve(
|
||||
canvasDir,
|
||||
'ui/features/screenreader_gradebook/ember/helpers/common.js'
|
||||
)
|
||||
const emberJSTRoot = path.resolve(canvasDir, 'ui/features/screenreader_gradebook/jst')
|
||||
|
||||
module.exports = function (source) {
|
||||
this.cacheable()
|
||||
|
||||
const pathFromMeToEmberHelpers = withLeadingDotSlash(path.relative(this.context, emberHelpers))
|
||||
|
||||
const name = this.resourcePath.slice(emberJSTRoot.length + 1).replace(/\.hbs$/, '')
|
||||
const dependencies = [pathFromMeToEmberHelpers]
|
||||
|
||||
const result = compileHandlebars({path: this.resourcePath, source, ember: true})
|
||||
|
||||
if (result.error) {
|
||||
console.log('THERE WAS AN ERROR IN PRECOMPILATION', result)
|
||||
throw result
|
||||
}
|
||||
|
||||
if (result.translationCount > 0) {
|
||||
dependencies.push('@canvas/i18n')
|
||||
}
|
||||
|
||||
return emitTemplate({name, template: result.template, dependencies})
|
||||
}
|
|
@ -23,7 +23,6 @@
|
|||
// template in an AMD module, giving it dependencies on handlebars, it's scoped
|
||||
// i18n object if it needs one.
|
||||
const Handlebars = require('handlebars')
|
||||
const {EmberHandlebars} = require('ember-template-compiler')
|
||||
const ScopedHbsExtractor = require('@instructure/i18nliner-canvas/scoped_hbs_extractor')
|
||||
const ScopedHbsPreProcessor = require('@instructure/i18nliner-canvas/scoped_hbs_pre_processor')
|
||||
const {readI18nScopeFromJSONFile} = require('@instructure/i18nliner-canvas/scoped_hbs_resolver')
|
||||
|
@ -44,7 +43,7 @@ const compileHandlebars = data => {
|
|||
ScopedHbsPreProcessor.processWithScope(scope, ast)
|
||||
extractor.forEach(() => translationCount++)
|
||||
|
||||
const precompiler = data.ember ? EmberHandlebars : Handlebars
|
||||
const precompiler = Handlebars
|
||||
const template = precompiler.precompile(ast).toString()
|
||||
return {template, scope, translationCount}
|
||||
} catch (e) {
|
||||
|
|
|
@ -33,7 +33,6 @@ const isDev = process.env.NODE_ENV === 'development'
|
|||
const {
|
||||
swc,
|
||||
css,
|
||||
emberHandlebars,
|
||||
fonts,
|
||||
handlebars,
|
||||
images,
|
||||
|
@ -190,7 +189,6 @@ module.exports = {
|
|||
fonts,
|
||||
...swc,
|
||||
handlebars,
|
||||
emberHandlebars,
|
||||
].filter(Boolean),
|
||||
},
|
||||
|
||||
|
|
|
@ -171,12 +171,6 @@ exports.handlebars = {
|
|||
],
|
||||
}
|
||||
|
||||
exports.emberHandlebars = {
|
||||
test: /\.hbs$/,
|
||||
include: [join(canvasDir, 'ui/features/screenreader_gradebook/jst')],
|
||||
use: [require.resolve('./emberHandlebars')],
|
||||
}
|
||||
|
||||
// since istanbul-instrumenter-loader adds so much overhead,
|
||||
// only use it when generating crystalball map
|
||||
// i.e. process.env.CRYSTALBALL_MAP === '1'
|
||||
|
|
|
@ -187,7 +187,6 @@ const featureBundles: {
|
|||
rubric_assessment: () => import('./features/rubric_assessment/index'),
|
||||
rubrics_index: () => import('./features/rubrics_index/index'),
|
||||
rubrics_show: () => import('./features/rubrics_show/index'),
|
||||
screenreader_gradebook: () => import('./features/screenreader_gradebook/index'),
|
||||
search: () => import('./features/search/index'),
|
||||
section: () => import('./features/section/index'),
|
||||
select_content_dialog: () => import('./features/select_content_dialog/index'),
|
||||
|
|
|
@ -57,9 +57,6 @@ export default function EnhancedIndividualGradebookWrapper() {
|
|||
<GradebookMenu
|
||||
courseUrl={ENV.GRADEBOOK_OPTIONS.context_url}
|
||||
learningMasteryEnabled={Boolean(ENV.GRADEBOOK_OPTIONS.outcome_gradebook_enabled)}
|
||||
enhancedIndividualGradebookEnabled={Boolean(
|
||||
ENV.GRADEBOOK_OPTIONS.individual_gradebook_enhancements
|
||||
)}
|
||||
variant="EnhancedIndividualGradebook"
|
||||
/>
|
||||
<ApolloProvider client={client}>
|
||||
|
|
|
@ -5192,7 +5192,6 @@ class Gradebook extends React.Component<GradebookProps, GradebookState> {
|
|||
<Portal node={this.props.gradebookMenuNode}>
|
||||
<GradebookMenu
|
||||
courseUrl={this.options.context_url}
|
||||
enhancedIndividualGradebookEnabled={this.options.individual_gradebook_enhancements}
|
||||
learningMasteryEnabled={this.options.outcome_gradebook_enabled}
|
||||
variant="DefaultGradebook"
|
||||
/>
|
||||
|
|
|
@ -144,7 +144,6 @@ export type GradebookOptions = {
|
|||
grading_standard_points_based: boolean
|
||||
group_weighting_scheme: null | string
|
||||
has_modules: boolean
|
||||
individual_gradebook_enhancements: boolean
|
||||
late_policy: LatePolicy | null
|
||||
login_handle_name: null | string
|
||||
message_attachment_upload_folder_id: string
|
||||
|
|
|
@ -26,7 +26,6 @@ ready(() => {
|
|||
<GradebookHistoryApp
|
||||
courseUrl={ENV.COURSE_URL}
|
||||
learningMasteryEnabled={ENV.OUTCOME_GRADEBOOK_ENABLED}
|
||||
enhancedIndividualGradebookEnabled={ENV.individual_gradebook_enhancements}
|
||||
/>,
|
||||
document.getElementById('content')
|
||||
)
|
||||
|
|
|
@ -31,14 +31,9 @@ const I18n = useI18nScope('gradebook_history')
|
|||
type Props = {
|
||||
courseUrl: string
|
||||
learningMasteryEnabled?: boolean
|
||||
enhancedIndividualGradebookEnabled?: boolean
|
||||
}
|
||||
|
||||
const GradebookHistoryApp = ({
|
||||
courseUrl,
|
||||
learningMasteryEnabled,
|
||||
enhancedIndividualGradebookEnabled,
|
||||
}: Props) => (
|
||||
const GradebookHistoryApp = ({courseUrl, learningMasteryEnabled}: Props) => (
|
||||
<Provider store={GradebookHistoryStore}>
|
||||
<div>
|
||||
<h1 className="screenreader-only">{I18n.t('Gradebook History')}</h1>
|
||||
|
@ -51,7 +46,6 @@ const GradebookHistoryApp = ({
|
|||
>
|
||||
<GradebookMenu
|
||||
courseUrl={courseUrl}
|
||||
enhancedIndividualGradebookEnabled={enhancedIndividualGradebookEnabled}
|
||||
learningMasteryEnabled={learningMasteryEnabled}
|
||||
variant="GradebookHistory"
|
||||
/>
|
||||
|
|
|
@ -109,9 +109,6 @@ export default class LearningMastery {
|
|||
const props = {
|
||||
courseUrl: this.options.context_url,
|
||||
learningMasteryEnabled: true,
|
||||
enhancedIndividualGradebookEnabled: Boolean(
|
||||
ENV.GRADEBOOK_OPTIONS.individual_gradebook_enhancements
|
||||
),
|
||||
variant: 'DefaultGradebookLearningMastery',
|
||||
}
|
||||
ReactDOM.render(<GradebookMenu {...props} />, $container)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ember/helpers/t.js
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 - 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 'jquery-migrate'
|
||||
import GradebookHelpers from '../helpers'
|
||||
import GradebookConstants from '../constants'
|
||||
|
||||
QUnit.module('GradebookHelpers#noErrorsOnPage', {
|
||||
setup() {
|
||||
sandbox.stub($, 'find')
|
||||
},
|
||||
})
|
||||
|
||||
test('noErrorsOnPage returns true when the dom has no errors', () => {
|
||||
$.find.returns([])
|
||||
ok(GradebookHelpers.noErrorsOnPage())
|
||||
})
|
||||
|
||||
test('noErrorsOnPage returns false when the dom contains errors', () => {
|
||||
$.find.returns(['dom element with error message'])
|
||||
notOk(GradebookHelpers.noErrorsOnPage())
|
||||
})
|
||||
|
||||
QUnit.module('GradebookHelpers#textareaIsGreaterThanMaxLength')
|
||||
|
||||
test('textareaIsGreaterThanMaxLength is false at exactly the max allowed length', () =>
|
||||
notOk(GradebookHelpers.textareaIsGreaterThanMaxLength(GradebookConstants.MAX_NOTE_LENGTH)))
|
||||
|
||||
test('textareaIsGreaterThanMaxLength is true at greater than the max allowed length', () =>
|
||||
ok(GradebookHelpers.textareaIsGreaterThanMaxLength(GradebookConstants.MAX_NOTE_LENGTH + 1)))
|
||||
|
||||
QUnit.module('GradebookHelpers#maxLengthErrorShouldBeShown', {
|
||||
setup() {
|
||||
sandbox.stub($, 'find')
|
||||
},
|
||||
})
|
||||
|
||||
test('maxLengthErrorShouldBeShown is false when text length is exactly the max allowed length', () =>
|
||||
notOk(GradebookHelpers.maxLengthErrorShouldBeShown(GradebookConstants.MAX_NOTE_LENGTH)))
|
||||
|
||||
test('maxLengthErrorShouldBeShown is false when there are DOM errors', () => {
|
||||
$.find.returns(['dom element with error message'])
|
||||
notOk(GradebookHelpers.maxLengthErrorShouldBeShown(GradebookConstants.MAX_NOTE_LENGTH + 1))
|
||||
})
|
||||
|
||||
test(
|
||||
'maxLengthErrorShouldBeShown is true when text length is greater than' +
|
||||
'the max allowed length AND there are no DOM errors',
|
||||
() => {
|
||||
$.find.returns([])
|
||||
ok(GradebookHelpers.maxLengthErrorShouldBeShown(GradebookConstants.MAX_NOTE_LENGTH + 1))
|
||||
}
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 - 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/>.
|
||||
*/
|
||||
|
||||
const constants = {
|
||||
MAX_NOTE_LENGTH: 255,
|
||||
}
|
||||
|
||||
export default constants
|
|
@ -1,79 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
import AssignmentMuter from '../../jquery/AssignmentMuter'
|
||||
|
||||
const I18n = useI18nScope('sr_gradebook')
|
||||
|
||||
// http://emberjs.com/guides/components/
|
||||
// http://emberjs.com/api/classes/Ember.Component.html
|
||||
|
||||
const AssignmentMuterComponent = Ember.Component.extend({
|
||||
click(e) {
|
||||
e.preventDefault()
|
||||
if (this.get('assignment.muted')) {
|
||||
this.unmute()
|
||||
} else {
|
||||
this.mute()
|
||||
}
|
||||
},
|
||||
mute() {
|
||||
return AssignmentMuter.prototype.showDialog.call(this.muter)
|
||||
},
|
||||
unmute() {
|
||||
return AssignmentMuter.prototype.confirmUnmute.call(this.muter)
|
||||
},
|
||||
|
||||
tagName: 'input',
|
||||
type: 'checkbox',
|
||||
attributeBindings: ['type', 'checked', 'ariaLabel:aria-label', 'disabled'],
|
||||
|
||||
checked: function () {
|
||||
return this.get('assignment.muted')
|
||||
}.property('assignment.muted'),
|
||||
|
||||
ariaLabel: function () {
|
||||
if (this.get('assignment.muted')) {
|
||||
return I18n.t('assignment_muted', 'Click to unmute.')
|
||||
} else {
|
||||
return I18n.t('assignment_unmuted', 'Click to mute.')
|
||||
}
|
||||
}.property('assignment.muted'),
|
||||
|
||||
disabled: function () {
|
||||
return (
|
||||
this.get('assignment.muted') &&
|
||||
this.get('assignment.moderated_grading') &&
|
||||
!this.get('assignment.grades_published')
|
||||
)
|
||||
}.property('assignment.muted', 'assignment.moderated_grading', 'assignment.grades_published'),
|
||||
|
||||
setup: function () {
|
||||
let assignment
|
||||
if ((assignment = this.get('assignment'))) {
|
||||
const url = `${ENV.GRADEBOOK_OPTIONS.context_url}/assignments/${assignment.id}/mute`
|
||||
this.muter = new AssignmentMuter(null, assignment, url, Ember.set)
|
||||
this.muter.show()
|
||||
}
|
||||
}
|
||||
.observes('assignment')
|
||||
.on('init'),
|
||||
})
|
||||
|
||||
export default AssignmentMuterComponent
|
|
@ -1,91 +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 I18n from '@canvas/i18n'
|
||||
import Ember from 'ember'
|
||||
import round from '@canvas/round'
|
||||
import {scoreToGrade} from '@instructure/grading-utils'
|
||||
import {scoreToPercentage, scoreToScaledPoints} from '@canvas/grading/GradeCalculationHelper'
|
||||
|
||||
const AssignmentSubtotalGradesComponent = Ember.Component.extend({
|
||||
tagName: '',
|
||||
subtotal: null,
|
||||
student: null,
|
||||
weightingScheme: null,
|
||||
gradingStandard: null,
|
||||
hasGrade: Ember.computed.bool('values.possible'),
|
||||
hasWeightedGroups: Ember.computed.equal('weightingScheme', 'percent'),
|
||||
|
||||
letterGrade: function () {
|
||||
const standard = this.get('gradingStandard')
|
||||
if (!standard || !this.get('hasGrade')) {
|
||||
return null
|
||||
}
|
||||
const percentage = parseFloat(this.get('rawPercent').toPrecision(4))
|
||||
return scoreToGrade(percentage, standard)
|
||||
}.property('gradingStandard', 'hasGrade'),
|
||||
|
||||
values: function () {
|
||||
const student = this.get('student')
|
||||
return Ember.get(student, `${this.get('subtotal.key')}`)
|
||||
}.property('subtotal', 'student', 'student.total_grade'),
|
||||
|
||||
points: function () {
|
||||
const values = this.get('values')
|
||||
return `${I18n.n(round(values.score, round.DEFAULT))} / ${I18n.n(
|
||||
round(values.possible, round.DEFAULT)
|
||||
)}`
|
||||
}.property('values'),
|
||||
|
||||
rawPercent: function () {
|
||||
const values = this.get('values')
|
||||
return scoreToPercentage(values.score, values.possible)
|
||||
}.property('values'),
|
||||
|
||||
percent: function () {
|
||||
let scoreText = I18n.n(round(this.get('rawPercent'), round.DEFAULT), {percentage: true})
|
||||
|
||||
if (this.get('gradingStandard') && this.get('gradingStandardPointsBased')) {
|
||||
const scalingFactor = this.get('gradingStandardScalingFactor')
|
||||
const values = this.get('values')
|
||||
if (values.possible) {
|
||||
const scaledPossible = I18n.n(scalingFactor, {
|
||||
precision: 1,
|
||||
})
|
||||
const scaledScore = I18n.n(
|
||||
scoreToScaledPoints(values.score, values.possible, scalingFactor),
|
||||
{
|
||||
precision: 1,
|
||||
}
|
||||
)
|
||||
scoreText = `${scaledScore} / ${scaledPossible}`
|
||||
}
|
||||
}
|
||||
return scoreText
|
||||
}.property('values'),
|
||||
|
||||
scoreDetail: function () {
|
||||
const points = this.get('points')
|
||||
return `(${points})`
|
||||
}.property('points'),
|
||||
|
||||
weight: function () {
|
||||
return I18n.n(this.get('subtotal').weight, {percentage: true})
|
||||
}.property('subtotal'),
|
||||
})
|
||||
|
||||
export default AssignmentSubtotalGradesComponent
|
|
@ -1,102 +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 Ember from 'ember'
|
||||
import GradebookHelpers from '../../helpers'
|
||||
import GradebookConstants from '../../constants'
|
||||
|
||||
const CustomColumnCellComponent = Ember.Component.extend({
|
||||
column: null,
|
||||
student: null,
|
||||
dataForStudent: null,
|
||||
id: function () {
|
||||
return `custom_col_${this.get('column.id')}`
|
||||
}.property('column'),
|
||||
|
||||
dataForColumn: function () {
|
||||
const studentData = this.get('dataForStudent')
|
||||
if (!studentData) {
|
||||
return null
|
||||
}
|
||||
return studentData.findBy('column_id', this.get('column.id'))
|
||||
}.property('student', 'column', 'column.isLoaded', 'dataForStudent.@each.content'),
|
||||
|
||||
contentDidChange: function () {
|
||||
return this.set('value', this.get('dataForColumn.content'))
|
||||
}
|
||||
.observes('dataForColumn.content')
|
||||
.on('didInsertElement'),
|
||||
|
||||
ajax(url, options) {
|
||||
const {type, data} = options
|
||||
return Ember.$.ajaxJSON(url, type, data)
|
||||
},
|
||||
|
||||
customColURL() {
|
||||
return ENV.GRADEBOOK_OPTIONS.custom_column_datum_url
|
||||
},
|
||||
|
||||
disabled: function () {
|
||||
return this.get('column.isLoading') || this.get('column.read_only')
|
||||
}.property('column', 'column.isLoading', 'column.read_only'),
|
||||
|
||||
saveURL: function () {
|
||||
return this.customColURL()
|
||||
.replace(/:id/, this.get('column.id'))
|
||||
.replace(/:user_id/, this.get('student.id'))
|
||||
}.property('column', 'student'),
|
||||
|
||||
focusOut() {
|
||||
const value = this.$('textarea').val()
|
||||
if (
|
||||
(value === '' && !this.get('dataForColumn')) ||
|
||||
value === this.get('dataForColumn.content')
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.get('dataForColumn.content')
|
||||
const xhr = this.ajax(this.get('saveURL'), {
|
||||
type: 'PUT',
|
||||
data: {
|
||||
'column_data[content]': value,
|
||||
},
|
||||
})
|
||||
|
||||
return xhr.then(this.boundSaveSuccess)
|
||||
},
|
||||
|
||||
textAreaInput: function (event) {
|
||||
const note = event.target.value
|
||||
if (GradebookHelpers.textareaIsGreaterThanMaxLength(note.length)) {
|
||||
event.target.value = note.substring(0, GradebookConstants.MAX_NOTE_LENGTH)
|
||||
const showError = GradebookHelpers.maxLengthErrorShouldBeShown(note.length)
|
||||
if (showError) {
|
||||
return GradebookHelpers.flashMaxLengthError()
|
||||
}
|
||||
}
|
||||
}.on('input'),
|
||||
|
||||
bindSave: function () {
|
||||
return (this.boundSaveSuccess = this.onSaveSuccess.bind(this))
|
||||
}.on('init'),
|
||||
|
||||
onSaveSuccess(columnDatum) {
|
||||
return this.sendAction('on-column-save', columnDatum, this.get('column.id'))
|
||||
},
|
||||
})
|
||||
|
||||
export default CustomColumnCellComponent
|
|
@ -1,170 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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/>.
|
||||
|
||||
// converted to coffeescript from:
|
||||
// https://gist.github.com/kselden/7758990
|
||||
|
||||
import {Component, get, set} from 'ember'
|
||||
|
||||
const doc = document
|
||||
|
||||
const FastSelectComponent = Component.extend({
|
||||
initialized: false,
|
||||
items: null,
|
||||
valuePath: 'value',
|
||||
labelPath: 'label',
|
||||
labelDefault: null,
|
||||
valueDefault: '',
|
||||
value: null,
|
||||
selected: null,
|
||||
ariaDescribedBy: null,
|
||||
|
||||
tagName: 'select',
|
||||
|
||||
didInsertElement() {
|
||||
const self = this
|
||||
if (this.get('ariaDescribedBy')) {
|
||||
this.$().attr('aria-describedby', this.get('ariaDescribedBy'))
|
||||
}
|
||||
return this.$().on('change', function () {
|
||||
return set(self, 'value', this.value)
|
||||
})
|
||||
},
|
||||
|
||||
valueDidChange: function () {
|
||||
let selected = null
|
||||
if (this.value && this.items) {
|
||||
selected = this.items.findBy(this.valuePath, this.value)
|
||||
}
|
||||
set(this, 'selected', selected || null)
|
||||
}.observes('value'),
|
||||
|
||||
initialize: function () {
|
||||
const value = this.value || this.valueDefault
|
||||
let selected
|
||||
if (value && this.items) {
|
||||
selected = this.items.findBy(this.valuePath, value)
|
||||
}
|
||||
set(this, 'selected', selected || null)
|
||||
}.on('init'),
|
||||
|
||||
itemsWillChange: function () {
|
||||
const {items} = this
|
||||
if (items) {
|
||||
items.removeArrayObserver(this)
|
||||
this.arrayWillChange(items, 0, get(items, 'length'), 0)
|
||||
}
|
||||
}
|
||||
.observesBefore('items')
|
||||
.on('willDestroyElement'),
|
||||
|
||||
itemsDidChange: function () {
|
||||
const {items} = this
|
||||
if (items) {
|
||||
items.addArrayObserver(this)
|
||||
this.arrayDidChange(items, 0, 0, get(items, 'length'))
|
||||
}
|
||||
}
|
||||
.observes('items')
|
||||
.on('didInsertElement'),
|
||||
|
||||
arrayWillChange(items, start, removeCount, _addCount) {
|
||||
const select = get(this, 'element')
|
||||
const options = select.childNodes
|
||||
let i = start + removeCount - 1
|
||||
if (get(this, 'hasDefaultOption')) {
|
||||
start += 1
|
||||
i += 1
|
||||
}
|
||||
return (() => {
|
||||
const result = []
|
||||
while (i >= start) {
|
||||
select.removeChild(options[i])
|
||||
result.push(i--)
|
||||
}
|
||||
return result
|
||||
})()
|
||||
},
|
||||
|
||||
updateSelection: function () {
|
||||
const selected = get(this, 'selected')
|
||||
if (!selected) {
|
||||
return
|
||||
}
|
||||
const currentValue = get(selected, this.valuePath)
|
||||
const select = this.$(`[value=${currentValue}]`)
|
||||
__guard__(select != null ? select[0] : undefined, x => (x.selected = true))
|
||||
if (currentValue && currentValue !== this.value) {
|
||||
set(this, 'value', currentValue)
|
||||
}
|
||||
}.observes('selected'),
|
||||
|
||||
updateOptions: function () {
|
||||
this.arrayWillChange(this.items, 0, get(this.items, 'length'), 0)
|
||||
this.arrayDidChange(this.items, 0, 0, get(this.items, 'length'))
|
||||
}.observes('labelPath'),
|
||||
|
||||
arrayDidChange(items, start, _removeCount, addCount) {
|
||||
let value
|
||||
const select = get(this, 'element')
|
||||
const hasDefault = get(this, 'hasDefaultOption')
|
||||
if (hasDefault) {
|
||||
start += 1
|
||||
}
|
||||
let i = start
|
||||
const l = start + addCount
|
||||
|
||||
while (i < l) {
|
||||
const ind = hasDefault ? i - 1 : i
|
||||
const item = items.objectAt(ind)
|
||||
value = get(item, this.valuePath)
|
||||
const label = get(item, this.labelPath)
|
||||
const option = doc.createElement('option')
|
||||
option.textContent = label
|
||||
option.value = value
|
||||
if ((this.value || this.valueDefault) === value) {
|
||||
option.selected = true
|
||||
set(this, 'selected', item)
|
||||
}
|
||||
select.appendChild(option)
|
||||
i++
|
||||
}
|
||||
|
||||
set(this, 'value', select.value)
|
||||
},
|
||||
|
||||
insertDefaultOption: function () {
|
||||
if (!this.labelDefault || !!this.hasDefaultOption) {
|
||||
return
|
||||
}
|
||||
const select = get(this, 'element')
|
||||
const option = doc.createElement('option')
|
||||
option.textContent = this.labelDefault
|
||||
option.value = this.valueDefault
|
||||
select.appendChild(option)
|
||||
|
||||
set(this, 'hasDefaultOption', true)
|
||||
}
|
||||
.observes('items')
|
||||
.on('didInsertElement'),
|
||||
})
|
||||
|
||||
export default FastSelectComponent
|
||||
|
||||
function __guard__(value, transform) {
|
||||
return typeof value !== 'undefined' && value !== null ? transform(value) : undefined
|
||||
}
|
|
@ -1,79 +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 Ember from 'ember'
|
||||
import {scoreToGrade} from '@instructure/grading-utils'
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import {scoreToScaledPoints} from '@canvas/grading/GradeCalculationHelper'
|
||||
|
||||
const I18n = useI18nScope('sr_gradebook')
|
||||
|
||||
const FinalGradeComponent = Ember.Component.extend({
|
||||
percent: function () {
|
||||
const percent = this.get('student.total_percent')
|
||||
let scoreText = I18n.n(percent, {percentage: true})
|
||||
|
||||
if (this.get('gradingStandard') && this.get('gradingStandardPointsBased')) {
|
||||
const scalingFactor = this.get('gradingStandardScalingFactor')
|
||||
const studentTotalGrade = this.get('student.total_grade')
|
||||
if (studentTotalGrade.possible) {
|
||||
const scaledPossible = I18n.n(scalingFactor, {
|
||||
precision: 1,
|
||||
})
|
||||
const scaledScore = I18n.n(
|
||||
scoreToScaledPoints(studentTotalGrade.score, studentTotalGrade.possible, scalingFactor),
|
||||
{
|
||||
precision: 1,
|
||||
}
|
||||
)
|
||||
scoreText = `${scaledScore} / ${scaledPossible}`
|
||||
}
|
||||
}
|
||||
return scoreText
|
||||
}.property('student.total_percent', 'student.total_grade', 'grading_standard', 'student'),
|
||||
|
||||
pointRatioDisplay: function () {
|
||||
return I18n.t('final_point_ratio', '%{pointRatio} points', {pointRatio: this.get('pointRatio')})
|
||||
}.property('pointRatio'),
|
||||
|
||||
pointRatio: function () {
|
||||
return `${I18n.n(this.get('student.total_grade.score'))} / ${I18n.n(
|
||||
this.get('student.total_grade.possible')
|
||||
)}`
|
||||
}.property('hide_points_possible', 'student.total_grade.score', 'student.total_grade.possible'),
|
||||
|
||||
letterGrade: function () {
|
||||
const percent = this.get('student.total_percent')
|
||||
return scoreToGrade(percent, this.get('gradingStandard'))
|
||||
}.property('gradingStandard', 'percent'),
|
||||
|
||||
showGrade: Ember.computed.bool('student.total_grade.possible'),
|
||||
|
||||
showPoints: function () {
|
||||
return !!(!this.get('hide_points_possible') && this.get('student.total_grade'))
|
||||
}.property('hide_points_possible', 'student.total_grade'),
|
||||
|
||||
showLetterGrade: Ember.computed.bool('gradingStandard'),
|
||||
|
||||
actions: {
|
||||
onEditFinalGradeOverride(grade) {
|
||||
this.sendAction('onEditFinalGradeOverride', grade)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default FinalGradeComponent
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 - 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 Ember from 'ember'
|
||||
import {scoreToGrade} from '@instructure/grading-utils'
|
||||
import GradeFormatHelper from '@canvas/grading/GradeFormatHelper'
|
||||
|
||||
const FinalGradeOverrideComponent = Ember.Component.extend({
|
||||
inputValue: null,
|
||||
internalInputValue: null,
|
||||
|
||||
inputDescription: function () {
|
||||
const percentage = this.get('finalGradeOverride.percentage')
|
||||
const gradingStandard = this.get('gradingStandard')
|
||||
|
||||
if (percentage == null || !gradingStandard) {
|
||||
return null
|
||||
}
|
||||
if (gradingStandard) {
|
||||
if (this.get('gradingStandardPointsBased')) {
|
||||
// points based grading schemes never show percentages
|
||||
return null
|
||||
}
|
||||
}
|
||||
return GradeFormatHelper.formatGrade(percentage, {gradingType: 'percent'})
|
||||
}.property('finalGradeOverride', 'gradingStandard', 'gradingStandardPointsBased'),
|
||||
|
||||
finalGradeOverrideChanged: function () {
|
||||
const percentage = this.get('finalGradeOverride.percentage')
|
||||
const gradingStandard = this.get('gradingStandard')
|
||||
|
||||
if (percentage == null) {
|
||||
this.set('internalInputValue', null)
|
||||
} else if (!gradingStandard) {
|
||||
this.set(
|
||||
'internalInputValue',
|
||||
GradeFormatHelper.formatGrade(percentage, {gradingType: 'percent'})
|
||||
)
|
||||
} else {
|
||||
this.set('internalInputValue', scoreToGrade(percentage, gradingStandard))
|
||||
}
|
||||
|
||||
this.set('inputValue', this.get('internalInputValue'))
|
||||
}
|
||||
.observes('finalGradeOverride', 'gradingStandard')
|
||||
.on('init'),
|
||||
|
||||
focusOut() {
|
||||
this.sendAction('onEditFinalGradeOverride', this.get('inputValue'))
|
||||
// Always show a valid grade in the input on blur.
|
||||
this.set('inputValue', this.get('internalInputValue'))
|
||||
},
|
||||
})
|
||||
|
||||
export default FinalGradeOverrideComponent
|
|
@ -1,274 +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 numberHelper from '@canvas/i18n/numberHelper'
|
||||
import GRADEBOOK_TRANSLATIONS from '@canvas/grading/GradebookTranslations'
|
||||
import GradeFormatHelper from '@canvas/grading/GradeFormatHelper'
|
||||
import OutlierScoreHelper from '@canvas/grading/OutlierScoreHelper'
|
||||
import Ember from 'ember'
|
||||
import $ from 'jquery'
|
||||
import '@canvas/jquery/jquery.ajaxJSON'
|
||||
|
||||
const I18n = useI18nScope('grading_cell')
|
||||
|
||||
const GradingCellComponent = Ember.Component.extend({
|
||||
value: null,
|
||||
excused: null,
|
||||
shouldSaveExcused: false,
|
||||
|
||||
isPoints: Ember.computed.equal('assignment.grading_type', 'points'),
|
||||
isPercent: Ember.computed.equal('assignment.grading_type', 'percent'),
|
||||
isLetterGrade: Ember.computed.equal('assignment.grading_type', 'letter_grade'),
|
||||
isPassFail: Ember.computed.equal('assignment.grading_type', 'pass_fail'),
|
||||
isInPastGradingPeriodAndNotAdmin: function () {
|
||||
return this.submission != null ? this.submission.gradeLocked : undefined
|
||||
}.property('submission'),
|
||||
nilPointsPossible: Ember.computed.none('assignment.points_possible'),
|
||||
isGpaScale: Ember.computed.equal('assignment.grading_type', 'gpa_scale'),
|
||||
|
||||
passFailGrades: [
|
||||
{
|
||||
label: I18n.t('grade_ungraded', 'Ungraded'),
|
||||
value: '-',
|
||||
},
|
||||
{
|
||||
label: I18n.t('grade_complete', 'Complete'),
|
||||
value: 'complete',
|
||||
},
|
||||
{
|
||||
label: I18n.t('grade_incomplete', 'Incomplete'),
|
||||
value: 'incomplete',
|
||||
},
|
||||
{
|
||||
label: I18n.t('Excused'),
|
||||
value: 'EX',
|
||||
},
|
||||
],
|
||||
|
||||
outOfText: function () {
|
||||
if (this.submission && this.submission.excused) {
|
||||
return I18n.t('Excused')
|
||||
} else if (this.get('isGpaScale')) {
|
||||
return ''
|
||||
} else if (this.get('isLetterGrade') || this.get('isPassFail')) {
|
||||
return I18n.t('(%{score} out of %{points})', {
|
||||
points: I18n.n(this.assignment.points_possible),
|
||||
score: this.get('entered_score'),
|
||||
})
|
||||
} else if (this.get('nilPointsPossible')) {
|
||||
return I18n.t('No points possible')
|
||||
} else {
|
||||
return I18n.t('(out of %{points})', {points: I18n.n(this.assignment.points_possible)})
|
||||
}
|
||||
}.property('submission.score', 'assignment'),
|
||||
|
||||
changeGradeURL() {
|
||||
return ENV.GRADEBOOK_OPTIONS.change_grade_url
|
||||
},
|
||||
|
||||
isExcused(value) {
|
||||
return (
|
||||
value &&
|
||||
typeof value === 'string' &&
|
||||
(value?.toUpperCase() === 'EXCUSED' || value?.toUpperCase() === 'EX')
|
||||
)
|
||||
},
|
||||
|
||||
saveURL: function () {
|
||||
const submission = this.get('submission')
|
||||
return this.changeGradeURL()
|
||||
.replace(':assignment', submission.assignment_id)
|
||||
.replace(':submission', submission.user_id)
|
||||
}.property('submission.assignment_id', 'submission.user_id'),
|
||||
|
||||
score: function () {
|
||||
if (this.submission.score != null) {
|
||||
return I18n.n(this.submission.score)
|
||||
} else {
|
||||
return ' -'
|
||||
}
|
||||
}.property('submission.score'),
|
||||
|
||||
entered_score: function () {
|
||||
if (this.submission.entered_score != null) {
|
||||
return I18n.n(this.submission.entered_score)
|
||||
} else {
|
||||
return ' -'
|
||||
}
|
||||
}.property('submission.entered_score'),
|
||||
|
||||
late_penalty: function () {
|
||||
if (this.submission.points_deducted != null) {
|
||||
return I18n.n(-1 * this.submission.points_deducted)
|
||||
} else {
|
||||
return ' -'
|
||||
}
|
||||
}.property('submission.points_deducted'),
|
||||
|
||||
points_possible: function () {
|
||||
if (this.assignment.points_possible != null) {
|
||||
return I18n.n(this.assignment.points_possible)
|
||||
} else {
|
||||
return ' -'
|
||||
}
|
||||
}.property('assignment.points_possible'),
|
||||
|
||||
final_grade: function () {
|
||||
if (this.submission.grade != null) {
|
||||
return GradeFormatHelper.formatGrade(this.submission.grade)
|
||||
} else {
|
||||
return ' -'
|
||||
}
|
||||
}.property('submission.grade'),
|
||||
|
||||
ajax(url, options) {
|
||||
const {type, data} = options
|
||||
return $.ajaxJSON(url, type, data)
|
||||
},
|
||||
|
||||
excusedToggled: function () {
|
||||
if (this.shouldSaveExcused) {
|
||||
this.updateSubmissionExcused()
|
||||
}
|
||||
}.observes('excused'),
|
||||
|
||||
updateSubmissionExcused() {
|
||||
const url = this.get('saveURL')
|
||||
const value = __guard__(this.$('#submission-excused'), x => x[0].checked)
|
||||
|
||||
const save = this.ajax(url, {
|
||||
type: 'PUT',
|
||||
data: {'submission[excuse]': value},
|
||||
})
|
||||
return save.then(this.boundUpdateSuccess, this.onUpdateError)
|
||||
},
|
||||
|
||||
setExcusedWithoutTriggeringSave(isExcused) {
|
||||
this.shouldSaveExcused = false
|
||||
this.set('excused', isExcused)
|
||||
return (this.shouldSaveExcused = true)
|
||||
},
|
||||
|
||||
submissionDidChange: function () {
|
||||
const newVal = (this.submission != null ? this.submission.excused : undefined)
|
||||
? 'EX'
|
||||
: (this.submission != null ? this.submission.entered_grade : undefined) || '-'
|
||||
|
||||
this.setExcusedWithoutTriggeringSave(
|
||||
this.submission != null ? this.submission.excused : undefined
|
||||
)
|
||||
if (this.get('isPassFail')) {
|
||||
this.set('value', newVal)
|
||||
} else {
|
||||
this.set('value', GradeFormatHelper.formatGrade(newVal))
|
||||
}
|
||||
}
|
||||
.observes('submission')
|
||||
.on('init'),
|
||||
|
||||
onUpdateSuccess(submission) {
|
||||
this.sendAction('on-submit-grade', submission.all_submissions)
|
||||
if (!submission.excused) {
|
||||
const outlierScoreHelper = new OutlierScoreHelper(
|
||||
submission.score,
|
||||
this.assignment.points_possible
|
||||
)
|
||||
if (outlierScoreHelper.hasWarning()) {
|
||||
$.flashWarning(outlierScoreHelper.warningMessage())
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onUpdateError() {
|
||||
$.flashError(GRADEBOOK_TRANSLATIONS.submission_update_error)
|
||||
},
|
||||
|
||||
focusOut(event) {
|
||||
const isGradeInput = event.target.id === 'student_and_assignment_grade'
|
||||
const submission = this.get('submission')
|
||||
|
||||
if (!submission || !isGradeInput) {
|
||||
return
|
||||
}
|
||||
|
||||
const url = this.get('saveURL')
|
||||
let value = this.$('input, select').val() || this.value
|
||||
|
||||
const excused = this.isExcused(value)
|
||||
if (this.get('excused') && excused) {
|
||||
return
|
||||
} else {
|
||||
this.setExcusedWithoutTriggeringSave(excused)
|
||||
}
|
||||
if (this.get('isPassFail') && value === '-') {
|
||||
value = ''
|
||||
}
|
||||
|
||||
value = GradeFormatHelper.delocalizeGrade(value)
|
||||
|
||||
if (
|
||||
value === submission.grade ||
|
||||
((value === '-' || value === '') && submission.grade === null)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if ((!this.isExcused(value) && this.get('isPoints')) || this.get('isPercent')) {
|
||||
let formattedGrade = value
|
||||
formattedGrade = numberHelper.parse(formattedGrade?.replace(/%/g, '')).toString()
|
||||
if (formattedGrade === 'NaN') {
|
||||
return $.flashError(I18n.t('Invalid Grade'))
|
||||
}
|
||||
}
|
||||
|
||||
const data = this.isExcused(value)
|
||||
? {'submission[excuse]': true}
|
||||
: {'submission[posted_grade]': value}
|
||||
const save = this.ajax(url, {
|
||||
type: 'PUT',
|
||||
data,
|
||||
})
|
||||
return save.then(this.boundUpdateSuccess, this.onUpdateError)
|
||||
},
|
||||
|
||||
bindSave: function () {
|
||||
this.boundUpdateSuccess = this.onUpdateSuccess.bind(this)
|
||||
}.on('init'),
|
||||
|
||||
click(event) {
|
||||
const {target} = event
|
||||
const hasCheckboxClass = target.classList[0] === 'checkbox'
|
||||
const isCheckBox = target.type === 'checkbox'
|
||||
|
||||
if (hasCheckboxClass || isCheckBox) {
|
||||
return this.$('#submission-excused').focus()
|
||||
} else {
|
||||
return this.$('input, select').select()
|
||||
}
|
||||
},
|
||||
|
||||
focus() {
|
||||
return this.$('input, select').select()
|
||||
},
|
||||
})
|
||||
|
||||
export default GradingCellComponent
|
||||
|
||||
function __guard__(value, transform) {
|
||||
return typeof value !== 'undefined' && value !== null ? transform(value) : undefined
|
||||
}
|
|
@ -1,190 +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 'jquery'
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import Ember from 'ember'
|
||||
import register from '../helpers/register'
|
||||
import '../../jst/components/ic-submission-download-dialog.hbs'
|
||||
import 'jqueryui/progressbar'
|
||||
import 'jqueryui/dialog'
|
||||
|
||||
const I18n = useI18nScope('submissions')
|
||||
|
||||
// example usage:
|
||||
// {{
|
||||
// ic-submission-download-dialog
|
||||
// submissionsDownloadUrl=assignment_submissions_url
|
||||
// }}
|
||||
export default register(
|
||||
'component',
|
||||
'ic-submission-download-dialog',
|
||||
Ember.Component.extend({
|
||||
isOpened: false,
|
||||
|
||||
isChecking: true,
|
||||
|
||||
attachment: {},
|
||||
|
||||
percentComplete: 0,
|
||||
|
||||
hideIndicator: Ember.computed.not('isChecking'),
|
||||
|
||||
showFileLink: Ember.computed.equal('status', 'finished'),
|
||||
|
||||
sizeOfFile: Ember.computed.alias('attachment.readable_size'),
|
||||
|
||||
dialogTitle: I18n.t('download_submissions_title', 'Download Assignment Submissions'),
|
||||
|
||||
bindFunctions: function () {
|
||||
this.reviewProgress = this.reviewProgress.bind(this)
|
||||
this.progressError = this.progressError.bind(this)
|
||||
return (this.checkForChange = this.checkForChange.bind(this))
|
||||
}.on('init'),
|
||||
|
||||
status: function () {
|
||||
if (this.fileReady()) {
|
||||
return 'finished'
|
||||
} else if (this.get('percentComplete') >= 95) {
|
||||
return 'zipping'
|
||||
} else {
|
||||
return 'starting'
|
||||
}
|
||||
}.property('attachment', 'percentComplete', 'isOpened'),
|
||||
|
||||
progress: function () {
|
||||
const attachment = this.get('attachment')
|
||||
let new_val = 0
|
||||
if (attachment && this.fileReady()) {
|
||||
new_val = 100
|
||||
} else if (attachment) {
|
||||
new_val = this.get('percentComplete')
|
||||
if (this.get('percentComplete') < 95) {
|
||||
new_val += 5
|
||||
}
|
||||
const state = parseInt(this.get('attachment.file_state'), 10)
|
||||
if (Number.isNaN(Number(state))) {
|
||||
new_val = 0
|
||||
}
|
||||
}
|
||||
|
||||
return this.set('percentComplete', new_val)
|
||||
}.observes('attachment'),
|
||||
|
||||
keepChecking: function () {
|
||||
if (this.get('percentComplete') !== 100 && !!this.get('isOpened')) {
|
||||
return true
|
||||
}
|
||||
}.property('percentComplete', 'isOpened'),
|
||||
|
||||
url: function () {
|
||||
return `${this.get('submissionsDownloadUrl')}`
|
||||
}.property('submissionsDownloadUrl'),
|
||||
|
||||
statusText: function () {
|
||||
switch (this.get('status')) {
|
||||
case 'starting':
|
||||
return I18n.t('gathering_files', 'Gathering Files (%{progress})...', {
|
||||
progress: I18n.toPercentage(this.get('percentComplete'), {precision: 0}),
|
||||
})
|
||||
case 'zipping':
|
||||
return I18n.t('creating_zip', 'Creating zip file...')
|
||||
case 'finished':
|
||||
return I18n.t('finished_redirecting', 'Finished! Redirecting to File...')
|
||||
}
|
||||
}.property('status', 'percentComplete'),
|
||||
|
||||
updateProgressBar: function () {
|
||||
return $('#progressbar').progressbar({value: this.get('percentComplete')})
|
||||
}.observes('percentComplete'),
|
||||
|
||||
downloadCompletedFile: function () {
|
||||
if (this.get('percentComplete') === 100) {
|
||||
return (window.location.href = this.get('url'))
|
||||
}
|
||||
}.observes('percentComplete'),
|
||||
|
||||
resetAttachment: function () {
|
||||
return this.set('attachment', null)
|
||||
}.observes('isOpened'),
|
||||
|
||||
closeOnEsc: function (event) {
|
||||
if (event.keyCode === 27) {
|
||||
// esc
|
||||
return this.close()
|
||||
}
|
||||
}.on('keyDown'),
|
||||
|
||||
actions: {
|
||||
openDialog() {
|
||||
this.set('isOpened', true)
|
||||
if (this.dialogOptions == null) {
|
||||
this.dialogOptions = {
|
||||
title: 'Download Assignment Submissions',
|
||||
resizable: false,
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
}
|
||||
}
|
||||
if (this.$dialog == null) {
|
||||
this.$dialog = $('#submissions_download_dialog form').dialog(this.dialogOptions)
|
||||
}
|
||||
this.$dialog.dialog({
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
return this.checkForChange()
|
||||
},
|
||||
|
||||
closeDialog() {
|
||||
return this.close()
|
||||
},
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$dialog.dialog('close')
|
||||
return this.set('isOpened', false)
|
||||
},
|
||||
|
||||
fileReady() {
|
||||
const state = this.get('attachment.workflow_state')
|
||||
return state === 'zipped' || state === 'available'
|
||||
},
|
||||
|
||||
checkForChange() {
|
||||
this.set('isChecking', true)
|
||||
return $.ajaxJSON(this.get('url'), 'GET', {}, this.reviewProgress, this.progressError)
|
||||
},
|
||||
|
||||
reviewProgress(data) {
|
||||
this.set('isChecking', false)
|
||||
this.set('attachment', data.attachment)
|
||||
return this.setCheckTimeOut(3000)
|
||||
},
|
||||
|
||||
progressError() {
|
||||
this.set('isChecking', false)
|
||||
return this.setCheckTimeOut(1000)
|
||||
},
|
||||
|
||||
setCheckTimeOut(time) {
|
||||
if (this.get('keepChecking')) {
|
||||
return setTimeout(this.checkForChange, time)
|
||||
}
|
||||
},
|
||||
})
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
import '@canvas/handlebars-helpers'
|
||||
|
||||
export default Ember.Application.extend({
|
||||
rootElement: '#content',
|
||||
})
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 - 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/>.
|
||||
*/
|
||||
|
||||
export default function route() {
|
||||
return this.resource('screenreader_gradebook', {path: '/'})
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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/>.
|
||||
|
||||
// This file gets included in all ember templates, ever, therefore:
|
||||
// - Only require helpers that are necessary for all ember apps.
|
||||
// - Be strict about what you include or allow to be included here.
|
||||
// - Don't write code here, include helpers from their own files
|
||||
|
||||
import './t'
|
||||
import './format-date'
|
||||
import './n'
|
|
@ -1,37 +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 Ember from 'ember'
|
||||
import * as tz from '@instructure/moment-utils'
|
||||
|
||||
const {Handlebars} = Ember
|
||||
|
||||
// #
|
||||
// Formats a parsable date with normal strftime formats
|
||||
//
|
||||
// ```html
|
||||
// {{format-date datetime '%b %d'}}
|
||||
// ```
|
||||
export default Handlebars.registerBoundHelper('format-date', (datetime, format) => {
|
||||
if (datetime == null) {
|
||||
return
|
||||
}
|
||||
if (typeof format !== 'string') {
|
||||
format = '%b %e, %Y %l:%M %P'
|
||||
}
|
||||
return tz.format(tz.parse(datetime), format)
|
||||
})
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2017 - 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 Ember from 'ember'
|
||||
import I18n from '@canvas/i18n'
|
||||
import numberFormat from '@canvas/i18n/numberFormat'
|
||||
|
||||
Ember.Handlebars.registerBoundHelper('n', (number, options) => I18n.n(number, options.hash))
|
||||
|
||||
export default Ember.Handlebars.registerBoundHelper('nf', (number, options) =>
|
||||
numberFormat[options.hash.format](number)
|
||||
)
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
|
||||
// Registers objects on the application container, like components. This
|
||||
// prevents us from having to add App.WhateverThing to every app, and instead
|
||||
// just require the shared object into your app without any extra fuss.
|
||||
export default function register(type, name, obj) {
|
||||
Ember.Application.initializer({
|
||||
name,
|
||||
initialize(container) {
|
||||
return container.register(`${type}:${name}`, obj)
|
||||
},
|
||||
})
|
||||
return obj
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
import I18n from '@canvas/i18n'
|
||||
import htmlEscape from '@instructure/html-escape'
|
||||
|
||||
Ember.Handlebars.registerHelper('t', (...args1) => {
|
||||
const adjustedLength = Math.max(args1.length, 1),
|
||||
args = args1.slice(0, adjustedLength - 1),
|
||||
hbsOptions = args1[adjustedLength - 1]
|
||||
const {hash, hashTypes, hashContexts} = hbsOptions
|
||||
const options = {}
|
||||
for (const key of Object.keys(hash || {})) {
|
||||
const value = hash[key]
|
||||
const type = hashTypes[key]
|
||||
if (type === 'ID') {
|
||||
options[key] = Ember.get(hashContexts[key], value)
|
||||
} else {
|
||||
options[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
const wrappers = []
|
||||
let key
|
||||
while ((key = `w${wrappers.length}`) && options[key]) {
|
||||
wrappers.push(options[key])
|
||||
delete options[key]
|
||||
}
|
||||
if (wrappers.length) {
|
||||
options.wrapper = wrappers
|
||||
}
|
||||
return new Ember.Handlebars.SafeString(htmlEscape(I18n.t(...Array.from(args), options)))
|
||||
})
|
||||
|
||||
Ember.Handlebars.registerHelper('__i18nliner_escape', htmlEscape)
|
||||
|
||||
Ember.Handlebars.registerHelper('__i18nliner_safe', val => new htmlEscape.SafeString(val))
|
||||
|
||||
export default Ember.Handlebars.registerHelper('__i18nliner_concat', (...args1) => {
|
||||
const adjustedLength = Math.max(args1.length, 1),
|
||||
args = args1.slice(0, adjustedLength - 1)
|
||||
return args.join('')
|
||||
})
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 {$, ArrayProxy} from 'ember'
|
||||
import ajax from 'ic-ajax'
|
||||
import parseLinkHeader from './parse_link_header'
|
||||
|
||||
function fetch(url, options) {
|
||||
const opts = $.extend({dataType: 'json'}, {data: options.data})
|
||||
const {records} = options
|
||||
return ajax.raw(url, opts).then(result => {
|
||||
const response = options.process ? options.process(result.response) : result.response
|
||||
records.pushObjects(response)
|
||||
const meta = parseLinkHeader(result.jqXHR)
|
||||
if (meta.next) {
|
||||
return fetch(meta.next, options)
|
||||
} else {
|
||||
records.set('isLoaded', true)
|
||||
records.set('isLoading', false)
|
||||
return records
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default function fetchAllPages(url, options = {}) {
|
||||
const records = options.records || (options.records = ArrayProxy.create({content: []}))
|
||||
records.set('isLoading', true)
|
||||
records.set('promise', fetch(url, options))
|
||||
return records
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 - 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/>.
|
||||
*/
|
||||
|
||||
const regex = /<(http.*?)>; rel="([a-z]*)",/g
|
||||
|
||||
export default function parseLinkHeader(jqXhr) {
|
||||
let link
|
||||
const links = {}
|
||||
const header = jqXhr.getResponseHeader('Link')
|
||||
if (!header) {
|
||||
return links
|
||||
}
|
||||
while ((link = regex.exec(header))) {
|
||||
links[link[2]] = link[1]
|
||||
}
|
||||
return links
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2017 - 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 App from './config/app'
|
||||
import routes from './config/routes'
|
||||
import AssignmentSubtotalGradesComponent from './components/assignment_subtotal_grades_component'
|
||||
import AssignmentMuterComponent from './components/assignment_muter_component'
|
||||
import CustomColumnCellComponent from './components/custom_column_cell_component'
|
||||
import FastSelectComponent from './components/fast_select_component'
|
||||
import FinalGradeComponent from './components/final_grade_component'
|
||||
import FinalGradeOverrideComponent from './components/final_grade_override_component'
|
||||
import GradingCellComponent from './components/grading_cell_component'
|
||||
import ScreenreaderGradebookController from './controllers/screenreader_gradebook_controller'
|
||||
import ScreenreaderGradebookRoute from './routes/screenreader_gradebook_route'
|
||||
import AssignmentsView from './views/assignments_view'
|
||||
import LearningMasteryView from './views/learning_mastery_view'
|
||||
import ScreenreaderGradebookView from './views/screenreader_gradebook_view'
|
||||
import SelectionButtonsView from './views/selection_buttons_view'
|
||||
import '../jst/aria_announcer.hbs'
|
||||
import '../jst/assignment_information/actions.hbs'
|
||||
import '../jst/assignment_information/details.hbs'
|
||||
import '../jst/assignment_information/index.hbs'
|
||||
import '../jst/assignments.hbs'
|
||||
import '../jst/components/assignment-subtotal-grades.hbs'
|
||||
import '../jst/components/custom-column-cell.hbs'
|
||||
import '../jst/components/final-grade.hbs'
|
||||
import '../jst/components/final-grade-override.hbs'
|
||||
import '../jst/components/grading-cell.hbs'
|
||||
import '../jst/content_selection/assignment.hbs'
|
||||
import '../jst/content_selection/header.hbs'
|
||||
import '../jst/content_selection/outcome.hbs'
|
||||
import '../jst/content_selection/selection_buttons.hbs'
|
||||
import '../jst/content_selection/student.hbs'
|
||||
import '../jst/gradebookHeader.hbs'
|
||||
import '../jst/grading.hbs'
|
||||
import '../jst/learning_mastery.hbs'
|
||||
import '../jst/outcome_information.hbs'
|
||||
import '../jst/screenreader_gradebook.hbs'
|
||||
import '../jst/settings/assignment_toggles_and_actions.hbs'
|
||||
import '../jst/settings/grading_period_select.hbs'
|
||||
import '../jst/settings/header.hbs'
|
||||
import '../jst/settings/mastery_toggles_and_actions.hbs'
|
||||
import '../jst/settings/section_select.hbs'
|
||||
import '../jst/settings/sort_select.hbs'
|
||||
import '../jst/student_information/assignment_subtotals.hbs'
|
||||
import '../jst/student_information/details.hbs'
|
||||
import '../jst/student_information/index.hbs'
|
||||
|
||||
App.initializer({
|
||||
name: 'routes',
|
||||
initialize(container, application) {
|
||||
return application.Router.map(routes)
|
||||
},
|
||||
})
|
||||
|
||||
export default App.reopen({
|
||||
AssignmentSubtotalGradesComponent,
|
||||
AssignmentMuterComponent,
|
||||
CustomColumnCellComponent,
|
||||
FastSelectComponent,
|
||||
FinalGradeComponent,
|
||||
FinalGradeOverrideComponent,
|
||||
GradingCellComponent,
|
||||
ScreenreaderGradebookController,
|
||||
ScreenreaderGradebookRoute,
|
||||
AssignmentsView,
|
||||
LearningMasteryView,
|
||||
ScreenreaderGradebookView,
|
||||
SelectionButtonsView,
|
||||
})
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 {ArrayProxy, ObjectProxy, Route} from 'ember'
|
||||
import {flattenDeep} from 'lodash'
|
||||
import fetchAllPages from '../helpers/xhr/fetch_all_pages'
|
||||
import {getFinalGradeOverrides} from '@canvas/grading/FinalGradeOverrideApi'
|
||||
|
||||
const ScreenreaderGradebookRoute = Route.extend({
|
||||
model() {
|
||||
const model = {
|
||||
enrollments: fetchAllPages(ENV.GRADEBOOK_OPTIONS.enrollments_url),
|
||||
assignment_groups: ArrayProxy.create({content: []}),
|
||||
submissions: ArrayProxy.create({content: []}),
|
||||
custom_columns: fetchAllPages(ENV.GRADEBOOK_OPTIONS.custom_columns_url),
|
||||
sections: fetchAllPages(ENV.GRADEBOOK_OPTIONS.sections_url),
|
||||
}
|
||||
|
||||
if (ENV.GRADEBOOK_OPTIONS.final_grade_override_enabled) {
|
||||
const records = ObjectProxy.create({content: {}, isLoaded: false})
|
||||
|
||||
records.set(
|
||||
'promise',
|
||||
getFinalGradeOverrides(ENV.GRADEBOOK_OPTIONS.context_id).then(data => {
|
||||
records.set('isLoaded', true)
|
||||
records.set('content', data)
|
||||
})
|
||||
)
|
||||
model.final_grade_overrides = records
|
||||
}
|
||||
|
||||
if (!ENV.GRADEBOOK_OPTIONS.outcome_gradebook_enabled) {
|
||||
model.outcomes = model.outcome_rollups = ArrayProxy.create({content: []})
|
||||
} else {
|
||||
model.outcomes = fetchAllPages(ENV.GRADEBOOK_OPTIONS.outcome_links_url, {
|
||||
process(response) {
|
||||
return response.map(x => x.outcome)
|
||||
},
|
||||
})
|
||||
model.outcome_rollups = fetchAllPages(ENV.GRADEBOOK_OPTIONS.outcome_rollups_url, {
|
||||
process(response) {
|
||||
return flattenDeep(
|
||||
response.rollups.map(row =>
|
||||
row.scores.map(cell => ({
|
||||
user_id: row.links.user,
|
||||
outcome_id: cell.links.outcome,
|
||||
score: cell.score,
|
||||
}))
|
||||
)
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return model
|
||||
},
|
||||
})
|
||||
|
||||
export default ScreenreaderGradebookRoute
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"env": {
|
||||
"qunit": true
|
||||
},
|
||||
"globals": {
|
||||
"module": true,
|
||||
"test": true,
|
||||
"equal": true,
|
||||
"ok": true,
|
||||
"sandbox": true,
|
||||
"sinon": true,
|
||||
"deepEqual": true,
|
||||
"click": true,
|
||||
"andThen": true,
|
||||
"visit": true,
|
||||
"find": true,
|
||||
"App": true,
|
||||
"start": true
|
||||
},
|
||||
"extends": ["plugin:qunit/recommended", "plugin:qunit/two"],
|
||||
"plugins": ["qunit"],
|
||||
"rules": {
|
||||
"no-restricted-globals": "off",
|
||||
"func-names": "off",
|
||||
"prefer-arrow-callback": "off",
|
||||
"jest/no-identical-title": "off",
|
||||
"qunit/no-global-stop-start": "off",
|
||||
"qunit/no-setup-teardown": "off",
|
||||
"qunit/no-global-assertions": "off",
|
||||
"qunit/no-global-module-test": "off",
|
||||
"qunit/require-expect": "off",
|
||||
"qunit/no-assert-logical-expression": "error",
|
||||
"qunit/no-commented-tests": "error",
|
||||
"qunit/no-compare-relation-boolean": "error"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2018 - 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 Ember from 'ember'
|
||||
|
||||
export default class AsyncHelper {
|
||||
constructor() {
|
||||
this.pendingRequests = 0
|
||||
}
|
||||
|
||||
start = () => {
|
||||
Ember.RSVP.configure('instrument', true)
|
||||
Ember.RSVP.on('created', this.incrementRequest)
|
||||
Ember.RSVP.on('fulfilled', this.decrementRequest)
|
||||
return Ember.RSVP.on('rejected', this.decrementRequest)
|
||||
}
|
||||
|
||||
stop = () => {
|
||||
Ember.RSVP.off('created', this.incrementRequest)
|
||||
Ember.RSVP.off('fulfilled', this.decrementRequest)
|
||||
Ember.RSVP.off('rejected', this.decrementRequest)
|
||||
Ember.RSVP.configure('instrument', false)
|
||||
return (this.pendingRequests = 0)
|
||||
}
|
||||
|
||||
incrementRequest = () => {
|
||||
return this.pendingRequests++
|
||||
}
|
||||
|
||||
decrementRequest = () => {
|
||||
return this.pendingRequests--
|
||||
}
|
||||
|
||||
waitForRequests = () => {
|
||||
return new Promise(resolve => {
|
||||
const defer = () =>
|
||||
Ember.run.later(() => {
|
||||
if (this.pendingRequests) {
|
||||
return defer()
|
||||
} else {
|
||||
return resolve()
|
||||
}
|
||||
})
|
||||
|
||||
return defer()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,862 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 ajax from 'ic-ajax'
|
||||
import Ember from 'ember'
|
||||
|
||||
const clone = obj => Ember.copy(obj, true)
|
||||
|
||||
const default_grade_response = [
|
||||
{
|
||||
submission: {
|
||||
assignment_id: '1',
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_2',
|
||||
created_at: '2013-12-12T22:57:34Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:44Z',
|
||||
grader_id: '1',
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: '34291',
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '150',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:45Z',
|
||||
url: null,
|
||||
user_id: '1',
|
||||
workflow_state: 'graded',
|
||||
submission_history: [
|
||||
{
|
||||
submission: {
|
||||
assignment_id: 1,
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_2',
|
||||
created_at: '2013-12-12T22:57:34Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:44Z',
|
||||
grader_id: 1,
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: 34291,
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '150',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:45Z',
|
||||
url: null,
|
||||
user_id: 1,
|
||||
workflow_state: 'graded',
|
||||
versioned_attachments: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
submission_comments: [],
|
||||
attachments: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
submission: {
|
||||
assignment_id: '1',
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_1',
|
||||
created_at: '2013-12-12T22:57:35Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:47Z',
|
||||
grader_id: '1',
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: '34292',
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '100',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:47Z',
|
||||
url: null,
|
||||
user_id: '2',
|
||||
workflow_state: 'graded',
|
||||
submission_history: [
|
||||
{
|
||||
submission: {
|
||||
assignment_id: 1,
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_2',
|
||||
created_at: '2013-12-12T22:57:35Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:47Z',
|
||||
grader_id: 1,
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: 34292,
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '100',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:47Z',
|
||||
url: null,
|
||||
user_id: 2,
|
||||
workflow_state: 'graded',
|
||||
versioned_attachments: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
submission_comments: [],
|
||||
attachments: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
submission: {
|
||||
assignment_id: '1',
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_2',
|
||||
created_at: '2013-12-12T22:57:34Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:44Z',
|
||||
grader_id: '1',
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: '34291',
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '150',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:45Z',
|
||||
url: null,
|
||||
user_id: '3',
|
||||
workflow_state: 'graded',
|
||||
submission_history: [
|
||||
{
|
||||
submission: {
|
||||
assignment_id: 1,
|
||||
attachment_id: null,
|
||||
attachment_ids: null,
|
||||
attempt: null,
|
||||
body: null,
|
||||
cached_due_date: '2013-12-19T06:59:59Z',
|
||||
context_code: 'course_2',
|
||||
created_at: '2013-12-12T22:57:34Z',
|
||||
grade: '100',
|
||||
grade_matches_current_submission: true,
|
||||
graded_at: '2013-12-16T21:25:44Z',
|
||||
grader_id: 1,
|
||||
group_id: null,
|
||||
has_admin_comment: false,
|
||||
has_rubric_assessment: null,
|
||||
id: 34291,
|
||||
media_comment_id: null,
|
||||
media_comment_type: null,
|
||||
media_object_id: null,
|
||||
process_attempts: 0,
|
||||
processed: null,
|
||||
published_grade: '150',
|
||||
published_score: 100.0,
|
||||
quiz_submission_id: null,
|
||||
score: 100.0,
|
||||
student_entered_score: null,
|
||||
submission_comments_count: null,
|
||||
submission_type: null,
|
||||
submitted_at: null,
|
||||
turnitin_data: null,
|
||||
updated_at: '2013-12-16T21:25:45Z',
|
||||
url: null,
|
||||
user_id: 3,
|
||||
workflow_state: 'graded',
|
||||
versioned_attachments: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
submission_comments: [],
|
||||
attachments: [],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const students = [
|
||||
{
|
||||
user_id: '1',
|
||||
user: {id: '1', name: 'Bob Barnes', group_ids: [], sections: [], sortable_name: 'Barnes, Bob'},
|
||||
course_section_id: '1',
|
||||
},
|
||||
{
|
||||
user_id: '2',
|
||||
user: {id: '2', name: 'Fred Flint', group_ids: [], sections: [], sortable_name: 'Flint, Fred'},
|
||||
course_section_id: '1',
|
||||
},
|
||||
{
|
||||
user_id: '3',
|
||||
user: {id: '3', name: 'Suzy Smith', group_ids: [], sections: [], sortable_name: 'Smith, Suzy'},
|
||||
course_section_id: '1',
|
||||
},
|
||||
{
|
||||
user_id: '4',
|
||||
user: {
|
||||
id: '4',
|
||||
name: 'Buffy Baker',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'Baker, Buffy',
|
||||
},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '5',
|
||||
user: {
|
||||
id: '5',
|
||||
name: 'Willow West',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'West, Willow',
|
||||
},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '5',
|
||||
user: {
|
||||
id: '5',
|
||||
name: 'Willow West',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'West, Willow',
|
||||
},
|
||||
course_section_id: '1',
|
||||
},
|
||||
{
|
||||
user_id: '6',
|
||||
user: {
|
||||
id: '6',
|
||||
name: 'Giles Green',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'Green, Giles',
|
||||
},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '7',
|
||||
user: {
|
||||
id: '7',
|
||||
name: 'Xander Xiao',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'Xiao, Xander',
|
||||
},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '8',
|
||||
user: {
|
||||
id: '8',
|
||||
name: 'Cordelia Lu',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'Lu, Cordelia',
|
||||
},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '9',
|
||||
user: {
|
||||
id: '9',
|
||||
name: 'Drusilla Da',
|
||||
group_ids: [],
|
||||
sections: [],
|
||||
sortable_name: 'Da, Drusilla',
|
||||
},
|
||||
course_section_id: '1',
|
||||
},
|
||||
{
|
||||
user_id: '10',
|
||||
user: {id: '10', name: 'Spike Long', group_ids: [], sections: [], sortable_name: 'Long, Spike'},
|
||||
course_section_id: '2',
|
||||
},
|
||||
{
|
||||
user_id: '10',
|
||||
user: {id: '10', name: 'Spike Long', group_ids: [], sections: [], sortable_name: 'Long, Spike'},
|
||||
course_section_id: '1',
|
||||
},
|
||||
]
|
||||
|
||||
const concludedStudents = [
|
||||
{
|
||||
user: {id: '105', name: 'Lyra', group_ids: [], sections: []},
|
||||
course_section_id: '1',
|
||||
user_id: '105',
|
||||
workflow_state: 'completed',
|
||||
completed_at: '2013-10-01T10:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
const assignmentGroups = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'AG1',
|
||||
position: 1,
|
||||
group_weight: 0,
|
||||
assignments: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Z Eats Soup',
|
||||
points_possible: 100,
|
||||
grading_type: 'points',
|
||||
submission_types: ['none'],
|
||||
due_at: '2013-10-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '1',
|
||||
published: true,
|
||||
muted: false,
|
||||
only_visible_to_overrides: true,
|
||||
assignment_visibility: ['1'],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Drink Water',
|
||||
grading_type: 'points',
|
||||
points_possible: null,
|
||||
due_at: null,
|
||||
position: 10,
|
||||
submission_types: ['online_url', 'online_text_entry'],
|
||||
assignment_group_id: '1',
|
||||
published: true,
|
||||
muted: true,
|
||||
only_visible_to_overrides: true,
|
||||
assignment_visibility: ['2'],
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Apples are good',
|
||||
points_possible: 1000,
|
||||
grading_type: 'points',
|
||||
submission_types: ['none'],
|
||||
due_at: '2013-12-01T10:00:00Z',
|
||||
position: 12,
|
||||
assignment_group_id: '1',
|
||||
published: true,
|
||||
muted: false,
|
||||
assignment_visibility: ['1', '2', '3'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'AG2',
|
||||
position: 10,
|
||||
group_weight: 0,
|
||||
assignments: [
|
||||
{
|
||||
id: '4',
|
||||
name: 'Big Bowl of Nachos',
|
||||
points_possible: 20,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['none'],
|
||||
due_at: null,
|
||||
position: 5,
|
||||
assignment_group_id: '2',
|
||||
published: true,
|
||||
muted: false,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Can You Eat Just One?',
|
||||
points_possible: 40,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['none'],
|
||||
due_at: '2013-08-01T10:00:00Z',
|
||||
position: 6,
|
||||
assignment_group_id: '2',
|
||||
published: true,
|
||||
muted: true,
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
name: 'Da Fish and Chips!',
|
||||
points_possible: 40,
|
||||
grading_type: 'pass_fail',
|
||||
submission_types: ['none'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 9,
|
||||
published: true,
|
||||
assignment_group_id: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Silent Assignments',
|
||||
position: 2,
|
||||
group_weight: 0,
|
||||
assignments: [
|
||||
{
|
||||
id: '20',
|
||||
name: 'Published Assignment',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['none'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 5,
|
||||
assignment_group_id: '4',
|
||||
published: true,
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
name: 'Not Graded',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
published: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Invalid AG',
|
||||
position: 3,
|
||||
group_weight: 0,
|
||||
assignments: [
|
||||
{
|
||||
id: '24',
|
||||
name: 'No Points Assignment',
|
||||
points_possible: 0,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
published: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
name: 'moderated grading',
|
||||
position: 4,
|
||||
group_weight: 0,
|
||||
assignments: [
|
||||
{
|
||||
id: '25',
|
||||
name: 'muted, moderated, grades not published',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
muted: true,
|
||||
moderated_grading: true,
|
||||
grades_published: false,
|
||||
published: true,
|
||||
},
|
||||
{
|
||||
id: '26',
|
||||
name: 'not muted, moderated, grades not published',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
muted: false,
|
||||
moderated_grading: true,
|
||||
grades_published: false,
|
||||
published: true,
|
||||
},
|
||||
{
|
||||
id: '27',
|
||||
name: 'muted, not moderated, grades not published',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
muted: true,
|
||||
moderated_grading: false,
|
||||
grades_published: false,
|
||||
published: true,
|
||||
},
|
||||
{
|
||||
id: '28',
|
||||
name: 'muted, moderated, grades published',
|
||||
points_possible: 10,
|
||||
grading_type: 'percent',
|
||||
submission_types: ['not_graded'],
|
||||
due_at: '2013-09-01T10:00:00Z',
|
||||
position: 1,
|
||||
assignment_group_id: '4',
|
||||
muted: true,
|
||||
moderated_grading: true,
|
||||
grades_published: true,
|
||||
published: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const submissions = [
|
||||
{
|
||||
user_id: '1',
|
||||
submissions: [
|
||||
{id: '1', user_id: '1', assignment_id: '1', grade: '3', score: '3'},
|
||||
{id: '2', user_id: '1', assignment_id: '2', grade: null, score: null},
|
||||
{
|
||||
id: '5',
|
||||
user_id: '1',
|
||||
assignment_id: '6',
|
||||
grade: 'incomplete',
|
||||
score: 'incomplete',
|
||||
entered_grade: 'incomplete',
|
||||
entered_score: 'incomplete',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
user_id: '2',
|
||||
submissions: [
|
||||
{id: '3', user_id: '2', assignment_id: '1', grade: '9', score: '9'},
|
||||
{id: '4', user_id: '2', assignment_id: '2', grade: null, score: null},
|
||||
],
|
||||
},
|
||||
{
|
||||
user_id: '3',
|
||||
submissions: [
|
||||
{id: '5', user_id: '3', assignment_id: '1', grade: '10', score: '10'},
|
||||
{id: '6', user_id: '3', assignment_id: '2', grade: null, score: null},
|
||||
],
|
||||
},
|
||||
{
|
||||
user_id: '4',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '5',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '6',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '7',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '8',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '9',
|
||||
submissions: [],
|
||||
},
|
||||
{
|
||||
user_id: '10',
|
||||
submissions: [],
|
||||
},
|
||||
]
|
||||
|
||||
const sections = [
|
||||
{id: '1', name: 'Vampires and Demons'},
|
||||
{id: '2', name: 'Slayers and Scoobies'},
|
||||
]
|
||||
|
||||
const customColumns = [
|
||||
{
|
||||
hidden: false,
|
||||
id: '1',
|
||||
position: 1,
|
||||
teacher_notes: true,
|
||||
title: 'Notes',
|
||||
},
|
||||
]
|
||||
|
||||
const outcomesRaw = [
|
||||
{outcome: {id: '1', title: 'Eating', mastery_points: 3}},
|
||||
{outcome: {id: '2', title: 'Drinking', mastery_points: 5}},
|
||||
]
|
||||
|
||||
const outcomes = [
|
||||
{id: '1', title: 'Eating', mastery_points: 3},
|
||||
{id: '2', title: 'Drinking', mastery_points: 5},
|
||||
]
|
||||
|
||||
const outcomeRollupsRaw = {
|
||||
rollups: [
|
||||
{
|
||||
links: {user: '1'},
|
||||
scores: [
|
||||
{links: {outcome: '1'}, score: 5},
|
||||
{links: {outcome: '2'}, score: 4},
|
||||
{links: {outcome: '3'}, score: 5},
|
||||
],
|
||||
},
|
||||
{
|
||||
links: {user: '2'},
|
||||
scores: [{links: {outcome: '2'}, score: 3}],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const outcomeRollups = [
|
||||
{outcome_id: '1', user_id: '1', score: 5},
|
||||
{outcome_id: '2', user_id: '1', score: 4},
|
||||
{outcome_id: '2', user_id: '2', score: 3},
|
||||
]
|
||||
|
||||
export default {
|
||||
custom_columns: customColumns,
|
||||
set_default_grade_response: default_grade_response,
|
||||
students,
|
||||
concluded_enrollments: concludedStudents,
|
||||
assignment_groups: assignmentGroups,
|
||||
submissions,
|
||||
sections,
|
||||
outcomes,
|
||||
outcome_rollups: outcomeRollups,
|
||||
create() {
|
||||
window.ENV = {
|
||||
current_user_id: 1,
|
||||
context_asset_string: 'course_1',
|
||||
GRADEBOOK_OPTIONS: {
|
||||
enrollments_url: '/api/v1/enrollments',
|
||||
enrollments_with_concluded_url: '/api/v1/concluded_enrollments',
|
||||
assignment_groups_url: '/api/v1/assignment_groups',
|
||||
submissions_url: '/api/v1/submissions',
|
||||
sections_url: '/api/v1/sections',
|
||||
context_url: '/courses/1',
|
||||
context_id: 1,
|
||||
group_weighting_scheme: 'equal',
|
||||
change_grade_url: '/api/v1/courses/1/assignments/:assignment/submissions/:submission',
|
||||
custom_columns_url: 'api/v1/courses/1/custom_gradebook_columns',
|
||||
custom_column_data_url: 'api/v1/courses/1/custom_gradebook_columns/:id',
|
||||
setting_update_url: 'api/v1/courses/1/settings',
|
||||
outcome_gradebook_enabled: true,
|
||||
outcome_links_url: 'api/v1/courses/1/outcome_group_links',
|
||||
outcome_rollups_url: 'api/v1/courses/1/outcome_rollups',
|
||||
active_grading_periods: [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Fall Period 1',
|
||||
start_date: '2013-08-01T00:00:00Z',
|
||||
end_date: '2013-09-01T00:00:00Z',
|
||||
close_date: '2013-09-08T00:00:00Z',
|
||||
is_closed: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Fall Period 2',
|
||||
start_date: '2013-09-01T00:00:00Z',
|
||||
end_date: '2013-11-01T00:00:00Z',
|
||||
close_date: '2013-11-08T00:00:00Z',
|
||||
is_closed: true,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Fall Period 3',
|
||||
start_date: '2013-11-01T00:00:00Z',
|
||||
end_date: '2014-01-01T00:00:00Z',
|
||||
close_date: '2014-01-08T00:00:00Z',
|
||||
is_closed: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.enrollments_url, {
|
||||
response: clone(students),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.enrollments_with_concluded_url, {
|
||||
response: clone(concludedStudents),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.assignment_groups_url, {
|
||||
response: clone(assignmentGroups),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.submissions_url, {
|
||||
response: clone(submissions),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.sections_url, {
|
||||
response: clone(sections),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.custom_columns_url, {
|
||||
response: clone(customColumns),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
// the qUnit specs were sending a request for this that was 404'ing so I just
|
||||
// added this so it wouldn't
|
||||
ajax.defineFixture(`${window.ENV.GRADEBOOK_OPTIONS.custom_columns_url}/1`, {
|
||||
response: {},
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.setting_update_url, {
|
||||
response: true,
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.outcome_links_url, {
|
||||
response: clone(outcomesRaw),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
return ajax.defineFixture(window.ENV.GRADEBOOK_OPTIONS.outcome_rollups_url, {
|
||||
response: clone(outcomeRollupsRaw),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
},
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 startApp from './start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from './ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
|
||||
QUnit.module('screenreader_gradebook', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(
|
||||
() => (this.controller = App.__container__.lookup('controller:screenreader_gradebook'))
|
||||
)
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('fetches enrollments', function () {
|
||||
equal(this.controller.get('enrollments').objectAt(0).user.name, 'Bob Barnes')
|
||||
equal(this.controller.get('enrollments').objectAt(1).user.name, 'Fred Flint')
|
||||
})
|
||||
|
||||
test('fetches sections', function () {
|
||||
equal(this.controller.get('sections').objectAt(0).name, 'Vampires and Demons')
|
||||
equal(this.controller.get('sections').objectAt(1).name, 'Slayers and Scoobies')
|
||||
})
|
||||
|
||||
test('fetches custom_columns', function () {
|
||||
equal(this.controller.get('custom_columns.length'), 1)
|
||||
equal(this.controller.get('custom_columns.firstObject').title, fixtures.custom_columns[0].title)
|
||||
})
|
||||
|
||||
test('fetches outcomes', function () {
|
||||
equal(this.controller.get('outcomes').objectAt(0).title, 'Eating')
|
||||
equal(this.controller.get('outcomes').objectAt(1).title, 'Drinking')
|
||||
})
|
|
@ -1,166 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import startApp from '../start_app'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
const {run} = Ember
|
||||
|
||||
const groupScores = {
|
||||
assignment_group_1: {
|
||||
possible: 1000,
|
||||
score: 946.65,
|
||||
submission_count: 10,
|
||||
submissions: [],
|
||||
weight: 90,
|
||||
},
|
||||
}
|
||||
const periodScores = {
|
||||
grading_period_1: {
|
||||
possible: 1800.111,
|
||||
score: 95.1225,
|
||||
submission_count: 30,
|
||||
submissions: [],
|
||||
weight: 60,
|
||||
},
|
||||
}
|
||||
|
||||
QUnit.module('assignment_subtotal_grades_component by group', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
const App = startApp()
|
||||
this.component = App.AssignmentSubtotalGradesComponent.create()
|
||||
this.component.reopen({
|
||||
gradingStandard: function () {
|
||||
return [
|
||||
['A', 0.5],
|
||||
['C', 0.05],
|
||||
['F', 0.0],
|
||||
]
|
||||
}.property(),
|
||||
weightingScheme: function () {
|
||||
return 'percent'
|
||||
}.property(),
|
||||
})
|
||||
return run(() => {
|
||||
this.assignment_group = Ember.copy(fixtures.assignment_groups, true).findBy('id', '1')
|
||||
this.student = Ember.Object.create(Ember.copy(groupScores))
|
||||
return this.component.setProperties({
|
||||
student: this.student,
|
||||
subtotal: {
|
||||
name: this.assignment_group.name,
|
||||
weight: this.assignment_group.group_weight,
|
||||
key: `assignment_group_${this.assignment_group.id}`,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
return App.destroy()
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
test('values', function () {
|
||||
deepEqual(this.component.get('values'), groupScores.assignment_group_1)
|
||||
})
|
||||
|
||||
test('points', function () {
|
||||
const expected = '946.65 / 1,000'
|
||||
equal(this.component.get('points'), expected)
|
||||
})
|
||||
|
||||
test('percent', function () {
|
||||
const expected = '94.67%'
|
||||
strictEqual((946.65 / 1000) * 100, 94.66499999999999)
|
||||
strictEqual(this.component.get('percent'), expected)
|
||||
})
|
||||
|
||||
test('letterGrade', function () {
|
||||
const expected = 'A'
|
||||
equal(this.component.get('letterGrade'), expected)
|
||||
})
|
||||
|
||||
test('scoreDetail', function () {
|
||||
const expected = '(946.65 / 1,000)'
|
||||
equal(this.component.get('scoreDetail'), expected)
|
||||
})
|
||||
|
||||
QUnit.module('assignment_subtotal_grades_component by period', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
const App = startApp()
|
||||
this.component = App.AssignmentSubtotalGradesComponent.create()
|
||||
this.component.reopen({
|
||||
gradingStandard: function () {
|
||||
return [
|
||||
['A', 0.5],
|
||||
['C', 0.05],
|
||||
['F', 0.0],
|
||||
]
|
||||
}.property(),
|
||||
})
|
||||
return run(() => {
|
||||
this.student = Ember.Object.create(Ember.copy(periodScores))
|
||||
return this.component.setProperties({
|
||||
student: this.student,
|
||||
subtotal: {
|
||||
name: 'Grading Period 1',
|
||||
weight: 0.65,
|
||||
key: 'grading_period_1',
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
return App.destroy()
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
test('values', function () {
|
||||
deepEqual(this.component.get('values'), periodScores.grading_period_1)
|
||||
})
|
||||
|
||||
test('points', function () {
|
||||
const expected = '95.12 / 1,800.11'
|
||||
equal(this.component.get('points'), expected)
|
||||
})
|
||||
|
||||
test('percent', function () {
|
||||
const expected = '5.28%'
|
||||
equal(this.component.get('percent'), expected)
|
||||
})
|
||||
|
||||
test('letterGrade', function () {
|
||||
const expected = 'C'
|
||||
equal(this.component.get('letterGrade'), expected)
|
||||
})
|
||||
|
||||
test('scoreDetail', function () {
|
||||
const expected = '(95.12 / 1,800.11)'
|
||||
equal(this.component.get('scoreDetail'), expected)
|
||||
})
|
|
@ -1,80 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import startApp from '../start_app'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
const {run} = Ember
|
||||
|
||||
const groupScores = {
|
||||
assignment_group_1: {
|
||||
possible: 100,
|
||||
score: 54.5,
|
||||
submission_count: 1,
|
||||
submissions: [],
|
||||
weight: 100,
|
||||
},
|
||||
}
|
||||
|
||||
QUnit.module('assignment_subtotal_grades_component_letter_grade', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
const App = startApp()
|
||||
this.component = App.AssignmentSubtotalGradesComponent.create()
|
||||
this.component.reopen({
|
||||
gradingStandard: function () {
|
||||
return [
|
||||
['A', 0.8],
|
||||
['B+', 55.5],
|
||||
['B', 54.5],
|
||||
['C', 0.05],
|
||||
['F', 0.0],
|
||||
]
|
||||
}.property(),
|
||||
weightingScheme: function () {
|
||||
return 'percent'
|
||||
}.property(),
|
||||
})
|
||||
return run(() => {
|
||||
this.assignment_group = Ember.copy(fixtures.assignment_groups, true).findBy('id', '1')
|
||||
this.student = Ember.Object.create(Ember.copy(groupScores))
|
||||
return this.component.setProperties({
|
||||
student: this.student,
|
||||
subtotal: {
|
||||
name: this.assignment_group.name,
|
||||
key: `assignment_group_${this.assignment_group.id}`,
|
||||
weight: this.assignment_group.group_weight,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
return App.destroy()
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
test('letterGrade', function () {
|
||||
const expected = 'C'
|
||||
equal(this.component.get('letterGrade'), expected)
|
||||
})
|
|
@ -1,150 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import startApp from '../start_app'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
import GradebookHelpers from '../../../helpers'
|
||||
import GradebookConstants from '../../../constants'
|
||||
|
||||
const {run} = Ember
|
||||
|
||||
QUnit.module('custom_column_cell', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
const App = startApp()
|
||||
this.component = App.CustomColumnCellComponent.create()
|
||||
|
||||
this.component.reopen({
|
||||
customColURL() {
|
||||
return '/api/v1/custom_gradebook_columns/:id/:user_id'
|
||||
},
|
||||
})
|
||||
return run(() => {
|
||||
this.column = Ember.Object.create({
|
||||
id: '22',
|
||||
title: 'Notes',
|
||||
read_only: false,
|
||||
is_loading: false,
|
||||
})
|
||||
this.student = Ember.Object.create({
|
||||
id: '45',
|
||||
})
|
||||
this.dataForStudent = [
|
||||
Ember.Object.create({
|
||||
column_id: '22',
|
||||
content: 'lots of content here',
|
||||
}),
|
||||
]
|
||||
this.component.setProperties({
|
||||
student: this.student,
|
||||
column: this.column,
|
||||
dataForStudent: this.dataForStudent,
|
||||
})
|
||||
return this.component.append()
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
return App.destroy()
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
test('id', function () {
|
||||
equal(this.component.get('id'), 'custom_col_22')
|
||||
})
|
||||
|
||||
test('value', function () {
|
||||
equal(this.component.get('value'), 'lots of content here')
|
||||
})
|
||||
|
||||
test('saveUrl', function () {
|
||||
equal(this.component.get('saveURL'), '/api/v1/custom_gradebook_columns/22/45')
|
||||
})
|
||||
|
||||
test('disabled is true when column isLoading', function () {
|
||||
this.component.column.set('isLoading', true)
|
||||
this.component.column.set('read_only', false)
|
||||
equal(this.component.get('disabled'), true)
|
||||
})
|
||||
|
||||
test('disabled is true when column is read_only', function () {
|
||||
this.component.column.set('isLoading', false)
|
||||
this.component.column.set('read_only', true)
|
||||
equal(this.component.get('disabled'), true)
|
||||
})
|
||||
|
||||
test('disabled is false when column is not loading and not read_only', function () {
|
||||
this.component.column.set('isLoading', false)
|
||||
this.component.column.set('read_only', false)
|
||||
equal(this.component.get('disabled'), false)
|
||||
})
|
||||
|
||||
test('focusOut', function (assert) {
|
||||
assert.expect(1)
|
||||
const stub = sandbox.stub(this.component, 'boundSaveSuccess')
|
||||
|
||||
let requestStub = null
|
||||
run(
|
||||
() =>
|
||||
(requestStub = Ember.RSVP.resolve({
|
||||
id: '22',
|
||||
title: 'Notes',
|
||||
content: 'less content now',
|
||||
}))
|
||||
)
|
||||
|
||||
sandbox.stub(this.component, 'ajax').returns(requestStub)
|
||||
|
||||
run(() => {
|
||||
this.component.set('value', 'such success')
|
||||
return this.component.send('focusOut')
|
||||
})
|
||||
|
||||
ok(stub.called)
|
||||
})
|
||||
|
||||
test('textAreaInput does not flash an error if note length is exactly the max allowed length', function () {
|
||||
const note = 'a'.repeat(GradebookConstants.MAX_NOTE_LENGTH)
|
||||
const noteInputEvent = {target: {value: note}}
|
||||
const maxLengthError = sandbox.spy(GradebookHelpers, 'flashMaxLengthError')
|
||||
this.component.textAreaInput(noteInputEvent)
|
||||
ok(maxLengthError.notCalled)
|
||||
})
|
||||
|
||||
test('textAreaInput flashes an error if note length is greater than the max allowed length', function () {
|
||||
const note = 'a'.repeat(GradebookConstants.MAX_NOTE_LENGTH + 1)
|
||||
const noteInputEvent = {target: {value: note}}
|
||||
const maxLengthError = sandbox.spy(GradebookHelpers, 'flashMaxLengthError')
|
||||
this.component.textAreaInput(noteInputEvent)
|
||||
ok(maxLengthError.calledOnce)
|
||||
})
|
||||
|
||||
test('textAreaInput does not flash an error if there is already an error showing, even if note length is greater than the max allowed length', function () {
|
||||
const note = 'a'.repeat(GradebookConstants.MAX_NOTE_LENGTH + 1)
|
||||
const noteInputEvent = {target: {value: note}}
|
||||
const maxLengthError = sandbox.spy(GradebookHelpers, 'flashMaxLengthError')
|
||||
const findStub = sandbox.stub($, 'find')
|
||||
findStub.withArgs('.ic-flash-error').returns(['a non-empty error array'])
|
||||
this.component.textAreaInput(noteInputEvent)
|
||||
ok(maxLengthError.notCalled)
|
||||
})
|
|
@ -1,42 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2018 - 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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
|
||||
QUnit.module('FinalGradeComponent', hooks => {
|
||||
let App
|
||||
let component
|
||||
|
||||
hooks.beforeEach(() => {
|
||||
App = startApp()
|
||||
component = App.FinalGradeComponent.create({})
|
||||
})
|
||||
|
||||
test('bubbles up an onEditFinalGradeOverride action with the grade', () => {
|
||||
const targetObject = {
|
||||
onEditFinalGradeOverride(grade) {
|
||||
strictEqual(grade, '93%')
|
||||
},
|
||||
}
|
||||
|
||||
component.set('onEditFinalGradeOverride', 'onEditFinalGradeOverride')
|
||||
component.set('targetObject', targetObject)
|
||||
component.send('onEditFinalGradeOverride', '93%')
|
||||
})
|
||||
})
|
|
@ -1,96 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2018 - 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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
|
||||
QUnit.module('FinalGradeOverrideComponent', hooks => {
|
||||
let App
|
||||
let component
|
||||
let finalGradeOverride
|
||||
|
||||
hooks.beforeEach(() => {
|
||||
App = startApp()
|
||||
finalGradeOverride = {
|
||||
percentage: 92.32,
|
||||
}
|
||||
const gradingStandard = [
|
||||
['A', 0.9],
|
||||
['B', 0.8],
|
||||
['C', 0.0],
|
||||
]
|
||||
component = App.FinalGradeOverrideComponent.create({finalGradeOverride, gradingStandard})
|
||||
})
|
||||
|
||||
test('inputValue returns the override grade', () => {
|
||||
strictEqual(component.get('inputValue'), 'A')
|
||||
})
|
||||
|
||||
test('inputValue returns the percentage when grading schemes are not enabled', () => {
|
||||
component.set('gradingStandard', undefined)
|
||||
strictEqual(component.get('inputValue'), '92.32%')
|
||||
})
|
||||
|
||||
test('inputDescription returns a formatted percentage', () => {
|
||||
strictEqual(component.get('inputDescription'), '92.32%')
|
||||
})
|
||||
|
||||
test('inputDescription returns null when grading schemes are not enabled', () => {
|
||||
component.set('gradingStandard', undefined)
|
||||
strictEqual(component.get('inputDescription'), null)
|
||||
})
|
||||
|
||||
test('changing the override percentage changes the inputValue', () => {
|
||||
finalGradeOverride.percentage = 86.7
|
||||
component.set('finalGradeOverride', {...finalGradeOverride})
|
||||
strictEqual(component.get('inputValue'), 'B')
|
||||
})
|
||||
|
||||
test('changing the override percentage changes the inputDescription', () => {
|
||||
finalGradeOverride.percentage = 86.7
|
||||
strictEqual(component.get('inputDescription'), '86.7%')
|
||||
})
|
||||
|
||||
test('changing the grading standard changes the inputValue', () => {
|
||||
const gradingStandard = [
|
||||
['A', 0.99],
|
||||
['F', 0.0],
|
||||
]
|
||||
component.set('gradingStandard', gradingStandard)
|
||||
strictEqual(component.get('inputValue'), 'F')
|
||||
})
|
||||
|
||||
test('focusOut sends onEditFinalGradeOverride with the inputValue', () => {
|
||||
const targetObject = {
|
||||
onEditFinalGradeOverride(grade) {
|
||||
strictEqual(grade, 92.1)
|
||||
},
|
||||
}
|
||||
|
||||
component.set('onEditFinalGradeOverride', 'onEditFinalGradeOverride')
|
||||
component.set('targetObject', targetObject)
|
||||
component.set('inputValue', 92.1)
|
||||
component.focusOut()
|
||||
})
|
||||
|
||||
test('focusOut sets the inputValue to the internalInputValue', () => {
|
||||
component.set('internalInputValue', 'C')
|
||||
component.focusOut()
|
||||
strictEqual(component.get('inputValue'), 'C')
|
||||
})
|
||||
})
|
|
@ -1,197 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import * as tz from '@instructure/moment-utils'
|
||||
import startApp from '../start_app'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
import GradeFormatHelper from '@canvas/grading/GradeFormatHelper'
|
||||
|
||||
const {run} = Ember
|
||||
|
||||
let setType = null
|
||||
|
||||
QUnit.module('grading_cell', {
|
||||
setup() {
|
||||
window.ENV = {}
|
||||
fixtures.create()
|
||||
const App = startApp()
|
||||
this.component = App.GradingCellComponent.create()
|
||||
|
||||
ENV.GRADEBOOK_OPTIONS.grading_period_set = {
|
||||
id: '1',
|
||||
weighted: false,
|
||||
display_totals_for_all_grading_periods: false,
|
||||
}
|
||||
ENV.current_user_roles = []
|
||||
|
||||
setType = type => run(() => this.assignment.set('grading_type', type))
|
||||
this.component.reopen({
|
||||
changeGradeURL() {
|
||||
return '/api/v1/assignment/:assignment/:submission'
|
||||
},
|
||||
})
|
||||
return run(() => {
|
||||
this.submission = Ember.Object.create({
|
||||
grade: 'B',
|
||||
entered_grade: 'A',
|
||||
score: 8,
|
||||
entered_score: 10,
|
||||
points_deducted: 2,
|
||||
gradeLocked: false,
|
||||
assignment_id: 1,
|
||||
user_id: 1,
|
||||
})
|
||||
this.assignment = Ember.Object.create({
|
||||
due_at: tz.parse('2013-10-01T10:00:00Z'),
|
||||
grading_type: 'points',
|
||||
points_possible: 10,
|
||||
})
|
||||
this.component.setProperties({
|
||||
submission: this.submission,
|
||||
assignment: this.assignment,
|
||||
})
|
||||
return this.component.append()
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
App.destroy()
|
||||
return (window.ENV = {})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
test('setting value on init', function () {
|
||||
const component = App.GradingCellComponent.create()
|
||||
equal(component.get('value'), '-')
|
||||
equal(this.component.get('value'), 'A')
|
||||
})
|
||||
|
||||
test('entered_score', function () {
|
||||
equal(this.component.get('entered_score'), 10)
|
||||
})
|
||||
|
||||
test('late_penalty', function () {
|
||||
equal(this.component.get('late_penalty'), -2)
|
||||
})
|
||||
|
||||
test('points_possible', function () {
|
||||
equal(this.component.get('points_possible'), 10)
|
||||
})
|
||||
|
||||
test('final_grade', function () {
|
||||
equal(this.component.get('final_grade'), 'B')
|
||||
})
|
||||
|
||||
test('saveURL', function () {
|
||||
equal(this.component.get('saveURL'), '/api/v1/assignment/1/1')
|
||||
})
|
||||
|
||||
test('isPoints', function () {
|
||||
setType('points')
|
||||
ok(this.component.get('isPoints'))
|
||||
})
|
||||
|
||||
test('isPercent', function () {
|
||||
setType('percent')
|
||||
ok(this.component.get('isPercent'))
|
||||
})
|
||||
|
||||
test('isLetterGrade', function () {
|
||||
setType('letter_grade')
|
||||
ok(this.component.get('isLetterGrade'))
|
||||
})
|
||||
|
||||
test('isInPastGradingPeriodAndNotAdmin is true when the submission is gradeLocked', function () {
|
||||
run(() => this.submission.set('gradeLocked', true))
|
||||
equal(this.component.get('isInPastGradingPeriodAndNotAdmin'), true)
|
||||
})
|
||||
|
||||
test('isInPastGradingPeriodAndNotAdmin is false when the submission is not gradeLocked', function () {
|
||||
run(() => this.submission.set('gradeLocked', false))
|
||||
equal(this.component.get('isInPastGradingPeriodAndNotAdmin'), false)
|
||||
})
|
||||
|
||||
test('nilPointsPossible', function () {
|
||||
run(() => this.assignment.set('points_possible', null))
|
||||
ok(this.component.get('nilPointsPossible'))
|
||||
run(() => this.assignment.set('points_possible', 10))
|
||||
equal(this.component.get('nilPointsPossible'), false)
|
||||
})
|
||||
|
||||
test('isGpaScale', function () {
|
||||
setType('gpa_scale')
|
||||
ok(this.component.get('isGpaScale'))
|
||||
})
|
||||
|
||||
test('isPassFail', function () {
|
||||
setType('pass_fail')
|
||||
ok(this.component.get('isPassFail'))
|
||||
})
|
||||
|
||||
test('does not translate pass_fail grades', function () {
|
||||
setType('pass_fail')
|
||||
sandbox.stub(GradeFormatHelper, 'formatGrade').returns('completo')
|
||||
run(() => this.submission.set('entered_grade', 'complete'))
|
||||
this.component.submissionDidChange()
|
||||
equal(this.component.get('value'), 'complete')
|
||||
})
|
||||
|
||||
test('formats percent grades', function () {
|
||||
setType('percent')
|
||||
sandbox.stub(GradeFormatHelper, 'formatGrade').returns('32,4%')
|
||||
run(() => this.submission.set('entered_grade', '32.4'))
|
||||
this.component.submissionDidChange()
|
||||
equal(this.component.get('value'), '32,4%')
|
||||
})
|
||||
|
||||
test('focusOut', function (assert) {
|
||||
const done = assert.async()
|
||||
const stub = sandbox.stub(this.component, 'boundUpdateSuccess')
|
||||
const submissions = []
|
||||
|
||||
let requestStub = null
|
||||
run(() => {
|
||||
requestStub = Ember.RSVP.resolve({all_submissions: submissions})
|
||||
})
|
||||
|
||||
sandbox.stub(this.component, 'ajax').returns(requestStub)
|
||||
|
||||
run(() => {
|
||||
this.component.set('value', '10')
|
||||
return this.component.send('focusOut', {target: {id: 'student_and_assignment_grade'}})
|
||||
})
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
Promise.resolve().then(() => {
|
||||
ok(stub.called)
|
||||
// eslint-disable-next-line promise/no-callback-in-promise
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
test('onUpdateSuccess', function () {
|
||||
run(() => this.assignment.set('points_possible', 100))
|
||||
const flashWarningStub = sandbox.stub($, 'flashWarning')
|
||||
this.component.onUpdateSuccess({all_submissions: [], score: 150})
|
||||
ok(flashWarningStub.called)
|
||||
})
|
|
@ -1,95 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import {extend} from 'lodash'
|
||||
import DownloadDialog from '../../components/ic_submission_download_dialog_component'
|
||||
import fixtures from '../shared_ajax_fixtures'
|
||||
|
||||
function buildComponent(props) {
|
||||
props = extend(props, {assignmentUrl: '/courses/1/assignments/1'})
|
||||
return DownloadDialog.create(props)
|
||||
}
|
||||
|
||||
QUnit.module('ic_submission_download_dialog', {
|
||||
setup() {
|
||||
return fixtures.create()
|
||||
},
|
||||
})
|
||||
|
||||
test('is "finished" if file ready', () => {
|
||||
const component = buildComponent({
|
||||
attachment: {workflow_state: 'available'},
|
||||
})
|
||||
equal(component.get('status'), 'finished')
|
||||
})
|
||||
|
||||
test('is "zipping" if percent complete is > 95', () => {
|
||||
const component = buildComponent({
|
||||
percentComplete: 95,
|
||||
})
|
||||
equal(component.get('status'), 'zipping')
|
||||
})
|
||||
|
||||
test('is "starting" otherwise', () => {
|
||||
const component = buildComponent()
|
||||
equal(component.get('status'), 'starting')
|
||||
})
|
||||
|
||||
QUnit.module('progress:')
|
||||
|
||||
test('percentComplete is 100 if file ready', () => {
|
||||
// initialize percentComplete at 100
|
||||
// so the observer that updates the progressbar doesn't fire
|
||||
// otherwise the test fails because there is no DOM
|
||||
const component = buildComponent({
|
||||
attachment: {workflow_state: 'available'},
|
||||
percentComplete: 100,
|
||||
})
|
||||
component.progress()
|
||||
equal(component.get('percentComplete'), 100)
|
||||
})
|
||||
|
||||
test('percentComplete is 0 if file_state is a string', () => {
|
||||
const component = buildComponent({
|
||||
attachment: {file_state: 'ready_to_download'},
|
||||
})
|
||||
component.progress()
|
||||
equal(component.get('percentComplete'), 0)
|
||||
})
|
||||
|
||||
QUnit.module('keepChecking')
|
||||
|
||||
test('is true if open', () => {
|
||||
const component = buildComponent({
|
||||
isOpened: true,
|
||||
})
|
||||
equal(component.get('keepChecking'), true)
|
||||
})
|
||||
|
||||
test('is undefined if closed', () => {
|
||||
const component = buildComponent()
|
||||
equal(component.get('keepChecking'), undefined)
|
||||
})
|
||||
|
||||
test('is undefined if percentComplete is 100', () => {
|
||||
const component = buildComponent({
|
||||
percentComplete: 100,
|
||||
})
|
||||
equal(component.get('keepChecking'), undefined)
|
||||
})
|
|
@ -1,104 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import startApp from '../start_app'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
const {run} = Ember
|
||||
|
||||
let mutedAssignment = null
|
||||
let unmutedAssignment = null
|
||||
|
||||
function compareIdentity(assignment, fixture) {
|
||||
equal(assignment.muted, fixture.muted, 'muted status')
|
||||
equal(assignment.id, fixture.id, 'assignment id')
|
||||
}
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment_muter_component', hooks => {
|
||||
hooks.beforeEach(function (_assert) {
|
||||
fixtures.create()
|
||||
mutedAssignment = fixtures.assignment_groups[0].assignments[1]
|
||||
unmutedAssignment = fixtures.assignment_groups[0].assignments[0]
|
||||
const App = startApp()
|
||||
return run(() => {
|
||||
this.assignment = Ember.copy(mutedAssignment, true)
|
||||
return (this.component = App.AssignmentMuterComponent.create({assignment: this.assignment}))
|
||||
})
|
||||
})
|
||||
|
||||
hooks.afterEach(function (_assert) {
|
||||
return run(() => {
|
||||
this.component.destroy()
|
||||
return (this.component = null)
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.test('it works', function () {
|
||||
compareIdentity(this.component.get('assignment'), mutedAssignment)
|
||||
|
||||
Ember.run(() => {
|
||||
this.assignment = Ember.copy(unmutedAssignment, true)
|
||||
return this.component.setProperties({
|
||||
assignment: this.assignment,
|
||||
})
|
||||
})
|
||||
|
||||
compareIdentity(this.component.get('assignment'), unmutedAssignment)
|
||||
})
|
||||
|
||||
QUnit.module('moderated grading', _hooks => {
|
||||
QUnit.test('it is not disabled if assignment is not muted', function () {
|
||||
unmutedAssignment = fixtures.assignment_groups[4].assignments[1]
|
||||
Ember.run(() => {
|
||||
this.assignment = Ember.copy(unmutedAssignment, true)
|
||||
return (this.component = App.AssignmentMuterComponent.create({assignment: this.assignment}))
|
||||
})
|
||||
strictEqual(this.component.get('disabled'), false)
|
||||
})
|
||||
|
||||
QUnit.test('it is not disabled if assignment is not moderated', function () {
|
||||
const nonmoderatedAssignment = fixtures.assignment_groups[4].assignments[2]
|
||||
Ember.run(() => {
|
||||
this.assignment = Ember.copy(nonmoderatedAssignment, true)
|
||||
return (this.component = App.AssignmentMuterComponent.create({assignment: this.assignment}))
|
||||
})
|
||||
strictEqual(this.component.get('disabled'), false)
|
||||
})
|
||||
|
||||
QUnit.test('it is not disabled if assignment has grades published', function () {
|
||||
const gradesPublishedAssignment = fixtures.assignment_groups[4].assignments[3]
|
||||
Ember.run(() => {
|
||||
this.assignment = Ember.copy(gradesPublishedAssignment, true)
|
||||
return (this.component = App.AssignmentMuterComponent.create({assignment: this.assignment}))
|
||||
})
|
||||
strictEqual(this.component.get('disabled'), false)
|
||||
})
|
||||
|
||||
QUnit.test('it is disabled if muted, moderated, and grades not published', function () {
|
||||
const mutedModeratedGradesNotPublishedAssignment =
|
||||
fixtures.assignment_groups[4].assignments[0]
|
||||
Ember.run(() => {
|
||||
this.assignment = Ember.copy(mutedModeratedGradesNotPublishedAssignment, true)
|
||||
return (this.component = App.AssignmentMuterComponent.create({assignment: this.assignment}))
|
||||
})
|
||||
strictEqual(this.component.get('disabled'), true)
|
||||
})
|
||||
})
|
||||
})
|
File diff suppressed because it is too large
Load Diff
|
@ -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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
|
||||
QUnit.module('grading_cell_component integration test for isPoints', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
this.assignment = this.controller.get('assignments').findBy('id', '6')
|
||||
this.student = this.controller.get('students').findBy('id', '1')
|
||||
return Ember.run(() =>
|
||||
this.controller.setProperties({
|
||||
submissions: Ember.copy(fixtures.submissions, true),
|
||||
selectedAssignment: this.assignment,
|
||||
selectedStudent: this.student,
|
||||
})
|
||||
)
|
||||
})
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('fast-select instance is used for grade input', () => {
|
||||
ok(find('#student_and_assignment_grade').is('select'))
|
||||
equal(find('#student_and_assignment_grade').val(), 'incomplete')
|
||||
})
|
|
@ -1,534 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
|
||||
const buttonDisabled = (trigger, expectedBoolean) =>
|
||||
equal(find(trigger).prop('disabled'), expectedBoolean)
|
||||
|
||||
const checkSelection = (id, selection) => equal(id, find(selection).val())
|
||||
|
||||
const checkSelectedText = (text, selection) =>
|
||||
equal(text, find(selection).find('option:selected').text())
|
||||
|
||||
const checkText = (selector, expectedText) =>
|
||||
equal(Ember.$.trim(find(`.assignmentsPanel ${selector}`).text()), expectedText)
|
||||
|
||||
function studentSectionAssertions(selected, currentIndex, expectedIndex) {
|
||||
equal(currentIndex, expectedIndex)
|
||||
checkSelection(selected.id, '#student_select')
|
||||
return checkSelectedText(selected.sortable_name, '#student_select')
|
||||
}
|
||||
|
||||
QUnit.module('screenreader_gradebook student/assignment navigation: on page load', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(
|
||||
() => (this.controller = App.__container__.lookup('controller:screenreader_gradebook'))
|
||||
)
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('Previous Student button is disabled', () =>
|
||||
buttonDisabled('.student_navigation .previous_object:first', true))
|
||||
|
||||
test('Previous Assignment button is disabled', () =>
|
||||
buttonDisabled('.assignment_navigation .previous_object', true))
|
||||
|
||||
test('Next Student button is active', () =>
|
||||
buttonDisabled('.student_navigation .next_object:first', false))
|
||||
|
||||
test('Next Assignment button is active', () =>
|
||||
buttonDisabled('.assignment_navigation .next_object', false))
|
||||
|
||||
test('no student or assignment is loaded', () => {
|
||||
checkText('.student_selection', 'Select a student to view additional information here.')
|
||||
return checkText(
|
||||
'.assignment_selection',
|
||||
'Select an assignment to view additional information here.'
|
||||
)
|
||||
})
|
||||
|
||||
QUnit.module('screenreader_gradebook student/assignment navigation: with first item selected', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() => {
|
||||
this.controller.set('selectedStudent', this.controller.get('students.firstObject'))
|
||||
return this.controller.set(
|
||||
'selectedAssignment',
|
||||
this.controller.get('assignments.firstObject')
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('Previous buttons are disabled', () => {
|
||||
buttonDisabled('.student_navigation .previous_object:first', true)
|
||||
buttonDisabled('.assignment_navigation .previous_object', true)
|
||||
checkText('.student_selection', 'Bob Barnes')
|
||||
return checkText('.assignment_selection', 'Z Eats Soup')
|
||||
})
|
||||
|
||||
// compares & checks before/after objects
|
||||
test('clicking Next Student button displays next student', function () {
|
||||
const before = this.controller.get('selectedStudent')
|
||||
checkSelection(before.id, '#student_select')
|
||||
return click('.student_navigation .next_object:first').then(() => {
|
||||
const after = this.controller.get('selectedStudent')
|
||||
checkSelection(after.id, '#student_select')
|
||||
notEqual(before.id, after.id)
|
||||
const next = this.controller.get('students').indexOf(before) + 1
|
||||
equal(next, this.controller.get('students').indexOf(after))
|
||||
})
|
||||
})
|
||||
|
||||
// compares & checks before/after objects
|
||||
test('clicking Next Assignment button displays next assignment', function () {
|
||||
const before = this.controller.get('selectedAssignment')
|
||||
checkSelection(before.id, '#assignment_select')
|
||||
return click('.assignment_navigation .next_object').then(() => {
|
||||
const after = this.controller.get('selectedAssignment')
|
||||
checkSelection(after.id, '#assignment_select')
|
||||
notEqual(before, after)
|
||||
const next = this.controller.get('assignments').indexOf(before) + 1
|
||||
equal(next, this.controller.get('assignments').indexOf(after))
|
||||
})
|
||||
})
|
||||
|
||||
test('clicking next then previous will refocus on next student', () =>
|
||||
click('.student_navigation .next_object:first').then(() =>
|
||||
click('.student_navigation .previous_object:first').then(() => {
|
||||
equal($('.student_navigation .next_object:first')[0], document.activeElement)
|
||||
})
|
||||
))
|
||||
|
||||
test('clicking next then previous will refocus on next assignment', () =>
|
||||
click('.assignment_navigation .next_object').then(() =>
|
||||
click('.assignment_navigation .previous_object').then(() => {
|
||||
equal($('.assignment_navigation .next_object')[0], document.activeElement)
|
||||
})
|
||||
))
|
||||
|
||||
QUnit.module('screenreader_gradebook student/assignment navigation: with second item selected', {
|
||||
setup() {
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() => {
|
||||
this.controller.set('selectedStudent', this.controller.get('students').objectAt(1))
|
||||
return this.controller.set(
|
||||
'selectedAssignment',
|
||||
this.controller.get('assignments').objectAt(1)
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('Previous/Next Student buttons are both active', () => {
|
||||
buttonDisabled('.student_navigation .previous_object:first', false)
|
||||
return buttonDisabled('.student_navigation .next_object:first', false)
|
||||
})
|
||||
|
||||
test('Previous/Next Assignment buttons are both active', () => {
|
||||
buttonDisabled('.assignment_navigation .previous_object', false)
|
||||
return buttonDisabled('.assignment_navigation .next_object', false)
|
||||
})
|
||||
|
||||
QUnit.module('screenreader_gradebook student/assignment navigation: with last item selected', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() => {
|
||||
this.controller.set('selectedStudent', this.controller.get('students.lastObject'))
|
||||
return this.controller.set(
|
||||
'selectedAssignment',
|
||||
this.controller.get('assignments.lastObject')
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('Previous Student button is active', () =>
|
||||
buttonDisabled('.student_navigation .previous_object:first', false))
|
||||
|
||||
test('Previous Assignment button is active', () =>
|
||||
buttonDisabled('.assignment_navigation .previous_object', false))
|
||||
|
||||
test('Next Student button is disabled', () =>
|
||||
buttonDisabled('.student_navigation .next_object:first', true))
|
||||
|
||||
test('Next Assignment button is disabled', () =>
|
||||
buttonDisabled('.assignment_navigation .next_object', true))
|
||||
|
||||
// compares & checks before/after objects
|
||||
test('clicking Previous Student button displays previous student', function () {
|
||||
const before = this.controller.get('selectedStudent')
|
||||
checkSelection(before.id, '#student_select')
|
||||
return click('.student_navigation .previous_object:first').then(() => {
|
||||
const after = this.controller.get('selectedStudent')
|
||||
checkSelection(after.id, '#student_select')
|
||||
notEqual(before.id, after.id)
|
||||
const previous = this.controller.get('students').indexOf(before) - 1
|
||||
equal(previous, this.controller.get('students').indexOf(after))
|
||||
})
|
||||
})
|
||||
|
||||
// compares & checks before/after objects
|
||||
test('clicking Previous Assignment button displays previous assignment', function () {
|
||||
const before = this.controller.get('selectedAssignment')
|
||||
checkSelection(before.id, '#assignment_select')
|
||||
return click('.assignment_navigation .previous_object').then(() => {
|
||||
const after = this.controller.get('selectedAssignment')
|
||||
checkSelection(after.id, '#assignment_select')
|
||||
notEqual(before.id, after.id)
|
||||
const previous = this.controller.get('assignments').indexOf(before) - 1
|
||||
equal(previous, this.controller.get('assignments').indexOf(after))
|
||||
})
|
||||
})
|
||||
|
||||
test('clicking previous then next will reset the focus for students', () =>
|
||||
click('.student_navigation .previous_object:first').then(() =>
|
||||
click('.student_navigation .next_object:first').then(() => {
|
||||
equal($('.student_navigation .previous_object:first')[0], document.activeElement)
|
||||
})
|
||||
))
|
||||
|
||||
test('clicking previous then next will reset the focus for assignments', () =>
|
||||
click('.assignment_navigation .previous_object').then(() =>
|
||||
click('.assignment_navigation .next_object').then(() => {
|
||||
equal($('.assignment_navigation .previous_object')[0], document.activeElement)
|
||||
})
|
||||
))
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment navigation: display update', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() => {
|
||||
this.controller.set('selectedStudent', this.controller.get('students.firstObject'))
|
||||
return this.controller.set(
|
||||
'selectedAssignment',
|
||||
this.controller.get('assignments.firstObject')
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('screenreader_gradebook assignment selection: grade for field updates', function () {
|
||||
const assignment_name_selector = "label[for='student_and_assignment_grade']"
|
||||
|
||||
const selectedAssigName = this.controller.get('selectedAssignment.name')
|
||||
const selectedStudentName = this.controller.get('selectedStudent.name')
|
||||
checkText(assignment_name_selector, `Grade for ${selectedStudentName} - ${selectedAssigName}`)
|
||||
|
||||
Ember.run(() =>
|
||||
this.controller.set('selectedAssignment', this.controller.get('assignments').objectAt(2))
|
||||
)
|
||||
|
||||
const newSelectedAssigName = this.controller.get('selectedAssignment.name')
|
||||
return checkText(
|
||||
assignment_name_selector,
|
||||
`Grade for ${selectedStudentName} - ${newSelectedAssigName}`
|
||||
)
|
||||
})
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment navigation: assignment sorting', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(
|
||||
() => (this.controller = App.__container__.lookup('controller:screenreader_gradebook'))
|
||||
)
|
||||
},
|
||||
teardown() {
|
||||
// resetting userSettings to default
|
||||
Ember.run(() =>
|
||||
this.controller.set(
|
||||
'assignmentSort',
|
||||
this.controller.get('assignmentSortOptions').findBy('value', 'assignment_group')
|
||||
)
|
||||
)
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('alphabetical', function () {
|
||||
const before = this.controller.get('assignments.firstObject')
|
||||
Ember.run(() =>
|
||||
this.controller.set(
|
||||
'assignmentSort',
|
||||
this.controller.get('assignmentSortOptions').findBy('value', 'alpha')
|
||||
)
|
||||
)
|
||||
buttonDisabled('.assignment_navigation .next_object', false)
|
||||
buttonDisabled('.assignment_navigation .previous_object', true)
|
||||
const first = this.controller.get('assignments.firstObject')
|
||||
notEqual(before, first)
|
||||
return click('.assignment_navigation .next_object').then(() =>
|
||||
checkSelection(first.id, '#assignment_select')
|
||||
)
|
||||
})
|
||||
|
||||
test('due date', function () {
|
||||
const before = this.controller.get('assignments.firstObject')
|
||||
Ember.run(() =>
|
||||
this.controller.set(
|
||||
'assignmentSort',
|
||||
this.controller.get('assignmentSortOptions').findBy('value', 'due_date')
|
||||
)
|
||||
)
|
||||
buttonDisabled('.assignment_navigation .next_object', false)
|
||||
buttonDisabled('.assignment_navigation .previous_object', true)
|
||||
const first = this.controller.get('assignments.firstObject')
|
||||
notEqual(before, first)
|
||||
return click('.assignment_navigation .next_object').then(() =>
|
||||
checkSelection(first.id, '#assignment_select')
|
||||
)
|
||||
})
|
||||
|
||||
test('changing sorting option with selectedAssignment', function () {
|
||||
// SORT BY: alphabetical
|
||||
Ember.run(() =>
|
||||
this.controller.set(
|
||||
'assignmentSort',
|
||||
this.controller.get('assignmentSortOptions').findBy('value', 'alpha')
|
||||
)
|
||||
)
|
||||
|
||||
// check first assignment
|
||||
return click('.assignment_navigation .next_object').then(() => {
|
||||
const first = this.controller.get('selectedAssignment')
|
||||
checkSelection(first.id, '#assignment_select')
|
||||
equal(first.name, 'Apples are good')
|
||||
const second = this.controller
|
||||
.get('assignments')
|
||||
.objectAt(this.controller.get('assignmentIndex') + 1)
|
||||
|
||||
// check Next
|
||||
return click('.assignment_navigation .next_object').then(() => {
|
||||
checkSelection(second.id, '#assignment_select')
|
||||
notEqual(first.id, second.id)
|
||||
equal(second.name, 'Big Bowl of Nachos')
|
||||
|
||||
// check Previous
|
||||
return click('.assignment_navigation .previous_object').then(() => {
|
||||
const selected = this.controller.get('selectedAssignment')
|
||||
equal(selected.id, first.id)
|
||||
checkSelection(selected.id, '#assignment_select')
|
||||
const oldIndex = this.controller.get('assignmentIndex')
|
||||
|
||||
// SORT BY: due date
|
||||
Ember.run(() =>
|
||||
this.controller.set(
|
||||
'assignmentSort',
|
||||
this.controller.get('assignmentSortOptions').findBy('value', 'due_date')
|
||||
)
|
||||
)
|
||||
|
||||
// check selectedAssignment identity and index
|
||||
equal(selected.id, this.controller.get('selectedAssignment.id'))
|
||||
notEqual(oldIndex, this.controller.get('assignmentIndex'))
|
||||
|
||||
// check Next
|
||||
const selectedIndex = this.controller.get('assignmentIndex')
|
||||
const next = this.controller.get('assignments').objectAt(selectedIndex + 1)
|
||||
return click('.assignment_navigation .next_object').then(() =>
|
||||
checkSelection(next.id, '#assignment_select')
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('screenreader_gradebook student navigation: section selection', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() =>
|
||||
this.controller.set('selectedSection', this.controller.get('sections.lastObject'))
|
||||
)
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('prev/next still work', function () {
|
||||
buttonDisabled('.student_navigation .previous_object:first', true)
|
||||
buttonDisabled('.student_navigation .next_object:first', false)
|
||||
|
||||
// first in section
|
||||
return click('.student_navigation .next_object:first').then(() => {
|
||||
const first = this.controller.get('selectedStudent')
|
||||
let index = this.controller.get('studentIndex')
|
||||
buttonDisabled('.student_navigation .previous_object:first', true)
|
||||
studentSectionAssertions(first, index, 0)
|
||||
|
||||
// second in section
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
click('.student_navigation .next_object:first').then(() => {
|
||||
const second = this.controller.get('selectedStudent')
|
||||
index = this.controller.get('studentIndex')
|
||||
buttonDisabled('.student_navigation .previous_object:first', false)
|
||||
studentSectionAssertions(second, index, 1)
|
||||
return notEqual(first, second)
|
||||
})
|
||||
|
||||
return click('.student_navigation .previous_object:first').then(() => {
|
||||
buttonDisabled('.student_navigation .previous_object:first', true)
|
||||
return buttonDisabled('.student_navigation .next_object:first', false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('resets selectedStudent when student is not in both sections', function () {
|
||||
return click('.student_navigation .next_object:first').then(() => {
|
||||
const firstStudent = this.controller.get('selectedStudent')
|
||||
|
||||
Ember.run(() =>
|
||||
this.controller.set('selectedSection', this.controller.get('sections.firstObject'))
|
||||
)
|
||||
const resetStudent = this.controller.get('selectedStudent')
|
||||
notEqual(firstStudent, resetStudent)
|
||||
equal(resetStudent, null)
|
||||
|
||||
return click('.student_navigation .next_object:first').then(() => {
|
||||
const current = this.controller.get('selectedStudent')
|
||||
notEqual(current, firstStudent)
|
||||
return notEqual(current, resetStudent)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('maintains selectedStudent when student is in both sections and updates navigation points', function () {
|
||||
Ember.run(() =>
|
||||
// requires a fixture for a student with enrollment in 2 sections
|
||||
// and a previous/next option for all sections
|
||||
this.controller.set('selectedStudent', this.controller.get('students').objectAt(4))
|
||||
)
|
||||
|
||||
return visit('/').then(() => {
|
||||
buttonDisabled('.student_navigation .previous_object:first', false)
|
||||
buttonDisabled('.student_navigation .next_object:first', false)
|
||||
|
||||
const selected = this.controller.get('selectedStudent')
|
||||
checkSelectedText(selected.sortable_name, '#student_select')
|
||||
checkSelectedText(this.controller.get('selectedSection.name'), '#section_select')
|
||||
|
||||
// position in selected dropdown
|
||||
let position = this.controller.get('studentsInSelectedSection').indexOf(selected)
|
||||
equal(position, 1)
|
||||
equal(this.controller.get('studentIndex'), position)
|
||||
|
||||
// change section
|
||||
Ember.run(() =>
|
||||
this.controller.set('selectedSection', this.controller.get('sections.firstObject'))
|
||||
)
|
||||
buttonDisabled('.student_navigation .previous_object:first', false)
|
||||
buttonDisabled('.student_navigation .next_object:first', false)
|
||||
|
||||
const newSelected = this.controller.get('selectedStudent')
|
||||
checkSelectedText(newSelected.sortable_name, '#student_select')
|
||||
checkSelectedText(this.controller.get('selectedSection.name'), '#section_select')
|
||||
equal(selected, newSelected)
|
||||
|
||||
// position in selected dropdown
|
||||
position = this.controller.get('studentsInSelectedSection').indexOf(selected)
|
||||
equal(position, 3)
|
||||
equal(this.controller.get('studentIndex'), position)
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module(
|
||||
'screenreader_gradebook student/assignment navigation: announcing selection with aria-live',
|
||||
{
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return Ember.run(() => {
|
||||
this.controller.set('selectedStudent', this.controller.get('students.firstObject'))
|
||||
return this.controller.set(
|
||||
'selectedAssignment',
|
||||
this.controller.get('assignments.firstObject')
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('aria-announcer', function () {
|
||||
equal(Ember.$.trim(find('.aria-announcer').text()), '')
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
click('.student_navigation .next_object:first').then(() => {
|
||||
const expected = this.controller.get('selectedStudent.name')
|
||||
equal(Ember.$.trim(find('.aria-announcer').text()), expected)
|
||||
})
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
click('.assignment_navigation .next_object').then(() => {
|
||||
const expected = this.controller.get('selectedAssignment.name')
|
||||
equal(Ember.$.trim(find('.aria-announcer').text()), expected)
|
||||
})
|
||||
|
||||
return click('#hide_names_checkbox').then(() =>
|
||||
Ember.run(() => equal(Ember.$.trim(find('.aria-announcer').text()), ''))
|
||||
)
|
||||
})
|
|
@ -1,197 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
const ariaMuted = 'Click to unmute.'
|
||||
const ariaUnmuted = 'Click to mute.'
|
||||
const dialogTitleMuted = 'Unmute Assignment'
|
||||
const dialogTitleUnmuted = 'Mute Assignment'
|
||||
|
||||
const sendSuccess = (server, url, state) =>
|
||||
server.respond('POST', url, [
|
||||
200,
|
||||
{'Content-Type': 'application/json'},
|
||||
JSON.stringify({assignment: {muted: state}}),
|
||||
])
|
||||
|
||||
const checkLabel = stateLabel =>
|
||||
equal(find('#assignment_muted_check').attr('aria-label'), stateLabel)
|
||||
|
||||
const checkChecked = expectedBool =>
|
||||
equal(find('#assignment_muted_check').prop('checked'), expectedBool)
|
||||
|
||||
function checkDialogClosed() {
|
||||
const dialog = find('.ui-dialog:visible', 'body')
|
||||
equal(dialog.length, 0, 'the dialog closes')
|
||||
}
|
||||
|
||||
function closeDialog(dialog) {
|
||||
click(find('.ui-dialog-titlebar-close', dialog))
|
||||
return checkDialogClosed()
|
||||
}
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment_muter_component: muted', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.con = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
Ember.run(() =>
|
||||
this.con.set(
|
||||
'selectedAssignment',
|
||||
Ember.copy(fixtures.assignment_groups[0].assignments[1], true)
|
||||
)
|
||||
)
|
||||
return (this.server = sinon.fakeServer.create())
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
this.server.restore()
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog cancels dialog without changes', () => {
|
||||
checkLabel(ariaMuted)
|
||||
checkChecked(true)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
const dialog = find('.ui-dialog:visible', 'body')
|
||||
click('[data-action="cancel"]', dialog)
|
||||
checkDialogClosed()
|
||||
checkChecked(true)
|
||||
return checkLabel(ariaMuted)
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog opens and closes without changes', () => {
|
||||
checkLabel(ariaMuted)
|
||||
checkChecked(true)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
const dialog = find('.ui-dialog:visible', 'body')
|
||||
equal(find('[data-action="unmute"]', dialog).text(), dialogTitleMuted)
|
||||
closeDialog(dialog)
|
||||
checkChecked(true)
|
||||
return checkLabel(ariaMuted)
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog opens and makes changes upon confirmation', function () {
|
||||
const {server} = this
|
||||
checkLabel(ariaMuted)
|
||||
checkChecked(true)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
let dialog = find('.ui-dialog:visible', 'body')
|
||||
click('[data-action="unmute"]', dialog)
|
||||
sendSuccess(
|
||||
server,
|
||||
`${ENV.GRADEBOOK_OPTIONS.context_url}/assignments/${this.con.get(
|
||||
'selectedAssignment.id'
|
||||
)}/mute`,
|
||||
false
|
||||
)
|
||||
return andThen(() => {
|
||||
dialog = find('.ui-dialog:visible', 'body')
|
||||
equal(dialog.length, 0, 'the dialog is closed')
|
||||
checkChecked(false)
|
||||
checkLabel(ariaUnmuted)
|
||||
equal(this.con.get('selectedAssignment.muted'), false)
|
||||
return server.restore()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment_muter_component: unmuted', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.con = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
Ember.run(() =>
|
||||
this.con.set(
|
||||
'selectedAssignment',
|
||||
Ember.copy(fixtures.assignment_groups[0].assignments[0], true)
|
||||
)
|
||||
)
|
||||
return (this.server = sinon.fakeServer.create())
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
this.server.restore()
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog cancels dialog without changes', () => {
|
||||
checkLabel(ariaUnmuted)
|
||||
checkChecked(false)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
const dialog = find('.ui-dialog:visible', 'body')
|
||||
click('[data-action="cancel"]', dialog)
|
||||
checkDialogClosed()
|
||||
checkChecked(false)
|
||||
return checkLabel(ariaUnmuted)
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog opens and closes without changes', () => {
|
||||
checkLabel(ariaUnmuted)
|
||||
checkChecked(false)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
const dialog = find('.ui-dialog:visible', 'body')
|
||||
equal(find('[data-action="mute"]', dialog).text(), dialogTitleUnmuted)
|
||||
closeDialog(dialog)
|
||||
checkChecked(false)
|
||||
return checkLabel(ariaUnmuted)
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in FOO-4345
|
||||
QUnit.skip('dialog opens and makes changes upon confirmation', function () {
|
||||
const {server} = this
|
||||
checkLabel(ariaUnmuted)
|
||||
checkChecked(false)
|
||||
return click('#assignment_muted_check').then(() => {
|
||||
let dialog = find('.ui-dialog:visible', 'body')
|
||||
click('[data-action="mute"]', dialog)
|
||||
sendSuccess(
|
||||
server,
|
||||
`${ENV.GRADEBOOK_OPTIONS.context_url}/assignments/${this.con.get(
|
||||
'selectedAssignment.id'
|
||||
)}/mute`,
|
||||
true
|
||||
)
|
||||
return andThen(() => {
|
||||
dialog = find('.ui-dialog:visible', 'body')
|
||||
equal(dialog.length, 0, 'the dialog is closed')
|
||||
checkChecked(true)
|
||||
checkLabel(ariaMuted)
|
||||
equal(this.con.get('selectedAssignment.muted'), true)
|
||||
return server.restore()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,88 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
import $ from 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import 'jquery-tinypubsub'
|
||||
|
||||
let App = null
|
||||
|
||||
QUnit.module('global settings', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/').then(() => {
|
||||
this.controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
return this.controller.set('hideStudentNames', false)
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('student names are hidden', () => {
|
||||
const selection = '#student_select option[value=1]'
|
||||
equal($(selection).text(), 'Barnes, Bob')
|
||||
return click('#hide_names_checkbox').then(() => {
|
||||
return click('#hide_names_checkbox').then(() => {
|
||||
equal($(selection).text(), 'Barnes, Bob')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('secondary id says hidden', function () {
|
||||
Ember.run(() => {
|
||||
const student = this.controller.get('students.firstObject')
|
||||
Ember.setProperties(student, {
|
||||
isLoaded: true,
|
||||
isLoading: false,
|
||||
})
|
||||
return this.controller.set('selectedStudent', student)
|
||||
})
|
||||
|
||||
equal(Ember.$.trim(find('.secondary_id').text()), '')
|
||||
click('#hide_names_checkbox')
|
||||
return andThen(() => {
|
||||
equal($.trim(find('.secondary_id:first').text()), 'hidden')
|
||||
})
|
||||
})
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('view concluded enrollments', function () {
|
||||
let enrollments = this.controller.get('enrollments')
|
||||
ok(enrollments.content.length > 1)
|
||||
enrollments.content.forEach(enrollment => ok(enrollment.workflow_state === undefined))
|
||||
|
||||
return click('#concluded_enrollments').then(() => {
|
||||
enrollments = this.controller.get('enrollments')
|
||||
equal(enrollments.content.length, 1)
|
||||
const en = enrollments.objectAt(0)
|
||||
ok(en.workflow_state === 'completed')
|
||||
const completed_at = new Date(en.completed_at)
|
||||
ok(completed_at.getTime() < new Date().getTime())
|
||||
|
||||
return click('#concluded_enrollments').then(() => {
|
||||
enrollments = this.controller.get('enrollments')
|
||||
return ok(enrollments.content.length > 1)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
|
||||
const setSelection = selection => find('#arrange_assignments').val(selection)
|
||||
const checkSelection = selection => equal(selection, find('#arrange_assignments').val())
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment sorting: no saved setting', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/')
|
||||
},
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('defaults to assignment group', () => checkSelection('assignment_group'))
|
||||
|
||||
QUnit.module('screenreader_gradebook assignment sorting: toggle settings', {
|
||||
setup() {
|
||||
fixtures.create()
|
||||
App = startApp()
|
||||
return visit('/')
|
||||
},
|
||||
teardown() {
|
||||
setSelection('assignment_group')
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
test('loads alphabetical sorting', () => {
|
||||
setSelection('alpha')
|
||||
visit('/')
|
||||
checkSelection('alpha')
|
||||
setSelection('due_date')
|
||||
visit('/')
|
||||
return checkSelection('due_date')
|
||||
})
|
||||
export default {}
|
|
@ -1,67 +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 userSettings from '@canvas/user-settings'
|
||||
import startApp from '../start_app'
|
||||
import Ember from 'ember'
|
||||
import fixtures from '../ajax_fixtures'
|
||||
|
||||
let App = null
|
||||
|
||||
function setup(initialSetting) {
|
||||
fixtures.create()
|
||||
userSettings.contextSet('include_ungraded_assignments', initialSetting)
|
||||
App = startApp()
|
||||
return visit('/')
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
const controller = App.__container__.lookup('controller:screenreader_gradebook')
|
||||
const initial = controller.get('includeUngradedAssignments')
|
||||
click('#ungraded')
|
||||
return andThen(() => equal(!controller.get('includeUngradedAssignments'), initial))
|
||||
}
|
||||
|
||||
QUnit.module('include ungraded assignments setting:false', {
|
||||
setup() {
|
||||
return setup.call(this, false)
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('clicking the ungraded checkbox updates includeUngradedAssignments to true', () =>
|
||||
runTest()
|
||||
)
|
||||
|
||||
QUnit.module('include ungraded assignments setting:true', {
|
||||
setup() {
|
||||
return setup.call(this, true)
|
||||
},
|
||||
|
||||
teardown() {
|
||||
return Ember.run(App, 'destroy')
|
||||
},
|
||||
})
|
||||
|
||||
// unskip in EVAL-2505
|
||||
QUnit.skip('clicking the ungraded checkbox updates includeUngradedAssignments to false', () =>
|
||||
runTest()
|
||||
)
|
|
@ -1,93 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2018 - 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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import * as FinalGradeOverrideApi from '@canvas/grading/FinalGradeOverrideApi'
|
||||
import ScreenreaderGradebookRoute from '../../routes/screenreader_gradebook_route'
|
||||
|
||||
QUnit.module('ScreenreaderGradebookRoute', suiteHooks => {
|
||||
let server
|
||||
|
||||
suiteHooks.beforeEach(() => {
|
||||
server = sinon.createFakeServer()
|
||||
})
|
||||
|
||||
suiteHooks.afterEach(() => {
|
||||
server.restore()
|
||||
})
|
||||
|
||||
QUnit.module('model', contextHooks => {
|
||||
let originalENV
|
||||
let route
|
||||
|
||||
contextHooks.beforeEach(() => {
|
||||
originalENV = window.ENV
|
||||
window.ENV.GRADEBOOK_OPTIONS = {
|
||||
custom_columns_url: 'custom_columns',
|
||||
enrollments_url: 'enrollments',
|
||||
final_grade_overrides_url: 'final_grade_overrides',
|
||||
sections_url: 'sections',
|
||||
outcome_links_url: 'outcome_links',
|
||||
outcome_rollups_url: 'outcome_rollups',
|
||||
}
|
||||
route = ScreenreaderGradebookRoute.create()
|
||||
})
|
||||
|
||||
contextHooks.afterEach(() => {
|
||||
window.ENV = originalENV
|
||||
})
|
||||
|
||||
QUnit.module('final_grade_overrides', hooks => {
|
||||
hooks.beforeEach(() => {
|
||||
window.ENV.GRADEBOOK_OPTIONS.final_grade_override_enabled = true
|
||||
})
|
||||
|
||||
test('sets isLoaded to false while records are loading', () => {
|
||||
const model = route.model()
|
||||
strictEqual(model.final_grade_overrides.isLoaded, false)
|
||||
})
|
||||
|
||||
test('sets isLoaded to true after records are loaded', async () => {
|
||||
const apiStub = sinon
|
||||
.stub(FinalGradeOverrideApi, 'getFinalGradeOverrides')
|
||||
.returns(Promise.resolve({status: 200}))
|
||||
const model = await route.model()
|
||||
strictEqual(model.final_grade_overrides.isLoaded, true)
|
||||
apiStub.restore()
|
||||
})
|
||||
|
||||
test('sets content after records are loaded', async () => {
|
||||
const overrideData = {
|
||||
23: {
|
||||
courseGrade: {
|
||||
percentage: 91.1,
|
||||
},
|
||||
gradingPeriodGrades: {},
|
||||
},
|
||||
}
|
||||
const apiStub = sinon
|
||||
.stub(FinalGradeOverrideApi, 'getFinalGradeOverrides')
|
||||
.returns(Promise.resolve({finalGradeOverrides: overrideData}))
|
||||
const model = await route.model()
|
||||
deepEqual(model.final_grade_overrides.content, {finalGradeOverrides: overrideData})
|
||||
apiStub.restore()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,65 +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 ajax from 'ic-ajax'
|
||||
import Ember from 'ember'
|
||||
|
||||
const clone = obj => Ember.copy(obj, true)
|
||||
|
||||
const data = {
|
||||
attachment: {
|
||||
file_state: '0',
|
||||
workflow_state: 'to_be_zipped',
|
||||
readable_size: '73 KB',
|
||||
},
|
||||
}
|
||||
|
||||
const numbers = [1, 2, 3]
|
||||
|
||||
export default {
|
||||
create() {
|
||||
window.ENV = {
|
||||
submission_zip_url: '/courses/1/assignments/1/submissions?zip=1',
|
||||
numbers_url: '/courses/1/numbers',
|
||||
}
|
||||
|
||||
ajax.defineFixture(window.ENV.submission_zip_url, {
|
||||
response: clone(data),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
|
||||
return ajax.defineFixture(window.ENV.numbers_url, {
|
||||
response: clone(numbers),
|
||||
jqXHR: {
|
||||
getResponseHeader() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
textStatus: 'success',
|
||||
})
|
||||
},
|
||||
|
||||
makeAvailable() {
|
||||
data.attachment.file_state = 100
|
||||
return (data.attachment.workflow_state = 'available')
|
||||
},
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Application from '../index'
|
||||
import Ember from 'ember'
|
||||
|
||||
export default function startApp() {
|
||||
let App = null
|
||||
|
||||
// supresses this from logging during tests:
|
||||
// DEBUG LOG: 'DEBUG: -------------------------------'
|
||||
// DEBUG LOG: 'DEBUG: Ember : 1.4.0'
|
||||
// DEBUG LOG: 'DEBUG: Handlebars : 1.3.0'
|
||||
// DEBUG LOG: 'DEBUG: jQuery : 1.7.2'
|
||||
// DEBUG LOG: 'DEBUG: -------------------------------'
|
||||
Ember.LOG_VERSION = false
|
||||
|
||||
// since we don't plan on upgrading any of our ember code to new versions
|
||||
// and we consider it "done" we don't care about deprecation warnings
|
||||
Ember.TESTING_DEPRECATION = true
|
||||
|
||||
Ember.run.join(() => {
|
||||
App = Application.create({
|
||||
rootElement: '#fixtures',
|
||||
})
|
||||
App.Router.reopen({history: 'none'})
|
||||
App.setupForTesting()
|
||||
return App.injectTestHelpers()
|
||||
})
|
||||
window.App = App
|
||||
return App
|
||||
}
|
|
@ -1,72 +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 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import Ember from 'ember'
|
||||
import fetchAllPages from '../../helpers/xhr/fetch_all_pages'
|
||||
import fixtures from '../shared_ajax_fixtures'
|
||||
|
||||
const {ArrayProxy} = Ember
|
||||
|
||||
QUnit.module('Fetch all pages component', {
|
||||
setup() {
|
||||
// yes, this looks weird. if you run
|
||||
// screenreader gradebook tests before this, it puts
|
||||
// ember into test mode, and everything dies here when we
|
||||
// try to do asynchronous work. This spec was originally written
|
||||
// assuming that Ember was unmodified. This will not impact the
|
||||
// screenreader gradebook tests, because they call "setupForTesting"
|
||||
// in every setup.
|
||||
Ember.testing = false
|
||||
fixtures.create()
|
||||
this.server = sinon.createFakeServer()
|
||||
},
|
||||
|
||||
teardown() {
|
||||
this.server.restore()
|
||||
},
|
||||
})
|
||||
|
||||
test('passes records through by default', assert => {
|
||||
const start = assert.async()
|
||||
return fetchAllPages(ENV.numbers_url).promise.then(records => {
|
||||
start()
|
||||
deepEqual(records.get('content'), [1, 2, 3])
|
||||
})
|
||||
})
|
||||
|
||||
test('populates existing array if provided', assert => {
|
||||
const start = assert.async()
|
||||
const myArray = ArrayProxy.create({content: []})
|
||||
return fetchAllPages(ENV.numbers_url, {records: myArray}).promise.then(() => {
|
||||
start()
|
||||
deepEqual(myArray.get('content'), [1, 2, 3])
|
||||
})
|
||||
})
|
||||
|
||||
test('calls process if provided', assert => {
|
||||
const start = assert.async()
|
||||
return fetchAllPages(ENV.numbers_url, {
|
||||
process(response) {
|
||||
return response.map(x => x * 2)
|
||||
},
|
||||
}).promise.then(records => {
|
||||
start()
|
||||
deepEqual(records.get('content'), [2, 4, 6])
|
||||
})
|
||||
})
|
|
@ -1,81 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
import GradebookHeaderMenu from '../../jquery/GradebookHeaderMenu'
|
||||
import SubmissionDetailsDialog from '../../jquery/SubmissionDetailsDialog'
|
||||
|
||||
const AssignmentsView = Ember.View.extend({
|
||||
templateName: 'assignments',
|
||||
|
||||
mergeObjects(old_ag, new_ag) {
|
||||
return Ember.setProperties(old_ag, new_ag)
|
||||
},
|
||||
|
||||
actions: {
|
||||
openDialog(dialogType) {
|
||||
const con = this.controller
|
||||
const assignment = con.get('selectedAssignment')
|
||||
const options = {
|
||||
assignment,
|
||||
students: con.studentsThatCanSeeAssignment(assignment),
|
||||
selected_section: __guard__(con.get('selectedSection'), x => x.id),
|
||||
context_id: ENV.GRADEBOOK_OPTIONS.context_id,
|
||||
context_url: ENV.GRADEBOOK_OPTIONS.context_url,
|
||||
speed_grader_enabled: ENV.GRADEBOOK_OPTIONS.speed_grader_enabled,
|
||||
change_grade_url: ENV.GRADEBOOK_OPTIONS.change_grade_url,
|
||||
isAdmin: ENV.current_user_is_admin,
|
||||
show_message_students_with_observers_dialog:
|
||||
ENV.GRADEBOOK_OPTIONS.show_message_students_with_observers_dialog,
|
||||
messageAttachmentUploadFolderId: ENV.GRADEBOOK_OPTIONS.message_attachment_upload_folder_id,
|
||||
current_user_id: ENV.current_user.id,
|
||||
}
|
||||
|
||||
const dialogs = {
|
||||
assignment_details: GradebookHeaderMenu.prototype.showAssignmentDetails,
|
||||
message_students: GradebookHeaderMenu.prototype.messageStudentsWho,
|
||||
set_default_grade(opts) {
|
||||
const onClose = () => $('#set_default_grade').focus()
|
||||
return GradebookHeaderMenu.prototype.setDefaultGrade.call(this, {...opts, onClose})
|
||||
},
|
||||
curve_grades: GradebookHeaderMenu.prototype.curveGrades,
|
||||
submission: SubmissionDetailsDialog.open,
|
||||
}
|
||||
|
||||
switch (dialogType) {
|
||||
case 'submission':
|
||||
return dialogs[dialogType] != null
|
||||
? dialogs[dialogType].call(
|
||||
this,
|
||||
con.get('selectedAssignment'),
|
||||
con.get('selectedStudent'),
|
||||
options
|
||||
)
|
||||
: undefined
|
||||
default:
|
||||
return dialogs[dialogType] != null ? dialogs[dialogType].call(this, options) : undefined
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default AssignmentsView
|
||||
|
||||
function __guard__(value, transform) {
|
||||
return typeof value !== 'undefined' && value !== null ? transform(value) : undefined
|
||||
}
|
|
@ -1,24 +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 Ember from 'ember'
|
||||
|
||||
const LearningMasteryView = Ember.View.extend({
|
||||
templateName: 'learning_mastery',
|
||||
})
|
||||
|
||||
export default LearningMasteryView
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2013 - 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 Ember from 'ember'
|
||||
import 'ic-tabs/dist/cjs/main'
|
||||
|
||||
const ScreenreaderGradebookView = Ember.View.extend({
|
||||
didInsertElement() {
|
||||
// horrible hack to get disabled instead of disabled="disabled" on buttons
|
||||
return this.$('button:disabled').prop('disabled', true)
|
||||
},
|
||||
})
|
||||
|
||||
export default ScreenreaderGradebookView
|
|
@ -1,86 +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 Ember from 'ember'
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
|
||||
function capitalize(inputString) {
|
||||
return inputString.charAt(0).toUpperCase() + inputString.substring(1).toLowerCase()
|
||||
}
|
||||
|
||||
const I18n = useI18nScope('sr_gradebook')
|
||||
|
||||
const SelectionButtonsView = Ember.View.extend({
|
||||
templateName: 'content_selection/selection_buttons',
|
||||
|
||||
list: null,
|
||||
type: null,
|
||||
selected: null,
|
||||
|
||||
classPath: function () {
|
||||
return `${this.get('type')}_navigation`
|
||||
}.property('type'),
|
||||
|
||||
previousLabel: function () {
|
||||
const type = capitalize(this.get('type'))
|
||||
return I18n.t('previous_object', 'Previous %{type}', {type})
|
||||
}.property('type'),
|
||||
|
||||
nextLabel: function () {
|
||||
const type = capitalize(this.get('type'))
|
||||
return I18n.t('next_object', 'Next %{type}', {type})
|
||||
}.property('type'),
|
||||
|
||||
disablePreviousButton: Ember.computed.lte('currentIndex', 0),
|
||||
|
||||
disableNextButton: function () {
|
||||
const next = this.get('list').objectAt(this.get('currentIndex') + 1)
|
||||
return !(this.get('list.length') && next)
|
||||
}.property('currentIndex', 'list.@each'),
|
||||
|
||||
currentIndex: function () {
|
||||
return this.get('list').indexOf(this.get('selected'))
|
||||
}.property('selected', 'list.@each'),
|
||||
|
||||
actions: {
|
||||
selectItem(goTo) {
|
||||
const index = this.get('currentIndex')
|
||||
const list = this.get('list')
|
||||
let item = null
|
||||
|
||||
if (goTo === 'previous') {
|
||||
item = list.objectAt(index - 1)
|
||||
if (!list.objectAt(index - 2)) {
|
||||
this.$('.next_object').focus()
|
||||
}
|
||||
}
|
||||
if (goTo === 'next') {
|
||||
item = list.objectAt(index + 1)
|
||||
if (!list.objectAt(index + 2)) {
|
||||
this.$('.previous_object').focus()
|
||||
}
|
||||
}
|
||||
|
||||
if (item) {
|
||||
this.set('selected', item)
|
||||
return this.get('controller').send('selectItem', this.get('type'), item)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default SelectionButtonsView
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 - 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 {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import GradebookConstants from './constants'
|
||||
|
||||
const I18n = useI18nScope('gradebookHelpers')
|
||||
|
||||
export default {
|
||||
FLASH_ERROR_CLASS: '.ic-flash-error',
|
||||
flashMaxLengthError() {
|
||||
return $.flashError(
|
||||
I18n.t('Note length cannot exceed %{maxLength} characters.', {
|
||||
maxLength: GradebookConstants.MAX_NOTE_LENGTH,
|
||||
})
|
||||
)
|
||||
},
|
||||
maxLengthErrorShouldBeShown(textareaLength) {
|
||||
return this.textareaIsGreaterThanMaxLength(textareaLength) && this.noErrorsOnPage()
|
||||
},
|
||||
noErrorsOnPage() {
|
||||
return $.find(this.FLASH_ERROR_CLASS).length === 0
|
||||
},
|
||||
textareaIsGreaterThanMaxLength(textareaLength) {
|
||||
return !this.textareaIsLessThanOrEqualToMaxLength(textareaLength)
|
||||
},
|
||||
textareaIsLessThanOrEqualToMaxLength(textareaLength) {
|
||||
return textareaLength <= GradebookConstants.MAX_NOTE_LENGTH
|
||||
},
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - 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 React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import GradebookMenu from '@canvas/gradebook-menu'
|
||||
import App from './ember/index'
|
||||
|
||||
ReactDOM.render(
|
||||
<GradebookMenu
|
||||
courseUrl={ENV.GRADEBOOK_OPTIONS.context_url}
|
||||
learningMasteryEnabled={Boolean(ENV.GRADEBOOK_OPTIONS.outcome_gradebook_enabled)}
|
||||
enhancedIndividualGradebookEnabled={Boolean(
|
||||
ENV.GRADEBOOK_OPTIONS.individual_gradebook_enhancements
|
||||
)}
|
||||
variant="IndividualGradebook"
|
||||
/>,
|
||||
document.querySelector('[data-component="GradebookSelector"]')
|
||||
)
|
||||
|
||||
window.App = App.create()
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 - 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 assignmentDetailsDialogTemplate from '../jst/AssignmentDetailsDialog.handlebars'
|
||||
import round from '@canvas/round'
|
||||
import 'jqueryui/dialog'
|
||||
import '@canvas/util/jquery/fixDialogButtons'
|
||||
|
||||
const I18n = useI18nScope('assignment_details')
|
||||
|
||||
export default class AssignmentDetailsDialog {
|
||||
static show(opts) {
|
||||
const dialog = new AssignmentDetailsDialog(opts)
|
||||
return dialog.show()
|
||||
}
|
||||
|
||||
constructor({assignment, students}) {
|
||||
this.compute = this.compute.bind(this)
|
||||
this.assignment = assignment
|
||||
this.students = students
|
||||
}
|
||||
|
||||
show() {
|
||||
const {locals} = this.compute()
|
||||
const totalWidth = 100
|
||||
|
||||
const widthForValue = val => (totalWidth * val) / this.assignment.points_possible
|
||||
|
||||
$.extend(locals, {
|
||||
showDistribution: locals.average && this.assignment.points_possible,
|
||||
|
||||
lowLeft: widthForValue(locals.min),
|
||||
lqLeft: widthForValue(locals.lowerQuartile),
|
||||
medianLeft: widthForValue(locals.median),
|
||||
uqLeft: widthForValue(locals.upperQuartile),
|
||||
highLeft: widthForValue(locals.max),
|
||||
maxLeft: totalWidth,
|
||||
|
||||
highWidth: widthForValue(locals.max - locals.upperQuartile),
|
||||
lowLqWidth: widthForValue(locals.lowerQuartile - locals.min),
|
||||
medianLowWidth: widthForValue(locals.median - locals.lowerQuartile) + 1,
|
||||
medianHighWidth: widthForValue(locals.upperQuartile - locals.median),
|
||||
})
|
||||
|
||||
return $(assignmentDetailsDialogTemplate(locals)).dialog({
|
||||
width: 500,
|
||||
close() {
|
||||
$(this).remove()
|
||||
},
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
}
|
||||
|
||||
compute(opts = {students: this.students, assignment: this.assignment}) {
|
||||
const {students, assignment} = opts
|
||||
|
||||
const scores = Object.values(students)
|
||||
.filter(
|
||||
student =>
|
||||
student[`assignment_${assignment.id}`] &&
|
||||
student[`assignment_${assignment.id}`].score != null
|
||||
)
|
||||
.map(student => student[`assignment_${assignment.id}`].score)
|
||||
.sort()
|
||||
|
||||
const locals = {
|
||||
assignment,
|
||||
cnt: I18n.n(scores.length),
|
||||
max: this.nonNumericGuard(Math.max(...scores)),
|
||||
min: this.nonNumericGuard(Math.min(...scores)),
|
||||
pointsPossible: this.nonNumericGuard(assignment.points_possible, I18n.t('N/A')),
|
||||
average: this.nonNumericGuard(round(scores.reduce((a, b) => a + b, 0) / scores.length, 2)),
|
||||
median: this.nonNumericGuard(this.percentile(scores, 0.5)),
|
||||
lowerQuartile: this.nonNumericGuard(this.percentile(scores, 0.25)),
|
||||
upperQuartile: this.nonNumericGuard(this.percentile(scores, 0.75)),
|
||||
}
|
||||
|
||||
return {scores, locals}
|
||||
}
|
||||
|
||||
nonNumericGuard(number, message = I18n.t('No graded submissions')) {
|
||||
return Number.isFinite(number) && !Number.isNaN(number) ? I18n.n(number) : message
|
||||
}
|
||||
|
||||
percentile(values, percentile) {
|
||||
const k = Math.floor(percentile * (values.length - 1) + 1) - 1
|
||||
const f = (percentile * (values.length - 1) + 1) % 1
|
||||
|
||||
return values[k] + f * (values[k + 1] - values[k])
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 - 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 mute_dialog_template from '../jst/mute_dialog.handlebars'
|
||||
import '@canvas/jquery/jquery.ajaxJSON'
|
||||
import '@canvas/jquery/jquery.disableWhileLoading'
|
||||
import 'jqueryui/dialog'
|
||||
import 'jquery-tinypubsub'
|
||||
|
||||
const I18n = useI18nScope('assignment_muter')
|
||||
|
||||
export default class AssignmentMuter {
|
||||
constructor($link, assignment, url, setter, options) {
|
||||
;['confirmUnmute', 'afterUpdate', 'showDialog', 'updateLink'].forEach(
|
||||
m => (this[m] = this[m].bind(this))
|
||||
)
|
||||
this.$link = $link
|
||||
this.assignment = assignment
|
||||
this.url = url
|
||||
this.setter = setter
|
||||
this.options = options
|
||||
}
|
||||
|
||||
show(onClose) {
|
||||
if (this.options && this.options.openDialogInstantly) {
|
||||
if (this.assignment.muted) {
|
||||
this.confirmUnmute()
|
||||
} else {
|
||||
this.showDialog(onClose)
|
||||
}
|
||||
} else {
|
||||
this.$link = $(this.$link)
|
||||
this.updateLink()
|
||||
if (!this.options || this.options.canUnmute) {
|
||||
this.$link.click(event => {
|
||||
event.preventDefault()
|
||||
if (this.assignment.muted) {
|
||||
this.confirmUnmute()
|
||||
} else {
|
||||
this.showDialog(onClose)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLink() {
|
||||
this.$link.text(this.assignment.muted ? I18n.t('Unmute Assignment') : I18n.t('Mute Assignment'))
|
||||
}
|
||||
|
||||
showDialog(onClose) {
|
||||
this.$dialog = $(mute_dialog_template()).dialog({
|
||||
buttons: [
|
||||
{
|
||||
text: I18n.t('Cancel'),
|
||||
class: 'Button',
|
||||
'data-action': 'cancel',
|
||||
click: () => this.$dialog.dialog('close'),
|
||||
},
|
||||
{
|
||||
text: I18n.t('Mute Assignment'),
|
||||
class: 'Button Button--primary',
|
||||
'data-action': 'mute',
|
||||
'data-text-while-loading': I18n.t('Muting Assignment...'),
|
||||
click: () =>
|
||||
this.$dialog.disableWhileLoading(
|
||||
$.ajaxJSON(this.url, 'put', {status: true}, this.afterUpdate)
|
||||
),
|
||||
},
|
||||
],
|
||||
open: () =>
|
||||
setTimeout(() => this.$dialog.parent().find('.ui-dialog-titlebar-close').focus(), 100),
|
||||
close: () => this.$dialog.remove(),
|
||||
resizable: false,
|
||||
width: 400,
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
this.$dialog.on('dialogclose', onClose)
|
||||
}
|
||||
|
||||
afterUpdate(serverResponse) {
|
||||
const assignment = serverResponse.assignment
|
||||
if (this.setter) {
|
||||
this.setter(this.assignment, 'anonymize_students', assignment.anonymize_students)
|
||||
this.setter(this.assignment, 'muted', assignment.muted)
|
||||
} else {
|
||||
this.assignment.anonymize_students = assignment.anonymize_students
|
||||
this.assignment.muted = assignment.muted
|
||||
}
|
||||
if (!(this.options && this.options.openDialogInstantly)) this.updateLink()
|
||||
|
||||
this.$dialog.dialog('close')
|
||||
$.publish('assignment_muting_toggled', [
|
||||
{
|
||||
...this.assignment,
|
||||
anonymize_students: assignment.anonymize_students,
|
||||
muted: assignment.muted,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
confirmUnmute() {
|
||||
this.$dialog = $('<div />')
|
||||
.text(
|
||||
I18n.t(
|
||||
"This assignment is currently muted. That means students can't see their grades and feedback. Would you like to unmute now?"
|
||||
)
|
||||
)
|
||||
.dialog({
|
||||
buttons: [
|
||||
{
|
||||
text: I18n.t('Cancel'),
|
||||
class: 'Button',
|
||||
'data-action': 'cancel',
|
||||
click: () => this.$dialog.dialog('close'),
|
||||
},
|
||||
{
|
||||
text: I18n.t('unmute_button', 'Unmute Assignment'),
|
||||
class: 'Button Button--primary',
|
||||
'data-action': 'unmute',
|
||||
'data-text-while-loading': I18n.t('unmuting_assignment', 'Unmuting Assignment...'),
|
||||
click: () =>
|
||||
this.$dialog.disableWhileLoading(
|
||||
$.ajaxJSON(this.url, 'put', {status: false}, this.afterUpdate)
|
||||
),
|
||||
},
|
||||
],
|
||||
open: () =>
|
||||
setTimeout(() => this.$dialog.parent().find('.ui-dialog-titlebar-close').focus(), 100),
|
||||
close: () => this.$dialog.dialog('close'),
|
||||
resizable: false,
|
||||
title: I18n.t('unmute_assignment', 'Unmute Assignment'),
|
||||
width: 400,
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,372 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 - 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 messageStudents from '@canvas/message-students-dialog/jquery/message_students'
|
||||
import AssignmentDetailsDialog from './AssignmentDetailsDialog'
|
||||
import AssignmentMuter from './AssignmentMuter'
|
||||
import * as FlashAlert from '@canvas/alerts/react/FlashAlert'
|
||||
import SetDefaultGradeDialog from '@canvas/grading/jquery/SetDefaultGradeDialog'
|
||||
import CurveGradesDialog from '@canvas/grading/jquery/CurveGradesDialog'
|
||||
import gradebookHeaderMenuTemplate from '../jst/GradebookHeaderMenu.handlebars'
|
||||
import re_upload_submissions_form from '@canvas/grading/jst/re_upload_submissions_form.handlebars'
|
||||
import {map, filter} from 'lodash'
|
||||
import authenticity_token from '@canvas/authenticity-token'
|
||||
import MessageStudentsWhoHelper from '@canvas/grading/messageStudentsWhoHelper'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import MessageStudentsWithObserversDialog from '@canvas/message-students-dialog/react/MessageStudentsWhoDialog'
|
||||
import {ApolloProvider} from 'react-apollo'
|
||||
import {createClient} from '@canvas/apollo'
|
||||
import '@canvas/jquery/jquery.instructure_forms'
|
||||
import 'jqueryui/dialog'
|
||||
import '@canvas/jquery/jquery.instructure_misc_helpers'
|
||||
import '@canvas/jquery/jquery.instructure_misc_plugins'
|
||||
import 'jquery-kyle-menu'
|
||||
import replaceTags from '@canvas/util/replaceTags'
|
||||
|
||||
const I18n = useI18nScope('gradebookHeaderMenu')
|
||||
|
||||
const isAdmin = function () {
|
||||
return ENV.current_user_is_admin
|
||||
}
|
||||
|
||||
export default class GradebookHeaderMenu {
|
||||
constructor(assignment1, $trigger, gradebook) {
|
||||
this.showAssignmentDetails = this.showAssignmentDetails.bind(this)
|
||||
this.messageStudentsWho = this.messageStudentsWho.bind(this)
|
||||
this.setDefaultGrade = this.setDefaultGrade.bind(this)
|
||||
this.curveGrades = this.curveGrades.bind(this)
|
||||
this.downloadSubmissions = this.downloadSubmissions.bind(this)
|
||||
this.reuploadSubmissions = this.reuploadSubmissions.bind(this)
|
||||
this.canUnmute = this.canUnmute.bind(this)
|
||||
this.assignment = assignment1
|
||||
this.$trigger = $trigger
|
||||
this.gradebook = gradebook
|
||||
const templateLocals = {
|
||||
assignmentUrl: `${this.gradebook.options.context_url}/assignments/${this.assignment.id}`,
|
||||
speedGraderUrl: `${this.gradebook.options.context_url}/gradebook/speed_grader?assignment_id=${this.assignment.id}`,
|
||||
}
|
||||
if (!this.gradebook.options.speed_grader_enabled) {
|
||||
templateLocals.speedGraderUrl = null
|
||||
}
|
||||
this.gradebook.allSubmissionsLoaded.done(() => {
|
||||
// Reset the cache in case the user clicked on the menu while waiting for data
|
||||
return (this.allSubmissionsLoaded = true)
|
||||
})
|
||||
this.$menu = $(gradebookHeaderMenuTemplate(templateLocals)).insertAfter(this.$trigger)
|
||||
this.$trigger.kyleMenu({
|
||||
noButton: true,
|
||||
})
|
||||
// need it to be a child of #gradebook_grid (not the header cell) to get over overflow:hidden obstacles.
|
||||
this.$menu
|
||||
.appendTo('#gradebook_grid')
|
||||
.on('click', 'a', event => {
|
||||
const action = this[$(event.target).data('action')]
|
||||
if (action) {
|
||||
action()
|
||||
return false
|
||||
}
|
||||
})
|
||||
.bind('popupopen popupclose', event => {
|
||||
this.$trigger.toggleClass('ui-menu-trigger-menu-is-open', event.type === 'popupopen')
|
||||
if (
|
||||
event.type === 'popupclose' &&
|
||||
event.originalEvent != null &&
|
||||
event.originalEvent.type !== 'focusout'
|
||||
) {
|
||||
// defer because there seems to make sure this occurs after all of the jquery ui events
|
||||
return setTimeout(() => {
|
||||
return this.gradebook.grid.editActiveCell()
|
||||
}, 0)
|
||||
}
|
||||
})
|
||||
.bind('popupopen', () => {
|
||||
return this.menuPopupOpenHandler(this.$menu)
|
||||
})
|
||||
.popup('open')
|
||||
new AssignmentMuter(
|
||||
this.$menu.find('[data-action=toggleMuting]'),
|
||||
this.assignment,
|
||||
`${this.gradebook.options.context_url}/assignments/${this.assignment.id}/mute`,
|
||||
(a, _z, status) => {
|
||||
a.muted = status
|
||||
return this.gradebook.setAssignmentWarnings()
|
||||
},
|
||||
{
|
||||
canUnmute: this.canUnmute(),
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
menuPopupOpenHandler(menu) {
|
||||
// Hide any menu options that haven't had their dependencies met yet
|
||||
this.hideMenuActionsWithUnmetDependencies(menu)
|
||||
// Disable menu options if needed
|
||||
return this.disableUnavailableMenuActions(menu)
|
||||
}
|
||||
|
||||
hideMenuActionsWithUnmetDependencies(menu) {
|
||||
let action, condition
|
||||
const ref = {
|
||||
showAssignmentDetails: this.allSubmissionsLoaded,
|
||||
messageStudentsWho: this.allSubmissionsLoaded,
|
||||
setDefaultGrade: this.allSubmissionsLoaded,
|
||||
curveGrades:
|
||||
this.allSubmissionsLoaded &&
|
||||
this.assignment.grading_type !== 'pass_fail' &&
|
||||
this.assignment.points_possible,
|
||||
downloadSubmissions:
|
||||
`${this.assignment.submission_types}`.match(
|
||||
/(online_upload|online_text_entry|online_url)/
|
||||
) && this.assignment.has_submitted_submissions,
|
||||
reuploadSubmissions:
|
||||
this.gradebook.options.gradebook_is_editable && this.assignment.submissions_downloads > 0,
|
||||
}
|
||||
const results = []
|
||||
for (action in ref) {
|
||||
condition = ref[action]
|
||||
results.push(menu.find(`[data-action=${action}]`).showIf(condition))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
disableUnavailableMenuActions(menu) {
|
||||
let actionToDisable, actionsToDisable, i, len, menuItem, ref
|
||||
if (menu == null) {
|
||||
return
|
||||
}
|
||||
actionsToDisable = []
|
||||
if (((ref = this.assignment) != null ? ref.inClosedGradingPeriod : undefined) && !isAdmin()) {
|
||||
actionsToDisable = ['curveGrades', 'setDefaultGrade']
|
||||
}
|
||||
if (!this.canUnmute()) {
|
||||
actionsToDisable.push('toggleMuting')
|
||||
}
|
||||
const results = []
|
||||
for (i = 0, len = actionsToDisable.length; i < len; i++) {
|
||||
actionToDisable = actionsToDisable[i]
|
||||
menuItem = menu.find(`[data-action=${actionToDisable}]`)
|
||||
menuItem.addClass('ui-state-disabled')
|
||||
results.push(menuItem.attr('aria-disabled', true))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
showAssignmentDetails(
|
||||
opts = {
|
||||
assignment: this.assignment,
|
||||
students: this.gradebook.studentsThatCanSeeAssignment(
|
||||
this.gradebook.students,
|
||||
this.assignment
|
||||
),
|
||||
}
|
||||
) {
|
||||
const dialog = new AssignmentDetailsDialog(opts)
|
||||
return dialog.show()
|
||||
}
|
||||
|
||||
messageStudentsWho(
|
||||
opts = {
|
||||
assignment: this.assignment,
|
||||
students: this.gradebook.studentsThatCanSeeAssignment(
|
||||
this.gradebook.students,
|
||||
this.assignment
|
||||
),
|
||||
messageAttachmentUploadFolderId: this.gradebook.options.message_attachment_upload_folder_id,
|
||||
}
|
||||
) {
|
||||
let {students} = opts
|
||||
const {assignment, messageAttachmentUploadFolderId} = opts
|
||||
students = filter(students, student => {
|
||||
return !student.isInactive && !student.isTestStudent
|
||||
})
|
||||
students = map(students, student => {
|
||||
const sub = student[`assignment_${assignment.id}`]
|
||||
return {
|
||||
excused: sub.excused,
|
||||
grade: sub.grade,
|
||||
id: student.id,
|
||||
latePolicyStatus: sub.late_policy_status,
|
||||
name: student.name,
|
||||
redoRequest: sub.redo_request,
|
||||
score: sub != null ? sub.score : undefined,
|
||||
// Both gradebooks share the Message Students dialog; prefer New Gradebook's casing
|
||||
sortableName: student.sortable_name,
|
||||
submittedAt: sub != null ? sub.submitted_at : undefined,
|
||||
}
|
||||
})
|
||||
|
||||
if (opts.show_message_students_with_observers_dialog) {
|
||||
const mountPoint = document.querySelector(
|
||||
"[data-component='MessageStudentsWithObserversModal']"
|
||||
)
|
||||
const props = {
|
||||
assignment: {
|
||||
allowedAttempts: assignment.allowed_attempts,
|
||||
anonymizeStudents: assignment.anonymize_students,
|
||||
courseId: assignment.course_id,
|
||||
dueDate: assignment.due_at,
|
||||
htmlUrl: assignment.html_url,
|
||||
muted: assignment.muted,
|
||||
pointsPossible: assignment.points_possible,
|
||||
postManually: assignment.post_manually,
|
||||
published: assignment.published,
|
||||
gradingType: assignment.grading_type,
|
||||
id: assignment.id,
|
||||
name: assignment.name,
|
||||
submissionTypes: assignment.submission_types,
|
||||
},
|
||||
onClose: () => {
|
||||
ReactDOM.unmountComponentAtNode(mountPoint)
|
||||
},
|
||||
onSend: args => {
|
||||
return MessageStudentsWhoHelper.sendMessageStudentsWho(
|
||||
args.recipientsIds,
|
||||
args.subject,
|
||||
args.body,
|
||||
`course_${assignment.course_id}`,
|
||||
args.mediaFile,
|
||||
args.attachmentIds
|
||||
)
|
||||
.then(FlashAlert.showFlashSuccess(I18n.t('Message sent successfully')))
|
||||
.catch(FlashAlert.showFlashError(I18n.t('There was an error sending the message')))
|
||||
},
|
||||
messageAttachmentUploadFolderId,
|
||||
students,
|
||||
userId: opts.current_user_id,
|
||||
}
|
||||
ReactDOM.render(
|
||||
<ApolloProvider client={createClient()}>
|
||||
<MessageStudentsWithObserversDialog {...props} />
|
||||
</ApolloProvider>,
|
||||
mountPoint
|
||||
)
|
||||
} else {
|
||||
const settings = MessageStudentsWhoHelper.settings(assignment, students)
|
||||
return messageStudents(settings)
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultGrade(
|
||||
opts = {
|
||||
assignment: this.assignment,
|
||||
students: this.gradebook.studentsThatCanSeeAssignment(
|
||||
this.gradebook.students,
|
||||
this.assignment
|
||||
),
|
||||
context_id: this.gradebook.options.context_id,
|
||||
selected_section: this.gradebook.sectionToShow,
|
||||
}
|
||||
) {
|
||||
if (isAdmin() || !opts.assignment.inClosedGradingPeriod) {
|
||||
return new SetDefaultGradeDialog(opts).show()
|
||||
} else {
|
||||
return $.flashError(
|
||||
I18n.t(
|
||||
'Unable to set default grade because this ' +
|
||||
'assignment is due in a closed grading period for at least one student'
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
curveGrades(
|
||||
opts = {
|
||||
assignment: this.assignment,
|
||||
students: this.gradebook.studentsThatCanSeeAssignment(
|
||||
this.gradebook.students,
|
||||
this.assignment
|
||||
),
|
||||
context_url: this.gradebook.options.context_url,
|
||||
}
|
||||
) {
|
||||
let dialog
|
||||
if (isAdmin() || !opts.assignment.inClosedGradingPeriod) {
|
||||
dialog = new CurveGradesDialog(opts)
|
||||
return dialog.show()
|
||||
} else {
|
||||
return $.flashError(
|
||||
I18n.t(
|
||||
'Unable to curve grades because this ' +
|
||||
'assignment is due in a closed grading period for at least ' +
|
||||
'one student'
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
downloadSubmissions() {
|
||||
let base
|
||||
const url = replaceTags(
|
||||
this.gradebook.options.download_assignment_submissions_url,
|
||||
'assignment_id',
|
||||
this.assignment.id
|
||||
)
|
||||
INST.downloadSubmissions(url)
|
||||
return (this.assignment.submissions_downloads =
|
||||
((base = this.assignment).submissions_downloads != null
|
||||
? base.submissions_downloads
|
||||
: (base.submissions_downloads = 0)) + 1)
|
||||
}
|
||||
|
||||
reuploadSubmissions() {
|
||||
let locals
|
||||
if (!this.$re_upload_submissions_form) {
|
||||
locals = {
|
||||
authenticityToken: authenticity_token(),
|
||||
}
|
||||
GradebookHeaderMenu.prototype.$re_upload_submissions_form = $(
|
||||
re_upload_submissions_form(locals)
|
||||
)
|
||||
.dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
resizable: false,
|
||||
autoOpen: false,
|
||||
zIndex: 1000,
|
||||
})
|
||||
.submit(function () {
|
||||
const data = $(this).getFormData()
|
||||
if (!data.submissions_zip) {
|
||||
return false
|
||||
} else if (!data.submissions_zip.match(/\.zip$/)) {
|
||||
$(this).formErrors({
|
||||
submissions_zip: I18n.t('errors.upload_as_zip', 'Please upload files as a .zip'),
|
||||
})
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
const url = replaceTags(
|
||||
this.gradebook.options.re_upload_submissions_url,
|
||||
'assignment_id',
|
||||
this.assignment.id
|
||||
)
|
||||
return this.$re_upload_submissions_form.attr('action', url).dialog('open')
|
||||
}
|
||||
|
||||
canUnmute() {
|
||||
return !(
|
||||
this.assignment?.muted &&
|
||||
this.assignment?.moderated_grading &&
|
||||
!this.assignment?.grades_published
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 - 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 submissionDetailsDialog from '../jst/SubmissionDetailsDialog.handlebars'
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import GradeFormatHelper from '@canvas/grading/GradeFormatHelper'
|
||||
import {originalityReportSubmissionKey} from '@canvas/grading/originalityReportHelper'
|
||||
import {extractDataForTurnitin} from '@canvas/grading/Turnitin'
|
||||
import OutlierScoreHelper from '@canvas/grading/OutlierScoreHelper'
|
||||
import '../jst/_submission_detail.handlebars' // a partial needed by the SubmissionDetailsDialog template
|
||||
import '@canvas/grading/jst/_turnitinScore.handlebars' // a partial needed by the submission_detail partial
|
||||
import '@canvas/jquery/jquery.ajaxJSON'
|
||||
import '@canvas/jquery/jquery.disableWhileLoading'
|
||||
import '@canvas/jquery/jquery.instructure_forms'
|
||||
import 'jqueryui/dialog'
|
||||
import '@canvas/jquery/jquery.instructure_misc_plugins'
|
||||
import 'jquery-scroll-to-visible/jquery.scrollTo'
|
||||
import 'jquery-tinypubsub'
|
||||
|
||||
const I18n = useI18nScope('submission_details_dialog')
|
||||
|
||||
export default class SubmissionDetailsDialog {
|
||||
constructor(assignment, student, options) {
|
||||
this.assignment = assignment
|
||||
this.student = student
|
||||
this.options = options
|
||||
const speedGraderUrl = this.options.speed_grader_enabled ? this.buildSpeedGraderUrl() : null
|
||||
|
||||
this.url = this.options.change_grade_url
|
||||
.replace(':assignment', this.assignment.id)
|
||||
.replace(':submission', this.student.id)
|
||||
const submission = this.student[`assignment_${this.assignment.id}`]
|
||||
this.submission = $.extend({}, submission, {
|
||||
label: `student_grading_${this.assignment.id}`,
|
||||
inputName: 'submission[posted_grade]',
|
||||
assignment: this.assignment,
|
||||
speedGraderUrl,
|
||||
loading: true,
|
||||
showPointsPossible:
|
||||
(this.assignment.points_possible || this.assignment.points_possible === '0') &&
|
||||
this.assignment.grading_type !== 'gpa_scale',
|
||||
formattedPointsPossible: I18n.n(this.assignment.points_possible),
|
||||
shouldShowExcusedOption: true,
|
||||
isInPastGradingPeriodAndNotAdmin: submission.gradeLocked,
|
||||
})
|
||||
this.submission[`assignment_grading_type_is_${this.assignment.grading_type}`] = true
|
||||
if (this.submission.excused) this.submission.grade = 'EX'
|
||||
this.$el = $('<div class="use-css-transitions-for-show-hide" style="padding:0;"/>')
|
||||
this.$el.html(submissionDetailsDialog(this.submission))
|
||||
|
||||
this.dialog = this.$el.dialog({
|
||||
title: this.student.name,
|
||||
width: 600,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
|
||||
this.dialog.on('dialogclose', this.options.onClose)
|
||||
this.dialog.on('dialogclose', () => {
|
||||
this.dialog.dialog('destroy')
|
||||
this.$el.remove()
|
||||
})
|
||||
this.dialog
|
||||
.on('change', 'select[id="submission_to_view"]', event =>
|
||||
this.dialog.find('.submission_detail').each(function (index) {
|
||||
$(this).showIf(index === event.currentTarget.selectedIndex)
|
||||
})
|
||||
)
|
||||
.on('submit', '.submission_details_grade_form', event => {
|
||||
event.preventDefault()
|
||||
let formData = $(event.currentTarget).getFormData()
|
||||
const rawGrade = formData['submission[posted_grade]']
|
||||
if (rawGrade.toUpperCase() === 'EX') {
|
||||
formData = {'submission[excuse]': true}
|
||||
} else {
|
||||
formData['submission[posted_grade]'] = GradeFormatHelper.delocalizeGrade(rawGrade)
|
||||
}
|
||||
$(event.currentTarget.form).disableWhileLoading(
|
||||
$.ajaxJSON(this.url, 'PUT', formData, data => {
|
||||
this.update(data)
|
||||
if (!data.excused) {
|
||||
const outlierScoreHelper = new OutlierScoreHelper(
|
||||
this.submission.score,
|
||||
this.submission.assignment.points_possible
|
||||
)
|
||||
if (outlierScoreHelper.hasWarning()) {
|
||||
$.flashWarning(outlierScoreHelper.warningMessage())
|
||||
}
|
||||
}
|
||||
$.publish('submissions_updated', [this.submission.all_submissions])
|
||||
setTimeout(() => this.dialog.dialog('close'), 500)
|
||||
})
|
||||
)
|
||||
})
|
||||
.on('submit', '.submission_details_add_comment_form', event => {
|
||||
event.preventDefault()
|
||||
$(event.currentTarget).disableWhileLoading(
|
||||
$.ajaxJSON(this.url, 'PUT', $(event.currentTarget).getFormData(), data => {
|
||||
this.update(data)
|
||||
setTimeout(() => this.dialog.dialog('close'), 500)
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
const url = `${this.url}&include[]=submission_history&include[]=submission_comments&include[]=rubric_assessment`
|
||||
const deferred = $.ajaxJSON(url, 'GET', {}, this.update)
|
||||
this.dialog.find('.submission_details_comments').disableWhileLoading(deferred)
|
||||
}
|
||||
|
||||
buildSpeedGraderUrl = () => {
|
||||
const assignmentParam = `assignment_id=${this.assignment.id}`
|
||||
const speedGraderUrlParams = this.assignment.anonymize_students
|
||||
? assignmentParam
|
||||
: `${assignmentParam}&student_id=${this.student.id}`
|
||||
return encodeURI(`${this.options.context_url}/gradebook/speed_grader?${speedGraderUrlParams}`)
|
||||
}
|
||||
|
||||
open = () => {
|
||||
this.dialog.dialog('open')
|
||||
this.scrollCommentsToBottom()
|
||||
$('.ui-dialog-titlebar-close').focus()
|
||||
}
|
||||
|
||||
scrollCommentsToBottom = () => this.dialog.find('.submission_details_comments').scrollTop(999999)
|
||||
|
||||
update = newData => {
|
||||
$.extend(this.submission, newData)
|
||||
this.submission.moreThanOneSubmission = this.submission.submission_history.length > 1
|
||||
this.submission.loading = false
|
||||
this.submission.submission_history.forEach(submission => {
|
||||
submission.submission_comments &&
|
||||
submission.submission_comments.forEach(comment => {
|
||||
comment.url = `${this.options.context_url}/users/${comment.author_id}`
|
||||
const urlPrefix = `${window.location.protocol}//${window.location.host}`
|
||||
comment.image_url = `${urlPrefix}/images/users/${comment.author_id}`
|
||||
})
|
||||
submission.turnitin = extractDataForTurnitin(
|
||||
submission,
|
||||
originalityReportSubmissionKey(submission),
|
||||
this.options.context_url
|
||||
)
|
||||
|
||||
if (Object.keys(submission.turnitin).length === 0) {
|
||||
submission.turnitin = extractDataForTurnitin(
|
||||
submission,
|
||||
`submission_${submission.id}`,
|
||||
this.options.context_url
|
||||
)
|
||||
}
|
||||
|
||||
submission.attachments &&
|
||||
submission.attachments.forEach(attachment => {
|
||||
attachment.turnitin = extractDataForTurnitin(
|
||||
submission,
|
||||
`attachment_${attachment.id}`,
|
||||
this.options.context_url
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
if (this.options.anonymous) {
|
||||
this.submission.submission_comments.forEach(comment => {
|
||||
if (comment.author.id !== ENV.current_user_id) {
|
||||
comment.anonymous = comment.author.anonymous = true
|
||||
comment.author_name = I18n.t('Student')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (this.submission.excused) {
|
||||
this.submission.grade = 'EX'
|
||||
} else if (['points', 'percent'].includes(this.assignment.grading_type)) {
|
||||
this.submission.grade = GradeFormatHelper.formatGrade(this.submission.grade)
|
||||
}
|
||||
this.dialog.html(submissionDetailsDialog(this.submission))
|
||||
this.dialog.find('select').trigger('change')
|
||||
return this.scrollCommentsToBottom()
|
||||
}
|
||||
|
||||
static open(assignment, student, options) {
|
||||
return new SubmissionDetailsDialog(assignment, student, options).open()
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue