@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
279 lines (275 loc) • 13.7 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
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 _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _uuid = require("uuid");
var _uiText = require("@instructure/ui-text");
var _uiA11yContent = require("@instructure/ui-a11y-content");
var _quizRce = require("@instructure/quiz-rce");
var _WordCount = require("../helpers/WordCount");
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
var _quizCommon = require("@instructure/quiz-common");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
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));
}
/**
---
category: Essay
---
Essay Take component
```jsx_example
function Example (props) {
const exampleProps = {
itemBody: 'Why did the Roman Empire fall?',
interactionData: {
rce: true,
spellCheck: true,
wordCount: true,
wordLimitEnabled: true,
wordLimitMax: 10,
wordLimitMin: 1,
notes: 'Teachers grading notes'
},
userResponse: {
value: 'So it could learn to pick itself back up again.'
}
}
return (
<EssayTake {...exampleProps} {...props} />
)
}
<SettingsSwitcher locales={LOCALES}>
<TakeStateProvider>
<Example />
</TakeStateProvider>
</SettingsSwitcher>
```
**/
var EssayTake = exports["default"] = /*#__PURE__*/function (_Component) {
function EssayTake(props) {
var _this2;
(0, _classCallCheck2["default"])(this, EssayTake);
_this2 = _callSuper(this, EssayTake, [props]);
(0, _defineProperty2["default"])(_this2, "verifyErrors", function (text) {
var documentTreeDepthOverLimit = _this2.isDocumentTreeDepthOverLimit(text);
var dynamoRecordSize = _this2.getContentSize(text);
_this2.setState({
documentTreeDepthOverLimit: documentTreeDepthOverLimit,
dynamoRecordSize: dynamoRecordSize
});
});
(0, _defineProperty2["default"])(_this2, "isDocumentTreeDepthOverLimit", function (text) {
if (!text) return false;
try {
var template = document.createElement('template');
template.innerHTML = text;
return _this2.isLevelOfChildrenOverLimit(template.content);
} catch (e) {
console.error(e);
return false;
}
});
(0, _defineProperty2["default"])(_this2, "isLevelOfChildrenOverLimit", function (element) {
var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
if (level > _quizCommon.DOCUMENT_TREE_DEPTH_LIMIT) return true;
if (!element) return false;
var children = element.childNodes;
if (children.length === 0) return false;
var childrenLevel = level + 1;
return Array.from(children).some(function (e) {
return _this2.isLevelOfChildrenOverLimit(e, childrenLevel);
});
});
(0, _defineProperty2["default"])(_this2, "getContentSize", function (text) {
if (!text) return 0;
var match = new RegExp('[\&\<\>]', 'g'); // eslint-disable-line no-useless-escape
// In backend the whole response is serialized into Unicode
// every answer occupies CONTENT_SIZE_BY_ANSWER
// every text answer is serialized twice
// and then every ampersand, greater than and less than character
// when converted to Unicode occupies 5 more bytes twice
// Example, an & is turned into \u0026
return _quizCommon.CONTENT_SIZE_BY_ANSWER + text.length * 2 + (text.match(match) || []).length * 10;
});
(0, _defineProperty2["default"])(_this2, "handleOnBlur", function (event, rceContent) {
if (!_this2.props.readOnly) {
var newVal = _this2.props.interactionData.rce ? rceContent.editorContent : event.target.value;
if (newVal !== void 0 && newVal !== _this2.state.workingEssayContent) {
_this2.props.handleResponseUpdate(newVal);
_this2.verifyErrors(newVal);
_this2.setState({
workingEssayContent: newVal
});
}
}
});
(0, _defineProperty2["default"])(_this2, "handleOnChange", function (event, rceContent) {
if (!_this2.props.readOnly) {
var newVal = _this2.props.interactionData.rce ? rceContent.editorContent : event.target.value;
if (newVal !== void 0 && newVal !== _this2.state.workingEssayContent) {
_this2.props.handleResponseUpdate(newVal);
_this2.setState({
workingEssayContent: newVal
});
}
}
});
_this2.uniqId = (0, _uuid.v4)();
var workingEssayContent = props.userResponse && props.userResponse.value || '';
var _documentTreeDepthOverLimit = _this2.isDocumentTreeDepthOverLimit(workingEssayContent);
var _dynamoRecordSize = _this2.getContentSize(workingEssayContent);
_this2.state = {
workingEssayContent: workingEssayContent,
documentTreeDepthOverLimit: _documentTreeDepthOverLimit,
dynamoRecordSize: _dynamoRecordSize,
contentId: (0, _uuid.v4)()
};
return _this2;
}
(0, _inherits2["default"])(EssayTake, _Component);
return (0, _createClass2["default"])(EssayTake, [{
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var _prevProps$userRespon;
var userResponse = this.props.userResponse;
var prevValue = (_prevProps$userRespon = prevProps.userResponse) === null || _prevProps$userRespon === void 0 ? void 0 : _prevProps$userRespon.value;
var currentValue = userResponse === null || userResponse === void 0 ? void 0 : userResponse.value;
if (currentValue && prevValue === undefined) {
this.setState({
workingEssayContent: currentValue || '',
contentId: (0, _uuid.v4)()
});
}
}
}, {
key: "renderEditor",
value: function renderEditor() {
var commonProps = {
label: /*#__PURE__*/_react["default"].createElement(_uiA11yContent.ScreenReaderContent, null, /*#__PURE__*/_react["default"].createElement(_quizRce.RichContentRenderer, {
content: this.props.itemBody
})),
readOnly: this.props.readOnly,
onChange: this.handleOnChange,
onBlur: this.handleOnBlur
};
if (this.props.interactionData.rce) {
var _this$props$interacti = this.props.interactionData,
spellCheck = _this$props$interacti.spellCheck,
wordCount = _this$props$interacti.wordCount;
return /*#__PURE__*/_react["default"].createElement(_quizRce.RichContentInput, Object.assign({}, commonProps, {
textareaId: "rceTextArea_".concat(this.uniqId),
onKeyUp: this.handleOnChange,
openImportModal: this.props.openImportModal,
defaultContent: this.state.workingEssayContent,
stem: this.props.itemBody,
height: _quizRce.RCE_THREE_LINES_HEIGHT,
editorOptions: {
spellCheck: spellCheck,
wordCount: wordCount
},
key: this.state.contentId,
disableDocumentAccess: this.props.disableDocumentAccess
}));
}
return /*#__PURE__*/_react["default"].createElement(_quizCommon.TextArea, Object.assign({}, commonProps, {
value: this.state.workingEssayContent,
resize: "vertical",
spellCheck: this.props.interactionData.spellCheck,
autoGrow: this.context.disableTextAreaAutoGrow ? false : null
}));
}
}, {
key: "renderErrors",
value: function renderErrors() {
var _this$state = this.state,
documentTreeDepthOverLimit = _this$state.documentTreeDepthOverLimit,
dynamoRecordSize = _this$state.dynamoRecordSize;
return /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement(_uiText.Text, {
color: "danger",
size: "small"
}, documentTreeDepthOverLimit ? (0, _formatMessage["default"])('Formatting error. Please ensure that the text entry has not been pasted from a different source. Type text to submit response.') : '', dynamoRecordSize > _quizCommon.CONTENT_SIZE_LIMIT ? (0, _formatMessage["default"])('This submission is too large. Please adjust and try to submit again.') : ''));
}
}, {
key: "renderWordCountMessage",
value: function renderWordCountMessage() {
var _this$props$interacti2 = this.props.interactionData,
wordCount = _this$props$interacti2.wordCount,
wordLimitMin = _this$props$interacti2.wordLimitMin,
wordLimitEnabled = _this$props$interacti2.wordLimitEnabled,
wordLimitMax = _this$props$interacti2.wordLimitMax;
if (wordCount || wordLimitEnabled) {
return /*#__PURE__*/_react["default"].createElement(_uiA11yContent.ScreenReaderContent, null, wordLimitEnabled && wordLimitMin ? (0, _formatMessage["default"])('This essay has a minimum word count of {wordLimitMin}.', {
wordLimitMin: wordLimitMin
}) : '', wordLimitEnabled && wordLimitMax ? (0, _formatMessage["default"])('This essay has a maximum word count of {wordLimitMax}.', {
wordLimitMax: wordLimitMax
}) : '', wordCount ? (0, _formatMessage["default"])('There is a word count below the text area.') : '');
}
}
}, {
key: "render",
value: function render() {
var _this$props = this.props,
interactionData = _this$props.interactionData,
itemBody = _this$props.itemBody,
notifyScreenreader = _this$props.notifyScreenreader;
return /*#__PURE__*/_react["default"].createElement(_quizRce.ItemBodyWrapper, {
itemBody: itemBody
}, this.renderWordCountMessage(), /*#__PURE__*/_react["default"].createElement("div", {
className: "fs-mask"
}, this.renderEditor()), /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement(_WordCount.WordCount, {
rce: interactionData.rce,
isEditing: true,
essay: this.state.workingEssayContent,
wordCount: interactionData.wordCount,
wordLimitEnabled: interactionData.wordLimitEnabled,
wordLimitMin: parseInt(interactionData.wordLimitMin, 10),
wordLimitMax: parseInt(interactionData.wordLimitMax, 10),
notifyScreenreader: notifyScreenreader
})), this.renderErrors());
}
}]);
}(_react.Component);
(0, _defineProperty2["default"])(EssayTake, "propTypes", {
handleResponseUpdate: _propTypes["default"].func,
interactionData: _propTypes["default"].object.isRequired,
itemBody: _propTypes["default"].string.isRequired,
userResponse: _propTypes["default"].object,
notifyScreenreader: _propTypes["default"].func,
openImportModal: _propTypes["default"].func,
readOnly: _propTypes["default"].bool,
disableDocumentAccess: _propTypes["default"].bool
});
(0, _defineProperty2["default"])(EssayTake, "defaultProps", {
handleResponseUpdate: function handleResponseUpdate() {},
openImportModal: function openImportModal() {},
readOnly: false,
userResponse: void 0,
notifyScreenreader: void 0,
disableDocumentAccess: false
});
(0, _defineProperty2["default"])(EssayTake, "contextTypes", {
disableTextAreaAutoGrow: _propTypes["default"].bool
});