UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

370 lines (366 loc) • 16.4 kB
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 _object_spread(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === "function") { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _define_property(target, key, source[key]); }); } return target; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function(sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _object_spread_props(target, source) { source = source != null ? source : {}; if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function(key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } 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; })(); } import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { v4 as uuid } from 'uuid'; import { Text } from '@instructure/ui-text'; import { ScreenReaderContent } from '@instructure/ui-a11y-content'; import { ItemBodyWrapper, RichContentInput, RichContentRenderer, RCE_THREE_LINES_HEIGHT } from '@instructure/quiz-rce'; import { WordCount } from '../helpers/WordCount'; import t from '@instructure/quiz-i18n/format-message'; import { DOCUMENT_TREE_DEPTH_LIMIT, CONTENT_SIZE_LIMIT, CONTENT_SIZE_BY_ANSWER, TextArea } from '@instructure/quiz-common'; var EssayTake = /*#__PURE__*/ function(Component) { "use strict"; _inherits(EssayTake, Component); function EssayTake(props) { _class_call_check(this, EssayTake); var _this; _this = _call_super(this, EssayTake, [ props ]), _define_property(_this, "verifyErrors", function(text) { var documentTreeDepthOverLimit = _this.isDocumentTreeDepthOverLimit(text); var dynamoRecordSize = _this.getContentSize(text); _this.setState({ documentTreeDepthOverLimit: documentTreeDepthOverLimit, dynamoRecordSize: dynamoRecordSize }); }), _define_property(_this, "isDocumentTreeDepthOverLimit", function(text) { if (!text) return false; try { var template = document.createElement('template'); template.innerHTML = text; return _this.isLevelOfChildrenOverLimit(template.content); } catch (e) { console.error(e); return false; } }), _define_property(_this, "isLevelOfChildrenOverLimit", function(element) { var level = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0; if (level > 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 _this.isLevelOfChildrenOverLimit(e, childrenLevel); }); }), _define_property(_this, "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 CONTENT_SIZE_BY_ANSWER + text.length * 2 + (text.match(match) || []).length * 10; }), _define_property(_this, "handleOnBlur", function(event, rceContent) { if (!_this.props.readOnly) { var newVal = _this.props.interactionData.rce ? rceContent.editorContent : event.target.value; if (newVal !== void 0 && newVal !== _this.state.workingEssayContent) { _this.props.handleResponseUpdate(newVal); _this.verifyErrors(newVal); _this.setState({ workingEssayContent: newVal }); } } }), _define_property(_this, "handleOnChange", function(event, rceContent) { if (!_this.props.readOnly) { var newVal = _this.props.interactionData.rce ? rceContent.editorContent : event.target.value; if (newVal !== void 0 && newVal !== _this.state.workingEssayContent) { _this.props.handleResponseUpdate(newVal); _this.setState({ workingEssayContent: newVal }); } } }); _this.uniqId = uuid(); var workingEssayContent = props.userResponse && props.userResponse.value || ''; var documentTreeDepthOverLimit = _this.isDocumentTreeDepthOverLimit(workingEssayContent); var dynamoRecordSize = _this.getContentSize(workingEssayContent); _this.state = { workingEssayContent: workingEssayContent, documentTreeDepthOverLimit: documentTreeDepthOverLimit, dynamoRecordSize: dynamoRecordSize, contentId: uuid() }; return _this; } _create_class(EssayTake, [ { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var _prevProps_userResponse; var userResponse = this.props.userResponse; var prevValue = (_prevProps_userResponse = prevProps.userResponse) === null || _prevProps_userResponse === void 0 ? void 0 : _prevProps_userResponse.value; var currentValue = userResponse === null || userResponse === void 0 ? void 0 : userResponse.value; if (currentValue && prevValue === undefined) { this.setState({ workingEssayContent: currentValue || '', contentId: uuid() }); } } }, { key: "renderEditor", value: function renderEditor() { var commonProps = { label: /*#__PURE__*/ React.createElement(ScreenReaderContent, null, /*#__PURE__*/ React.createElement(RichContentRenderer, { content: this.props.itemBody })), readOnly: this.props.readOnly, onChange: this.handleOnChange, onBlur: this.handleOnBlur }; if (this.props.interactionData.rce) { var _this_props_interactionData = this.props.interactionData, spellCheck = _this_props_interactionData.spellCheck, wordCount = _this_props_interactionData.wordCount; return /*#__PURE__*/ React.createElement(RichContentInput, _object_spread_props(_object_spread({}, commonProps), { textareaId: "rceTextArea_".concat(this.uniqId), onKeyUp: this.handleOnChange, openImportModal: this.props.openImportModal, defaultContent: this.state.workingEssayContent, stem: this.props.itemBody, height: RCE_THREE_LINES_HEIGHT, editorOptions: { spellCheck: spellCheck, wordCount: wordCount }, key: this.state.contentId, disableDocumentAccess: this.props.disableDocumentAccess })); } return /*#__PURE__*/ React.createElement(TextArea, _object_spread_props(_object_spread({}, 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.createElement("div", null, /*#__PURE__*/ React.createElement(Text, { color: "danger", size: "small" }, documentTreeDepthOverLimit ? t('Formatting error. Please ensure that the text entry has not been pasted from a different source. Type text to submit response.') : '', dynamoRecordSize > CONTENT_SIZE_LIMIT ? t('This submission is too large. Please adjust and try to submit again.') : '')); } }, { key: "renderWordCountMessage", value: function renderWordCountMessage() { var _this_props_interactionData = this.props.interactionData, wordCount = _this_props_interactionData.wordCount, wordLimitMin = _this_props_interactionData.wordLimitMin, wordLimitEnabled = _this_props_interactionData.wordLimitEnabled, wordLimitMax = _this_props_interactionData.wordLimitMax; if (wordCount || wordLimitEnabled) { return /*#__PURE__*/ React.createElement(ScreenReaderContent, null, wordLimitEnabled && wordLimitMin ? t('This essay has a minimum word count of {wordLimitMin}.', { wordLimitMin: wordLimitMin }) : '', wordLimitEnabled && wordLimitMax ? t('This essay has a maximum word count of {wordLimitMax}.', { wordLimitMax: wordLimitMax }) : '', wordCount ? t('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.createElement(ItemBodyWrapper, { itemBody: itemBody }, this.renderWordCountMessage(), /*#__PURE__*/ React.createElement("div", { className: "fs-mask" }, this.renderEditor()), /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement(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()); } } ]); return EssayTake; }(Component); _define_property(EssayTake, "propTypes", { handleResponseUpdate: PropTypes.func, interactionData: PropTypes.object.isRequired, itemBody: PropTypes.string.isRequired, userResponse: PropTypes.object, notifyScreenreader: PropTypes.func, openImportModal: PropTypes.func, readOnly: PropTypes.bool, disableDocumentAccess: PropTypes.bool }); _define_property(EssayTake, "defaultProps", { handleResponseUpdate: function() {}, openImportModal: function() {}, readOnly: false, userResponse: void 0, notifyScreenreader: void 0, disableDocumentAccess: false }); _define_property(EssayTake, "contextTypes", { disableTextAreaAutoGrow: PropTypes.bool }); /** --- 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> ``` **/ export { EssayTake as default };