Skip to content

Commit

Permalink
feat: add toggleCorrectResponse method to display correct answer in Q…
Browse files Browse the repository at this point in the history
…tiMatchInteraction
  • Loading branch information
Patrick de Klein committed Feb 18, 2025
1 parent 6f25014 commit 5f2e7f6
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { DragDropInteractionMixin } from '../internal/drag-drop/drag-drop-intera
import styles from './qti-match-interaction.styles';
import { Interaction } from '../../../exports/interaction';

import type { ResponseVariable } from '../../../exports/variables';
import type { CSSResultGroup } from 'lit';
import type { ResponseInteraction } from '../../../exports/expression-result';
import type { QtiSimpleAssociableChoice } from '../qti-simple-associable-choice';
Expand Down Expand Up @@ -96,6 +97,53 @@ export class QtiMatchInteraction extends DragDropInteractionMixin(
);
};

public toggleCorrectResponse(responseVariable: ResponseVariable, show: boolean): void {
if (show && responseVariable.correctResponse) {
let matches: { text: string; gap: string }[] = [];
const response = Array.isArray(responseVariable.correctResponse)
? responseVariable.correctResponse
: [responseVariable.correctResponse];

if (response) {
matches = response.map(x => {
const split = x.split(' ');
return { text: split[0], gap: split[1] };
});
}

const gaps = this.querySelectorAll('qti-simple-match-set > qti-simple-associable-choice');
gaps.forEach(gap => {
const identifier = gap.getAttribute('identifier');
const textIdentifier = matches.find(x => x.gap === identifier)?.text;
const text = this.querySelector(
`qti-simple-associable-choice[identifier="${textIdentifier}"]`
)?.textContent.trim();
if (textIdentifier && text) {
if (!gap.nextElementSibling?.classList.contains('correct-option')) {
const textSpan = document.createElement('span');
textSpan.classList.add('correct-option');
textSpan.textContent = text;

// Apply styles
textSpan.style.border = '1px solid var(--qti-correct)';
textSpan.style.borderRadius = '4px';
textSpan.style.padding = '2px 4px';
textSpan.style.display = 'inline-block';

gap.insertAdjacentElement('beforebegin', textSpan);
}
} else if (gap.nextElementSibling?.classList.contains('correct-option')) {
gap.nextElementSibling.remove();
}
});
} else {
const correctOptions = this.querySelectorAll('.correct-option');
correctOptions.forEach(option => {
option.remove();
});
}
}

set correctResponse(responseValue: string | string[]) {
if (responseValue === '') {
this.correctOptions = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';

import { DragDropInteractionMixin } from '../internal/drag-drop/drag-drop-interaction-mixin';
import { ShuffleMixin } from '../internal/shuffle/shuffle-mixin'; // Import the mixin
import { Interaction } from '../../../exports/interaction';
import styles from './qti-order-interaction.styles';

import type { ResponseVariable } from '../../../exports/variables';
import type { QtiSimpleChoice } from '../qti-simple-choice';
@customElement('qti-order-interaction')
export class QtiOrderInteraction extends ShuffleMixin(
Expand Down Expand Up @@ -34,38 +34,61 @@ export class QtiOrderInteraction extends ShuffleMixin(
<div part="container">
<slot part="drags"> </slot>
<div part="drops">
${Array.from(Array(this.nrChoices)).map(
(_, i) =>
html`<drop-list part="drop-list" identifier="droplist${i}"></drop-list>${this.showCorrectResponses &&
this.correctResponses.length > i
? unsafeHTML(`<span part='correct-response'>${this.correctResponses[i]}</span>`)
: ''}`
${[...Array(this.nrChoices)].map(
(_, i) => html`<drop-list part="drop-list" identifier="droplist${i}"></drop-list>`
)}
</div>
</div>`;
}

set correctResponse(value: string | string[]) {
if (value === '') {
this.showCorrectResponses = false;
return;
}
public toggleCorrectResponse(responseVariable: ResponseVariable, show: boolean): void {
if (show && responseVariable.correctResponse) {
let matches: { text: string }[] = [];
const response = Array.isArray(responseVariable.correctResponse)
? responseVariable.correctResponse
: [responseVariable.correctResponse];

if (this.correctResponses.length === 0) {
const responses = Array.isArray(value) ? value : [value];
if (response) {
matches = response.map(x => {
const split = x.split(' ');
return { text: split[0] };
});
}

responses.forEach(response => {
let simpleChoice = this.querySelector(`qti-simple-choice[identifier="${response}"]`);
if (!simpleChoice) {
simpleChoice = this.shadowRoot.querySelector(`qti-simple-choice[identifier="${response}"]`);
}
const gaps = this.querySelectorAll('qti-simple-choice');
gaps.forEach((gap, i) => {
const identifier = gap.getAttribute('identifier');
const textIdentifier = matches.find(x => x.text === identifier)?.text;
const text = this.querySelector(`qti-simple-choice[identifier="${textIdentifier}"]`)?.textContent.trim();
if (textIdentifier && text) {
if (!gap.nextElementSibling?.classList.contains('correct-option')) {
const textSpan = document.createElement('span');
textSpan.classList.add('correct-option');
textSpan.textContent = text;

// Apply styles
textSpan.style.border = '1px solid var(--qti-correct)';
textSpan.style.borderRadius = '4px';
textSpan.style.padding = '2px 4px';
textSpan.style.display = 'inline-block';

const relativeDrop = this.shadowRoot.querySelector(`drop-list[identifier="droplist${i}"]`);
relativeDrop.insertAdjacentElement('afterend', textSpan);
}
} else {
const relativeDrop = this.shadowRoot.querySelector(`drop-list[identifier="droplist${i}"]`);

const text = simpleChoice?.textContent.trim();
this.correctResponses = [...this.correctResponses, text];
if (relativeDrop.nextElementSibling?.classList.contains('correct-option')) {
gap.nextElementSibling.remove();
}
}
});
} else {
const correctOptions = this.shadowRoot.querySelectorAll('.correct-option');
correctOptions.forEach(option => {
option.remove();
});
}

this.showCorrectResponses = true;
}

// some interactions have a different way of getting the response
Expand Down

0 comments on commit 5f2e7f6

Please sign in to comment.