@pocketprep/ui-kit 3.5.30 → 3.7.0

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.
@@ -33,6 +33,8 @@
33
33
  'uikit-question__main--mcr': isMCR,
34
34
  'uikit-question__main--mcr-review-mode': isMCR && reviewMode,
35
35
  'uikit-question__main--matrix-question-review-mode': isMatrixQuestion && reviewMode,
36
+ 'uikit-question__main--mpmc-question-review-mode': isMPMCQuestion && reviewMode,
37
+ 'uikit-question__main--build-list-question-review-mode': isBuildListQuestion && reviewMode,
36
38
  }"
37
39
  >
38
40
  <div v-if="!showPassageAndImage && !showExplanation && !showPaywall">
@@ -100,7 +102,7 @@
100
102
  @upgradeClicked="emitUpgrade"
101
103
  />
102
104
  <div
103
- v-if="(showAnswers || showMatrixAnswers) && isTeachReview && isUnanswered"
105
+ v-if="(showAnswers || showMatrixAnswers || showMPMCAnswers) && isTeachReview && isUnanswered"
104
106
  v-dark="isDarkMode"
105
107
  class="uikit-question__unanswered-teach-review-label"
106
108
  >
@@ -117,9 +119,11 @@
117
119
  'uikit-question__choices--incorrect':
118
120
  showAnswers && (isMCR || isUnanswered) && !isCorrect && !isTeachReview,
119
121
  'uikit-question__choices--matrix': isMatrixQuestion,
122
+ 'uikit-question__choices--mpmc': isMPMCQuestion,
120
123
  'uikit-question__choices--unanswered': showAnswers && !isMCR && isUnanswered && !isCorrect,
121
124
  'uikit-question__choices--show-stats': globalMetrics,
122
- 'uikit-question__choices--no-actions': !(isMCR || isUnanswered || isMatrixQuestion)
125
+ 'uikit-question__choices--no-actions':
126
+ !(isMCR || isUnanswered || isMatrixQuestion || isBuildListQuestion || isMPMCQuestion)
123
127
  && !globalMetrics
124
128
  && (
125
129
  reviewMode
@@ -136,7 +140,16 @@
136
140
  "
137
141
  >
138
142
  <div
139
- v-if="showAnswers && !isMCR && !isMatrixQuestion && isUnanswered && !isCorrect && !isTeachReview"
143
+ v-if="
144
+ showAnswers
145
+ && !isMCR
146
+ && !isMatrixQuestion
147
+ && !isMPMCQuestion
148
+ && !isBuildListQuestion
149
+ && isUnanswered
150
+ && !isCorrect
151
+ && !isTeachReview
152
+ "
140
153
  v-dark="isDarkMode"
141
154
  class="uikit-question__unanswered-label"
142
155
  >
@@ -148,7 +161,11 @@
148
161
  />
149
162
  </div>
150
163
  <ChoicesContainer
151
- v-if="question.type !== 'Matrix Checkbox' && question.type !== 'Matrix Radio Button'"
164
+ v-if="
165
+ question.type !== 'Matrix Checkbox'
166
+ && question.type !== 'Matrix Radio Button'
167
+ && question.type !== 'Multi-Part Multiple Choice'
168
+ && question.type !== 'Build List'"
152
169
  ref="uikit-question__choices-container"
153
170
  @emitChoiceMouseOver="choiceMouseOver"
154
171
  @emitChoiceMouseLeave="choiceMouseLeave"
@@ -243,9 +260,34 @@
243
260
  <slot name="explanationBottomExperiment" />
244
261
  </template>
245
262
  </MobileMatrixChoicesContainer>
263
+ <MPMCChoicesContainer
264
+ v-if="question.type === 'Multi-Part Multiple Choice'"
265
+ class="uikit-question__mpmc-choices-container"
266
+ v-breakpoint="breakpointsWithEl"
267
+ @emitSelectedMPMCChoice="selectMPMCChoice"
268
+ >
269
+ <template #explanationBottomExperiment>
270
+ <slot name="explanationBottomExperiment" />
271
+ </template>
272
+ </MPMCChoicesContainer>
273
+ <BuildListChoicesContainer
274
+ v-if="question.type === 'Build List'"
275
+ class="uikit-question__build-list-choices-container"
276
+ v-breakpoint="breakpointsWithEl"
277
+ @reorderBuildList="handleBuildListReorder"
278
+ >
279
+ <template #explanationBottomExperiment>
280
+ <slot name="explanationBottomExperiment" />
281
+ </template>
282
+ </BuildListChoicesContainer>
246
283
  </div>
247
284
  <Summary
248
- v-if="((isMCR && showAnswers) || (isMatrixQuestion && showMatrixAnswers)) && !showPaywall"
285
+ v-if="
286
+ ((isMCR && showAnswers)
287
+ || (isMatrixQuestion && showMatrixAnswers))
288
+ || (isMPMCQuestion && showMPMCAnswers)
289
+ || (isBuildListQuestion && showBuildListOrder)
290
+ && !showPaywall"
249
291
  ref="uikit-question__summary"
250
292
  class="uikit-question__summary"
251
293
  @click="keywordClick"
@@ -294,7 +336,14 @@
294
336
  >
295
337
  <slot name="action">
296
338
  <PocketButton
297
- v-if="!showAnswers && !hideAnswer && (showCheckAnswer || isMCR) && !isMatrixQuestion"
339
+ v-if="
340
+ !showAnswers
341
+ && !hideAnswer
342
+ && (showCheckAnswer || isMCR)
343
+ && !isMatrixQuestion
344
+ && !isBuildListQuestion
345
+ && !isMPMCQuestion
346
+ "
298
347
  :disabled="!selectedChoices.length"
299
348
  :is-dark-mode="isDarkMode"
300
349
  @click="clickCheckAnswer"
@@ -310,14 +359,41 @@
310
359
  Check Answer
311
360
  </PocketButton>
312
361
  <PocketButton
313
- v-else-if="(showAnswers || showMatrixAnswers || hideAnswer) && (questionNumber >= quizLength)"
362
+ v-else-if="isBuildListQuestion && !showBuildListOrder && !hideAnswer"
363
+ :is-dark-mode="isDarkMode"
364
+ :disabled="!selectedBuildListChoiceOrder.length"
365
+ @click="clickCheckBuildListOrder"
366
+ >
367
+ Check Answer
368
+ </PocketButton>
369
+ <PocketButton
370
+ v-else-if="isMPMCQuestion && !showMPMCAnswers && !hideAnswer"
371
+ :disabled="!isMPMCQuestionAnswered"
372
+ :is-dark-mode="isDarkMode"
373
+ @click="clickCheckMPMCAnswer"
374
+ >
375
+ Check Answer
376
+ </PocketButton>
377
+
378
+ <PocketButton
379
+ v-else-if="(
380
+ showAnswers
381
+ || showMatrixAnswers
382
+ || showBuildListOrder
383
+ || showMPMCAnswers
384
+ || hideAnswer)
385
+ && (questionNumber >= quizLength)
386
+ "
314
387
  :is-dark-mode="isDarkMode"
