UNPKG

quiz-interactions

Version:

A React UI component Library for quiz interaction types.

259 lines (210 loc) 10.3 kB
"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 _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); 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 _reactDom = _interopRequireDefault(require("react-dom")); var _debounce = _interopRequireDefault(require("lodash/debounce")); var _partial = _interopRequireDefault(require("lodash/partial")); var _uiThemeable = require("@instructure/ui-themeable"); var _uiA11y = require("@instructure/ui-a11y"); var _uiElements = require("@instructure/ui-elements"); var _Errors = _interopRequireDefault(require("../../../common/edit/components/Errors")); var _ContentEditable = _interopRequireDefault(require("../../../common/edit/components/ContentEditable")); var _editStemController = _interopRequireDefault(require("./editStemController")); var _theme = _interopRequireDefault(require("./theme")); var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message")); var _dec, _class, _class2, _temp; 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 _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var styles = { componentId: 'sgCkN', template: function template(theme) { return "\n\n.sgCkN_fiOv{display:inline-block}\n\n[contenteditable=true]:empty:before{color:".concat(theme.tableColor || 'inherit', ";content:attr(placeholder)}\n\n.sgCkN_edUw{color:").concat(theme.editStemColor || 'inherit', ";display:inline-block;font-family:").concat(theme.editStemFontFamily || 'inherit', ";font-size:").concat(theme.editStemFontSize || 'inherit', ";font-weight:").concat(theme.editStemFontWeight || 'inherit', ";line-height:").concat(theme.editStemLineHeight || 'inherit', ";white-space:pre-wrap}\n\n.sgCkN_edUw:focus{outline:0 none}\n\n.sgCkN_eMDV{border:").concat(theme.highlightBorder || 'inherit', " solid ").concat(theme.highlightColor || 'inherit', ";border-radius:").concat(theme.highlightBorderRadius || 'inherit', ";margin-left:").concat(theme.highlightMargin || 'inherit', ";margin-right:").concat(theme.highlightMargin || 'inherit', ";padding:").concat(theme.highlightPadding || 'inherit', ";position:relative;word-wrap:break-word}"); }, 'blankScreenReaderContentWrapper': 'sgCkN_fiOv', 'editableText': 'sgCkN_edUw', 'highlight': 'sgCkN_eMDV' }; var NBSP_CHAR_CODE = 160; var _ref = /*#__PURE__*/ _react.default.createElement("hr", null); var EditStem = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_class = (_temp = _class2 = /*#__PURE__*/ function (_Component) { (0, _inherits2.default)(EditStem, _Component); function EditStem(props) { var _this; (0, _classCallCheck2.default)(this, EditStem); _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(EditStem).call(this, props)); _this.state = { isFocused: false // own functions for stubbing purposes }; _this.handlePaste = function (stemItem, e) { _this.controller.handlePaste(e); _this.props.onStemChange(stemItem, e); }; _this.setFocus = function (isFocused) { _this.setState({ isFocused: isFocused }); }; _this.renderStemItem = function (stemItem) { return stemItem.type === 'text' ? _this.renderContentEditable(stemItem) : _this.renderBlank(stemItem); }; _this.controller = new _editStemController.default(_objectSpread({}, props, { styles: styles })); _this.stemItemRefs = {}; return _this; } (0, _createClass2.default)(EditStem, [{ key: "_clearInterval", value: function _clearInterval(cb) { clearInterval(cb); } }, { key: "_setInterval", value: function _setInterval(cb, time) { setInterval(cb, time); } // ============= // LIFECYCLE // ============= }, { key: "componentDidMount", value: function componentDidMount() { var _this2 = this; var oldOnSelectionChange = document.onselectionchange; this._dom = _reactDom.default.findDOMNode(this); var newOnSelectionChange = (0, _debounce.default)(function () { var sel = window.getSelection(); var anchor = sel.anchorNode; if (!anchor) return; if (_this2._dom.contains(anchor) || // next line needed because of weird IE11 behavior _this2._dom.contains(anchor.parentNode)) { _this2.props.setSelectedText(sel.toString()); } }, 100); document.onselectionchange = function (e) { oldOnSelectionChange && oldOnSelectionChange(e); newOnSelectionChange(); }; this._oldOnSelectionChange = oldOnSelectionChange; } }, { key: "componentWillUnmount", value: function componentWillUnmount() { document.onselectionchange = this._oldOnSelectionChange; } }, { key: "componentWillReceiveProps", value: function componentWillReceiveProps(nextProps) { this.controller.componentWillReceiveProps(_objectSpread({}, nextProps, { styles: styles })); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (!this.state.isFocused) { return; } var focusData = this.controller.getFocusData(prevProps); if (!focusData) { return; } var focusRef = this.stemItemRefs[focusData.stemItem.id]; focusData.stemItem.type === 'blank' ? focusRef.focus() : focusRef.focusAndSetCursorOnPosition(focusData.cursorPosition); } }, { key: "renderContentEditable", // ============= // RENDERING // ============= value: function renderContentEditable(stemItem) { var _this3 = this; var usePlaceholder = this.props.stemItems.length <= 1 && !this.state.isFocused; var placeholder = usePlaceholder ? (0, _formatMessage.default)('Type a statement...') : ''; var content = this.controller.textForStemItem(stemItem); if (!content || content === String.fromCharCode(NBSP_CHAR_CODE)) { // nbsp is used to give a width to a final stem item if blank // if we only have one stem, just use the placeholder to do this content = usePlaceholder ? '' : String.fromCharCode(NBSP_CHAR_CODE); } return _react.default.createElement(_ContentEditable.default, { label: _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Statement')), key: stemItem.id, id: stemItem.id, ref: function ref(span) { _this3.stemItemRefs[stemItem.id] = span; }, placeholder: placeholder, enableFormatting: false, disabled: this.props.disabled, content: content, onChange: (0, _partial.default)(this.props.onStemChange, stemItem), onPaste: (0, _partial.default)(this.handlePaste, stemItem), onKeyDown: this.props.onCreateBlankHotkey, className: styles.editableText }); } }, { key: "renderBlank", value: function renderBlank(stemItem) { var _this4 = this; var dismissible = !this.props.disabled; var text = this.controller.textForStemItem(stemItem); return _react.default.createElement(_uiElements.Tag, { key: stemItem.id, dismissible: dismissible, elementRef: function elementRef(button) { _this4.stemItemRefs[stemItem.id] = button; }, onClick: dismissible ? (0, _partial.default)(this.props.destroyBlank, stemItem) : null, size: "large", text: _react.default.createElement(_uiA11y.AccessibleContent, { alt: (0, _formatMessage.default)('Delete "{ text }" blank', { text: text }) }, text), variant: "inline" }); } }, { key: "render", value: function render() { this.stemItemRefs = {}; return _react.default.createElement("div", { onFocus: (0, _partial.default)(this.setFocus, true), onBlur: (0, _partial.default)(this.setFocus, false) }, _react.default.createElement(_Errors.default, { errorList: this.props.errors }, this.props.stemItems.map(this.renderStemItem)), _ref); } }]); EditStem.displayName = "EditStem"; return EditStem; }(_react.Component), _class2.propTypes = { disabled: _propTypes.default.bool, errors: _propTypes.default.array, destroyBlank: _propTypes.default.func.isRequired, onCreateBlankHotkey: _propTypes.default.func.isRequired, onStemChange: _propTypes.default.func.isRequired, setSelectedText: _propTypes.default.func.isRequired, stemItems: _propTypes.default.array.isRequired }, _class2.defaultProps = { disabled: false, errors: void 0 }, _temp)) || _class); exports.default = EditStem;