@instructure/quiz-grading
Version:
The Quiz React SDK by Instructure Inc.
499 lines (498 loc) • 22.9 kB
JavaScript
/** @jsx jsx */ function _assert_this_initialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _call_super(_this, derived, args) {
derived = _get_prototype_of(derived);
return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
}
function _class_call_check(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for(var i = 0; i < props.length; i++){
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _create_class(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _get_prototype_of(o) {
_get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _get_prototype_of(o);
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _set_prototype_of(subClass, superClass);
}
function _possible_constructor_return(self, call) {
if (call && (_type_of(call) === "object" || typeof call === "function")) {
return call;
}
return _assert_this_initialized(self);
}
function _set_prototype_of(o, p) {
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _set_prototype_of(o, p);
}
function _type_of(obj) {
"@swc/helpers - typeof";
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
function _is_native_reflect_construct() {
try {
var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
} catch (_) {}
return (_is_native_reflect_construct = function() {
return !!result;
})();
}
import { Component } from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Map } from 'immutable';
import debounce from 'lodash/debounce';
import { IconArrowOpenEndLine, IconArrowOpenStartLine, IconCheckLine, IconDiscussionLine, IconDiscussionSolid, IconXLine } from '@instructure/ui-icons';
import { Button } from '@instructure/ui-buttons';
import NumberInput from '@instructure/quiz-number-input/components/NumberInput/index';
import { Text } from '@instructure/ui-text';
import { View } from '@instructure/ui-view';
import { PresentationContent, ScreenReaderContent } from '@instructure/ui-a11y-content';
import canvas from '@instructure/ui-themes';
import { jsx } from '@instructure/emotion';
import t from '@instructure/quiz-i18n/format-message';
import { Flex } from '@instructure/quiz-common/components/Flex/index';
import { HideableButton } from '@instructure/quiz-common/components/HideableButton/index';
import { GRADE_BY_QUESTION_PREVIOUS, GRADE_BY_QUESTION_NEXT } from '@instructure/quiz-common/constants';
import { withStyleOverrides } from '@instructure/quiz-common/util/withStyleOverrides';
import { RichContentInput } from '@instructure/quiz-rce/components/RichContentInput/index';
import generateStyle from './styles';
import generateComponentTheme from './theme';
export var BaseGradingBar = /*#__PURE__*/ function(Component) {
"use strict";
_inherits(BaseGradingBar, Component);
function BaseGradingBar(props) {
_class_call_check(this, BaseGradingBar);
var _this;
_this = _call_super(this, BaseGradingBar, [
props
]), _define_property(_this, "regradeButtonRef", null), _define_property(_this, "feedbackButtonRef", null), _define_property(_this, "_timeouts", []), // =============
// EXTERNALLY USED UTILS
// =============
_define_property(_this, "focusRegradeButton", function() {
_this.regradeButtonRef && _this.regradeButtonRef.focus();
}), _define_property(_this, "focusFeedbackButton", function() {
_this.feedbackButtonRef && _this.feedbackButtonRef.focus();
}), // =============
// HANDLERS
// =============
_define_property(_this, "updatePoints", debounce(function() {
_this.props.handleChangePoints(_this.state.normalizedPoints);
}, 250, {
leading: true,
trailing: true
})), _define_property(_this, "handleChangePoints", function(event, points, normalizedPoints) {
var parsedPoints = parseFloat(normalizedPoints) || 0;
_this.setState({
points: points,
normalizedPoints: parsedPoints
}, _this.updatePoints);
var gradeStatus = _this.getGradeStatus();
if (!gradeStatus || gradeStatus === 'waiting') {
_this.props.handleChangeGradeStatus('graded');
}
}), _define_property(_this, "handleBlurPoints", function() {
_this.updatePoints.flush();
_this.setState(function(param) {
var normalizedPoints = param.normalizedPoints;
return {
points: normalizedPoints || 0
};
});
}), _define_property(_this, "handleStatusCorrectToggle", function() {
var newPoints = +_this.props.sessionItemResult.pointsPossible;
_this.props.handleChangePoints(newPoints);
_this.setState({
points: "".concat(newPoints),
normalizedPoints: "".concat(newPoints)
});
var newStatus = _this.getGradeStatus() === 'correct' ? 'graded' : 'correct';
_this.props.handleChangeGradeStatus(newStatus, newStatus === 'graded');
}), _define_property(_this, "handleStatusIncorrectToggle", function() {
_this.props.handleChangePoints(0);
_this.setState({
points: '0',
normalizedPoints: '0'
});
var newStatus = _this.getGradeStatus() === 'incorrect' ? 'graded' : 'incorrect';
_this.props.handleChangeGradeStatus(newStatus, newStatus === 'graded');
}), _define_property(_this, "previousStudent", function(e) {
e.preventDefault();
_this.props.postToParent({
subject: GRADE_BY_QUESTION_PREVIOUS
});
}), _define_property(_this, "nextStudent", function(e) {
e.preventDefault();
_this.props.postToParent({
subject: GRADE_BY_QUESTION_NEXT
});
}), _define_property(_this, "jumpToSidebar", function(e) {
e.preventDefault();
var sidebarWrapper = document.getElementById('sidebar-wrapper');
if (sidebarWrapper && sidebarWrapper.focus) {
sidebarWrapper.focus();
}
}), _define_property(_this, "handleRegradeButtonRef", function(node) {
_this.regradeButtonRef = node;
}), _define_property(_this, "handleFeedbackButtonRef", function(node) {
_this.feedbackButtonRef = node;
});
var points = _this.props.sessionItemResult.getWorkingInstance().score;
if (typeof points === 'number' || typeof points === 'string') {
points = Number(points);
} else {
points = null;
}
_this.state = {
points: points,
normalizedPoints: points
};
return _this;
}
_create_class(BaseGradingBar, [
{
key: "regradeInfo",
get: // =============
// INTERNAL UTILS
// =============
function get() {
return this.props.sessionItemResult.regradeInfo;
}
},
{
key: "hasRegradeInfo",
value: function hasRegradeInfo() {
return this.regradeInfo && this.regradeInfo.size > 1;
}
},
{
key: "pointsPossibleDescription",
value: function pointsPossibleDescription(pointsPossible) {
return t("{\n points, plural,\n one {# point}\n other {# points}\n }", {
points: pointsPossible
});
}
},
{
key: "getGradeStatus",
value: function getGradeStatus() {
var resultMods = this.props.itemResultsModifications || Map();
var workingGradeStatus = resultMods.getIn([
'scoredData',
'gradeStatus'
]);
if (workingGradeStatus) {
return workingGradeStatus;
}
return this.props.sessionItemResult.getIn([
'scoredData',
'gradeStatus'
]);
}
},
{
// =============
// RENDERING
// =============
key: "renderToSidebarButton",
value: function renderToSidebarButton() {
return /*#__PURE__*/ jsx(Flex, {
justifyItems: "end",
margin: "small medium"
}, /*#__PURE__*/ jsx(HideableButton, {
href: "#",
onClick: this.jumpToSidebar
}, t('Jump to Question Navigator')));
}
},
{
key: "renderSubjectiveButtons",
value: function renderSubjectiveButtons() {
if (this.props.isSubjective) {
var correctVariant = this.getGradeStatus() === 'correct' ? 'success' : 'primary-inverse';
var correctText = this.getGradeStatus() === 'correct' ? t('toggle correct off') : t('toggle correct on');
var incorrectVariant = this.getGradeStatus() === 'incorrect' ? 'danger' : 'primary-inverse';
var incorrectText = this.getGradeStatus() === 'incorrect' ? t('toggle incorrect off') : t('toggle incorrect on');
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.subjectiveButtonsWrapper
}, /*#__PURE__*/ jsx(Button, {
color: correctVariant,
onClick: this.handleStatusCorrectToggle,
renderIcon: IconCheckLine
}, /*#__PURE__*/ jsx(ScreenReaderContent, null, correctText)), /*#__PURE__*/ jsx(Button, {
color: incorrectVariant,
margin: "0 xx-small",
onClick: this.handleStatusIncorrectToggle,
renderIcon: IconXLine
}, /*#__PURE__*/ jsx(ScreenReaderContent, null, incorrectText)));
}
}
},
{
key: "renderFeedbackSection",
value: function renderFeedbackSection() {
var workingSessionItemResult = this.props.sessionItemResult.getWorkingInstance();
var graderFeedbackContent = workingSessionItemResult.getIn([
'feedback',
'graderFeedback',
'content'
], '');
var icon, text;
if (graderFeedbackContent) {
icon = IconDiscussionSolid;
text = t('Edit Grader Level Feedback (present)');
} else {
icon = IconDiscussionLine;
text = t('Edit Grader Level Feedback');
}
return /*#__PURE__*/ jsx(Button, {
ref: this.handleFeedbackButtonRef,
onClick: this.props.startFeedbackEdit,
renderIcon: icon,
"data-automation": "sdk-grading-edit-feedback-button"
}, /*#__PURE__*/ jsx(ScreenReaderContent, null, text));
}
},
{
key: "renderRegradeInfo",
value: function renderRegradeInfo() {
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.regradeParent
}, /*#__PURE__*/ jsx("div", {
css: this.props.styles.originalScore
}, /*#__PURE__*/ jsx(Text, {
color: "secondary"
}, t("Previous score { possible, plural,\n one {{points, number} / # point}\n other {{points, number} / # points}\n }", {
points: this.regradeInfo.get('originalScore'),
possible: this.regradeInfo.get('originalPointsPossible')
})), /*#__PURE__*/ jsx(PresentationContent, null, /*#__PURE__*/ jsx("div", {
css: this.props.styles.divider
}, /*#__PURE__*/ jsx(Text, {
color: "secondary"
}, '|' /* eslint-disable-line react/jsx-no-literals */ )))), /*#__PURE__*/ jsx("div", {
css: this.props.styles.regradeText
}, /*#__PURE__*/ jsx(Text, {
color: "alert"
}, t('Regrade score:'))), this.renderNumberInput(), /*#__PURE__*/ jsx(Text, {
color: "alert"
}, // eslint-disable-next-line react/jsx-no-literals
"/ ".concat(this.pointsPossibleDescription(this.regradeInfo.get('newPointsPossible')))));
}
},
{
key: "renderNumberInput",
value: function renderNumberInput() {
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.points
}, /*#__PURE__*/ jsx(NumberInput, {
placeholder: "--",
renderLabel: /*#__PURE__*/ jsx(ScreenReaderContent, null, t('Edit Score')),
onChange: this.handleChangePoints,
onBlur: this.handleBlurPoints,
value: this.state.points,
width: "6rem",
"data-automation": "sdk-grading-edit-score-input"
}));
}
},
{
key: "renderDefaultNumberInput",
value: function renderDefaultNumberInput() {
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.defaultNumberInput
}, this.renderNumberInput(), /*#__PURE__*/ jsx("span", {
css: this.props.styles.pointsPossible
}, // eslint-disable-next-line react/jsx-no-literals
"/ ".concat(this.pointsPossibleDescription(this.props.sessionItemResult.pointsPossible))));
}
},
{
key: "renderRegradeButton",
value: function renderRegradeButton() {
if (!this.props.isAutogradeable || !this.props.regradingFromSpeedGrader || this.props.isSurvey) {
return null;
}
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.regradeButtonWrapper
}, /*#__PURE__*/ jsx(Button, {
margin: "0 small",
onClick: this.props.regradeToggleAction,
ref: this.handleRegradeButtonRef,
"data-automation": "sdk-regrade-request-button"
}, t.rich('Regrade <0>question {position, number}</0>', {
0: function(param) {
var children = param.children;
return /*#__PURE__*/ jsx(ScreenReaderContent, {
key: "0"
}, children);
},
position: this.props.sessionItem.position
})));
}
},
{
key: "renderEditGraderFeedback",
value: function renderEditGraderFeedback() {
if (!this.props.isEditing) {
return;
}
var textareaId = "edit_grader_feedback_".concat(this.props.sessionItem.id);
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.editFeedback
}, /*#__PURE__*/ jsx("label", {
htmlFor: "edit_grader_feedback"
}, t('Additional Comments')), /*#__PURE__*/ jsx(RichContentInput, {
label: "",
defaultContent: this.props.graderFeedback.get('content'),
onKeyUp: this.props.updateFeedbackEdit,
onChange: this.props.updateFeedbackEdit,
textareaId: textareaId
}), /*#__PURE__*/ jsx("div", {
className: "editFeedbackButtons",
css: this.props.styles.editFeedbackButtons
}, /*#__PURE__*/ jsx(Button, {
size: "small",
margin: "x-small",
onClick: this.props.cancelFeedbackEdit,
"data-automation": "sdk-grading-edit-feedback-cancel"
}, t('Cancel')), /*#__PURE__*/ jsx(Button, {
color: "primary",
size: "small",
margin: "x-small",
onClick: this.props.submitFeedbackEdit,
"data-automation": "sdk-grading-edit-feedback-submit"
}, t('Done'))));
}
},
{
key: "renderGradeByQuestionControls",
value: function renderGradeByQuestionControls() {
var _this_props = this.props, activeItemId = _this_props.activeItemId, gradeByQuestionEnabled = _this_props.gradeByQuestionEnabled, sessionItem = _this_props.sessionItem;
if (gradeByQuestionEnabled && sessionItem.itemRecord.id === activeItemId) {
return /*#__PURE__*/ jsx(Flex, {
justifyItems: "end",
margin: "small medium"
}, this.props.renderUpdateButton({
margin: '0 xx-small'
}), /*#__PURE__*/ jsx(Button, {
margin: "0 xx-small",
href: "#",
onClick: this.previousStudent
}, /*#__PURE__*/ jsx(Flex, {
alignItems: "center"
}, /*#__PURE__*/ jsx(IconArrowOpenStartLine, null), /*#__PURE__*/ jsx(View, {
margin: "0 0 0 x-small"
}, t('Previous Student')))), /*#__PURE__*/ jsx(Button, {
margin: "0 xx-small",
href: "#",
onClick: this.nextStudent
}, /*#__PURE__*/ jsx(Flex, {
alignItems: "center"
}, /*#__PURE__*/ jsx(View, {
margin: "0 x-small 0 0"
}, t('Next Student')), /*#__PURE__*/ jsx(IconArrowOpenEndLine, null))));
}
}
},
{
key: "render",
value: function render() {
var isSurvey = this.props.isSurvey;
return /*#__PURE__*/ jsx("div", null, this.renderEditGraderFeedback(), /*#__PURE__*/ jsx(View, {
as: "div",
borderWidth: "small none none none",
margin: "0 medium",
borderColor: canvas.colors.contrasts.grey1111
}, /*#__PURE__*/ jsx(Flex, {
as: "div",
alignItems: "center",
wrap: "wrap"
}, /*#__PURE__*/ jsx("div", {
css: this.props.styles.feedbackButtonWrapper
}, this.renderFeedbackSection()), this.renderRegradeButton(), !isSurvey && /*#__PURE__*/ jsx("div", {
className: "fs-mask",
css: this.props.styles.pointsSection
}, this.renderSubjectiveButtons(), this.hasRegradeInfo() ? this.renderRegradeInfo() : this.renderDefaultNumberInput()))), this.renderGradeByQuestionControls(), this.renderToSidebarButton());
}
}
]);
return BaseGradingBar;
}(Component);
_define_property(BaseGradingBar, "displayName", 'GradingBar');
_define_property(BaseGradingBar, "componentId", "Quizzes".concat(BaseGradingBar.displayName));
_define_property(BaseGradingBar, "propTypes", {
activeItemId: PropTypes.string,
gradeByQuestionEnabled: PropTypes.bool,
graderFeedback: ImmutablePropTypes.map.isRequired,
handleChangeGradeStatus: PropTypes.func.isRequired,
handleChangePoints: PropTypes.func.isRequired,
isAutogradeable: PropTypes.bool.isRequired,
isEditing: PropTypes.bool.isRequired,
isSubjective: PropTypes.bool.isRequired,
itemResultsModifications: ImmutablePropTypes.map.isRequired,
postToParent: PropTypes.func.isRequired,
regradeToggleAction: PropTypes.func.isRequired,
renderUpdateButton: PropTypes.func.isRequired,
sessionItem: ImmutablePropTypes.record.isRequired,
sessionItemResult: ImmutablePropTypes.record.isRequired,
startFeedbackEdit: PropTypes.func.isRequired,
submitFeedbackEdit: PropTypes.func.isRequired,
updateFeedbackEdit: PropTypes.func.isRequired,
cancelFeedbackEdit: PropTypes.func.isRequired,
styles: PropTypes.object,
regradingFromSpeedGrader: PropTypes.bool,
isSurvey: PropTypes.bool.isRequired
});
_define_property(BaseGradingBar, "defaultProps", {
activeItemId: null,
gradeByQuestionEnabled: false
});
export var GradingBar = withStyleOverrides(generateStyle, generateComponentTheme)(BaseGradingBar);
export default GradingBar;