@pocketprep/ui-kit 3.4.52 → 3.4.53
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/dist/@pocketprep/ui-kit.js +12251 -11129
- package/dist/@pocketprep/ui-kit.js.map +1 -1
- package/dist/@pocketprep/ui-kit.umd.cjs +10 -10
- package/dist/@pocketprep/ui-kit.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/lib/components/Forms/Checkbox.vue +9 -1
- package/lib/components/Forms/Radio.vue +11 -11
- package/lib/components/Forms/RadioButton.vue +140 -0
- package/lib/components/Quiz/Question/MatrixChoicesContainer.vue +614 -0
- package/lib/components/Quiz/Question/MatrixRadioGroup.vue +98 -0
- package/lib/components/Quiz/Question/MobileMatrixChoicesContainer.vue +710 -0
- package/lib/components/Quiz/Question/MobileMatrixRadioGroup.vue +131 -0
- package/lib/components/Quiz/Question/StatsSummary.vue +11 -3
- package/lib/components/Quiz/Question/Summary.vue +9 -2
- package/lib/components/Quiz/Question.vue +252 -11
- package/lib/components/Quiz/question.d.ts +12 -0
- package/package.json +2 -2
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import RadioButton from '../../Forms/RadioButton.vue'
|
|
3
|
+
import { dark as vDark } from '../../../directives'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
isDarkMode: boolean
|
|
7
|
+
choices: string[]
|
|
8
|
+
labels: string[]
|
|
9
|
+
showAnswers: boolean
|
|
10
|
+
disabled: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
+
isDarkMode: false,
|
|
15
|
+
showAnswers: false,
|
|
16
|
+
disabled: false,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const selectedChoice = defineModel<string>()
|
|
20
|
+
|
|
21
|
+
const selectChoice = (choiceKey: string) => {
|
|
22
|
+
selectedChoice.value = choiceKey
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const radioButtonColor = (choice: string) => {
|
|
26
|
+
if (props.showAnswers) {
|
|
27
|
+
if (choice === selectedChoice.value && selectedChoice.value?.startsWith('a')) {
|
|
28
|
+
return 'green'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (choice === selectedChoice.value && selectedChoice.value?.startsWith('d')) {
|
|
32
|
+
return 'gray'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (choice.startsWith('a')) {
|
|
36
|
+
return 'green'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return 'blue'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const stripText = (string?: string) => {
|
|
44
|
+
return string?.replace(/<[^\s>]+[^>]*>/gi, ' ').trim()
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<ul
|
|
50
|
+
v-if="choices.length"
|
|
51
|
+
class="uikit-mobile-matrix-radio-group"
|
|
52
|
+
v-dark="isDarkMode"
|
|
53
|
+
role="radiogroup"
|
|
54
|
+
>
|
|
55
|
+
<li
|
|
56
|
+
class="uikit-mobile-matrix-radio-group__option"
|
|
57
|
+
v-dark="isDarkMode"
|
|
58
|
+
role="radio"
|
|
59
|
+
v-for="(choice, index) in choices"
|
|
60
|
+
:key="choice"
|
|
61
|
+
>
|
|
62
|
+
<RadioButton
|
|
63
|
+
class="uikit-mobile-matrix-radio-group__radio-btn"
|
|
64
|
+
:selected="(choice === selectedChoice) || (showAnswers && choice.startsWith('a'))"
|
|
65
|
+
:disabled="disabled"
|
|
66
|
+
:isDarkMode="isDarkMode"
|
|
67
|
+
:color="radioButtonColor(choice)"
|
|
68
|
+
@click="!disabled && !showAnswers && selectChoice(choice)"
|
|
69
|
+
/>
|
|
70
|
+
<div
|
|
71
|
+
v-if="labels"
|
|
72
|
+
v-dark="props.isDarkMode"
|
|
73
|
+
class="uikit-mobile-matrix-radio-group__label"
|
|
74
|
+
:class="{
|
|
75
|
+
'uikit-mobile-matrix-radio-group__label--distractor':
|
|
76
|
+
showAnswers && choice?.startsWith('d')
|
|
77
|
+
}"
|
|
78
|
+
@click="!disabled && !showAnswers && selectChoice(choice)"
|
|
79
|
+
>
|
|
80
|
+
{{ stripText(labels[index]) }}
|
|
81
|
+
</div>
|
|
82
|
+
</li>
|
|
83
|
+
</ul>
|
|
84
|
+
</template>
|
|
85
|
+
|
|
86
|
+
<style lang="scss" scoped>
|
|
87
|
+
@import '../../../styles/breakpoints';
|
|
88
|
+
@import '../../../styles/colors';
|
|
89
|
+
|
|
90
|
+
.uikit-mobile-matrix-radio-group {
|
|
91
|
+
list-style: none;
|
|
92
|
+
margin: 0;
|
|
93
|
+
padding: 0;
|
|
94
|
+
display: block;
|
|
95
|
+
background: $white;
|
|
96
|
+
border-radius: 0px 0px 5px 5px;
|
|
97
|
+
|
|
98
|
+
&--dark {
|
|
99
|
+
background: $brand-black;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&__option {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
padding-left: 15px;
|
|
106
|
+
height: 47px;
|
|
107
|
+
max-width: 325px;
|
|
108
|
+
border: 0.5px solid rgba($pewter, 0.85);
|
|
109
|
+
border-top: none;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
&__label {
|
|
114
|
+
display: block;
|
|
115
|
+
margin-left: 12px;
|
|
116
|
+
color: $brand-black;
|
|
117
|
+
font-size: 16px;
|
|
118
|
+
font-weight: 500;
|
|
119
|
+
line-height: 23px;
|
|
120
|
+
letter-spacing: -0.1px;
|
|
121
|
+
|
|
122
|
+
&--dark {
|
|
123
|
+
color: $barely-background;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&--distractor {
|
|
127
|
+
text-decoration: line-through;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
</style>
|
|
@@ -4,17 +4,23 @@
|
|
|
4
4
|
class="uikit-question-stats-summary"
|
|
5
5
|
>
|
|
6
6
|
<div v-dark="isDarkMode" class="uikit-question-stats-summary__stats-summary-total">
|
|
7
|
-
<div class="uikit-question-stats-summary__stats-summary-value">
|
|
7
|
+
<div v-if="!isMatrixQuestion" class="uikit-question-stats-summary__stats-summary-value">
|
|
8
8
|
{{ choiceScores.totalAnswered }}
|
|
9
9
|
</div>
|
|
10
|
+
<div v-else class="uikit-question-stats-summary__stats-summary-value">
|
|
11
|
+
{{ matrixChoiceScores.totalAnswered }}
|
|
12
|
+
</div>
|
|
10
13
|
<div v-dark="isDarkMode" class="uikit-question-stats-summary__stats-summary-label">
|
|
11
14
|
Studiers Answered
|
|
12
15
|
</div>
|
|
13
16
|
</div>
|
|
14
17
|
<div v-dark="isDarkMode" class="uikit-question-stats-summary__stats-summary-correct">
|
|
15
|
-
<div class="uikit-question-stats-summary__stats-summary-value">
|
|
18
|
+
<div v-if="!isMatrixQuestion" class="uikit-question-stats-summary__stats-summary-value">
|
|
16
19
|
{{ Math.round((choiceScores.answeredCorrectly / choiceScores.totalAnswered) * 100) }}%
|
|
17
20
|
</div>
|
|
21
|
+
<div v-else class="uikit-question-stats-summary__stats-summary-value">
|
|
22
|
+
{{ Math.round((matrixChoiceScores.answeredCorrectly / matrixChoiceScores.totalAnswered) * 100) }}%
|
|
23
|
+
</div>
|
|
18
24
|
<div v-dark="isDarkMode" class="uikit-question-stats-summary__stats-summary-label">
|
|
19
25
|
Answered Correctly
|
|
20
26
|
</div>
|
|
@@ -26,7 +32,7 @@
|
|
|
26
32
|
import { Component, Vue, Prop } from 'vue-facing-decorator'
|
|
27
33
|
import type { Study } from '@pocketprep/types'
|
|
28
34
|
import { dark, breakpoint } from '../../../directives'
|
|
29
|
-
import type { TChoiceScores } from './../question'
|
|
35
|
+
import type { TChoiceScores, TMatrixChoiceScores } from './../question'
|
|
30
36
|
|
|
31
37
|
|
|
32
38
|
@Component({
|
|
@@ -39,6 +45,8 @@ export default class StatsSummary extends Vue {
|
|
|
39
45
|
@Prop({ default: null }) globalMetrics!: Study.Class.GlobalQuestionMetricJSON | null
|
|
40
46
|
@Prop() choiceScores!: TChoiceScores
|
|
41
47
|
@Prop({ default: false }) isDarkMode!: boolean
|
|
48
|
+
@Prop({ default: false }) isMatrixQuestion!: boolean
|
|
49
|
+
@Prop() matrixChoiceScores!: TMatrixChoiceScores
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
</script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
class="uikit-question-summary"
|
|
7
7
|
>
|
|
8
8
|
<div class="uikit-question-summary__summary-title">
|
|
9
|
-
{{
|
|
9
|
+
{{ isQuestionCorrect ? 'Correct': isUnanswered ? 'Unanswered' : 'Incorrect' }}
|
|
10
10
|
</div>
|
|
11
11
|
<PocketButton
|
|
12
12
|
v-breakpoint:questionEl="breakpoints"
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
</div>
|
|
98
98
|
</div>
|
|
99
99
|
<Icon
|
|
100
|
-
v-if="
|
|
100
|
+
v-if="isQuestionCorrect"
|
|
101
101
|
v-dark="isDarkMode"
|
|
102
102
|
type="correct"
|
|
103
103
|
class="uikit-question-summary__summary-correct-icon"
|
|
@@ -139,9 +139,11 @@ export default class Summary extends Vue {
|
|
|
139
139
|
@Prop({ default: undefined }) reference!: string | undefined
|
|
140
140
|
@Prop({ default: false }) hideReferences!: boolean
|
|
141
141
|
@Prop({ default: false }) isCorrect!: boolean
|
|
142
|
+
@Prop({ default: false }) isMatrixQuestionCorrect!: boolean
|
|
142
143
|
@Prop({ default: false }) isUnanswered!: boolean
|
|
143
144
|
@Prop({ default: false }) reviewMode!: boolean
|
|
144
145
|
@Prop({ default: false }) isDarkMode!: boolean
|
|
146
|
+
@Prop({ default: false }) isMatrixQuestion!: boolean
|
|
145
147
|
@Prop({ default: null }) questionEl!: Element | null
|
|
146
148
|
@Prop({ default: {
|
|
147
149
|
'mobile': 767,
|
|
@@ -149,6 +151,10 @@ export default class Summary extends Vue {
|
|
|
149
151
|
'tablet-landscape': 1439,
|
|
150
152
|
} }) breakpoints!: TBreakPointsObject
|
|
151
153
|
|
|
154
|
+
get isQuestionCorrect () {
|
|
155
|
+
return (!this.isMatrixQuestion && this.isCorrect) || (this.isMatrixQuestion && this.isMatrixQuestionCorrect)
|
|
156
|
+
}
|
|
157
|
+
|
|
152
158
|
@Emit('toggleSummaryExplanation')
|
|
153
159
|
toggleSummaryExplanation () {
|
|
154
160
|
return
|
|
@@ -186,6 +192,7 @@ export default class Summary extends Vue {
|
|
|
186
192
|
display: inline-block;
|
|
187
193
|
}
|
|
188
194
|
|
|
195
|
+
|
|
189
196
|
&__summary-title {
|
|
190
197
|
font-weight: 600;
|
|
191
198
|
font-size: 15.5px;
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
showAnswers && (isMCR || isUnanswered) && !isCorrect && !isTeachReview,
|
|
124
124
|
'uikit-question__choices--unanswered': showAnswers && !isMCR && isUnanswered && !isCorrect,
|
|
125
125
|
'uikit-question__choices--show-stats': globalMetrics,
|
|
126
|
-
'uikit-question__choices--no-actions': !(isMCR || isUnanswered)
|
|
126
|
+
'uikit-question__choices--no-actions': !(isMCR || isUnanswered || isMatrixQuestion)
|
|
127
127
|
&& !globalMetrics
|
|
128
128
|
&& (
|
|
129
129
|
reviewMode
|
|
@@ -152,6 +152,7 @@
|
|
|
152
152
|
/>
|
|
153
153
|
</div>
|
|
154
154
|
<ChoicesContainer
|
|
155
|
+
v-if="question.type !== 'Matrix Checkbox' && question.type !== 'Matrix Radio Button'"
|
|
155
156
|
ref="uikit-question__choices-container"
|
|
156
157
|
:question="question"
|
|
157
158
|
:choices="choices"
|
|
@@ -216,10 +217,88 @@
|
|
|
216
217
|
/>
|
|
217
218
|
</template>
|
|
218
219
|
</ChoicesContainer>
|
|
220
|
+
<MatrixChoicesContainer
|
|
221
|
+
v-if="question.type === 'Matrix Checkbox' || question.type === 'Matrix Radio Button'"
|
|
222
|
+
class="uikit-question__matrix-choices-container"
|
|
223
|
+
ref="uikit-question__matrix-choices-container"
|
|
224
|
+
v-breakpoint:questionEl="breakpoints"
|
|
225
|
+
:question="question"
|
|
226
|
+
:matrix-choice-layout="question.matrixChoiceLayout"
|
|
227
|
+
:is-matrix-question-correct="isMatrixQuestionCorrect"
|
|
228
|
+
:matrix-answer-keys="matrixAnswerKeys"
|
|
229
|
+
:matrix-distractor-keys="matrixDistractorKeys"
|
|
230
|
+
:selected-matrix-choices="selectedMatrixChoices"
|
|
231
|
+
:show-matrix-answers="showMatrixAnswers"
|
|
232
|
+
:review-mode="reviewMode"
|
|
233
|
+
:matrix-choice-scores="matrixChoiceScores"
|
|
234
|
+
:global-metrics="globalMetrics"
|
|
235
|
+
:is-dark-mode="isDarkMode"
|
|
236
|
+
:question-el="questionEl"
|
|
237
|
+
:breakpoints="breakpoints"
|
|
238
|
+
@emitSelectedMatrixChoice="selectMatrixChoice"
|
|
239
|
+
@emitAnsweredMatrixRowIndex="answeredMatrixRowIndex"
|
|
240
|
+
>
|
|
241
|
+
<template #motivationalMoment="{
|
|
242
|
+
isCorrect,
|
|
243
|
+
choiceKey,
|
|
244
|
+
showAnswers,
|
|
245
|
+
answerKeys,
|
|
246
|
+
}">
|
|
247
|
+
<slot
|
|
248
|
+
name="motivationalMoment"
|
|
249
|
+
:showAnswers="showAnswers"
|
|
250
|
+
:answerKeys="answerKeys"
|
|
251
|
+
:choiceKey="choiceKey"
|
|
252
|
+
:isCorrect="isCorrect"
|
|
253
|
+
/>
|
|
254
|
+
</template>
|
|
255
|
+
<template #showNamesTable="{
|
|
256
|
+
choiceKey,
|
|
257
|
+
}" >
|
|
258
|
+
<slot
|
|
259
|
+
name="showNamesTable"
|
|
260
|
+
:choiceKey="choiceKey"
|
|
261
|
+
/>
|
|
262
|
+
</template>
|
|
263
|
+
</MatrixChoicesContainer>
|
|
264
|
+
<MobileMatrixChoicesContainer
|
|
265
|
+
v-if="question.type === 'Matrix Checkbox' || question.type === 'Matrix Radio Button'"
|
|
266
|
+
class="uikit-question__mobile-matrix-choices-container"
|
|
267
|
+
v-breakpoint:questionEl="breakpoints"
|
|
268
|
+
:question="question"
|
|
269
|
+
:matrix-choice-layout="question.matrixChoiceLayout"
|
|
270
|
+
:is-matrix-question-correct="isMatrixQuestionCorrect"
|
|
271
|
+
:matrix-answer-keys="matrixAnswerKeys"
|
|
272
|
+
:matrix-distractor-keys="matrixDistractorKeys"
|
|
273
|
+
:selected-matrix-choices="selectedMatrixChoices"
|
|
274
|
+
:show-matrix-answers="showMatrixAnswers"
|
|
275
|
+
:review-mode="reviewMode"
|
|
276
|
+
:global-metrics="globalMetrics"
|
|
277
|
+
:is-dark-mode="isDarkMode"
|
|
278
|
+
:question-el="questionEl"
|
|
279
|
+
:breakpoints="breakpoints"
|
|
280
|
+
@emitSelectedMatrixChoice="selectMatrixChoice"
|
|
281
|
+
@emitAnsweredMatrixRowIndex="answeredMatrixRowIndex"
|
|
282
|
+
>
|
|
283
|
+
<template #motivationalMoment="{
|
|
284
|
+
isCorrect,
|
|
285
|
+
choiceKey,
|
|
286
|
+
showAnswers,
|
|
287
|
+
answerKeys,
|
|
288
|
+
}">
|
|
289
|
+
<slot
|
|
290
|
+
name="motivationalMoment"
|
|
291
|
+
:showAnswers="showAnswers"
|
|
292
|
+
:answerKeys="answerKeys"
|
|
293
|
+
:choiceKey="choiceKey"
|
|
294
|
+
:isCorrect="isCorrect"
|
|
295
|
+
/>
|
|
296
|
+
</template>
|
|
297
|
+
</MobileMatrixChoicesContainer>
|
|
219
298
|
<slot name="unansweredFlaggedNamesTable" />
|
|
220
299
|
</div>
|
|
221
300
|
<Summary
|
|
222
|
-
v-if="isMCR && showAnswers && !showPaywall"
|
|
301
|
+
v-if="((isMCR && showAnswers) || (isMatrixQuestion && showMatrixAnswers)) && !showPaywall"
|
|
223
302
|
ref="uikit-question__summary"
|
|
224
303
|
class="uikit-question__summary"
|
|
225
304
|
:question="question"
|
|
@@ -231,6 +310,8 @@
|
|
|
231
310
|
:reference="reference"
|
|
232
311
|
:hide-references="hideReferences"
|
|
233
312
|
:is-correct="isCorrect"
|
|
313
|
+
:is-matrix-question-correct="isMatrixQuestionCorrect"
|
|
314
|
+
:is-matrix-question="isMatrixQuestion"
|
|
234
315
|
:is-unanswered="isUnanswered"
|
|
235
316
|
:review-mode="reviewMode"
|
|
236
317
|
:is-dark-mode="isDarkMode"
|
|
@@ -245,6 +326,8 @@
|
|
|
245
326
|
class="uikit-question__stats-summary"
|
|
246
327
|
:global-metrics="globalMetrics"
|
|
247
328
|
:choice-scores="choiceScores"
|
|
329
|
+
:matrix-choice-scores="matrixChoiceScores"
|
|
330
|
+
:is-matrix-question="isMatrixQuestion"
|
|
248
331
|
:is-dark-mode="isDarkMode"
|
|
249
332
|
/>
|
|
250
333
|
</slot>
|
|
@@ -277,13 +360,21 @@
|
|
|
277
360
|
>
|
|
278
361
|
<slot name="action">
|
|
279
362
|
<PocketButton
|
|
280
|
-
v-if="!showAnswers && !hideAnswer && (showCheckAnswer || isMCR)"
|
|
363
|
+
v-if="!showAnswers && !hideAnswer && (showCheckAnswer || isMCR) && !isMatrixQuestion"
|
|
281
364
|
:disabled="!selectedChoices.length"
|
|
282
365
|
:is-dark-mode="isDarkMode"
|
|
283
366
|
@click="clickCheckAnswer"
|
|
284
367
|
>
|
|
285
368
|
Check Answer
|
|
286
369
|
</PocketButton>
|
|
370
|
+
<PocketButton
|
|
371
|
+
v-if="!showMatrixAnswers && !hideAnswer && isMatrixQuestion && allMatrixRowsAreAnswered"
|
|
372
|
+
:disabled="!selectedMatrixChoices.length"
|
|
373
|
+
:is-dark-mode="isDarkMode"
|
|
374
|
+
@click="clickCheckMatrixAnswer"
|
|
375
|
+
>
|
|
376
|
+
Check Answer
|
|
377
|
+
</PocketButton>
|
|
287
378
|
<PocketButton
|
|
288
379
|
v-else-if="(showAnswers || hideAnswer) && (questionNumber >= quizLength)"
|
|
289
380
|
:is-dark-mode="isDarkMode"
|
|
@@ -376,10 +467,22 @@ import ChoicesContainer from '../Quiz/Question/ChoicesContainer.vue'
|
|
|
376
467
|
import StatsSummary from '../Quiz/Question/StatsSummary.vue'
|
|
377
468
|
import Explanation from '../Quiz/Question/Explanation.vue'
|
|
378
469
|
import PassageAndImage from '../Quiz/Question/PassageAndImage.vue'
|
|
470
|
+
import MatrixChoicesContainer from '../Quiz/Question/MatrixChoicesContainer.vue'
|
|
471
|
+
import MobileMatrixChoicesContainer from '../Quiz/Question/MobileMatrixChoicesContainer.vue'
|
|
379
472
|
import type { Study } from '@pocketprep/types'
|
|
380
473
|
import { breakpoint, dark } from '../../directives'
|
|
381
474
|
import { highlightKeywordsInText, studyModes } from '../../utils'
|
|
382
|
-
import type {
|
|
475
|
+
import type {
|
|
476
|
+
Ref,
|
|
477
|
+
TQuizMode,
|
|
478
|
+
TChoiceKey,
|
|
479
|
+
TMatrixChoiceKey,
|
|
480
|
+
TChoice,
|
|
481
|
+
TChoiceScores,
|
|
482
|
+
TMatrixChoiceScores,
|
|
483
|
+
TNamesRow,
|
|
484
|
+
TViewNames,
|
|
485
|
+
} from './question'
|
|
383
486
|
|
|
384
487
|
@Component({
|
|
385
488
|
components: {
|
|
@@ -396,6 +499,8 @@ import type { Ref, TQuizMode, TChoiceKey, TChoice, TChoiceScores, TNamesRow, TVi
|
|
|
396
499
|
StatsSummary,
|
|
397
500
|
Explanation,
|
|
398
501
|
PassageAndImage,
|
|
502
|
+
MatrixChoicesContainer,
|
|
503
|
+
MobileMatrixChoicesContainer,
|
|
399
504
|
},
|
|
400
505
|
directives: {
|
|
401
506
|
breakpoint,
|
|
@@ -414,6 +519,7 @@ export default class Question extends Vue {
|
|
|
414
519
|
@Prop({ default: true }) showNextQuestion!: boolean
|
|
415
520
|
@Prop({ default: false }) reviewMode!: boolean
|
|
416
521
|
@Prop({ default: null }) previousChoices!: TChoiceKey[] | null
|
|
522
|
+
@Prop({ default: null }) previousMatrixChoices!: TMatrixChoiceKey[] | null
|
|
417
523
|
@Prop({ default: null }) globalMetrics!: Study.Class.GlobalQuestionMetricJSON | null
|
|
418
524
|
@Prop({ default: null }) showNames!: TViewNames | null
|
|
419
525
|
@Prop({ default: true }) allowKeyboardShortcuts!: boolean
|
|
@@ -432,7 +538,11 @@ export default class Question extends Vue {
|
|
|
432
538
|
focusChoiceKey: TChoiceKey | null = null
|
|
433
539
|
choiceStrikes: TChoiceKey[] = []
|
|
434
540
|
selectedChoices: TChoiceKey[] = []
|
|
541
|
+
selectedMatrixChoices: TMatrixChoiceKey[] = []
|
|
542
|
+
answeredMatrixRowIndexes: number[] = []
|
|
543
|
+
allMatrixRowsAreAnswered = false
|
|
435
544
|
showAnswers = false
|
|
545
|
+
showMatrixAnswers = false
|
|
436
546
|
showExplanation = false
|
|
437
547
|
showPassageImageLongAlt = false
|
|
438
548
|
showExplanationImageDropdown = false
|
|
@@ -488,6 +598,10 @@ export default class Question extends Vue {
|
|
|
488
598
|
return this.question.type === 'Multiple Correct Response'
|
|
489
599
|
}
|
|
490
600
|
|
|
601
|
+
get isMatrixQuestion () {
|
|
602
|
+
return this.question.type === 'Matrix Checkbox' || this.question.type === 'Matrix Radio Button'
|
|
603
|
+
}
|
|
604
|
+
|
|
491
605
|
get passageImageUrl () {
|
|
492
606
|
const imageUrl = this.question.passageImage?.url
|
|
493
607
|
|
|
@@ -522,11 +636,13 @@ export default class Question extends Vue {
|
|
|
522
636
|
|
|
523
637
|
get passageAndImageTitle () {
|
|
524
638
|
if (this.question.passage && this.passageImageUrl) {
|
|
525
|
-
return
|
|
639
|
+
return this.question.passageLabel ? `${this.question.passageLabel} + Image` :
|
|
640
|
+
'Passage + Image'
|
|
526
641
|
} else if (!this.question.passage && this.passageImageUrl) {
|
|
527
642
|
return 'Image'
|
|
528
643
|
} else {
|
|
529
|
-
return
|
|
644
|
+
return this.question.passageLabel ? `${this.question.passageLabel}` :
|
|
645
|
+
'Passage'
|
|
530
646
|
}
|
|
531
647
|
}
|
|
532
648
|
|
|
@@ -547,6 +663,20 @@ export default class Question extends Vue {
|
|
|
547
663
|
return this.answers.map(choice => choice.key)
|
|
548
664
|
}
|
|
549
665
|
|
|
666
|
+
get matrixAnswerKeys () {
|
|
667
|
+
if (this.question?.matrixChoiceLayout) {
|
|
668
|
+
return this.question?.matrixChoiceLayout.flat().filter(choice => choice.startsWith('a'))
|
|
669
|
+
}
|
|
670
|
+
return []
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
get matrixDistractorKeys () {
|
|
674
|
+
if (this.question?.matrixChoiceLayout) {
|
|
675
|
+
return this.question?.matrixChoiceLayout.flat().filter(choice => choice.startsWith('d'))
|
|
676
|
+
}
|
|
677
|
+
return []
|
|
678
|
+
}
|
|
679
|
+
|
|
550
680
|
get distractors (): TChoice[] {
|
|
551
681
|
const distractors = this.question.choices.filter(choice => !choice.isCorrect).map((choice, index) => ({
|
|
552
682
|
text: choice.text,
|
|
@@ -574,6 +704,12 @@ export default class Question extends Vue {
|
|
|
574
704
|
&& !this.selectedChoices.join(' ').includes('d')
|
|
575
705
|
}
|
|
576
706
|
|
|
707
|
+
get isMatrixQuestionCorrect () {
|
|
708
|
+
return this.showMatrixAnswers
|
|
709
|
+
&& this.selectedMatrixChoices.length === this.matrixAnswerKeys.length
|
|
710
|
+
&& !this.selectedMatrixChoices.join(' ').includes('d')
|
|
711
|
+
}
|
|
712
|
+
|
|
577
713
|
get choiceScores (): TChoiceScores {
|
|
578
714
|
const globalMetrics = this.globalMetrics
|
|
579
715
|
|
|
@@ -608,8 +744,32 @@ export default class Question extends Vue {
|
|
|
608
744
|
return scores
|
|
609
745
|
}
|
|
610
746
|
|
|
747
|
+
get matrixChoiceScores (): TMatrixChoiceScores {
|
|
748
|
+
const globalMetrics = this.globalMetrics
|
|
749
|
+
|
|
750
|
+
const scores: TMatrixChoiceScores = {
|
|
751
|
+
totalAnswered: this.selectedMatrixChoices.length &&
|
|
752
|
+
this.showMatrixAnswers && !this.reviewMode ? 1 : 0,
|
|
753
|
+
answeredCorrectly: this.isCorrect && !this.reviewMode ? 1 : 0,
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (!globalMetrics) {
|
|
757
|
+
return scores
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
scores.totalAnswered += (
|
|
761
|
+
(globalMetrics.answeredCorrectlyCount || 0)
|
|
762
|
+
+ (globalMetrics.answeredIncorrectlyCount || 0)
|
|
763
|
+
)
|
|
764
|
+
scores.answeredCorrectly += (globalMetrics.answeredCorrectlyCount || 0)
|
|
765
|
+
return scores
|
|
766
|
+
}
|
|
767
|
+
|
|
611
768
|
get isUnanswered () {
|
|
612
|
-
|
|
769
|
+
if (!this.isMatrixQuestion) {
|
|
770
|
+
return this.selectedChoices.length === 0
|
|
771
|
+
}
|
|
772
|
+
return this.selectedMatrixChoices.length === 0
|
|
613
773
|
}
|
|
614
774
|
|
|
615
775
|
get prompt () {
|
|
@@ -626,12 +786,17 @@ export default class Question extends Vue {
|
|
|
626
786
|
this.startReviewMode()
|
|
627
787
|
}
|
|
628
788
|
|
|
629
|
-
if (this.previousChoices) {
|
|
789
|
+
if (!this.isMatrixQuestion && this.previousChoices) {
|
|
630
790
|
this.updateSelectedChoices(this.previousChoices)
|
|
631
791
|
}
|
|
632
792
|
|
|
793
|
+
if (this.isMatrixQuestion && this.previousMatrixChoices) {
|
|
794
|
+
this.updateSelectedMatrixChoices(this.previousMatrixChoices)
|
|
795
|
+
}
|
|
796
|
+
|
|
633
797
|
if (this.initialShowAnswers) {
|
|
634
798
|
this.showAnswers = this.initialShowAnswers
|
|
799
|
+
this.showMatrixAnswers = this.initialShowAnswers
|
|
635
800
|
}
|
|
636
801
|
|
|
637
802
|
if (this.allowKeyboardShortcuts) {
|
|
@@ -750,21 +915,33 @@ export default class Question extends Vue {
|
|
|
750
915
|
}
|
|
751
916
|
|
|
752
917
|
startReviewMode () {
|
|
753
|
-
this.
|
|
754
|
-
|
|
755
|
-
|
|
918
|
+
if (!this.isMatrixQuestion) {
|
|
919
|
+
this.showAnswers = true
|
|
920
|
+
this.showExplanation = this.defaultShowExplanation === null ? true : this.defaultShowExplanation
|
|
921
|
+
this.selectedChoices = this.answerKeys
|
|
922
|
+
} else {
|
|
923
|
+
this.showMatrixAnswers = true
|
|
924
|
+
this.showExplanation = this.defaultShowExplanation === null ? true : this.defaultShowExplanation
|
|
925
|
+
this.selectedMatrixChoices = this.matrixAnswerKeys as TMatrixChoiceKey[]
|
|
926
|
+
}
|
|
756
927
|
}
|
|
757
928
|
|
|
758
929
|
stopReviewMode () {
|
|
759
930
|
this.showAnswers = false
|
|
931
|
+
this.showMatrixAnswers = false
|
|
760
932
|
this.showExplanation = false
|
|
761
933
|
this.selectedChoices = []
|
|
934
|
+
this.selectedMatrixChoices = []
|
|
762
935
|
}
|
|
763
936
|
|
|
764
937
|
updateSelectedChoices (choices: TChoiceKey[]) {
|
|
765
938
|
this.selectedChoices = [ ...choices ]
|
|
766
939
|
}
|
|
767
940
|
|
|
941
|
+
updateSelectedMatrixChoices (matrixChoices: TMatrixChoiceKey[]) {
|
|
942
|
+
this.selectedMatrixChoices = [ ...matrixChoices ]
|
|
943
|
+
}
|
|
944
|
+
|
|
768
945
|
// deterministic shuffling of choices so they don't change order everytime you reload the component
|
|
769
946
|
shuffleChoices (choices: TChoice[]): TChoice[] {
|
|
770
947
|
const sortedChoices = choices.sort((a, b) => {
|
|
@@ -936,6 +1113,21 @@ export default class Question extends Vue {
|
|
|
936
1113
|
}
|
|
937
1114
|
}
|
|
938
1115
|
|
|
1116
|
+
selectMatrixChoice (matrixChoiceKeys: TMatrixChoiceKey[]) {
|
|
1117
|
+
if (this.showMatrixAnswers) {
|
|
1118
|
+
return
|
|
1119
|
+
}
|
|
1120
|
+
this.selectedMatrixChoices = matrixChoiceKeys
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
answeredMatrixRowIndex (answeredRowIndexes: number[]) {
|
|
1124
|
+
if (this.showMatrixAnswers) {
|
|
1125
|
+
return
|
|
1126
|
+
}
|
|
1127
|
+
this.answeredMatrixRowIndexes = answeredRowIndexes
|
|
1128
|
+
this.allMatrixRowsAreAnswered = this.answeredMatrixRowIndexes.length === this.question.matrixLabels?.rows.length
|
|
1129
|
+
}
|
|
1130
|
+
|
|
939
1131
|
togglePassageImageLongAlt () {
|
|
940
1132
|
this.showPassageImageLongAlt = !this.showPassageImageLongAlt
|
|
941
1133
|
|
|
@@ -1080,6 +1272,29 @@ export default class Question extends Vue {
|
|
|
1080
1272
|
}
|
|
1081
1273
|
}
|
|
1082
1274
|
|
|
1275
|
+
clickCheckMatrixAnswer () {
|
|
1276
|
+
if (!this.hideAnswer) {
|
|
1277
|
+
this.showMatrixAnswers = true
|
|
1278
|
+
|
|
1279
|
+
this.emitCheckAnswer({
|
|
1280
|
+
isCorrect: this.isMatrixQuestionCorrect,
|
|
1281
|
+
selectedChoices: this.selectedMatrixChoices,
|
|
1282
|
+
questionSerial: this.question.serial,
|
|
1283
|
+
})
|
|
1284
|
+
|
|
1285
|
+
setTimeout(() => {
|
|
1286
|
+
const summaryMatrixComp =
|
|
1287
|
+
this.$refs['uikit-question__summary'] as ComponentPublicInstance | undefined
|
|
1288
|
+
const summaryMatrixExplanation =
|
|
1289
|
+
// eslint-disable-next-line max-len
|
|
1290
|
+
summaryMatrixComp?.$refs['uikit-question-summary__summary-toggle-explanation-text'] as HTMLElement | undefined
|
|
1291
|
+
if (summaryMatrixExplanation) {
|
|
1292
|
+
summaryMatrixExplanation?.focus()
|
|
1293
|
+
}
|
|
1294
|
+
}, 500)
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1083
1298
|
mappedNameRows (choiceKey: string) {
|
|
1084
1299
|
/*
|
|
1085
1300
|
There is a specific order in which we have to fill the rows in the table for visible names.
|
|
@@ -1140,6 +1355,11 @@ export default class Question extends Vue {
|
|
|
1140
1355
|
this.updateSelectedChoices(choices)
|
|
1141
1356
|
}
|
|
1142
1357
|
|
|
1358
|
+
@Watch('previousMatrixChoices', { deep: true })
|
|
1359
|
+
previousMatrixChoicesChanged (matrixChoice: TMatrixChoiceKey[]) {
|
|
1360
|
+
this.updateSelectedMatrixChoices(matrixChoice)
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1143
1363
|
@Emit('selectedChoices')
|
|
1144
1364
|
emitSelectedChoices (selectedChoices: Study.Cloud.IQuizAnswer) {
|
|
1145
1365
|
return selectedChoices
|
|
@@ -1155,6 +1375,16 @@ export default class Question extends Vue {
|
|
|
1155
1375
|
} as Study.Cloud.IQuizAnswer)
|
|
1156
1376
|
}
|
|
1157
1377
|
|
|
1378
|
+
@Watch('selectedMatrixChoices', { deep: true })
|
|
1379
|
+
selectedMatrixChoicesChanged () {
|
|
1380
|
+
this.emitSelectedChoices({
|
|
1381
|
+
isCorrect: this.selectedMatrixChoices.length === this.matrixAnswerKeys.length
|
|
1382
|
+
&& !this.selectedMatrixChoices.join(' ').includes('d'),
|
|
1383
|
+
selectedChoices: this.selectedMatrixChoices,
|
|
1384
|
+
questionSerial: this.question.serial,
|
|
1385
|
+
} as Study.Cloud.IQuizAnswer)
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1158
1388
|
@Watch('showExplanation')
|
|
1159
1389
|
showExplanationChanged () {
|
|
1160
1390
|
this.emitUpdateShowExplanation()
|
|
@@ -1637,5 +1867,16 @@ export default class Question extends Vue {
|
|
|
1637
1867
|
margin-top: 24px;
|
|
1638
1868
|
}
|
|
1639
1869
|
}
|
|
1870
|
+
|
|
1871
|
+
&__matrix-choices-container {
|
|
1872
|
+
display: block;
|
|
1873
|
+
@include breakpoint(black-bear) {
|
|
1874
|
+
display: none;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
&__mobile-matrix-choices-container {
|
|
1879
|
+
display: block;
|
|
1880
|
+
}
|
|
1640
1881
|
}
|
|
1641
1882
|
</style>
|