+
@@ -190,10 +154,10 @@
enhancedQuizManagementStrings,
} from 'kolibri-common/strings/enhancedQuizManagementStrings';
import useAccordion from 'kolibri-common/components/useAccordion';
- import { coreStrings } from 'kolibri.coreVue.mixins.commonCoreStrings';
+ import coreStrings from 'kolibri.utils.coreStrings';
import AccordionItem from 'kolibri-common/components/AccordionItem';
import AccordionContainer from 'kolibri-common/components/AccordionContainer';
- import { computed, watch } from 'kolibri.lib.vueCompositionApi';
+ import { computed, onMounted, watch } from 'kolibri.lib.vueCompositionApi';
import { toRefs } from '@vueuse/core';
import AttemptLogItem from './AttemptLogItem';
@@ -207,31 +171,17 @@
setup(props, { emit }) {
const { questionsLabel$, quizSectionsLabel$ } = enhancedQuizManagementStrings;
const { questionNumberLabel$ } = coreStrings;
- const { sections, selectedQuestionNumber } = toRefs(props);
+ const { currentSectionIndex, sections, selectedQuestionNumber } = toRefs(props);
const { expand, isExpanded, toggle } = useAccordion(sections);
/** Finds the section which the current attempt belongs to and expands it */
function expandCurrentSectionIfNeeded() {
- if (!sections.value || !sections.value.length) {
- return;
- }
- let qCount = 0;
- for (let i = 0; i < sections?.value?.length; i++) {
- qCount += sections?.value[i]?.questions?.length;
- if (qCount >= selectedQuestionNumber.value) {
- if (!isExpanded(i)) {
- expand(i);
- }
- break;
- }
+ if (!isExpanded(currentSectionIndex.value)) {
+ expand(currentSectionIndex.value);
}
}
- const allQuestionsInOrder = computed(() => {
- return sections.value.reduce((a, s) => [...a, ...s.questions], []);
- });
-
const sectionSelectOptions = computed(() => {
return sections.value.map((section, index) => ({
value: index,
@@ -239,33 +189,17 @@
}));
});
- const currentSectionIndex = computed(() => {
- let qCount = 0;
- for (let i = 0; i < sections.value.length; i++) {
- qCount += sections.value[i].questions.length;
- if (qCount >= selectedQuestionNumber.value) {
- return i;
- }
- }
- return 0;
- });
-
const currentSection = computed(() => {
return sections.value[currentSectionIndex.value];
});
const questionSelectOptions = computed(() => {
return currentSection.value.questions.map((question, index) => ({
- value: question.item,
+ value: index,
label: questionNumberLabel$({ questionNumber: index + 1 }),
}));
});
- // The question itself
- const currentQuestion = computed(() => {
- return allQuestionsInOrder.value[selectedQuestionNumber.value];
- });
-
// The KSelect-shaped object for the current section
const selectedSection = computed(() => {
return sectionSelectOptions.value[currentSectionIndex.value];
@@ -273,33 +207,24 @@
// The KSelect-shaped object for the current question
const selectedQuestion = computed(() => {
- return questionSelectOptions.value.find(opt => opt.value === currentQuestion.value.item);
+ return questionSelectOptions.value[
+ selectedQuestionNumber.value - currentSection.value.startQuestionNumber
+ ];
});
function handleQuestionChange(item) {
- const questionIndex = allQuestionsInOrder.value.findIndex(q => q.item === item);
- if (questionIndex !== -1) {
- emit('select', questionIndex);
- expandCurrentSectionIfNeeded();
- }
+ emit('select', item.value + currentSection.value.startQuestionNumber);
+ expandCurrentSectionIfNeeded();
}
function handleSectionChange(index) {
- const questionIndex = sections.value.slice(0, index).reduce((acc, s, i) => {
- if (i !== index) {
- acc += s.questions.length;
- return acc;
- } else {
- // This will always be the last iteration thanks to slice
- return acc + 1;
- }
- }, 0);
+ const questionIndex = sections.value[index].startQuestionNumber;
emit('select', questionIndex);
expandCurrentSectionIfNeeded();
}
watch(selectedQuestionNumber, expandCurrentSectionIfNeeded);
- expandCurrentSectionIfNeeded();
+ onMounted(expandCurrentSectionIfNeeded);
return {
handleSectionChange,
@@ -319,8 +244,11 @@
props: {
sections: {
type: Array,
- required: false,
- default: () => [],
+ required: true,
+ },
+ currentSectionIndex: {
+ type: Number,
+ required: true,
},
attemptLogs: {
type: Array,
diff --git a/kolibri/core/assets/src/views/ExamReport/index.vue b/kolibri/core/assets/src/views/ExamReport/index.vue
index f6a3672c48e..0378ed2be1e 100644
--- a/kolibri/core/assets/src/views/ExamReport/index.vue
+++ b/kolibri/core/assets/src/views/ExamReport/index.vue
@@ -94,7 +94,8 @@
:attemptLogs="attemptLogs"
:selectedQuestionNumber="questionNumber"
:isSurvey="isSurvey"
- :sections="sections"
+ :sections="annotatedSections"
+ :currentSectionIndex="currentSectionIndex"
@select="navigateToQuestion"
/>
@@ -115,7 +116,8 @@
:attemptLogs="attemptLogs"
:selectedQuestionNumber="questionNumber"
:isSurvey="isSurvey"
- :sections="sections"
+ :sections="annotatedSections"
+ :currentSectionIndex="currentSectionIndex"
@select="navigateToQuestion"
/>
-
{{ questionNumberInSectionLabel }}
+
{{ questionNumberInSectionLabel }}
+
+
+ {{ currentSection.description }}
+
[],
+ default: null,
},
// An array of questions in the format:
// {
@@ -353,19 +361,28 @@
};
},
computed: {
+ annotatedSections() {
+ return annotateSections(this.sections, this.questions);
+ },
+ currentSectionIndex() {
+ return this.annotatedSections.findIndex(
+ section =>
+ this.questionNumber >= section.startQuestionNumber &&
+ this.questionNumber <= section.endQuestionNumber,
+ );
+ },
+ currentSection() {
+ return this.annotatedSections[this.currentSectionIndex];
+ },
questionNumberInSectionLabel() {
- if (!this.sections) {
- return '';
- }
- for (let iSection = 0; iSection < this.sections.length; iSection++) {
- const section = this.sections[iSection];
- for (let iQuestion = 0; iQuestion < section.questions.length; iQuestion++) {
- if (section.questions[iQuestion].item === this.itemId) {
- return this.coreString('questionNumberLabel', { questionNumber: iQuestion + 1 });
- }
- }
+ const questionLabel = this.coreString('questionNumberLabel', {
+ questionNumber: this.questionNumber + 1,
+ });
+ if (this.annotatedSections.length === 1) {
+ return questionLabel;
}
- return '';
+ const sectionLabel = displaySectionTitle(this.currentSection, this.currentSectionIndex);
+ return `${sectionLabel} - ${questionLabel}`;
},
attemptLogs() {
if (this.isQuiz || this.isSurvey) {
diff --git a/kolibri/plugins/learn/assets/src/modules/examViewer/index.js b/kolibri/plugins/learn/assets/src/modules/examViewer/index.js
index 5a0c56df559..243c01409d0 100644
--- a/kolibri/plugins/learn/assets/src/modules/examViewer/index.js
+++ b/kolibri/plugins/learn/assets/src/modules/examViewer/index.js
@@ -20,36 +20,4 @@ export default {
Object.assign(state, defaultState());
},
},
- getters: {
- sections(state) {
- if (!state.exam.question_sources) return [];
- return state.exam.question_sources;
- },
- currentQuestion(state) {
- if (state.questions.length === 0) return null;
- return state.questions[state.questionNumber];
- },
- currentSection(state, { sections, currentSectionIndex }) {
- return sections[currentSectionIndex];
- },
- currentSectionIndex(state, { currentQuestion, sections }) {
- return sections.findIndex(section =>
- section.questions.map(q => q.item).includes(currentQuestion.item),
- );
- },
- sectionSelectOptions(state, { sections }) {
- return (
- sections.map((section, i) => ({
- label: displaySectionTitle(section, i),
- value: i,
- })) || []
- );
- },
- currentSectionOption(state, { currentSection, sectionSelectOptions }) {
- if (!currentSection) return {};
- return sectionSelectOptions.find(
- (opt, i) => opt.label === displaySectionTitle(currentSection, i),
- );
- },
- },
};
diff --git a/kolibri/plugins/learn/assets/src/views/ExamPage/AnswerHistory.vue b/kolibri/plugins/learn/assets/src/views/ExamPage/AnswerHistory.vue
index e3f69a4bb51..09ec8d3f184 100644
--- a/kolibri/plugins/learn/assets/src/views/ExamPage/AnswerHistory.vue
+++ b/kolibri/plugins/learn/assets/src/views/ExamPage/AnswerHistory.vue
@@ -13,7 +13,14 @@
@focus="expand(index)"
>
-