@pie-lib/rubric 0.8.31 → 0.8.32-next.1595
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +1 -407
- package/CHANGELOG.md +129 -35
- package/NEXT.CHANGELOG.json +1 -0
- package/lib/authoring.js +126 -27
- package/lib/authoring.js.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/__snapshots__/rubric.test.jsx.snap +48 -0
- package/src/__tests__/rubric.test.jsx +91 -0
- package/src/authoring.jsx +99 -12
- package/src/index.js +1 -0
package/src/authoring.jsx
CHANGED
|
@@ -21,6 +21,8 @@ import takeRight from 'lodash/takeRight';
|
|
|
21
21
|
import PointMenu from './point-menu';
|
|
22
22
|
|
|
23
23
|
import range from 'lodash/range';
|
|
24
|
+
import { InputContainer } from '@pie-lib/config-ui';
|
|
25
|
+
|
|
24
26
|
const log = debug('pie-lib:rubric:authoring');
|
|
25
27
|
|
|
26
28
|
const reorder = (list, startIndex, endIndex) => {
|
|
@@ -37,6 +39,7 @@ export const RubricType = PropTypes.shape({
|
|
|
37
39
|
points: PropTypes.arrayOf(PropTypes.string),
|
|
38
40
|
sampleAnswers: PropTypes.arrayOf(PropTypes.string),
|
|
39
41
|
maxPoints: PropTypes.number,
|
|
42
|
+
rubriclessInstruction: PropTypes.string,
|
|
40
43
|
});
|
|
41
44
|
|
|
42
45
|
const MaxPoints = withStyles((theme) => ({
|
|
@@ -53,7 +56,7 @@ const MaxPoints = withStyles((theme) => ({
|
|
|
53
56
|
Max Points
|
|
54
57
|
</InputLabel>
|
|
55
58
|
<Select value={value} onChange={(e) => onChange(e.target.value)} input={<OutlinedInput labelWidth={80} />}>
|
|
56
|
-
{range(1, max).map((v) => (
|
|
59
|
+
{range(1, max + 1).map((v) => (
|
|
57
60
|
<MenuItem key={`${v}`} value={v}>
|
|
58
61
|
{v}
|
|
59
62
|
</MenuItem>
|
|
@@ -94,8 +97,14 @@ export const PointConfig = withStyles((theme) => ({
|
|
|
94
97
|
position: 'absolute',
|
|
95
98
|
right: 0,
|
|
96
99
|
},
|
|
100
|
+
errorText: {
|
|
101
|
+
fontSize: theme.typography.fontSize - 2,
|
|
102
|
+
color: theme.palette.error.main,
|
|
103
|
+
paddingLeft: theme.spacing.unit * 3,
|
|
104
|
+
paddingTop: theme.spacing.unit,
|
|
105
|
+
},
|
|
97
106
|
}))((props) => {
|
|
98
|
-
const { points, content, classes, sampleAnswer, mathMlOptions = {} } = props;
|
|
107
|
+
const { points, content, classes, sampleAnswer, mathMlOptions = {}, error, pluginOpts = {} } = props;
|
|
99
108
|
const pointsLabel = `${points} ${points <= 1 ? 'pt' : 'pts'}`;
|
|
100
109
|
const showSampleAnswer = checkSampleAnswer(sampleAnswer);
|
|
101
110
|
|
|
@@ -109,6 +118,8 @@ export const PointConfig = withStyles((theme) => ({
|
|
|
109
118
|
<DragIndicator className={classes.dragIndicator} />
|
|
110
119
|
<EditableHtml
|
|
111
120
|
className={classes.editor}
|
|
121
|
+
error={error}
|
|
122
|
+
pluginProps={pluginOpts}
|
|
112
123
|
markup={content}
|
|
113
124
|
onChange={props.onChange}
|
|
114
125
|
mathMlOptions={mathMlOptions}
|
|
@@ -121,7 +132,7 @@ export const PointConfig = withStyles((theme) => ({
|
|
|
121
132
|
onChange={props.onMenuChange}
|
|
122
133
|
/>
|
|
123
134
|
</div>
|
|
124
|
-
|
|
135
|
+
{error && <div className={classes.errorText}>{error}</div>}
|
|
125
136
|
{!showSampleAnswer && (
|
|
126
137
|
<div className={classes.sampleAnswersEditor}>
|
|
127
138
|
<Typography variant="overline" className={classes.dragIndicator}>
|
|
@@ -130,6 +141,7 @@ export const PointConfig = withStyles((theme) => ({
|
|
|
130
141
|
<EditableHtml
|
|
131
142
|
className={classes.editor}
|
|
132
143
|
markup={sampleAnswer}
|
|
144
|
+
pluginProps={pluginOpts}
|
|
133
145
|
onChange={props.onSampleChange}
|
|
134
146
|
mathMlOptions={mathMlOptions}
|
|
135
147
|
/>
|
|
@@ -144,6 +156,9 @@ export class RawAuthoring extends React.Component {
|
|
|
144
156
|
classes: PropTypes.object.isRequired,
|
|
145
157
|
className: PropTypes.string,
|
|
146
158
|
value: RubricType,
|
|
159
|
+
config: PropTypes.object,
|
|
160
|
+
pluginOpts: PropTypes.object,
|
|
161
|
+
rubricless: PropTypes.bool,
|
|
147
162
|
onChange: PropTypes.func,
|
|
148
163
|
};
|
|
149
164
|
|
|
@@ -162,8 +177,13 @@ export class RawAuthoring extends React.Component {
|
|
|
162
177
|
onChange({ ...value, points, sampleAnswers });
|
|
163
178
|
};
|
|
164
179
|
|
|
165
|
-
|
|
180
|
+
changeRubriclessInstruction = (input) => {
|
|
166
181
|
const { value, onChange } = this.props;
|
|
182
|
+
onChange({ ...value, rubriclessInstruction: input });
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
changeMaxPoints = (maxPoints) => {
|
|
186
|
+
const { value, onChange, rubricless } = this.props;
|
|
167
187
|
const currentMax = value.points.length - 1;
|
|
168
188
|
|
|
169
189
|
log('current', currentMax, 'new: ', maxPoints);
|
|
@@ -184,8 +204,10 @@ export class RawAuthoring extends React.Component {
|
|
|
184
204
|
sampleAnswers = takeRight(value.sampleAnswers, maxPoints + 1);
|
|
185
205
|
}
|
|
186
206
|
|
|
187
|
-
if (points) {
|
|
188
|
-
onChange({ ...value, points, sampleAnswers });
|
|
207
|
+
if (points && !rubricless) {
|
|
208
|
+
onChange({ ...value, points, sampleAnswers, maxPoints });
|
|
209
|
+
} else {
|
|
210
|
+
onChange({ ...value, maxPoints });
|
|
189
211
|
}
|
|
190
212
|
};
|
|
191
213
|
|
|
@@ -242,21 +264,47 @@ export class RawAuthoring extends React.Component {
|
|
|
242
264
|
};
|
|
243
265
|
|
|
244
266
|
render() {
|
|
245
|
-
const {
|
|
246
|
-
|
|
247
|
-
|
|
267
|
+
const {
|
|
268
|
+
classes,
|
|
269
|
+
className,
|
|
270
|
+
value,
|
|
271
|
+
mathMlOptions = {},
|
|
272
|
+
config = {},
|
|
273
|
+
rubricless = false,
|
|
274
|
+
pluginOpts = {},
|
|
275
|
+
} = this.props;
|
|
276
|
+
let {
|
|
277
|
+
excludeZeroEnabled = true,
|
|
278
|
+
maxPointsEnabled = true,
|
|
279
|
+
errors = {},
|
|
280
|
+
rubriclessInstructionEnabled = false,
|
|
281
|
+
maxPoints = 10,
|
|
282
|
+
} = value || {};
|
|
283
|
+
// rubric will contain a max value for maxPoints
|
|
284
|
+
const { rubriclessInstruction = {}, maxMaxPoints = 10 } = config || {};
|
|
285
|
+
const { pointsDescriptorsErrors } = errors || {};
|
|
248
286
|
if (value && Number.isFinite(value.maxPoints)) {
|
|
249
287
|
// eslint-disable-next-line no-console
|
|
250
288
|
console.warn('maxPoints is deprecated - remove from model');
|
|
251
289
|
}
|
|
252
290
|
|
|
291
|
+
// for rubric value is computed based on points
|
|
292
|
+
const maxPointsValue = !rubricless ? value.points.length - 1 : maxPoints;
|
|
293
|
+
|
|
253
294
|
return (
|
|
254
295
|
<div className={classNames(classes.class, className)}>
|
|
255
296
|
<Typography variant="h5" className={classes.rubricTitle}>
|
|
256
297
|
Rubric
|
|
257
298
|
</Typography>
|
|
258
299
|
<FormGroup row>
|
|
259
|
-
{maxPointsEnabled &&
|
|
300
|
+
{maxPointsEnabled && (
|
|
301
|
+
<MaxPoints
|
|
302
|
+
max={maxMaxPoints < 100 ? maxMaxPoints : 100}
|
|
303
|
+
value={maxPointsValue}
|
|
304
|
+
onChange={this.changeMaxPoints}
|
|
305
|
+
pluginOpts={pluginOpts}
|
|
306
|
+
/>
|
|
307
|
+
)}
|
|
260
308
|
{excludeZeroEnabled && (
|
|
261
309
|
<FormControlLabel
|
|
262
310
|
label="Exclude zeros"
|
|
@@ -265,7 +313,22 @@ export class RawAuthoring extends React.Component {
|
|
|
265
313
|
)}
|
|
266
314
|
</FormGroup>
|
|
267
315
|
|
|
268
|
-
|
|
316
|
+
{rubriclessInstructionEnabled && rubricless && (
|
|
317
|
+
<InputContainer label={rubriclessInstruction.label} className={classes.inputContainer}>
|
|
318
|
+
<EditableHtml
|
|
319
|
+
className={classes.input}
|
|
320
|
+
markup={value.rubriclessInstruction || ''}
|
|
321
|
+
onChange={this.changeRubriclessInstruction}
|
|
322
|
+
pluginProps={pluginOpts}
|
|
323
|
+
nonEmpty={false}
|
|
324
|
+
disableUnderline
|
|
325
|
+
languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
|
|
326
|
+
mathMlOptions={mathMlOptions}
|
|
327
|
+
/>
|
|
328
|
+
</InputContainer>
|
|
329
|
+
)}
|
|
330
|
+
|
|
331
|
+
<div className={rubricless ? classes.rubricless : classes.container}>
|
|
269
332
|
<DragDropContext onDragEnd={this.dragEnd}>
|
|
270
333
|
<Droppable droppableId="droppable">
|
|
271
334
|
{(provided) => (
|
|
@@ -284,11 +347,15 @@ export class RawAuthoring extends React.Component {
|
|
|
284
347
|
<PointConfig
|
|
285
348
|
points={value.points.length - 1 - index}
|
|
286
349
|
content={p}
|
|
350
|
+
error={
|
|
351
|
+
pointsDescriptorsErrors && pointsDescriptorsErrors[value.points.length - 1 - index]
|
|
352
|
+
}
|
|
287
353
|
sampleAnswer={value.sampleAnswers && value.sampleAnswers[index]}
|
|
288
354
|
onChange={(content) => this.changeContent(index, content, 'points')}
|
|
289
355
|
onSampleChange={(content) => this.changeContent(index, content, 'sampleAnswers')}
|
|
290
356
|
onMenuChange={(clickedItem) => this.onPointMenuChange(index, clickedItem)}
|
|
291
357
|
mathMlOptions={mathMlOptions}
|
|
358
|
+
pluginOpts={pluginOpts}
|
|
292
359
|
/>
|
|
293
360
|
</div>
|
|
294
361
|
)}
|
|
@@ -315,6 +382,14 @@ const styles = (theme) => ({
|
|
|
315
382
|
padding: theme.spacing.unit * 2,
|
|
316
383
|
margin: theme.spacing.unit,
|
|
317
384
|
},
|
|
385
|
+
inputContainer: {
|
|
386
|
+
width: '100%',
|
|
387
|
+
paddingTop: theme.spacing.unit * 2,
|
|
388
|
+
marginBottom: theme.spacing.unit * 2,
|
|
389
|
+
},
|
|
390
|
+
rubricless: {
|
|
391
|
+
display: 'none',
|
|
392
|
+
},
|
|
318
393
|
configHolder: {
|
|
319
394
|
paddingTop: theme.spacing.unit,
|
|
320
395
|
paddingBottom: theme.spacing.unit,
|
|
@@ -328,6 +403,7 @@ const styles = (theme) => ({
|
|
|
328
403
|
const StyledRawAuthoring = withStyles(styles)(RawAuthoring);
|
|
329
404
|
|
|
330
405
|
const Reverse = (props) => {
|
|
406
|
+
const { rubricless = false, config = {}, pluginOpts = {} } = props || {};
|
|
331
407
|
const points = Array.from(props.value.points || []).reverse();
|
|
332
408
|
let sampleAnswers = Array.from(props.value.sampleAnswers || []).reverse();
|
|
333
409
|
|
|
@@ -347,11 +423,22 @@ const Reverse = (props) => {
|
|
|
347
423
|
});
|
|
348
424
|
};
|
|
349
425
|
|
|
350
|
-
return
|
|
426
|
+
return (
|
|
427
|
+
<StyledRawAuthoring
|
|
428
|
+
value={value}
|
|
429
|
+
config={config}
|
|
430
|
+
onChange={onChange}
|
|
431
|
+
rubricless={rubricless}
|
|
432
|
+
pluginOpts={pluginOpts}
|
|
433
|
+
/>
|
|
434
|
+
);
|
|
351
435
|
};
|
|
352
436
|
|
|
353
437
|
Reverse.propTypes = {
|
|
354
438
|
value: RubricType,
|
|
439
|
+
config: PropTypes.object,
|
|
440
|
+
pluginOpts: PropTypes.object,
|
|
441
|
+
rubricless: PropTypes.bool,
|
|
355
442
|
getIndex: PropTypes.func,
|
|
356
443
|
onChange: PropTypes.func,
|
|
357
444
|
};
|