@instructure/quiz-grading
Version:
The Quiz React SDK by Instructure Inc.
414 lines (411 loc) • 19 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.GradingBar = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = require("react");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes"));
var _immutable = require("immutable");
var _debounce = _interopRequireDefault(require("lodash/debounce"));
var _uiIcons = require("@instructure/ui-icons");
var _uiButtons = require("@instructure/ui-buttons");
var _quizNumberInput = _interopRequireDefault(require("@instructure/quiz-number-input"));
var _uiText = require("@instructure/ui-text");
var _uiView = require("@instructure/ui-view");
var _uiA11yContent = require("@instructure/ui-a11y-content");
var _emotion = require("@instructure/emotion");
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
var _quizCore = require("@instructure/quiz-core");
var _quizCommon = require("@instructure/quiz-common");
var _quizRce = require("@instructure/quiz-rce");
var _styles = _interopRequireDefault(require("./styles"));
var _theme = _interopRequireDefault(require("./theme"));
var _dec, _class, _GradingBar;
/** @jsx jsx */
function _callSuper(_this, derived, args) {
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (e) {
return false;
}
}
derived = (0, _getPrototypeOf2["default"])(derived);
return (0, _possibleConstructorReturn2["default"])(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], (0, _getPrototypeOf2["default"])(_this).constructor) : derived.apply(_this, args));
}
var GradingBar = exports.GradingBar = (_dec = (0, _quizCommon.withStyleOverrides)(_styles["default"], _theme["default"]), _dec(_class = (_GradingBar = /*#__PURE__*/function (_Component) {
function GradingBar(props) {
var _this2;
(0, _classCallCheck2["default"])(this, GradingBar);
_this2 = _callSuper(this, GradingBar, [props]);
(0, _defineProperty2["default"])(_this2, "regradeButtonRef", null);
(0, _defineProperty2["default"])(_this2, "feedbackButtonRef", null);
(0, _defineProperty2["default"])(_this2, "_timeouts", []);
// =============
// EXTERNALLY USED UTILS
// =============
(0, _defineProperty2["default"])(_this2, "focusRegradeButton", function () {
_this2.regradeButtonRef && _this2.regradeButtonRef.focus();
});
(0, _defineProperty2["default"])(_this2, "focusFeedbackButton", function () {
_this2.feedbackButtonRef && _this2.feedbackButtonRef.focus();
});
// =============
// HANDLERS
// =============
(0, _defineProperty2["default"])(_this2, "updatePoints", (0, _debounce["default"])(function () {
_this2.props.handleChangePoints(_this2.state.normalizedPoints);
}, 250, {
leading: true,
trailing: true
}));
(0, _defineProperty2["default"])(_this2, "handleChangePoints", function (event, points, normalizedPoints) {
var parsedPoints = parseFloat(normalizedPoints) || 0;
_this2.setState({
points: points,
normalizedPoints: parsedPoints
}, _this2.updatePoints);
var gradeStatus = _this2.getGradeStatus();
if (!gradeStatus || gradeStatus === 'waiting') {
_this2.props.handleChangeGradeStatus('graded');
}
});
(0, _defineProperty2["default"])(_this2, "handleBlurPoints", function () {
_this2.updatePoints.flush();
_this2.setState(function (_ref) {
var normalizedPoints = _ref.normalizedPoints;
return {
points: normalizedPoints || 0
};
});
});
(0, _defineProperty2["default"])(_this2, "handleStatusCorrectToggle", function () {
var newPoints = +_this2.props.sessionItemResult.pointsPossible;
_this2.props.handleChangePoints(newPoints);
_this2.setState({
points: "".concat(newPoints),
normalizedPoints: "".concat(newPoints)
});
var newStatus = _this2.getGradeStatus() === 'correct' ? 'graded' : 'correct';
_this2.props.handleChangeGradeStatus(newStatus, newStatus === 'graded');
});
(0, _defineProperty2["default"])(_this2, "handleStatusIncorrectToggle", function () {
_this2.props.handleChangePoints(0);
_this2.setState({
points: '0',
normalizedPoints: '0'
});
var newStatus = _this2.getGradeStatus() === 'incorrect' ? 'graded' : 'incorrect';
_this2.props.handleChangeGradeStatus(newStatus, newStatus === 'graded');
});
(0, _defineProperty2["default"])(_this2, "previousStudent", function (e) {
e.preventDefault();
_this2.props.postToParent({
subject: _quizCommon.GRADE_BY_QUESTION_PREVIOUS
});
});
(0, _defineProperty2["default"])(_this2, "nextStudent", function (e) {
e.preventDefault();
_this2.props.postToParent({
subject: _quizCommon.GRADE_BY_QUESTION_NEXT
});
});
(0, _defineProperty2["default"])(_this2, "jumpToSidebar", function (e) {
e.preventDefault();
var sidebarWrapper = document.getElementById('sidebar-wrapper');
if (sidebarWrapper && sidebarWrapper.focus) {
sidebarWrapper.focus();
}
});
(0, _defineProperty2["default"])(_this2, "handleRegradeButtonRef", function (node) {
_this2.regradeButtonRef = node;
});
(0, _defineProperty2["default"])(_this2, "handleFeedbackButtonRef", function (node) {
_this2.feedbackButtonRef = node;
});
var _points = _this2.props.sessionItemResult.getWorkingInstance().score;
if (typeof _points == 'number' || typeof _points == 'string') {
_points = Number(_points);
} else {
_points = null;
}
_this2.state = {
points: _points,
normalizedPoints: _points
};
return _this2;
}
(0, _inherits2["default"])(GradingBar, _Component);
return (0, _createClass2["default"])(GradingBar, [{
key: "regradeInfo",
get:
// =============
// INTERNAL UTILS
// =============
function get() {
return this.props.sessionItemResult.regradeInfo;
}
}, {
key: "pointsPossibleDescription",
value: function pointsPossibleDescription(pointsPossible) {
return (0, _formatMessage["default"])("{\n points, plural,\n one {# point}\n other {# points}\n }", {
points: pointsPossible
});
}
}, {
key: "getGradeStatus",
value: function getGradeStatus() {
var resultMods = this.props.itemResultsModifications || (0, _immutable.Map)();
var workingGradeStatus = resultMods.getIn(['scoredData', 'gradeStatus']);
if (workingGradeStatus) {
return workingGradeStatus;
}
return this.props.sessionItemResult.getIn(['scoredData', 'gradeStatus']);
}
}, {
key: "renderToSidebarButton",
value:
// =============
// RENDERING
// =============
function renderToSidebarButton() {
return (0, _emotion.jsx)(_quizCommon.Flex, {
justifyItems: "end",
margin: "small medium"
}, (0, _emotion.jsx)(_quizCommon.HideableButton, {
href: "#",
onClick: this.jumpToSidebar
}, (0, _formatMessage["default"])('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' ? (0, _formatMessage["default"])('toggle correct off') : (0, _formatMessage["default"])('toggle correct on');
var incorrectVariant = this.getGradeStatus() === 'incorrect' ? 'danger' : 'primary-inverse';
var incorrectText = this.getGradeStatus() === 'incorrect' ? (0, _formatMessage["default"])('toggle incorrect off') : (0, _formatMessage["default"])('toggle incorrect on');
return (0, _emotion.jsx)("div", {
css: this.props.styles.subjectiveButtonsWrapper
}, (0, _emotion.jsx)(_uiButtons.Button, {
color: correctVariant,
onClick: this.handleStatusCorrectToggle,
renderIcon: _uiIcons.IconCheckLine
}, (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, correctText)), (0, _emotion.jsx)(_uiButtons.Button, {
color: incorrectVariant,
margin: "0 xx-small",
onClick: this.handleStatusIncorrectToggle,
renderIcon: _uiIcons.IconXLine
}, (0, _emotion.jsx)(_uiA11yContent.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 = _uiIcons.IconDiscussionSolid;
text = (0, _formatMessage["default"])('Edit Grader Level Feedback (present)');
} else {
icon = _uiIcons.IconDiscussionLine;
text = (0, _formatMessage["default"])('Edit Grader Level Feedback');
}
return (0, _emotion.jsx)(_uiButtons.Button, {
ref: this.handleFeedbackButtonRef,
onClick: this.props.startFeedbackEdit,
renderIcon: icon,
"data-automation": "sdk-grading-edit-feedback-button"
}, (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, text));
}
}, {
key: "renderRegradeInfo",
value: function renderRegradeInfo() {
return (0, _emotion.jsx)("div", {
css: this.props.styles.regradeParent
}, (0, _emotion.jsx)("div", {
css: this.props.styles.originalScore
}, (0, _emotion.jsx)(_uiText.Text, {
color: "secondary"
}, (0, _formatMessage["default"])("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')
})), (0, _emotion.jsx)(_uiA11yContent.PresentationContent, null, (0, _emotion.jsx)("div", {
css: this.props.styles.divider
}, (0, _emotion.jsx)(_uiText.Text, {
color: "secondary"
}, '|' /* eslint-disable-line react/jsx-no-literals */)))), (0, _emotion.jsx)("div", {
css: this.props.styles.regradeText
}, (0, _emotion.jsx)(_uiText.Text, {
color: "alert"
}, (0, _formatMessage["default"])('Regrade score:'))), this.renderNumberInput(), (0, _emotion.jsx)(_uiText.Text, {
color: "alert"
}, // eslint-disable-next-line react/jsx-no-literals
"/ ".concat(this.pointsPossibleDescription(this.regradeInfo.get('newPointsPossible')))));
}
}, {
key: "renderNumberInput",
value: function renderNumberInput() {
return (0, _emotion.jsx)("div", {
css: this.props.styles.points
}, (0, _emotion.jsx)(_quizNumberInput["default"], {
placeholder: "--",
renderLabel: (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage["default"])('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 (0, _emotion.jsx)("div", {
css: this.props.styles.defaultNumberInput
}, this.renderNumberInput(), (0, _emotion.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) {
return (0, _emotion.jsx)(_quizCore.IfFeature, {
name: "regrading_from_speedgrader"
}, (0, _emotion.jsx)("div", {
css: this.props.styles.regradeButtonWrapper
}, (0, _emotion.jsx)(_uiButtons.Button, {
margin: "0 small",
onClick: this.props.regradeToggleAction,
ref: this.handleRegradeButtonRef,
"data-automation": "sdk-regrade-request-button"
}, _formatMessage["default"].rich('Regrade <0>question {position, number}</0>', {
0: function _(_ref2) {
var children = _ref2.children;
return (0, _emotion.jsx)(_uiA11yContent.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 (0, _emotion.jsx)("div", {
css: this.props.styles.editFeedback
}, (0, _emotion.jsx)("label", {
htmlFor: "edit_grader_feedback"
}, (0, _formatMessage["default"])('Additional Comments')), (0, _emotion.jsx)(_quizRce.RichContentInput, {
label: "",
defaultContent: this.props.graderFeedback.get('content'),
onKeyUp: this.props.updateFeedbackEdit,
onChange: this.props.updateFeedbackEdit,
textareaId: textareaId
}), (0, _emotion.jsx)("div", {
className: "editFeedbackButtons",
css: this.props.styles.editFeedbackButtons
}, (0, _emotion.jsx)(_uiButtons.Button, {
size: "small",
margin: "x-small",
onClick: this.props.cancelFeedbackEdit,
"data-automation": "sdk-grading-edit-feedback-cancel"
}, (0, _formatMessage["default"])('Cancel')), (0, _emotion.jsx)(_uiButtons.Button, {
color: "primary",
size: "small",
margin: "x-small",
onClick: this.props.submitFeedbackEdit,
"data-automation": "sdk-grading-edit-feedback-submit"
}, (0, _formatMessage["default"])('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 (0, _emotion.jsx)(_quizCommon.Flex, {
justifyItems: "end",
margin: "small medium"
}, this.props.renderUpdateButton({
margin: '0 xx-small'
}), (0, _emotion.jsx)(_uiButtons.Button, {
margin: "0 xx-small",
href: "#",
onClick: this.previousStudent
}, (0, _emotion.jsx)(_quizCommon.Flex, {
alignItems: "center"
}, (0, _emotion.jsx)(_uiIcons.IconArrowOpenStartLine, null), (0, _emotion.jsx)(_uiView.View, {
margin: "0 0 0 x-small"
}, (0, _formatMessage["default"])('Previous Student')))), (0, _emotion.jsx)(_uiButtons.Button, {
margin: "0 xx-small",
href: "#",
onClick: this.nextStudent
}, (0, _emotion.jsx)(_quizCommon.Flex, {
alignItems: "center"
}, (0, _emotion.jsx)(_uiView.View, {
margin: "0 x-small 0 0"
}, (0, _formatMessage["default"])('Next Student')), (0, _emotion.jsx)(_uiIcons.IconArrowOpenEndLine, null))));
}
}
}, {
key: "render",
value: function render() {
var hasRegradeInfo = this.regradeInfo && this.regradeInfo.size > 1;
return (0, _emotion.jsx)("div", null, this.renderEditGraderFeedback(), (0, _emotion.jsx)("div", {
className: "root",
css: this.props.styles.root
}, (0, _emotion.jsx)("div", {
css: this.props.styles.feedbackButtonWrapper
}, this.renderFeedbackSection()), this.renderRegradeButton(), (0, _emotion.jsx)("div", {
className: "fs-mask",
css: this.props.styles.pointsSection
}, this.renderSubjectiveButtons(), hasRegradeInfo ? this.renderRegradeInfo() : this.renderDefaultNumberInput())), this.renderGradeByQuestionControls(), this.renderToSidebarButton());
}
}]);
}(_react.Component), (0, _defineProperty2["default"])(_GradingBar, "displayName", 'GradingBar'), (0, _defineProperty2["default"])(_GradingBar, "componentId", "Quizzes".concat(_GradingBar.displayName)), (0, _defineProperty2["default"])(_GradingBar, "propTypes", {
activeItemId: _propTypes["default"].string,
gradeByQuestionEnabled: _propTypes["default"].bool,
graderFeedback: _reactImmutableProptypes["default"].map.isRequired,
handleChangeGradeStatus: _propTypes["default"].func.isRequired,
handleChangePoints: _propTypes["default"].func.isRequired,
isAutogradeable: _propTypes["default"].bool.isRequired,
isEditing: _propTypes["default"].bool.isRequired,
isSubjective: _propTypes["default"].bool.isRequired,
itemResultsModifications: _reactImmutableProptypes["default"].map.isRequired,
postToParent: _propTypes["default"].func.isRequired,
regradeToggleAction: _propTypes["default"].func.isRequired,
renderUpdateButton: _propTypes["default"].func.isRequired,
sessionItem: _reactImmutableProptypes["default"].record.isRequired,
sessionItemResult: _reactImmutableProptypes["default"].record.isRequired,
startFeedbackEdit: _propTypes["default"].func.isRequired,
submitFeedbackEdit: _propTypes["default"].func.isRequired,
updateFeedbackEdit: _propTypes["default"].func.isRequired,
cancelFeedbackEdit: _propTypes["default"].func.isRequired,
styles: _propTypes["default"].object
}), (0, _defineProperty2["default"])(_GradingBar, "defaultProps", {
activeItemId: null,
gradeByQuestionEnabled: false
}), _GradingBar)) || _class);
var _default = exports["default"] = GradingBar;