UNPKG

@pie-lib/math-toolbar

Version:

Math toolbar for editing math equations

575 lines (505 loc) 21.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.EditorAndPad = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _debug = _interopRequireDefault(require("debug")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _Button = _interopRequireDefault(require("@material-ui/core/Button")); var _styles = require("@material-ui/core/styles"); var _MenuItem = _interopRequireDefault(require("@material-ui/core/MenuItem")); var _Select = _interopRequireDefault(require("@material-ui/core/Select")); var _isEqual = _interopRequireDefault(require("lodash/isEqual")); var _mathInput = require("@pie-lib/math-input"); var _renderUi = require("@pie-lib/render-ui"); var _utils = require("./utils"); function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); 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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } var _mq$CommonMqStyles = _mathInput.mq.CommonMqStyles, commonMqFontStyles = _mq$CommonMqStyles.commonMqFontStyles, commonMqKeyboardStyles = _mq$CommonMqStyles.commonMqKeyboardStyles, longdivStyles = _mq$CommonMqStyles.longdivStyles, supsubStyles = _mq$CommonMqStyles.supsubStyles; var log = (0, _debug["default"])('@pie-lib:math-toolbar:editor-and-pad'); var decimalRegex = /\.|,/g; var toNodeData = function toNodeData(data) { if (!data) { return; } var type = data.type, value = data.value; if (type === 'command' || type === 'cursor') { return data; } else if (type === 'answer') { return _objectSpread({ type: 'answer' }, data); } else if (value === 'clear') { return { type: 'clear' }; } else { return { type: 'write', value: value }; } }; var EditorAndPad = /*#__PURE__*/function (_React$Component) { (0, _inherits2["default"])(EditorAndPad, _React$Component); var _super = _createSuper(EditorAndPad); function EditorAndPad(props) { var _this; (0, _classCallCheck2["default"])(this, EditorAndPad); _this = _super.call(this, props); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onClick", function (data) { var _this$props = _this.props, noDecimal = _this$props.noDecimal, noLatexHandling = _this$props.noLatexHandling, onChange = _this$props.onChange; var c = toNodeData(data); log('mathChange: ', c); if (noLatexHandling) { onChange(c.value); return; } // if decimals are not allowed for this response, we discard the input if (noDecimal && (c.value === '.' || c.value === ',')) { return; } if (!c) { return; } if (c.type === 'clear') { log('call clear...'); _this.input.clear(); } else if (c.type === 'command') { _this.input.command(c.value); } else if (c.type === 'cursor') { _this.input.keystroke(c.value); } else if (c.type === 'answer') { _this.input.write('%response%'); } else { _this.input.write(c.value); } }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "updateDisable", function (isEdit) { var maxResponseAreas = _this.props.maxResponseAreas; if (maxResponseAreas) { var shouldDisable = _this.checkResponseAreasNumber(maxResponseAreas, isEdit); _this.setState({ addDisabled: shouldDisable }); } }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onAnswerBlockClick", function () { _this.props.onAnswerBlockAdd(); _this.onClick({ type: 'answer' }); _this.updateDisable(true); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onEditorChange", function (latex) { var _this$props2 = _this.props, onChange = _this$props2.onChange, noDecimal = _this$props2.noDecimal; (0, _mathInput.updateSpans)(); (0, _utils.markFractionBaseSuperscripts)(); _this.updateDisable(true); // if no decimals are allowed and the last change is a decimal dot, discard the change if (noDecimal && (latex.indexOf('.') !== -1 || latex.indexOf(',') !== -1) && _this.input) { _this.input.clear(); _this.input.write(latex.replace(decimalRegex, '')); return; } // eslint-disable-next-line no-useless-escape var regexMatch = latex.match(/[0-9]\\ \\frac\{[^\{]*\}\{ \}/); if (_this.input && regexMatch && regexMatch !== null && regexMatch !== void 0 && regexMatch.length) { try { _this.input.mathField.__controller.cursor.insLeftOf(_this.input.mathField.__controller.cursor.parent[-1].parent); _this.input.mathField.el().dispatchEvent(new KeyboardEvent('keydown', { keyCode: 8 })); } catch (e) { // eslint-disable-next-line no-console console.error(e.toString()); } return; } onChange(latex); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onEditorTypeChange", function (evt) { _this.setState({ equationEditor: evt.target.value }); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "checkResponseAreasNumber", function (maxResponseAreas, isEdit) { var _ref = _this.input && _this.input.props || {}, latex = _ref.latex; if (latex) { var count = (latex.match(/answerBlock/g) || []).length; return isEdit ? count === maxResponseAreas - 1 : count === maxResponseAreas; } return false; }); _this.state = { equationEditor: 'item-authoring', addDisabled: false }; return _this; } (0, _createClass2["default"])(EditorAndPad, [{ key: "componentDidMount", value: function componentDidMount() { if (this.input && this.props.autoFocus) { this.input.focus(); } } }, { key: "shouldComponentUpdate", value: /** Only render if the mathquill instance's latex is different * or the keypad state changed from one state to the other (shown / hidden) */ function shouldComponentUpdate(nextProps, nextState) { var inputIsDifferent = this.input.mathField.latex() !== nextProps.latex; log('[shouldComponentUpdate] ', 'inputIsDifferent: ', inputIsDifferent); if (!(0, _isEqual["default"])(this.props.error, nextProps.error)) { return true; } if (!inputIsDifferent && this.props.keypadMode !== nextProps.keypadMode) { return true; } if (!inputIsDifferent && this.props.noDecimal !== nextProps.noDecimal) { return true; } if (!inputIsDifferent && this.state.equationEditor !== nextState.equationEditor) { return true; } if (!inputIsDifferent && this.props.controlledKeypad) { return this.props.showKeypad !== nextProps.showKeypad; } return inputIsDifferent; } }, { key: "render", value: function render() { var _this2 = this; var _this$props3 = this.props, classNames = _this$props3.classNames, keypadMode = _this$props3.keypadMode, allowAnswerBlock = _this$props3.allowAnswerBlock, additionalKeys = _this$props3.additionalKeys, controlledKeypad = _this$props3.controlledKeypad, controlledKeypadMode = _this$props3.controlledKeypadMode, showKeypad = _this$props3.showKeypad, setKeypadInteraction = _this$props3.setKeypadInteraction, noDecimal = _this$props3.noDecimal, hideInput = _this$props3.hideInput, layoutForKeyPad = _this$props3.layoutForKeyPad, latex = _this$props3.latex, _onFocus = _this$props3.onFocus, _onBlur = _this$props3.onBlur, classes = _this$props3.classes, error = _this$props3.error; var shouldShowKeypad = !controlledKeypad || controlledKeypad && showKeypad; var addDisabled = this.state.addDisabled; log('[render]', latex); return /*#__PURE__*/_react["default"].createElement("div", { className: (0, _classnames["default"])(classes.mathToolbar, classNames.mathToolbar) }, /*#__PURE__*/_react["default"].createElement("div", { className: (0, _classnames["default"])(classes.inputAndTypeContainer, (0, _defineProperty2["default"])({}, classes.hide, hideInput)) }, controlledKeypadMode && /*#__PURE__*/_react["default"].createElement(_renderUi.InputContainer, { label: "Equation Editor", className: classes.selectContainer }, /*#__PURE__*/_react["default"].createElement(_Select["default"], { className: classes.select, onChange: this.onEditorTypeChange, value: this.state.equationEditor }, /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: "non-negative-integers" }, "Numeric - Non-Negative Integers"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: "integers" }, "Numeric - Integers"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: "decimals" }, "Numeric - Decimals"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: "fractions" }, "Numeric - Fractions"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 1 }, "Grade 1 - 2"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 3 }, "Grade 3 - 5"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 6 }, "Grade 6 - 7"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 8 }, "Grade 8 - HS"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 'geometry' }, "Geometry"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 'advanced-algebra' }, "Advanced Algebra"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 'statistics' }, "Statistics"), /*#__PURE__*/_react["default"].createElement(_MenuItem["default"], { value: 'item-authoring' }, "Item Authoring"))), /*#__PURE__*/_react["default"].createElement("div", { className: (0, _classnames["default"])(classes.inputContainer, error ? classes.error : '') }, /*#__PURE__*/_react["default"].createElement(_mathInput.mq.Input, { onFocus: function onFocus() { _onFocus && _onFocus(); _this2.updateDisable(false); }, onBlur: function onBlur(event) { _this2.updateDisable(false); _onBlur && _onBlur(event); }, className: (0, _classnames["default"])(classes.mathEditor, classNames.editor, !controlledKeypadMode ? classes.longMathEditor : ''), innerRef: function innerRef(r) { return _this2.input = r; }, latex: latex, onChange: this.onEditorChange }))), allowAnswerBlock && /*#__PURE__*/_react["default"].createElement(_Button["default"], { className: classes.addAnswerBlockButton, type: "primary", style: { bottom: shouldShowKeypad ? '320px' : '20px' }, onClick: this.onAnswerBlockClick, disabled: addDisabled }, "+ Response Area"), /*#__PURE__*/_react["default"].createElement("hr", { className: classes.hr }), shouldShowKeypad && /*#__PURE__*/_react["default"].createElement(_mathInput.HorizontalKeypad, { className: (0, _classnames["default"])(classes[keypadMode], classes.keyboard), controlledKeypadMode: controlledKeypadMode, layoutForKeyPad: layoutForKeyPad, additionalKeys: additionalKeys, mode: controlledKeypadMode ? this.state.equationEditor : keypadMode, onClick: this.onClick, noDecimal: noDecimal, setKeypadInteraction: setKeypadInteraction })); } }]); return EditorAndPad; }(_react["default"].Component); exports.EditorAndPad = EditorAndPad; (0, _defineProperty2["default"])(EditorAndPad, "propTypes", { classNames: _propTypes["default"].object, keypadMode: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].number]), autoFocus: _propTypes["default"].bool, allowAnswerBlock: _propTypes["default"].bool, showKeypad: _propTypes["default"].bool, controlledKeypad: _propTypes["default"].bool, controlledKeypadMode: _propTypes["default"].bool, error: _propTypes["default"].string, noDecimal: _propTypes["default"].bool, hideInput: _propTypes["default"].bool, noLatexHandling: _propTypes["default"].bool, layoutForKeyPad: _propTypes["default"].object, maxResponseAreas: _propTypes["default"].number, additionalKeys: _propTypes["default"].array, latex: _propTypes["default"].string.isRequired, onAnswerBlockAdd: _propTypes["default"].func, onFocus: _propTypes["default"].func, onBlur: _propTypes["default"].func, onChange: _propTypes["default"].func.isRequired, classes: _propTypes["default"].object, setKeypadInteraction: _propTypes["default"].func }); var styles = function styles(theme) { return { inputAndTypeContainer: { display: 'flex', alignItems: 'center', '& .mq-editable-field .mq-cursor': { top: '-4px' }, '& .mq-math-mode .mq-selection, .mq-editable-field .mq-selection': { paddingTop: '18px' }, '& .mq-math-mode .mq-overarrow': { fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important' }, '& .mq-math-mode .mq-overline .mq-overline-inner': { paddingTop: '0.4em !important' }, '& .mq-overarrow.mq-arrow-both': { minWidth: '1.23em', '& *': { lineHeight: '1 !important' }, '&:before': { top: '-0.45em', left: '-1px' }, '&:after': { position: 'absolute !important', top: '0px !important', right: '-2px' }, '&.mq-empty:after': { top: '-0.45em' } }, '& .mq-overarrow.mq-arrow-right': { '&:before': { top: '-0.4em', right: '-1px' } }, '& *': _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, commonMqFontStyles), supsubStyles), longdivStyles), {}, { '& .mq-math-mode .mq-sqrt-prefix': { verticalAlign: 'baseline !important', top: '1px !important', left: '-0.1em !important' }, '& .mq-math-mode .mq-overarc ': { paddingTop: '0.45em !important' }, '& .mq-math-mode .mq-empty': { padding: '9px 1px !important' }, '& .mq-math-mode .mq-root-block': { paddingTop: '10px' }, '& .mq-scaled .mq-sqrt-prefix': { top: '0 !important' }, '& .mq-math-mode .mq-longdiv .mq-longdiv-inner': { marginLeft: '4px !important', paddingTop: '6px !important', paddingLeft: '6px !important' }, '& .mq-math-mode .mq-paren': { verticalAlign: 'top !important', padding: '1px 0.1em !important' }, '& .mq-math-mode .mq-sqrt-stem': { borderTop: '0.07em solid', marginLeft: '-1.5px', marginTop: '-2px !important', paddingTop: '5px !important' }, '& .mq-math-mode .mq-denominator': { marginTop: '-5px !important', padding: '0.5em 0.1em 0.1em !important' }, '& .mq-math-mode .mq-numerator, .mq-math-mode .mq-over': { padding: '0 0.1em !important', paddingBottom: '0 !important', marginBottom: '-2px' } }), '& span[data-prime="true"]': { fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important' } }, hide: { display: 'none' }, selectContainer: { flex: 'initial', width: '25%', minWidth: '100px', marginLeft: '15px', marginTop: '5px', marginBottom: '5px', marginRight: '5px', '& label': { fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important' }, '& div': { fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important' } }, mathEditor: { maxWidth: '400px', color: _renderUi.color.text(), backgroundColor: _renderUi.color.background(), padding: '2px' }, longMathEditor: { maxWidth: '500px' }, addAnswerBlockButton: { position: 'absolute', right: '12px', border: '1px solid lightgrey' }, hr: { padding: 0, margin: 0, height: '1px', border: 'none', borderBottom: "solid 1px ".concat(theme.palette.primary.main) }, mathToolbar: { zIndex: 9, position: 'relative', textAlign: 'center', width: 'auto', '& > .mq-math-mode': { border: 'solid 1px lightgrey' }, '& > .mq-focused': { outline: 'none', boxShadow: 'none', border: "dotted 1px ".concat(theme.palette.primary.main), borderRadius: '0px' }, '& .mq-overarrow-inner': { border: 'none !important', paddingTop: '0 !important' }, '& .mq-overarrow-inner-right': { display: 'none !important' }, '& .mq-overarrow-inner-left': { display: 'none !important' }, '& .mq-longdiv-inner': { borderTop: '1px solid !important', paddingTop: '1.5px !important' }, '& .mq-overarrow.mq-arrow-both': { top: '7.8px', marginTop: '0px', minWidth: '1.23em' }, '& .mq-parallelogram': { lineHeight: 0.85 } }, inputContainer: { minWidth: '500px', maxWidth: '900px', minHeight: '30px', width: '100%', display: 'flex', marginTop: theme.spacing.unit, marginBottom: theme.spacing.unit, '& .mq-sqrt-prefix .mq-scaled': { verticalAlign: 'middle !important' } }, error: { border: '2px solid red' }, keyboard: commonMqKeyboardStyles, language: { '& *': { fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important' } } }; }; var _default = (0, _styles.withStyles)(styles)(EditorAndPad); exports["default"] = _default; //# sourceMappingURL=editor-and-pad.js.map