@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
333 lines (332 loc) • 15.4 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;
})();
}
function _ts_decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
import { Component } from 'react';
import PropTypes from 'prop-types';
import concat from 'lodash/fp/concat';
import find from 'lodash/fp/find';
import get from 'lodash/get';
import { Button } from '@instructure/ui-buttons';
import { Text } from '@instructure/ui-text';
import { jsx } from '@instructure/emotion';
import Errors from '../../common/edit/components/Errors';
import QuestionSettingsContainer from '../../common/edit/components/QuestionSettingsContainer';
import QuestionContainer from '../../common/edit/components/QuestionContainer';
import FillBlankInteractionType from '../../../records/interactions/fill_blank';
import BlankTypeSelect from './answer_field/BlankTypeSelect';
import EditStem from './EditStem';
import EditController from './editController';
import generateStyle from './styles';
import generateComponentTheme from './theme';
import withEditTools from '../../../util/withEditTools';
import t from '@instructure/quiz-i18n/format-message';
import QuestionSettingsPanel from '../../common/edit/components/QuestionSettingsPanel';
import CalculatorOptionWithOqaatAlert from '../../common/edit/components/CalculatorOptionWithOqaatAlert';
import { ScreenReaderContent } from '@instructure/ui-a11y-content';
import { withStyleOverrides, FormFieldGroup } from '@instructure/quiz-common';
var SPACE_KEY_CODE = 32;
var ENTER_KEY_CODE = 13;
var FillBlankEdit = /*#__PURE__*/ function(Component) {
"use strict";
_inherits(FillBlankEdit, Component);
function FillBlankEdit(props) {
_class_call_check(this, FillBlankEdit);
var _this;
_this = _call_super(this, FillBlankEdit, [
props
]), _define_property(_this, "state", {
selectedText: ''
}), // Other edit components use the `getErrors` helper passed in from the
// withEditTools higher-order component, but fill blank has its own error
// handling logic
_define_property(_this, "getErrors", function(path) {
if (_this.props.errorsAreShowing) {
return get(_this.props.errors, path, null);
}
return null;
}), // ================
// HANDLERS
// ================
_define_property(_this, "setSelectedText", function(text) {
_this.setState({
selectedText: text
});
}), _define_property(_this, "handleCreateBlank", function(event) {
_this.controller.onCreateBlank(event);
_this.setState({
selectedText: ''
});
}), _define_property(_this, "handleCreateBlankHotkey", function(event) {
if (event.which === ENTER_KEY_CODE || event.which === SPACE_KEY_CODE && event.ctrlKey && event.altKey) {
event.preventDefault();
_this.handleCreateBlank(event);
_this.props.notifyScreenreader(t('Blank created. Navigate to edit blank below.'));
}
}), _define_property(_this, "handleDescriptionChange", function(prompt) {
_this.controller.updateInteractionData({
prompt: prompt
});
}), _define_property(_this, "updateBlank", function(blankId) {
return function(blankMods) {
_this.controller.updateBlank(blankId, blankMods);
};
}), _define_property(_this, "updateBlankScoringData", function(blankId) {
return function(scoringDataModifications) {
_this.controller.updateScoringDataForBlank(blankId, scoringDataModifications);
};
});
_this.controller = new EditController(props);
return _this;
}
_create_class(FillBlankEdit, [
{
key: "UNSAFE_componentWillReceiveProps",
value: function UNSAFE_componentWillReceiveProps(nextProps) {
this.controller.UNSAFE_componentWillReceiveProps(nextProps);
}
},
{
// =============
// RENDERING
// =============
key: "renderBlanksOptions",
value: function renderBlanksOptions() {
var _this = this;
return this.controller.sortedBlanks().map(function(blank, blankIndex) {
var blankScoringData = find({
id: blank.id
}, _this.props.scoringData.value) || {};
var choicesErrors = concat(_this.getErrors("scoringData.value[".concat(blankIndex, "].scoringData.value.$errors")) || [], _this.getErrors("interactionData.blanks[".concat(blankIndex, "].choices.$errors")) || []);
return /*#__PURE__*/ jsx(BlankTypeSelect, {
key: blank.id,
answerType: blank.answerType,
blankPosition: blankIndex + 1,
blankScoringAlgorithm: blankScoringData.scoringAlgorithm,
blankScoringData: blankScoringData.scoringData,
disabled: _this.props.overrideEditableForRegrading,
choices: blank.choices,
fitbCommonWordbankEnabled: _this.props.fitbCommonWordbankEnabled,
interactionDataErrors: _this.getErrors("interactionData.blanks[".concat(blankIndex, "]")) || {},
name: blank.id,
notifyScreenreader: _this.props.notifyScreenreader,
onModalClose: _this.props.onModalClose,
onModalOpen: _this.props.onModalOpen,
scoringDataErrors: _this.getErrors("scoringData.value[".concat(blankIndex, "].scoringData")) || {},
choicesErrors: choicesErrors,
validationErrorsFromApi: _this.props.validationErrorsFromApi[blank.id] || [],
updateBlank: _this.updateBlank(blank.id),
updateBlankScoringData: _this.updateBlankScoringData(blank.id),
useCommonWordbank: false
});
});
}
},
{
key: "renderCreateBlankButton",
value: function renderCreateBlankButton() {
if (this.state.selectedText.trim() && !this.props.overrideEditableForRegrading) {
return /*#__PURE__*/ jsx("div", {
css: this.props.styles.createButton
}, /*#__PURE__*/ jsx(Button, {
onClick: this.handleCreateBlank,
color: "primary-inverse"
}, /*#__PURE__*/ jsx("span", {
css: this.props.styles.createBlankText
}, t('Create Blank Space')), /*#__PURE__*/ jsx("span", {
css: this.props.styles.createBlankHotkeyText
}, t('(Enter)'))));
}
}
},
{
key: "renderOptionsDescription",
value: function renderOptionsDescription() {
return /*#__PURE__*/ jsx(ScreenReaderContent, null, t('Fill in the blank options'));
}
},
{
key: "render",
value: function render() {
return /*#__PURE__*/ jsx("div", null, /*#__PURE__*/ jsx(QuestionContainer, {
disabled: this.props.overrideEditableForRegrading,
enableRichContentEditor: this.props.enableRichContentEditor,
itemBody: this.props.interactionData.prompt,
onDescriptionChange: this.handleDescriptionChange,
onModalClose: this.props.onModalClose,
onModalOpen: this.props.onModalOpen,
openImportModal: this.props.openImportModal,
placeholder: t('Add Question Stem (optional)...'),
stemErrors: []
}, /*#__PURE__*/ jsx("div", {
css: this.props.styles.hint
}, /*#__PURE__*/ jsx(Text, {
color: "primary"
}, t('Type a statement, select text, and press Enter to create a new blank.'))), /*#__PURE__*/ jsx(EditStem, {
disabled: this.props.overrideEditableForRegrading,
errors: this.getErrors('itemBody') || [],
destroyBlank: this.controller.onDestroyBlank,
onCreateBlankHotkey: this.handleCreateBlankHotkey,
onStemChange: this.controller.onStemChange,
scoringData: this.props.scoringData,
setSelectedText: this.setSelectedText,
stemItems: this.controller.sortedStemItems()
}), /*#__PURE__*/ jsx("div", null, this.renderCreateBlankButton(), /*#__PURE__*/ jsx(Errors, {
errorList: this.getErrors([
'interactionData',
'blanks',
'$errors'
]) || []
}, this.renderBlanksOptions()))), /*#__PURE__*/ jsx(QuestionSettingsContainer, {
additionalOptions: this.props.additionalOptions
}, this.props.showCalculatorOption && /*#__PURE__*/ jsx(QuestionSettingsPanel, {
label: t('Options'),
defaultExpanded: true
}, /*#__PURE__*/ jsx(FormFieldGroup, {
rowSpacing: "small",
description: this.renderOptionsDescription()
}, /*#__PURE__*/ jsx(CalculatorOptionWithOqaatAlert, {
disabled: this.props.overrideEditableForRegrading,
calculatorValue: this.props.calculatorType,
onCalculatorTypeChange: this.controller.handleCalculatorTypeChange,
oqaatChecked: this.props.oneQuestionAtATime,
onOqaatChange: this.props.setOneQuestionAtATime
})))));
}
}
]);
return FillBlankEdit;
}(Component);
_define_property(FillBlankEdit, "displayName", 'FillBlankEdit');
_define_property(FillBlankEdit, "componentId", "Quizzes".concat(FillBlankEdit.displayName));
_define_property(FillBlankEdit, "interactionType", FillBlankInteractionType);
_define_property(FillBlankEdit, "propTypes", {
additionalOptions: PropTypes.array,
calculatorType: PropTypes.string,
enableRichContentEditor: PropTypes.bool,
errors: PropTypes.object,
errorsAreShowing: PropTypes.bool,
fitbCommonWordbankEnabled: PropTypes.bool,
interactionData: PropTypes.object.isRequired,
notifyScreenreader: PropTypes.func.isRequired,
onModalClose: PropTypes.func,
onModalOpen: PropTypes.func,
oneQuestionAtATime: PropTypes.bool,
openImportModal: PropTypes.func,
overrideEditableForRegrading: PropTypes.bool,
scoringData: PropTypes.object.isRequired,
setOneQuestionAtATime: PropTypes.func,
validationErrorsFromApi: PropTypes.object,
styles: PropTypes.object,
showCalculatorOption: PropTypes.bool
});
_define_property(FillBlankEdit, "defaultProps", {
calculatorType: 'none',
enableRichContentEditor: true,
fitbCommonWordbankEnabled: false,
oneQuestionAtATime: false,
overrideEditableForRegrading: false,
setOneQuestionAtATime: Function.prototype,
additionalOptions: void 0,
errors: void 0,
errorsAreShowing: void 0,
onModalClose: void 0,
onModalOpen: void 0,
openImportModal: void 0,
scoringData: void 0,
validationErrorsFromApi: {},
showCalculatorOption: true
});
export { FillBlankEdit as default };
FillBlankEdit = _ts_decorate([
withEditTools,
withStyleOverrides(generateStyle, generateComponentTheme)
], FillBlankEdit);