315
388
  @click="emitSubmitQuiz"
316
389
  >
317
390
  Submit Quiz
318
391
  </PocketButton>
319
392
  <PocketButton
320
- v-else-if="(showAnswers || showMatrixAnswers || hideAnswer ) && showNextQuestion"
393
+ v-else-if="
394
+ (showAnswers || showMatrixAnswers || showBuildListOrder || showMPMCAnswers || hideAnswer )
395
+ && showNextQuestion
396
+ "
321
397
  :is-dark-mode="isDarkMode"
322
398
  @click="emitNextQuestion"
323
399
  >
@@ -341,6 +417,7 @@
341
417
  :class="{
342
418
  'uikit-question__right-side--explanation': showExplanation && !showPaywall,
343
419
  'uikit-question__right-side--matrix-question-review-mode': isMatrixQuestion && reviewMode,
420
+ 'uikit-question__right-side--mpmc-question-review-mode': isMPMCQuestion && reviewMode,
344
421
  }"
345
422
  >
346
423
  <PassageAndImage
@@ -382,6 +459,8 @@ import Explanation from '../Quiz/Question/Explanation.vue'
382
459
  import PassageAndImage from '../Quiz/Question/PassageAndImage.vue'
383
460
  import MatrixChoicesContainer from '../Quiz/Question/MatrixChoicesContainer.vue'
384
461
  import MobileMatrixChoicesContainer from '../Quiz/Question/MobileMatrixChoicesContainer.vue'
462
+ import MPMCChoicesContainer from '../Quiz/Question/MPMCChoicesContainer.vue'
463
+ import BuildListChoicesContainer from './Question/BuildListChoicesContainer.vue'
385
464
  import type { Study } from '@pocketprep/types'
386
465
  import { highlightKeywordsInText, studyModes } from '../../utils'
