@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
361 lines (360 loc) • 19.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
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 _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = require("react");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _uiTable = require("@instructure/ui-table");
var _uiText = require("@instructure/ui-text");
var _uiSpinner = require("@instructure/ui-spinner");
var _uiCheckbox = require("@instructure/ui-checkbox");
var _uiA11yContent = require("@instructure/ui-a11y-content");
var _uiButtons = require("@instructure/ui-buttons");
var _emotion = require("@instructure/emotion");
var _uiView = require("@instructure/ui-view");
var _uiGrid = require("@instructure/ui-grid");
var _quizI18n = require("@instructure/quiz-i18n");
var _quizScientificNotation = require("@instructure/quiz-scientific-notation");
var _instUIMessages = require("../../../util/instUIMessages");
var util = _interopRequireWildcard(require("./util"));
var _styles = _interopRequireDefault(require("./styles"));
var _theme = _interopRequireDefault(require("./theme"));
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
var _quizNumberInput = require("@instructure/quiz-number-input");
var _quizCommon = require("@instructure/quiz-common");
var _uiAlerts = require("@instructure/ui-alerts");
var _dec, _class, _FormulaSection;
/** @jsx jsx */
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _callSuper(_this, derived, args) {
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (e) {
return false;
}
}
derived = (0, _getPrototypeOf2["default"])(derived);
return (0, _possibleConstructorReturn2["default"])(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], (0, _getPrototypeOf2["default"])(_this).constructor) : derived.apply(_this, args));
}
var FormulaSection = exports["default"] = (_dec = (0, _quizCommon.withStyleOverrides)(_styles["default"], _theme["default"]), _dec(_class = (_FormulaSection = /*#__PURE__*/function (_Component) {
function FormulaSection() {
var _this2;
(0, _classCallCheck2["default"])(this, FormulaSection);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this2 = _callSuper(this, FormulaSection, [].concat(args));
(0, _defineProperty2["default"])(_this2, "state", {
marginOfErrorValue: null
});
(0, _defineProperty2["default"])(_this2, "handleMarginOfErrorChange", function (event, value, normalizedValue) {
_this2.setState({
marginOfErrorValue: value
});
_this2.props.handleMarginOfErrorChange(event, value, normalizedValue);
});
(0, _defineProperty2["default"])(_this2, "handleMarginOfErrorBlur", function () {
_this2.setState({
marginOfErrorValue: null
});
});
(0, _defineProperty2["default"])(_this2, "localizedScientificNotation", function (value) {
var _ref = (value === null || value === void 0 ? void 0 : value.toString().split('*')) || [],
_ref2 = (0, _slicedToArray2["default"])(_ref, 2),
mantissa = _ref2[0],
exponent = _ref2[1];
return "".concat(_this2.localizedValue(mantissa), "*").concat(exponent);
});
(0, _defineProperty2["default"])(_this2, "localizedValue", function (value) {
return value ? _quizI18n.Decimal.toLocaleString(value.toString(), _this2.props.locale) : null;
});
(0, _defineProperty2["default"])(_this2, "renderRow", function (solution, idx) {
var inputValues = _this2.variableNames.map(function (variableName) {
var _solution$inputs$find;
return (_solution$inputs$find = solution.inputs.find(function (v) {
return v.name === variableName;
})) === null || _solution$inputs$find === void 0 ? void 0 : _solution$inputs$find.value;
});
var _this2$props$scoringD = _this2.props.scoringData.value.numeric,
margin = _this2$props$scoringD.margin,
marginType = _this2$props$scoringD.marginType;
var parsedMargin = Number.parseFloat(margin);
var marginString;
if (margin === '' || parsedMargin === 0 || Number.isNaN(parsedMargin)) {
marginString = null;
} else if (marginType === 'absolute') {
marginString = (0, _formatMessage["default"])(' +/- {margin}', {
margin: _this2.formatNumStr(parsedMargin)
});
} else {
marginString = (0, _formatMessage["default"])(' +/- {margin}%', {
margin: _this2.formatNumStr(parsedMargin)
});
}
return (0, _emotion.jsx)(_uiTable.Table.Row, {
key: idx
}, inputValues.map(function (value, index) {
return (
// eslint-disable-next-line react/no-array-index-key
(0, _emotion.jsx)(_uiTable.Table.Cell, {
key: index
}, _this2.formatNumStr(value))
);
}), (0, _emotion.jsx)(_uiTable.Table.Cell, null, _this2.formatNumStr(solution.output), (0, _emotion.jsx)("span", {
css: _this2.props.styles.marginPlusMinus
}, marginString)));
});
return _this2;
}
(0, _inherits2["default"])(FormulaSection, _Component);
return (0, _createClass2["default"])(FormulaSection, [{
key: "formatNumStr",
value: function formatNumStr(value) {
return (0, _quizScientificNotation.isScientificNotation)(value) ? this.localizedScientificNotation(value) : this.localizedValue(value);
}
}, {
key: "variableNames",
get: function get() {
return this.props.scoringData.value.variables.map(function (variable) {
return variable.name;
}).sort();
}
}, {
key: "renderGeneratedSolutionsTable",
value: function renderGeneratedSolutionsTable() {
if (this.props.status === util.STATUS_RUNNING) {
return (0, _emotion.jsx)("div", null, (0, _emotion.jsx)(_uiSpinner.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 (0, _emotion.jsx)("div", {
role: "alert"
}, (0, _emotion.jsx)(_uiAlerts.Alert, {
hasShadow: false,
variant: "warning"
}, (0, _formatMessage["default"])('We were not able to find any solutions.')));
}
if (this.props.status === util.STATUS_FAILED) {
errorMessage = util.buildSolutionsGeneratedMessage(this.props.status, solutions.length);
} else if (solutions.length === 0) {
return null;
}
var idPrefix = 'generated-results-';
return (0, _emotion.jsx)("div", null, errorMessage && (0, _emotion.jsx)("div", {
role: "alert"
}, (0, _emotion.jsx)(_uiAlerts.Alert, {
hasShadow: false,
variant: "warning"
}, errorMessage)), (0, _emotion.jsx)("div", {
css: this.props.styles.tableWrapper
}, (0, _emotion.jsx)(_uiTable.Table, {
caption: (0, _formatMessage["default"])('Generated Results'),
layout: "fixed"
}, (0, _emotion.jsx)(_uiTable.Table.Head, null, (0, _emotion.jsx)(_uiTable.Table.Row, null, this.variableNames.map(function (variableName, idx) {
return (0, _emotion.jsx)(_uiTable.Table.ColHeader, {
id: idPrefix + idx,
key: idx
}, variableName);
}), (0, _emotion.jsx)(_uiTable.Table.ColHeader, {
id: "generated-results-result"
}, (0, _formatMessage["default"])('Result')))), (0, _emotion.jsx)(_uiTable.Table.Body, null, solutions.map(this.renderRow)))));
}
}, {
key: "renderGeneratedSolutionsSection",
value: function renderGeneratedSolutionsSection() {
if (this.props.status === util.STATUS_CANCELED) {
return null;
}
return (0, _emotion.jsx)("div", {
css: this.props.styles.generatedSolutions
}, this.props.status === util.STATUS_FORMULA_SETUP_INVALID ? (0, _emotion.jsx)(_uiAlerts.Alert, {
liveRegionPoliteness: "polite",
variant: "warning"
}, (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() {
var currentSolutionsNumber = String(Number.parseInt(this.props.scoringData.value.answerCount, 10) || 0);
return (0, _emotion.jsx)(_quizNumberInput.NumberInput, {
disabled: this.props.overrideEditableForRegrading,
value: currentSolutionsNumber,
onChange: this.props.handleAnswerCountChange,
renderLabel: (0, _formatMessage["default"])('Number of solutions'),
isRequired: true,
messages: (0, _instUIMessages.toErrors)(this.props.generatedSolutionsErrors),
min: "1",
max: "200",
showArrows: true,
"data-automation": "sdk-number-of-solutions-input",
"aria-valuetext": "".concat(currentSolutionsNumber, " ").concat((0, _formatMessage["default"])('Solutions possible'))
});
}
}, {
key: "renderSolutionPrecisionInput",
value: function renderSolutionPrecisionInput() {
var currentDecimalPlaces = this.props.scoringData.value.answerPrecision || 0;
return (0, _emotion.jsx)(_quizNumberInput.NumberInput, {
decimalPrecision: 0,
disabled: this.props.overrideEditableForRegrading,
value: currentDecimalPlaces,
onChange: this.props.handleAnswerPrecisionChange,
renderLabel: (0, _formatMessage["default"])('Decimal places'),
min: "0",
max: "16",
showArrows: true,
"aria-valuetext": "".concat(currentDecimalPlaces, " ").concat((0, _formatMessage["default"])('Decimal places'))
});
}
}, {
key: "renderScientificNotationCheckbox",
value: function renderScientificNotationCheckbox() {
return (0, _emotion.jsx)(_uiCheckbox.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 (0, _emotion.jsx)(_quizCommon.SimpleSelect, {
onChange: this.props.handleMarginOfErrorTypeChange,
value: this.props.scoringData.value.numeric.marginType,
renderLabel: (0, _formatMessage["default"])('Margin type'),
"data-automation": "sdk-formula-margin-of-error-type"
}, (0, _emotion.jsx)(_quizCommon.SimpleSelect.Option, {
id: "formula-section-select-option-absolute",
value: "absolute"
}, (0, _formatMessage["default"])('Absolute')), (0, _emotion.jsx)(_quizCommon.SimpleSelect.Option, {
id: "formula-section-select-option-percent",
value: "percent"
}, (0, _formatMessage["default"])('Percent')));
}
}, {
key: "renderMarginOfErrorInput",
value: function renderMarginOfErrorInput() {
var value = this.state.marginOfErrorValue;
if (value === null) {
value = Number.parseFloat(this.props.scoringData.value.numeric.margin);
}
return (0, _emotion.jsx)(_quizNumberInput.NumberInput, {
value: value,
onChange: this.handleMarginOfErrorChange,
onBlur: this.handleMarginOfErrorBlur,
renderLabel: (0, _formatMessage["default"])('+/- margin of error'),
min: "0",
"data-automation": "sdk-formula-margin-of-error-value",
showArrows: true,
"aria-valuetext": "".concat(value, " ").concat((0, _formatMessage["default"])('+/- margin of error'))
});
}
}, {
key: "renderGenerateSolutionsButton",
value: function renderGenerateSolutionsButton() {
return (0, _emotion.jsx)(_uiButtons.Button, {
type: "submit",
disabled: this.props.overrideEditableForRegrading,
color: "primary",
onClick: this.props.handleGenerateSolutions,
"data-automation": "sdk-generate-button"
}, (0, _emotion.jsx)(_uiA11yContent.PresentationContent, null, (0, _formatMessage["default"])('Generate')), (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage["default"])('Generate Solutions')));
}
}, {
key: "render",
value: function render() {
return (0, _emotion.jsx)("div", null, (0, _emotion.jsx)("div", {
css: this.props.styles.sectionHeading
}, (0, _emotion.jsx)(_uiText.Text, {
size: "large"
}, (0, _formatMessage["default"])('Formula Definition'))), (0, _emotion.jsx)("div", {
css: this.props.styles.instructions
}, (0, _emotion.jsx)(_uiText.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")'))), (0, _emotion.jsx)(_quizCommon.TextArea, {
disabled: this.props.overrideEditableForRegrading,
value: this.props.scoringData.value.formula,
onChange: this.props.handleFormulaChange,
messages: this.formulaErrors(),
label: (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage["default"])('Formula')),
autoGrow: this.context.disableTextAreaAutoGrow ? false : null,
"data-automation": "sdk-formula-definition-text-area"
}), (0, _emotion.jsx)("div", null, (0, _emotion.jsx)("div", {
css: this.props.styles.sectionHeading
}, (0, _emotion.jsx)(_uiText.Text, {
size: "large"
}, (0, _formatMessage["default"])('Generate Possible Solutions'))), (0, _emotion.jsx)("div", {
css: this.props.styles.instructions
}, (0, _emotion.jsx)(_uiText.Text, {
color: "primary"
}, (0, _formatMessage["default"])('Finally, build as many variable-solution combinations as you need for your quiz.'))), (0, _emotion.jsx)("div", {
css: this.props.styles.generateSolutionsInput
}, (0, _emotion.jsx)(_uiGrid.Grid, {
vAlign: "top",
startAt: "medium"
}, (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, this.renderNumberOfGeneratedSolutionsInput()), (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, this.renderSolutionPrecisionInput()), (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, (0, _emotion.jsx)(_uiView.View, {
as: "div",
margin: "medium 0 0 0",
padding: "xx-small 0 0 0"
}, this.renderScientificNotationCheckbox()))), !this.props.scoringData.value.scientificNotation && (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, this.renderMarginOfErrorTypeSelect()), (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, this.renderMarginOfErrorInput())), (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, {
width: 4
}, this.renderGenerateSolutionsButton())))), this.renderGeneratedSolutionsSection()));
}
}]);
}(_react.Component), (0, _defineProperty2["default"])(_FormulaSection, "displayName", 'FormulaSection'), (0, _defineProperty2["default"])(_FormulaSection, "componentId", "Quizzes".concat(_FormulaSection.displayName)), (0, _defineProperty2["default"])(_FormulaSection, "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,
styles: _propTypes["default"].object
}), (0, _defineProperty2["default"])(_FormulaSection, "defaultProps", {
formulaErrors: void 0,
generatedSolutionsErrors: void 0
}), (0, _defineProperty2["default"])(_FormulaSection, "contextTypes", {
disableTextAreaAutoGrow: _propTypes["default"].bool
}), _FormulaSection)) || _class);