quiz-interactions
Version:
A React UI component Library for quiz interaction types.
371 lines (325 loc) • 16.6 kB
JavaScript
"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 _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf3 = _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 _isNaN = _interopRequireDefault(require("lodash/isNaN"));
var _uiElements = require("@instructure/ui-elements");
var _uiForms = require("@instructure/ui-forms");
var _quizNumberInput = _interopRequireDefault(require("@instructure/quiz-number-input"));
var _uiA11y = require("@instructure/ui-a11y");
var _uiButtons = require("@instructure/ui-buttons");
var _uiThemeable = require("@instructure/ui-themeable");
var _uiLayout = require("@instructure/ui-layout");
var _quizI18n = require("@instructure/quiz-i18n");
var _quizScientificNotation = require("@instructure/quiz-scientific-notation");
var _instUIMessages = require("../../../util/instUIMessages");
var util = _interopRequireWildcard(require("./util"));
var _theme = _interopRequireDefault(require("./theme"));
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message"));
var _dec, _class, _class2, _temp;
var styles = {
componentId: 'fCxPy',
template: function template(theme) {
return "\n\n.fCxPy_fKmi{padding-bottom:".concat(theme.sectionHeadingPaddingBottom || 'inherit', ";padding-top:").concat(theme.sectionHeadingPaddingTop || 'inherit', "}\n\n.fCxPy_pJNU{padding-bottom:").concat(theme.instructionsPaddingBottom || 'inherit', "}\n\n.fCxPy_ftwL{padding-top:").concat(theme.generateSolutionsInputPaddingTop || 'inherit', "}\n\n.fCxPy_cWFj{padding:").concat(theme.generateButtonPaddingLeft || 'inherit', "}\n\n.fCxPy_dVha{padding-top:").concat(theme.generatedSolutionsPaddingTop || 'inherit', "}\n\n.fCxPy_fqEc{padding-left:").concat(theme.marginTextPadding || 'inherit', ";padding-right:").concat(theme.marginTextPadding || 'inherit', "}\n\n.fCxPy_cdqO{color:").concat(theme.marginPlusMinusColor || 'inherit', ";font-weight:").concat(theme.marginPlusMinusWeight || 'inherit', "}\n\n.fCxPy_rMrG{overflow:auto}\n\n.fCxPy_rMrG>table{max-width:none}\n\n.fCxPy_ekQP{position:-webkit-sticky;position:sticky;right:0}");
},
'sectionHeading': 'fCxPy_fKmi',
'instructions': 'fCxPy_pJNU',
'generateSolutionsInput': 'fCxPy_ftwL',
'generateButtonWrapper': 'fCxPy_cWFj',
'generatedSolutions': 'fCxPy_dVha',
'marginText': 'fCxPy_fqEc',
'marginPlusMinus': 'fCxPy_cdqO',
'tableWrapper': 'fCxPy_rMrG',
'outputCol': 'fCxPy_ekQP'
};
var FormulaSection = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_class = (_temp = _class2 =
/*#__PURE__*/
function (_Component) {
(0, _inherits2.default)(FormulaSection, _Component);
function FormulaSection() {
var _getPrototypeOf2;
var _this;
(0, _classCallCheck2.default)(this, FormulaSection);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(FormulaSection)).call.apply(_getPrototypeOf2, [this].concat(args)));
_this.state = {
marginOfErrorValue: null
};
_this.handleMarginOfErrorChange = function (event, value, normalizedValue) {
_this.setState({
marginOfErrorValue: value
});
_this.props.handleMarginOfErrorChange(event, value, normalizedValue);
};
_this.handleMarginOfErrorBlur = function () {
_this.setState({
marginOfErrorValue: null
});
};
_this.renderRow = function (solution, idx) {
var inputValues = _this.variableNames.map(function (variableName) {
return solution.inputs.find(function (v) {
return v.name === variableName;
}).value;
});
var _this$props$scoringDa = _this.props.scoringData.value.numeric,
margin = _this$props$scoringDa.margin,
marginType = _this$props$scoringDa.marginType;
var parsedMargin = parseFloat(margin);
var marginString;
if (margin === '' || parsedMargin === 0 || (0, _isNaN.default)(parsedMargin)) {
marginString = null;
} else if (marginType === 'absolute') {
marginString = (0, _formatMessage.default)(' +/- {margin}', {
margin: _this.formatNumStr(parsedMargin)
});
} else {
marginString = (0, _formatMessage.default)(' +/- {margin}%', {
margin: _this.formatNumStr(parsedMargin)
});
}
return _react.default.createElement("tr", {
key: idx
}, inputValues.map(function (value, index) {
return _react.default.createElement("td", {
key: index
}, _this.formatNumStr(value));
}), _react.default.createElement("td", {
className: styles.outputCol
}, _this.formatNumStr(solution.output), _react.default.createElement("span", {
className: styles.marginPlusMinus
}, marginString)));
};
return _this;
}
(0, _createClass2.default)(FormulaSection, [{
key: "formatNumStr",
value: function formatNumStr(value) {
return (0, _quizScientificNotation.isScientificNotation)(value) ? value : _quizI18n.Decimal.toLocaleString(value.toString(), this.props.locale);
}
}, {
key: "renderGeneratedSolutionsTable",
value: function renderGeneratedSolutionsTable() {
if (this.props.status === util.STATUS_RUNNING) {
return _react.default.createElement("div", null, _react.default.createElement(_uiElements.Spinner, {
renderTitle: (0, _formatMessage.default)('Running')
}));
}
var solutions = this.props.scoringData.value.generatedSolutions;
var errorMessage = null;
if (this.props.status === util.STATUS_FAILED && solutions.length === 0) {
return _react.default.createElement(_uiElements.Text, {
color: "error"
}, (0, _formatMessage.default)('We were not able to find any solutions.'));
} else if (this.props.status === util.STATUS_FAILED) {
errorMessage = (0, _formatMessage.default)("{ number, plural,\n one {We were only able to find 1 solution.}\n other {We were only able to find # solutions.}\n } ", {
number: solutions.length
});
} else if (solutions.length === 0) {
return null;
}
return _react.default.createElement("div", null, _react.default.createElement(_uiElements.Text, {
color: "primary"
}, errorMessage), _react.default.createElement("div", {
className: styles.tableWrapper
}, _react.default.createElement(_uiElements.Table, {
caption: _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Generated Results')),
layout: "fixed"
}, _react.default.createElement("thead", null, _react.default.createElement("tr", null, this.variableNames.map(function (variableName, idx) {
return _react.default.createElement("th", {
key: idx
}, variableName);
}), _react.default.createElement("th", {
className: styles.outputCol
}, (0, _formatMessage.default)('Result')))), _react.default.createElement("tbody", null, solutions.map(this.renderRow)))));
}
}, {
key: "renderGeneratedSolutionsSection",
value: function renderGeneratedSolutionsSection() {
if (this.props.status === util.STATUS_CANCELED) {
return null;
}
return _react.default.createElement("div", {
className: styles.generatedSolutions
}, this.props.status === util.STATUS_FORMULA_SETUP_INVALID ? _react.default.createElement(_uiElements.Text, {
color: "error"
}, (0, _formatMessage.default)('Error in formula setup. See above for details.')) : this.renderGeneratedSolutionsTable());
}
}, {
key: "formulaErrors",
value: function formulaErrors() {
if (this.props.status === util.STATUS_FORMULA_SETUP_INVALID) {
return (0, _instUIMessages.toErrors)(this.props.formulaErrors || []);
}
}
}, {
key: "renderNumberOfGeneratedSolutionsInput",
value: function renderNumberOfGeneratedSolutionsInput() {
return _react.default.createElement(_quizNumberInput.default, {
disabled: this.props.overrideEditableForRegrading,
value: String(parseInt(this.props.scoringData.value.answerCount, 10) || 0),
onChange: this.props.handleAnswerCountChange,
label: (0, _formatMessage.default)('Number of solutions'),
messages: (0, _instUIMessages.toErrors)(this.props.generatedSolutionsErrors),
min: "1",
max: "200",
showArrows: true
});
}
}, {
key: "renderSolutionPrecisionInput",
value: function renderSolutionPrecisionInput() {
return _react.default.createElement(_quizNumberInput.default, {
disabled: this.props.overrideEditableForRegrading,
decimalPrecision: 0,
value: this.props.scoringData.value.answerPrecision || 0,
onChange: this.props.handleAnswerPrecisionChange,
label: (0, _formatMessage.default)('Decimal places'),
min: "0",
max: "16",
showArrows: true
});
}
}, {
key: "renderScientificNotationCheckbox",
value: function renderScientificNotationCheckbox() {
return _react.default.createElement(_uiForms.Checkbox, {
checked: this.props.scoringData.value.scientificNotation || false,
disabled: this.props.overrideEditableForRegrading,
label: (0, _formatMessage.default)('Display as Scientific Notation'),
onChange: this.props.handleScientificNotationChange,
variant: "toggle"
});
}
}, {
key: "renderMarginOfErrorTypeSelect",
value: function renderMarginOfErrorTypeSelect() {
return _react.default.createElement(_uiForms.Select, {
onChange: this.props.handleMarginOfErrorTypeChange,
selectedOption: this.props.scoringData.value.numeric.marginType,
label: (0, _formatMessage.default)('Margin type'),
"data-automation": "sdk-formula-margin-of-error-type"
}, _react.default.createElement("option", {
value: "absolute"
}, (0, _formatMessage.default)('Absolute')), _react.default.createElement("option", {
value: "percent"
}, (0, _formatMessage.default)('Percent')));
}
}, {
key: "renderMarginOfErrorInput",
value: function renderMarginOfErrorInput() {
var value = this.state.marginOfErrorValue;
if (value === null) {
value = parseFloat(this.props.scoringData.value.numeric.margin);
}
return _react.default.createElement(_quizNumberInput.default, {
value: value,
onChange: this.handleMarginOfErrorChange,
onBlur: this.handleMarginOfErrorBlur,
label: (0, _formatMessage.default)('+/- margin of error'),
min: "0",
"data-automation": "sdk-formula-margin-of-error-value",
showArrows: true
});
}
}, {
key: "renderGenerateSolutionsButton",
value: function renderGenerateSolutionsButton() {
return _react.default.createElement(_uiButtons.Button, {
disabled: this.props.overrideEditableForRegrading,
variant: "primary",
onClick: this.props.handleGenerateSolutions
}, _react.default.createElement(_uiA11y.PresentationContent, null, (0, _formatMessage.default)('Generate')), _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Generate Solutions')));
}
}, {
key: "render",
value: function render() {
return _react.default.createElement("div", null, _react.default.createElement("div", {
className: styles.sectionHeading
}, _react.default.createElement(_uiElements.Text, {
size: "large"
}, (0, _formatMessage.default)('Formula Definition'))), _react.default.createElement("div", {
className: styles.instructions
}, _react.default.createElement(_uiElements.Text, {
color: "primary"
}, (0, _formatMessage.default)('Next, write the formula or formulas used to compute' + ' the correct answer. Use the same variable names listed above. (e.g., "5 + x")'))), _react.default.createElement(_uiForms.TextArea, {
disabled: this.props.overrideEditableForRegrading,
value: this.props.scoringData.value.formula,
onChange: this.props.handleFormulaChange,
messages: this.formulaErrors(),
label: _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Formula')),
autoGrow: this.context.disableTextAreaAutoGrow ? false : null
}), _react.default.createElement("div", null, _react.default.createElement("div", {
className: styles.sectionHeading
}, _react.default.createElement(_uiElements.Text, {
size: "large"
}, (0, _formatMessage.default)('Generate Possible Solutions'))), _react.default.createElement("div", {
className: styles.instructions
}, _react.default.createElement(_uiElements.Text, {
color: "primary"
}, (0, _formatMessage.default)('Finally, build as many variable-solution combinations as you need for your quiz.'))), _react.default.createElement("div", {
className: styles.generateSolutionsInput
}, _react.default.createElement(_uiLayout.Grid, {
vAlign: "top",
startAt: "medium"
}, _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, this.renderNumberOfGeneratedSolutionsInput()), _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, this.renderSolutionPrecisionInput()), _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, _react.default.createElement(_uiLayout.View, {
as: "div",
margin: "medium 0 0 0",
padding: "xx-small 0 0 0"
}, this.renderScientificNotationCheckbox()))), !this.props.scoringData.value.scientificNotation && _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, this.renderMarginOfErrorTypeSelect()), _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, this.renderMarginOfErrorInput())), _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, {
width: 4
}, this.renderGenerateSolutionsButton())))), this.renderGeneratedSolutionsSection()));
}
}, {
key: "variableNames",
get: function get() {
return this.props.scoringData.value.variables.map(function (variable) {
return variable.name;
}).sort();
}
}]);
FormulaSection.displayName = "FormulaSection";
return FormulaSection;
}(_react.Component), _class2.propTypes = {
formulaErrors: _propTypes.default.arrayOf(_propTypes.default.string),
generatedSolutionsErrors: _propTypes.default.arrayOf(_propTypes.default.string),
handleAnswerCountChange: _propTypes.default.func.isRequired,
handleAnswerPrecisionChange: _propTypes.default.func.isRequired,
handleFormulaChange: _propTypes.default.func.isRequired,
handleGenerateSolutions: _propTypes.default.func.isRequired,
handleMarginOfErrorChange: _propTypes.default.func.isRequired,
handleMarginOfErrorTypeChange: _propTypes.default.func.isRequired,
handleScientificNotationChange: _propTypes.default.func.isRequired,
locale: _propTypes.default.string.isRequired,
overrideEditableForRegrading: _propTypes.default.bool.isRequired,
scoringData: _propTypes.default.object.isRequired,
status: _propTypes.default.string.isRequired
}, _class2.defaultProps = {
formulaErrors: void 0,
generatedSolutionsErrors: void 0
}, _class2.contextTypes = {
disableTextAreaAutoGrow: _propTypes.default.bool
}, _temp)) || _class);
exports.default = FormulaSection;