UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

380 lines (374 loc) • 15.2 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/esm/inherits"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; var _dec, _class, _FillBlankEdit; 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 = _getPrototypeOf(derived); return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args)); } /** @jsx jsx */ 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/es/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; /** --- 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 = withStyleOverrides(generateStyle, generateComponentTheme), withEditTools(_class = _dec(_class = (_FillBlankEdit = /*#__PURE__*/function (_Component) { function FillBlankEdit(props) { var _this2; _classCallCheck(this, FillBlankEdit); _this2 = _callSuper(this, FillBlankEdit, [props]); _defineProperty(_this2, "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 _defineProperty(_this2, "getErrors", function (path) { if (_this2.props.errorsAreShowing) { return get(_this2.props.errors, path, null); } return null; }); // ================ // HANDLERS // ================ _defineProperty(_this2, "setSelectedText", function (text) { _this2.setState({ selectedText: text }); }); _defineProperty(_this2, "handleCreateBlank", function (event) { _this2.controller.onCreateBlank(event); _this2.setState({ selectedText: '' }); }); _defineProperty(_this2, "handleCreateBlankHotkey", function (event) { if (event.which === ENTER_KEY_CODE || event.which === SPACE_KEY_CODE && event.ctrlKey && event.altKey) { event.preventDefault(); _this2.handleCreateBlank(event); _this2.props.notifyScreenreader(t('Blank created. Navigate to edit blank below.')); } }); _defineProperty(_this2, "handleDescriptionChange", function (prompt) { _this2.controller.updateInteractionData({ prompt: prompt }); }); _defineProperty(_this2, "updateBlank", function (blankId) { return function (blankMods) { _this2.controller.updateBlank(blankId, blankMods); }; }); _defineProperty(_this2, "updateBlankScoringData", function (blankId) { return function (scoringDataModifications) { _this2.controller.updateScoringDataForBlank(blankId, scoringDataModifications); }; }); _this2.controller = new EditController(props); return _this2; } _inherits(FillBlankEdit, _Component); return _createClass(FillBlankEdit, [{ key: "UNSAFE_componentWillReceiveProps", value: function UNSAFE_componentWillReceiveProps(nextProps) { this.controller.UNSAFE_componentWillReceiveProps(nextProps); } }, { key: "renderBlanksOptions", value: // ============= // RENDERING // ============= function renderBlanksOptions() { var _this3 = this; return this.controller.sortedBlanks().map(function (blank, blankIndex) { var blankScoringData = find({ id: blank.id }, _this3.props.scoringData.value) || {}; var choicesErrors = concat(_this3.getErrors("scoringData.value[".concat(blankIndex, "].scoringData.value.$errors")) || [], _this3.getErrors("interactionData.blanks[".concat(blankIndex, "].choices.$errors")) || []); return jsx(BlankTypeSelect, { key: blank.id, answerType: blank.answerType, blankPosition: blankIndex + 1, blankScoringAlgorithm: blankScoringData.scoringAlgorithm, blankScoringData: blankScoringData.scoringData, disabled: _this3.props.overrideEditableForRegrading, choices: blank.choices, fitbCommonWordbankEnabled: _this3.props.fitbCommonWordbankEnabled, interactionDataErrors: _this3.getErrors("interactionData.blanks[".concat(blankIndex, "]")) || {}, name: blank.id, notifyScreenreader: _this3.props.notifyScreenreader, onModalClose: _this3.props.onModalClose, onModalOpen: _this3.props.onModalOpen, scoringDataErrors: _this3.getErrors("scoringData.value[".concat(blankIndex, "].scoringData")) || {}, choicesErrors: choicesErrors, validationErrorsFromApi: _this3.props.validationErrorsFromApi[blank.id] || [], updateBlank: _this3.updateBlank(blank.id), updateBlankScoringData: _this3.updateBlankScoringData(blank.id), useCommonWordbank: false }); }); } }, { key: "renderCreateBlankButton", value: function renderCreateBlankButton() { if (this.state.selectedText.trim() && !this.props.overrideEditableForRegrading) { return jsx("div", { css: this.props.styles.createButton }, jsx(Button, { onClick: this.handleCreateBlank, color: "primary-inverse" }, jsx("span", { css: this.props.styles.createBlankText }, t('Create Blank Space')), jsx("span", { css: this.props.styles.createBlankHotkeyText }, t('(Enter)')))); } } }, { key: "renderOptionsDescription", value: function renderOptionsDescription() { return jsx(ScreenReaderContent, null, t('Fill in the blank options')); } }, { key: "render", value: function render() { return jsx("div", null, 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: [] }, jsx("div", { css: this.props.styles.hint }, jsx(Text, { color: "primary" }, t('Type a statement, select text, and press Enter to create a new blank.'))), 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() }), jsx("div", null, this.renderCreateBlankButton(), jsx(Errors, { errorList: this.getErrors(['interactionData', 'blanks', '$errors']) || [] }, this.renderBlanksOptions()))), jsx(QuestionSettingsContainer, { additionalOptions: this.props.additionalOptions }, this.props.showCalculatorOption && jsx(QuestionSettingsPanel, { label: t('Options'), defaultExpanded: true }, jsx(FormFieldGroup, { rowSpacing: "small", description: this.renderOptionsDescription() }, jsx(CalculatorOptionWithOqaatAlert, { disabled: this.props.overrideEditableForRegrading, calculatorValue: this.props.calculatorType, onCalculatorTypeChange: this.controller.handleCalculatorTypeChange, oqaatChecked: this.props.oneQuestionAtATime, onOqaatChange: this.props.setOneQuestionAtATime }))))); } }]); }(Component), _defineProperty(_FillBlankEdit, "displayName", 'FillBlankEdit'), _defineProperty(_FillBlankEdit, "componentId", "Quizzes".concat(_FillBlankEdit.displayName)), _defineProperty(_FillBlankEdit, "interactionType", FillBlankInteractionType), _defineProperty(_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 }), _defineProperty(_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 }), _FillBlankEdit)) || _class) || _class); export { FillBlankEdit as default };