quiz-interactions
Version:
A React UI component Library for quiz interaction types.
418 lines (366 loc) • 16.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = 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 _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _concat = _interopRequireDefault(require("lodash/fp/concat"));
var _find = _interopRequireDefault(require("lodash/fp/find"));
var _get = _interopRequireDefault(require("lodash/get"));
var _uiButtons = require("@instructure/ui-buttons");
var _uiElements = require("@instructure/ui-elements");
var _uiThemeable = require("@instructure/ui-themeable");
var _Errors = _interopRequireDefault(require("../../common/edit/components/Errors"));
var _QuestionSettingsContainer = _interopRequireDefault(require("../../common/edit/components/QuestionSettingsContainer"));
var _QuestionContainer = _interopRequireDefault(require("../../common/edit/components/QuestionContainer"));
var _fill_blank = _interopRequireDefault(require("../../../records/interactions/fill_blank"));
var _BlankTypeSelect = _interopRequireDefault(require("./answer_field/BlankTypeSelect"));
var _EditStem = _interopRequireDefault(require("./EditStem"));
var _editController = _interopRequireDefault(require("./editController"));
var _theme = _interopRequireDefault(require("./theme"));
var _withEditTools = _interopRequireDefault(require("../../../util/withEditTools"));
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message"));
var _QuestionSettingsPanel = _interopRequireDefault(require("../../common/edit/components/QuestionSettingsPanel"));
var _CalculatorOptionWithOqaatAlert = _interopRequireDefault(require("../../common/edit/components/CalculatorOptionWithOqaatAlert"));
var _uiFormField = require("@instructure/ui-form-field");
var _uiA11y = require("@instructure/ui-a11y");
var _dec, _class, _class2, _temp;
var styles = {
componentId: 'beqzy',
template: function template(theme) {
return "\n\n.beqzy_bgAF{margin-top:".concat(theme.createButtonMargin || 'inherit', "}\n\n.beqzy_dYYb{margin:").concat(theme.hintMargin || 'inherit', " 0}\n\n.beqzy_ULRc{font-weight:").concat(theme.createBlankTextWeight || 'inherit', "}\n\n.beqzy_eYQy{font-size:").concat(theme.createBlankHotkeyTextSize || 'inherit', ";font-weight:").concat(theme.createBlankHotkeyTextWeight || 'inherit', ";padding-left:").concat(theme.createBlankHotkeyTextPadding || 'inherit', "}");
},
'createButton': 'beqzy_bgAF',
'hint': 'beqzy_dYYb',
'createBlankText': 'beqzy_ULRc',
'createBlankHotkeyText': 'beqzy_eYQy'
};
var SPACE_KEY_CODE = 32;
var ENTER_KEY_CODE = 13;
/**
category: FillInTheBlank
Fill in the Blank Edit component
```jsx_example
function Example (props) {
const exampleProps = {
interactionData: {
prompt: '<p><strong>Please</strong> fill in all the blanks</p>',
blanks: [{
answerType: 'openEntry',
id: 'uuid-blank1'
}, {
answerType: 'openEntry',
id: 'uuid-blank2'
}, {
answerType: 'openEntry',
id: 'uuid-blank3'
}, {
answerType: 'openEntry',
id: 'uuid-blank4'
}, {
answerType: 'openEntry',
id: 'uuid-blank5'
}, {
answerType: 'dropdown',
id: 'uuid-blank6',
choices: [
{ id: 'uuid6-choice1', position: 1, itemBody: 'with' },
{ id: 'uuid6-choice2', position: 2, itemBody: 'on' },
{ id: 'uuid6-choice3', position: 3, itemBody: 'which' }
]
}, {
answerType: 'wordbank',
id: 'uuid-blank7',
choices: [
{ id: 'uuid7-choice1', position: 1, itemBody: 'bathwater' },
{ id: 'uuid7-choice2', position: 2, itemBody: 'bathtub' },
{ id: 'uuid7-choice3', position: 3, itemBody: 'water' }
]
}],
stemItems: [
{ id: 'uuid-stem0', position: 1, type: 'text', value: ' ' },
{ id: 'uuid-stem1', position: 2, type: 'blank', blankId: 'uuid-blank1' },
{ id: 'uuid-stem2', position: 3, type: 'text', value: ' ' },
{ id: 'uuid-stem3', position: 4, type: 'blank', blankId: 'uuid-blank2' },
{ id: 'uuid-stem4', position: 5, type: 'text', value: ' ' },
{ id: 'uuid-stem5', position: 6, type: 'blank', blankId: 'uuid-blank3' },
{ id: 'uuid-stem6', position: 7, type: 'text', value: ' ' },
{ id: 'uuid-stem7', position: 8, type: 'blank', blankId: 'uuid-blank4' },
{ id: 'uuid-stem8', position: 9, type: 'text', value: ' ' },
{ id: 'uuid-stem9', position: 10, type: 'blank', blankId: 'uuid-blank5' },
{ id: 'uuid-stem10', position: 11, type: 'text', value: ' ' },
{ id: 'uuid-stem11', position: 12, type: 'blank', blankId: 'uuid-blank6' },
{ id: 'uuid-stem12', position: 13, type: 'text', value: ' <the> ' },
{ id: 'uuid-stem13', position: 14, type: 'blank', blankId: 'uuid-blank7' },
{ id: 'uuid-stem14', position: 15, type: 'text', value: '.' }
]
},
scoringData: {
value: [{
id: 'uuid-blank1',
scoringAlgorithm: 'TextCloseEnough',
scoringData: {
blankText: 'Don\'t',
editDistance: '1',
ignoreCase: true,
value: 'Don\'t'
}
}, {
id: 'uuid-blank2',
scoringAlgorithm: 'TextEquivalence',
scoringData: {
blankText: 'throw',
value: 'throw'
}
}, {
id: 'uuid-blank3',
scoringAlgorithm: 'TextContainsAnswer',
scoringData: {
blankText: 'the',
value: 'the'
}
}, {
id: 'uuid-blank4',
scoringAlgorithm: 'TextInChoices',
scoringData: {
blankText: 'baby',
value: ['baby', 'kid', 'child']
}
}, {
id: 'uuid-blank5',
scoringAlgorithm: 'TextRegex',
scoringData: {
blankText: 'out',
value: 'out'
}
}, {
id: 'uuid-blank6',
scoringAlgorithm: 'Equivalence',
scoringData: {
blankText: 'with',
value: 'uuid6-choice1'
}
}, {
id: 'uuid-blank7',
scoringAlgorithm: 'Equivalence',
scoringData: {
blankText: 'bathwater',
value: 'uuid7-choice1'
}
}]
}
}
return (
<FillBlankEdit {...exampleProps} {...props} />
)
}
<SettingsSwitcher locales={LOCALES}>
<EditStateProvider>
<Example />
</EditStateProvider>
</SettingsSwitcher>
```
**/
var FillBlankEdit = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), (0, _withEditTools.default)(_class = _dec(_class = (_temp = _class2 =
/*#__PURE__*/
function (_Component) {
(0, _inherits2.default)(FillBlankEdit, _Component);
function FillBlankEdit(props) {
var _this;
(0, _classCallCheck2.default)(this, FillBlankEdit);
_this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(FillBlankEdit).call(this, props));
_this.state = {
selectedText: ''
};
_this.getErrors = function (path) {
if (_this.props.errorsAreShowing) {
return (0, _get.default)(_this.props.errors, path, null);
}
return null;
};
_this.setSelectedText = function (text) {
_this.setState({
selectedText: text
});
};
_this.handleCreateBlank = function (event) {
_this.controller.onCreateBlank(event);
_this.setState({
selectedText: ''
});
};
_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((0, _formatMessage.default)('Blank created. Navigate to edit blank below.'));
}
};
_this.handleDescriptionChange = function (prompt) {
_this.controller.updateInteractionData({
prompt: prompt
});
};
_this.controller = new _editController.default(props);
return _this;
}
(0, _createClass2.default)(FillBlankEdit, [{
key: "componentWillReceiveProps",
value: function componentWillReceiveProps(nextProps) {
this.controller.componentWillReceiveProps(nextProps);
} // Other edit components use the `getErrors` helper passed in from the
// withEditTools higher-order component, but fill blank has its own error
// handling logic
}, {
key: "renderBlanksOptions",
// =============
// RENDERING
// =============
value: function renderBlanksOptions() {
var _this2 = this;
return this.controller.sortedBlanks().map(function (blank, blankIndex) {
var blankScoringData = (0, _find.default)({
id: blank.id
}, _this2.props.scoringData.value) || {};
var choicesErrors = (0, _concat.default)(_this2.getErrors("scoringData.value[".concat(blankIndex, "].scoringData.value.$errors")) || [], _this2.getErrors("interactionData.blanks[".concat(blankIndex, "].choices.$errors")) || []);
return _react.default.createElement(_BlankTypeSelect.default, {
key: blank.id,
answerType: blank.answerType,
blankPosition: blankIndex + 1,
blankScoringAlgorithm: blankScoringData.scoringAlgorithm,
blankScoringData: blankScoringData.scoringData,
disabled: _this2.props.overrideEditableForRegrading,
choices: blank.choices,
interactionDataErrors: _this2.getErrors("interactionData.blanks[".concat(blankIndex, "]")) || {},
name: blank.id,
notifyScreenreader: _this2.props.notifyScreenreader,
onModalClose: _this2.props.onModalClose,
onModalOpen: _this2.props.onModalOpen,
scoringDataErrors: _this2.getErrors("scoringData.value[".concat(blankIndex, "].scoringData")) || {},
choicesErrors: choicesErrors,
updateBlank: function updateBlank(blankMods) {
_this2.controller.updateBlank(blank.id, blankMods);
},
updateBlankScoringData: function updateBlankScoringData(scoringDataModifications) {
_this2.controller.updateScoringDataForBlank(blank.id, scoringDataModifications);
}
});
});
}
}, {
key: "renderCreateBlankButton",
value: function renderCreateBlankButton() {
if (this.state.selectedText.trim() && !this.props.overrideEditableForRegrading) {
return _react.default.createElement("div", {
className: styles.createButton
}, _react.default.createElement(_uiButtons.Button, {
onClick: this.handleCreateBlank,
variant: "light"
}, _react.default.createElement("span", {
className: styles.createBlankText
}, (0, _formatMessage.default)('Create Blank Space')), _react.default.createElement("span", {
className: styles.createBlankHotkeyText
}, (0, _formatMessage.default)('(Enter)'))));
}
}
}, {
key: "renderOptionsDescription",
value: function renderOptionsDescription() {
return _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Fill in the blank options'));
}
}, {
key: "render",
value: function render() {
return _react.default.createElement("div", null, _react.default.createElement(_QuestionContainer.default, {
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: (0, _formatMessage.default)('Add Question Stem (optional)...'),
renderImportModal: this.props.renderImportModal,
stemErrors: []
}, _react.default.createElement("div", {
className: styles.hint
}, _react.default.createElement(_uiElements.Text, {
color: "primary"
}, (0, _formatMessage.default)('Type a statement, select text, and press Enter to create a new blank.'))), _react.default.createElement(_EditStem.default, {
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()
}), _react.default.createElement("div", null, this.renderCreateBlankButton(), _react.default.createElement(_Errors.default, {
errorList: this.getErrors(['interactionData', 'blanks', '$errors']) || []
}, this.renderBlanksOptions()))), _react.default.createElement(_QuestionSettingsContainer.default, {
additionalOptions: this.props.additionalOptions
}, !this.props.hiddenOptions.calculator && _react.default.createElement(_QuestionSettingsPanel.default, {
label: (0, _formatMessage.default)('Options'),
defaultExpanded: true
}, _react.default.createElement(_uiFormField.FormFieldGroup, {
rowSpacing: "small",
description: this.renderOptionsDescription()
}, _react.default.createElement(_CalculatorOptionWithOqaatAlert.default, {
disabled: this.props.overrideEditableForRegrading,
calculatorValue: this.props.calculatorType,
onCalculatorTypeChange: this.controller.handleCalculatorTypeChange,
oqaatChecked: this.props.oneQuestionAtATime,
onOqaatChange: this.props.setOneQuestionAtATime
})))));
}
}]);
FillBlankEdit.displayName = "FillBlankEdit";
return FillBlankEdit;
}(_react.Component), _class2.interactionType = _fill_blank.default, _class2.propTypes = {
additionalOptions: _propTypes.default.array,
calculatorType: _propTypes.default.string,
enableRichContentEditor: _propTypes.default.bool,
errors: _propTypes.default.object,
errorsAreShowing: _propTypes.default.bool,
hiddenOptions: _propTypes.default.shape({
calculator: _propTypes.default.bool
}),
interactionData: _propTypes.default.object.isRequired,
notifyScreenreader: _propTypes.default.func.isRequired,
onModalClose: _propTypes.default.func,
onModalOpen: _propTypes.default.func,
oneQuestionAtATime: _propTypes.default.bool,
openImportModal: _propTypes.default.func,
overrideEditableForRegrading: _propTypes.default.bool,
renderImportModal: _propTypes.default.func,
scoringData: _propTypes.default.object.isRequired,
setOneQuestionAtATime: _propTypes.default.func
}, _class2.defaultProps = {
calculatorType: 'none',
enableRichContentEditor: true,
hiddenOptions: {
calculator: true
},
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,
renderImportModal: void 0,
scoringData: void 0
}, _temp)) || _class) || _class);
exports.default = FillBlankEdit;