@pie-lib/math-toolbar
Version:
Math toolbar for editing math equations
575 lines (505 loc) • 21.1 kB
JavaScript
"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