387
466
  import type {
@@ -389,9 +468,12 @@ import type {
389
468
  TQuizMode,
390
469
  TChoiceKey,
391
470
  TMatrixChoiceKey,
471
+ TBuildListChoiceKey,
392
472
  TChoice,
473
+ TBuildListChoice,
393
474
  TChoiceScores,
394
475
  TMatrixChoiceScores,
476
+ TBuildListChoiceScores,
395
477
  TViewNames,
396
478
  IScenarioSerial,
397
479
  } from './question'
@@ -411,6 +493,8 @@ const props = withDefaults(defineProps<{
411
493
  reviewMode?: boolean
412
494
  previousChoices?: TChoiceKey[] | null
413
495
  previousMatrixChoices?: TMatrixChoiceKey[] | null
496
+ previousMultiPartMultipleChoiceChoices?: TChoiceKey[] | null
497
+ previousBuildListChoices?: TBuildListChoiceKey[] | null
414
498
  globalMetrics?: Study.Class.GlobalQuestionMetricJSON | null
415
499
  showNames?: TViewNames | null
416
500
  allowKeyboardShortcuts?: boolean
@@ -435,6 +519,8 @@ const props = withDefaults(defineProps<{
435
519
  reviewMode: false,
436
520
  previousChoices: null,
437
521
  previousMatrixChoices: null,
522
+ previousMultiPartMultipleChoiceChoices: null,
523
+ previousBuildListChoices: null,
438
524
  globalMetrics: null,
439
525
  showNames: null,
440
526
  allowKeyboardShortcuts: true,
@@ -488,8 +574,12 @@ const focusChoiceKey = ref<TChoiceKey | null>(null)
488
574
  const choiceStrikes = ref<TChoiceKey[]>([])
489
575
  const selectedChoices = ref<TChoiceKey[]>([])
490
576
  const selectedMatrixChoices = ref<TMatrixChoiceKey[]>([])
577
+ const selectedMPMCChoices = ref<TChoiceKey[]>([])
578
+ const selectedBuildListChoiceOrder = ref<TBuildListChoiceKey[]>([])
491
579
  const showAnswers = ref(false)
492
580
  const showMatrixAnswers = ref(false)
581
+ const showMPMCAnswers = ref(false)
582
+ const showBuildListOrder = ref(false)
493
583
  const showExplanation = ref(false)
494
584
  const showPassageImageLongAlt = ref(false)
495
585
  const showExplanationImageLongAlt = ref(false)
@@ -517,6 +607,7 @@ const questionSummaryRef = useTemplateRef<{
517
607
  mcrLongAltEl?: HTMLElement
518
608
  summaryMCRExplanationEl?: HTMLElement
519
609
  summaryMatrixExplanationEl?: HTMLElement
610
+ summaryBuildListExplanationEl?: HTMLElement
520
611
  }>('uikit-question__summary')
521
612
  const questionExplanationRef = useTemplateRef<{
522
613
  explanationTitleEl?: HTMLElement
@@ -561,6 +652,14 @@ const isMatrixQuestion = computed(() => {
561
652
  return props.question.type === 'Matrix Checkbox' || props.question.type === 'Matrix Radio Button'
562
653
  })
563
654
 
655
+ const isMPMCQuestion = computed(() => {
656
+ return props.question.type === 'Multi-Part Multiple Choice'
657
+ })
658
+
659
+ const isBuildListQuestion = computed(() => {
660
+ return props.question.type === 'Build List'
661
+ })
662
+
564
663
  const questionScenario = computed(() => {
565
664
  return props.question.questionScenario as Study.Class.QuestionScenarioJSON | undefined
566
665
  })
@@ -648,6 +747,16 @@ const matrixAnswerKeys = computed<TMatrixChoiceKey[]>(() => {
648
747
  return [] as TMatrixChoiceKey[]
649
748
  })
650
749
 
750
+ const correctOrderBuildListAnswerKeys = computed((): TBuildListChoiceKey[] => {
751
+ const buildListChoices = props.question.choices.map(choice => choice.id) as TBuildListChoiceKey[]
752
+ return buildListChoices
753
+ .sort((a, b) => {
754
+ const aNum = Number(a.substring(1))
755
+ const bNum = Number(b.substring(1))
756
+ return aNum - bNum
757
+ })
758
+ })
759
+
651
760
  const distractors = computed((): TChoice[] => {
652
761
  return props.question.choices.filter(choice => !choice.isCorrect).map((choice, index) => ({
653
762
  text: choice.text,
@@ -666,6 +775,32 @@ const choices = computed(() => {
666
775
  ])
667
776
  })
668
777
 
778
+ const buildListChoices = computed(() => {
779
+ const blChoices = props.question.choices.map(choice => {
780
+ return {
781
+ text: choice.text,
782
+ key: choice.id as TBuildListChoiceKey,
783
+ }
784
+ })
785
+
786
+ const shuffledChoices = shuffleBuildListChoices([ ...blChoices ])
787
+
788
+ // Check if the shuffled array is in correct order
789
+ const isInCorrectOrder = shuffledChoices.every((choice, index) => {
790
+ const expectedNumber = index + 1
791
+ const actualNumber = Number(choice.key.substring(1))
792
+ return actualNumber === expectedNumber
793
+ })
794
+
795
+ // If it is in the correct order, then we need to switch the first and second element
796
+ if (isInCorrectOrder && shuffledChoices.length >= 2) {
797
+ const [ first, second, ...rest ] = shuffledChoices
798
+ return [ second, first, ...rest ] as TBuildListChoice[]
799
+ }
800
+
801
+ return shuffledChoices
802
+ })
803
+
669
804
  const isCorrect = computed(() => {
670
805
  // In order to be correct, user must have selected all the answers and none of the distractors
671
806
  return showAnswers.value
@@ -679,6 +814,20 @@ const isMatrixQuestionCorrect = computed(() => {
679
814
  && !selectedMatrixChoices.value.join(' ').includes('d')
680
815
  })
681
816
 
817
+ const isMPMCQuestionCorrect = computed(() => {
818
+ return showMPMCAnswers.value
819
+ && selectedMPMCChoices.value.length === answerKeys.value.length
820
+ && !selectedMPMCChoices.value.join(' ').includes('d')
821
+ })
822
+
823
+ const isBuildListOrderCorrect = computed(() => {
824
+ return showBuildListOrder.value
825
+ && correctOrderBuildListAnswerKeys.value.length === selectedBuildListChoiceOrder.value.length
826
+ && correctOrderBuildListAnswerKeys.value.every(
827
+ (item, index) => item === selectedBuildListChoiceOrder.value[index]
828
+ )
829
+ })
830
+
682
831
  const choiceScores = computed((): TChoiceScores => {
683
832
  const metrics = globalMetrics.value
684
833
  const scores: TChoiceScores = {
@@ -718,7 +867,49 @@ const matrixChoiceScores = computed((): TMatrixChoiceScores => {
718
867
  const scores: TMatrixChoiceScores = {
719
868
  totalAnswered: selectedMatrixChoices.value.length &&
720
869
  showMatrixAnswers && !props.reviewMode ? 1 : 0,
721
- answeredCorrectly: isCorrect.value && !props.reviewMode ? 1 : 0,
870
+ answeredCorrectly: isMatrixQuestionCorrect.value && !props.reviewMode ? 1 : 0,
871
+ }
872
+
873
+ if (!metrics) {
874
+ return scores
875
+ }
876
+
877
+ scores.totalAnswered += (
878
+ (metrics.answeredCorrectlyCount || 0)
879
+ + (metrics.answeredIncorrectlyCount || 0)
880
+ )
881
+ scores.answeredCorrectly += (metrics.answeredCorrectlyCount || 0)
882
+ return scores
883
+ })
884
+
885
+ const mpmcChoiceScores = computed((): TChoiceScores => {
886
+ const metrics = props.globalMetrics
887
+
888
+ const scores: TChoiceScores = {
889
+ totalAnswered: selectedMPMCChoices.value.length &&
890
+ showMPMCAnswers && !props.reviewMode ? 1 : 0,
891
+ answeredCorrectly: isMPMCQuestionCorrect.value && !props.reviewMode ? 1 : 0,
892
+ }
893
+
894
+ if (!metrics) {
895
+ return scores
896
+ }
897
+
898
+ scores.totalAnswered += (
899
+ (metrics.answeredCorrectlyCount || 0)
900
+ + (metrics.answeredIncorrectlyCount || 0)
901
+ )
902
+ scores.answeredCorrectly += (metrics.answeredCorrectlyCount || 0)
903
+ return scores
904
+ })
905
+
906
+ const buildListChoiceScores = computed((): TBuildListChoiceScores => {
907
+ const metrics = props.globalMetrics
908
+
909
+ const scores: TBuildListChoiceScores = {
910
+ totalAnswered: selectedBuildListChoiceOrder.value.length &&
911
+ showBuildListOrder && !props.reviewMode ? 1 : 0,
912
+ answeredCorrectly: isBuildListOrderCorrect.value && !props.reviewMode ? 1 : 0,
722
913
  }
723
914
 
724
915
  if (!metrics) {
@@ -754,12 +945,38 @@ const isMatrixQuestionAnswered = computed(() => {
754
945
  return false
755
946
  })
756
947
 
948
+ const isMPMCQuestionAnswered = computed(() => {
949
+ const mpmcLabels = question.value.mpmcLabels
950
+ const mpmcChoices = question.value.choices
951
+ const selectedMPMCLabelIndexes: number[] = []
952
+
953
+ selectedMPMCChoices.value.forEach(choice => {
954
+ const mpmcChoiceObj = mpmcChoices.find(c => c.id === choice)
955
+ if (
956
+ mpmcChoiceObj?.labelIndex !== undefined
957
+ && !selectedMPMCLabelIndexes.includes(mpmcChoiceObj?.labelIndex)
958
+ ) {
959
+ selectedMPMCLabelIndexes.push(mpmcChoiceObj?.labelIndex)
960
+ }
961
+ })
962
+
963
+ return mpmcLabels?.length === selectedMPMCLabelIndexes.length
964
+ })
965
+
757
966
  const isUnanswered = computed(() => {
758
- if (!isMatrixQuestion.value) {
759
- return selectedChoices.value.length === 0
967
+ if (isBuildListQuestion.value) {
968
+ return selectedBuildListChoiceOrder.value.length === 0
969
+ }
970
+
971
+ if (isMPMCQuestion.value) {
972
+ return !isMPMCQuestionAnswered.value
760
973
  }
761
974
 
762
- return !isMatrixQuestionAnswered.value
975
+ if (isMatrixQuestion.value) {
976
+ return !isMatrixQuestionAnswered.value
977
+ }
978
+
979
+ return selectedChoices.value.length === 0
763
980
  })
764
981
 
765
982
  const prompt = computed(() => {
@@ -854,20 +1071,28 @@ const keywordClick = (event: MouseEvent) => {
854
1071
  }
855
1072
 
856
1073
  const startReviewMode = () => {
857
- if (!isMatrixQuestion.value) {
858
- showAnswers.value = true
859
- showExplanation.value = props.defaultShowExplanation === null ? true : props.defaultShowExplanation
860
- selectedChoices.value = answerKeys.value
861
- } else {
1074
+ showExplanation.value = props.defaultShowExplanation === null ? true : props.defaultShowExplanation
1075
+
1076
+ if (isBuildListQuestion.value) {
1077
+ showBuildListOrder.value = true
1078
+ selectedBuildListChoiceOrder.value = correctOrderBuildListAnswerKeys.value
1079
+ } else if (isMPMCQuestion.value) {
1080
+ showMPMCAnswers.value = true
1081
+ selectedMPMCChoices.value = answerKeys.value
1082
+ } else if (isMatrixQuestion.value) {
862
1083
  showMatrixAnswers.value = true
863
- showExplanation.value = props.defaultShowExplanation === null ? true : props.defaultShowExplanation
864
1084
  selectedMatrixChoices.value = matrixAnswerKeys.value
1085
+ } else {
1086
+ showAnswers.value = true
1087
+ selectedChoices.value = answerKeys.value
865
1088
  }
866
1089
  }
867
1090
 
868
1091
  const stopReviewMode = () => {
869
1092
  showAnswers.value = false
870
1093
  showMatrixAnswers.value = false
1094
+ showMPMCAnswers.value = false
1095
+ showBuildListOrder.value = false
871
1096
  showExplanation.value = false
872
1097
  selectedChoices.value = []
873
1098
  selectedMatrixChoices.value = []
@@ -881,8 +1106,16 @@ const updateSelectedMatrixChoices = (matrixChoices: TMatrixChoiceKey[]) => {
881
1106
  selectedMatrixChoices.value = [ ...matrixChoices ]
882
1107
  }
883
1108
 
1109
+ const updateSelectedMPMCChoices = (updatedChoices: TChoiceKey[]) => {
1110
+ selectedMPMCChoices.value = [ ...updatedChoices ]
1111
+ }
1112
+
1113
+ const updateSelectedBuildListChoiceOrder = (buildListChoiceOrder: TBuildListChoiceKey[]) => {
1114
+ selectedBuildListChoiceOrder.value = [ ...buildListChoiceOrder ]
1115
+ }
1116
+
884
1117
  // deterministic shuffling of choices so they don't change order everytime you reload the component
885
- const shuffleChoices = (choicesToShuffle: TChoice[]): TChoice[] => {
1118
+ const shuffleChoices = (choicesToShuffle: TChoice[]): TChoice[]=> {
886
1119
  const sortedChoices = choicesToShuffle.sort((a, b) => {
887
1120
  const hashChar = (char: string, num: number) => ((num << 5) - num) + char.charCodeAt(0)
888
1121
 
@@ -906,6 +1139,30 @@ const shuffleChoices = (choicesToShuffle: TChoice[]): TChoice[] => {
906
1139
  : sortedChoices
907
1140
  }
908
1141
 
1142
+ const shuffleBuildListChoices = (choicesToShuffle: TBuildListChoice[]): TBuildListChoice[]=> {
1143
+ const sortedChoices = choicesToShuffle.sort((a, b) => {
1144
+ const hashChar = (char: string, num: number) => ((num << 5) - num) + char.charCodeAt(0)
1145
+
1146
+ const aHash = a.text?.split('')
1147
+ .reduce((acc: number, char: string) => hashChar(char, acc) & hashChar(char, acc), 0)
1148
+ const bHash = b.text?.split('')
1149
+ .reduce((acc: number, char: string) => hashChar(char, acc) & hashChar(char, acc), 0)
1150
+
1151
+ return (aHash || 0) - (bHash || 0)
1152
+ })
1153
+
1154
+ return props.answerSeed
1155
+ ? props.answerSeed.reduce<TBuildListChoice[]>((acc, i) => {
1156
+ const sortedChoice = sortedChoices[i]
1157
+ if (sortedChoice) {
1158
+ acc.push(sortedChoice)
1159
+ }
1160
+
1161
+ return acc
1162
+ }, [])
1163
+ : sortedChoices
1164
+ }
1165
+
909
1166
  const choiceFocusOut = (event: FocusEvent) => {
910
1167
  const relatedTarget = event.relatedTarget
911
1168
  if (
@@ -1050,6 +1307,21 @@ const selectMatrixChoice = (matrixChoiceKeys: TMatrixChoiceKey[]) => {
1050
1307
  selectedMatrixChoices.value = matrixChoiceKeys
1051
1308
  }
1052
1309
 
1310
+ const selectMPMCChoice = (mpmcChoiceKeys: TChoiceKey[]) => {
1311
+ if (showMPMCAnswers.value) {
1312
+ return
1313
+ }
1314
+ selectedMPMCChoices.value = mpmcChoiceKeys
1315
+ }
1316
+
1317
+ const handleBuildListReorder = (reorderedChoices: TBuildListChoice[]) => {
1318
+ if (showBuildListOrder.value) {
1319
+ return
1320
+ }
1321
+
1322
+ selectedBuildListChoiceOrder.value = reorderedChoices.map(choice => choice.key)
1323
+ }
1324
+
1053
1325
  const togglePassageImageLongAlt = () => {
1054
1326
  showPassageImageLongAlt.value = !showPassageImageLongAlt.value
1055
1327
 
@@ -1151,6 +1423,41 @@ const clickCheckMatrixAnswer = () => {
1151
1423
  }
1152
1424
  }
1153
1425
 
1426
+ const clickCheckMPMCAnswer = () => {
1427
+ if (!props.hideAnswer) {
1428
+ showMPMCAnswers.value = true
1429
+
1430
+ emitCheckAnswer({
1431
+ isCorrect: isMPMCQuestionCorrect.value,
1432
+ selectedChoices: selectedMPMCChoices.value,
1433
+ questionSerial: props.question.serial,
1434
+ })
1435
+
1436
+ const summaryMatrixExplanationEl = questionSummaryRef?.value?.summaryMatrixExplanationEl
1437
+ if (summaryMatrixExplanationEl) {
1438
+ summaryMatrixExplanationEl?.focus()
1439
+ }
1440
+ }
1441
+ }
1442
+
1443
+ const clickCheckBuildListOrder = () => {
1444
+ if (!props.hideAnswer) {
1445
+ showBuildListOrder.value = true
1446
+
1447
+ emitCheckAnswer({
1448
+ isCorrect: isBuildListOrderCorrect.value,
1449
+ selectedChoices: selectedBuildListChoiceOrder.value,
1450
+ questionSerial: props.question.serial,
1451
+ })
1452
+
1453
+ const summaryBuildListExplanationEl = questionSummaryRef?.value?.summaryBuildListExplanationEl
1454
+
1455
+ if (summaryBuildListExplanationEl) {
1456
+ summaryBuildListExplanationEl?.focus()
1457
+ }
1458
+ }
1459
+ }
1460
+
1154
1461
  watch(reviewMode, () => {
1155
1462
  if (reviewMode.value) {
1156
1463
  startReviewMode()
@@ -1171,6 +1478,21 @@ watch(() => props.previousMatrixChoices, (previousMatrixChoices: TMatrixChoiceKe
1171
1478
  }
1172
1479
  }, { deep: true })
1173
1480
 
1481
+ watch(() =>
1482
+ props.previousMultiPartMultipleChoiceChoices,
1483
+ (previousMultiPartMultipleChoiceChoices: TChoiceKey[] | undefined | null
1484
+ ) => {
1485
+ if (previousMultiPartMultipleChoiceChoices) {
1486
+ updateSelectedMPMCChoices(previousMultiPartMultipleChoiceChoices)
1487
+ }
1488
+ }, { deep: true })
1489
+
1490
+ watch(() => props.previousBuildListChoices, (previousBuildListChoices: TBuildListChoiceKey[] | undefined | null) => {
1491
+ if (previousBuildListChoices) {
1492
+ updateSelectedBuildListChoiceOrder(previousBuildListChoices)
1493
+ }
1494
+ }, { deep: true })
1495
+
1174
1496
  watch(selectedChoices, () => {
1175
1497
  emitSelectedChoices({
1176
1498
  isCorrect: selectedChoices.value.length === answerKeys.value.length
@@ -1189,6 +1511,25 @@ watch(selectedMatrixChoices, () => {
1189
1511
  } as Study.Cloud.IQuizAnswer)
1190
1512
  }, { deep: true })
1191
1513
 
1514
+ watch(selectedBuildListChoiceOrder, () => {
1515
+ emitSelectedChoices({
1516
+ isCorrect: correctOrderBuildListAnswerKeys.value.length === selectedBuildListChoiceOrder.value.length
1517
+ && correctOrderBuildListAnswerKeys.value.every(
1518
+ (item, index) => item === selectedBuildListChoiceOrder.value[index]),
1519
+ selectedChoices: selectedBuildListChoiceOrder.value,
1520
+ questionSerial: props.question.serial,
1521
+ } as Study.Cloud.IQuizAnswer)
1522
+ }, { deep: true })
1523
+
1524
+ watch(selectedMPMCChoices, () => {
1525
+ emitSelectedChoices({
1526
+ isCorrect: selectedMPMCChoices.value.length === answerKeys.value.length
1527
+ && !selectedMPMCChoices.value.join(' ').includes('d'),
1528
+ selectedChoices: selectedMPMCChoices.value,
1529
+ questionSerial: props.question.serial,
1530
+ } as Study.Cloud.IQuizAnswer)
1531
+ }, { deep: true })
1532
+
1192
1533
  watch(showExplanation, () => {
1193
1534
  emitUpdateShowExplanation()
1194
1535
  })
@@ -1229,7 +1570,7 @@ if (props.reviewMode) {
1229
1570
  startReviewMode()
1230
1571
  }
1231
1572
 
1232
- if (!isMatrixQuestion.value && props.previousChoices) {
1573
+ if (!isMatrixQuestion.value && !isMPMCQuestion.value && !isBuildListQuestion.value && props.previousChoices) {
1233
1574
  updateSelectedChoices(props.previousChoices)
1234
1575
  }
1235
1576
 
@@ -1237,12 +1578,22 @@ if (isMatrixQuestion.value && props.previousMatrixChoices) {
1237
1578
  updateSelectedMatrixChoices(props.previousMatrixChoices)
1238
1579
  }
1239
1580
 
1581
+ if (isBuildListQuestion.value && props.previousBuildListChoices) {
1582
+ updateSelectedBuildListChoiceOrder(props.previousBuildListChoices)
1583
+ }
1584
+
1585
+ if (isMPMCQuestion.value && props.previousMultiPartMultipleChoiceChoices) {
1586
+ updateSelectedMPMCChoices(props.previousMultiPartMultipleChoiceChoices)
1587
+ }
1588
+
1240
1589
  onMounted(() => {
1241
1590
  questionEl.value = props.containerEl || questionRef.value
1242
1591
 
1243
1592
  if (props.initialShowAnswers) {
1244
1593
  showAnswers.value = props.initialShowAnswers
1245
1594
  showMatrixAnswers.value = props.initialShowAnswers
1595
+ showMPMCAnswers.value = props.initialShowAnswers
1596
+ showBuildListOrder.value = props.initialShowAnswers
1246
1597
  }
1247
1598
 
1248
1599
  if (props.allowKeyboardShortcuts) {
@@ -1269,6 +1620,7 @@ onBeforeUnmount(() => {
1269
1620
  // Provide question context once, instead of passing as props to every child
1270
1621
  provide(InjectionKeys.questionKey, question)
1271
1622
  provide(InjectionKeys.choicesKey, choices)
1623
+ provide(InjectionKeys.buildListChoicesKey, buildListChoices)
1272
1624
  provide(InjectionKeys.questionElKey, questionEl)
1273
1625
  provide(InjectionKeys.breakpointsWithElKey, breakpointsWithEl)
1274
1626
  provide(InjectionKeys.quizLengthKey, quizLength)
@@ -1279,6 +1631,8 @@ provide(InjectionKeys.isCorrectKey, isCorrect)
1279
1631
  provide(InjectionKeys.contextIconTypeKey, contextIconType)
1280
1632
  provide(InjectionKeys.showAnswersKey, showAnswers)
1281
1633
  provide(InjectionKeys.showMatrixAnswersKey, showMatrixAnswers)
1634
+ provide(InjectionKeys.showMPMCAnswersKey, showMPMCAnswers)
1635
+ provide(InjectionKeys.showBuildListOrderKey, showBuildListOrder)
1282
1636
  provide(InjectionKeys.imageUrlPrefixKey, imageUrlPrefix)
1283
1637
  provide(InjectionKeys.passageImageUrlKey, passageImageUrl)
1284
1638
  provide(InjectionKeys.passageImageAltKey, passageImageAlt)
@@ -1307,10 +1661,18 @@ provide(InjectionKeys.keywordDefinitionsKey, keywordDefinitions)
1307
1661
  provide(InjectionKeys.showPaywallKey, showPaywall)
1308
1662
  provide(InjectionKeys.showPassageAndImageKey, showPassageAndImage)
1309
1663
  provide(InjectionKeys.isMatrixQuestionKey, isMatrixQuestion)
1664
+ provide(InjectionKeys.isMPMCQuestionKey, isMPMCQuestion)
1310
1665
  provide(InjectionKeys.matrixChoiceScoresKey, matrixChoiceScores)
1666
+ provide(InjectionKeys.mpmcChoiceScoresKey, mpmcChoiceScores)
1311
1667
  provide(InjectionKeys.isMatrixQuestionCorrectKey, isMatrixQuestionCorrect)
1668
+ provide(InjectionKeys.isMPMCQuestionCorrectKey, isMPMCQuestionCorrect)
1312
1669
  provide(InjectionKeys.matrixAnswerKeysKey, matrixAnswerKeys)
1313
1670
  provide(InjectionKeys.selectedMatrixChoicesKey, selectedMatrixChoices)
1671
+ provide(InjectionKeys.selectedMPMCChoicesKey, selectedMPMCChoices)
1672
+ provide(InjectionKeys.isBuildListQuestionKey, isBuildListQuestion)
1673
+ provide(InjectionKeys.buildListChoiceScoresKey, buildListChoiceScores)
1674
+ provide(InjectionKeys.isBuildListOrderCorrectKey, isBuildListOrderCorrect)
1675
+ provide(InjectionKeys.selectedBuildListChoiceOrderKey, selectedBuildListChoiceOrder)
1314
1676
  provide(InjectionKeys.isTeachGroupReviewKey, isTeachGroupReview)
1315
1677
  </script>
1316
1678
 
@@ -1392,16 +1754,19 @@ provide(InjectionKeys.isTeachGroupReviewKey, isTeachGroupReview)
1392
1754
  padding: 0 17px;
1393
1755
  }
1394
1756
 
1395
- &--matrix-question-review-mode#{&}--tablet-landscape:not(&--tablet-portrait) {
1757
+ &--matrix-question-review-mode#{&}--tablet-landscape:not(&--tablet-portrait),
1758
+ &--mpmc-question-review-mode#{&}--tablet-landscape:not(&--tablet-portrait) {
1396
1759
  width: 100%;
1397
1760
  padding-right: 42px;
1398
1761
  }
1399
1762
 
1400
- &--matrix-question-review-mode#{&}--mobile {
1763
+ &--matrix-question-review-mode#{&}--mobile,
1764
+ &--mpmc-question-review-mode#{&}--mobile {
1401
1765
  overflow-y: scroll;
1402
1766
  }
1403
1767
 
1404
- &--mcr-review-mode#{&}--mobile {
1768
+ &--mcr-review-mode#{&}--mobile,
1769
+ &--build-list-question-review-mode#{&}--mobile {
1405
1770
  overflow-y: scroll;
1406
1771
  width: 100%;
1407
1772
  padding-right: 17px;
@@ -1421,7 +1786,8 @@ provide(InjectionKeys.isTeachGroupReviewKey, isTeachGroupReview)
1421
1786
  display: none;
1422
1787
  }
1423
1788
 
1424
- &--matrix-question-review-mode#{&}--tablet-landscape {
1789
+ &--matrix-question-review-mode#{&}--tablet-landscape,
1790
+ &--mpmc-question-review-mode#{&}--tablet-landscape {
1425
1791
  display: none;
1426
1792
  }
1427
1793
 
@@ -1727,6 +2093,10 @@ provide(InjectionKeys.isTeachGroupReviewKey, isTeachGroupReview)
1727
2093
  &--matrix {
1728
2094
  max-width: 518px;
1729
2095
  }
2096
+
2097
+ &--mpmc {
2098
+ max-width: 518px;
2099
+ }
1730
2100
  }
1731
2101
 
1732
2102
  &__unanswered-label {