This commit is contained in:
C. Fuhrman 2025-01-26 09:33:42 -05:00
parent a59574a8b3
commit 910b83def2
11 changed files with 47 additions and 42 deletions

View file

@ -1,4 +1,4 @@
import { FormatTextTemplate } from "src/components/GiftTemplate/templates/TextTypeTemplate"; import { FormattedTextTemplate } from "src/components/GiftTemplate/templates/TextTypeTemplate";
import { TextFormat } from "gift-pegjs"; import { TextFormat } from "gift-pegjs";
describe('TextType', () => { describe('TextType', () => {
@ -8,7 +8,7 @@ describe('TextType', () => {
format: 'moodle' format: 'moodle'
}; };
const expectedOutput = 'Hello, world! 5 > 3, right?'; const expectedOutput = 'Hello, world! 5 > 3, right?';
expect(FormatTextTemplate(input)).toBe(expectedOutput); expect(FormattedTextTemplate(input)).toBe(expectedOutput);
}); });
it('should format text with newlines correctly', () => { it('should format text with newlines correctly', () => {
@ -17,7 +17,7 @@ describe('TextType', () => {
format: 'plain' format: 'plain'
}; };
const expectedOutput = 'Hello,<br>world!<br>5 > 3, right?'; const expectedOutput = 'Hello,<br>world!<br>5 > 3, right?';
expect(FormatTextTemplate(input)).toBe(expectedOutput); expect(FormattedTextTemplate(input)).toBe(expectedOutput);
}); });
it('should format text with LaTeX correctly', () => { it('should format text with LaTeX correctly', () => {
@ -31,7 +31,7 @@ describe('TextType', () => {
// by running the test and copying the "Received string:" in jest output // by running the test and copying the "Received string:" in jest output
// when it fails (assuming the output is correct) // when it fails (assuming the output is correct)
const expectedOutput = '<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E=mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>'; const expectedOutput = '<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E=mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>';
expect(FormatTextTemplate(input)).toContain(expectedOutput); expect(FormattedTextTemplate(input)).toContain(expectedOutput);
}); });
it('should format text with two equations (inline and separate) correctly', () => { it('should format text with two equations (inline and separate) correctly', () => {
@ -41,7 +41,7 @@ describe('TextType', () => {
}; };
// hint: katex-display is the class that indicates a separate equation // hint: katex-display is the class that indicates a separate equation
const expectedOutput = '<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>+</mo><mi>b</mi><mo>=</mo><mi>c</mi></mrow><annotation encoding="application/x-tex">a + b = c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">c</span></span></span></span> ? <span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E=mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>'; const expectedOutput = '<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>+</mo><mi>b</mi><mo>=</mo><mi>c</mi></mrow><annotation encoding="application/x-tex">a + b = c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">c</span></span></span></span> ? <span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E=mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>';
expect(FormatTextTemplate(input)).toContain(expectedOutput); expect(FormattedTextTemplate(input)).toContain(expectedOutput);
}); });
it('should format text with a katex matrix correctly', () => { it('should format text with a katex matrix correctly', () => {
@ -51,7 +51,7 @@ describe('TextType', () => {
format: 'plain' format: 'plain'
}; };
const expectedOutput = 'Donnez le déterminant de la matrice suivante.<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow></mrow><annotation encoding="application/x-tex"></annotation></semantics></math></span><span class="katex-html" aria-hidden="true"></span></span>\\begin{pmatrix}<br> a&b \\\\<br> c&d<br>\\end{pmatrix}'; const expectedOutput = 'Donnez le déterminant de la matrice suivante.<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow></mrow><annotation encoding="application/x-tex"></annotation></semantics></math></span><span class="katex-html" aria-hidden="true"></span></span>\\begin{pmatrix}<br> a&b \\\\<br> c&d<br>\\end{pmatrix}';
expect(FormatTextTemplate(input)).toContain(expectedOutput); expect(FormattedTextTemplate(input)).toContain(expectedOutput);
}); });
it('should format text with Markdown correctly', () => { it('should format text with Markdown correctly', () => {
@ -61,7 +61,7 @@ describe('TextType', () => {
}; };
// TODO: investigate why the output has an extra newline // TODO: investigate why the output has an extra newline
const expectedOutput = '<strong>Bold</strong>\n'; const expectedOutput = '<strong>Bold</strong>\n';
expect(FormatTextTemplate(input)).toBe(expectedOutput); expect(FormattedTextTemplate(input)).toBe(expectedOutput);
}); });
it('should format text with HTML correctly', () => { it('should format text with HTML correctly', () => {
@ -70,7 +70,7 @@ describe('TextType', () => {
format: 'html' format: 'html'
}; };
const expectedOutput = '<em>yes</em>'; const expectedOutput = '<em>yes</em>';
expect(FormatTextTemplate(input)).toBe(expectedOutput); expect(FormattedTextTemplate(input)).toBe(expectedOutput);
}); });
it('should format plain text correctly', () => { it('should format plain text correctly', () => {
@ -79,7 +79,7 @@ describe('TextType', () => {
format: 'plain' format: 'plain'
}; };
const expectedOutput = 'Just plain text'; const expectedOutput = 'Just plain text';
expect(FormatTextTemplate(input)).toBe(expectedOutput); expect(FormattedTextTemplate(input)).toBe(expectedOutput);
}); });
// Add more tests for other formats if needed // Add more tests for other formats if needed

View file

@ -1,5 +1,5 @@
import { TemplateOptions } from './types'; import { TemplateOptions } from './types';
import {FormatTextTemplate} from './TextTypeTemplate'; import {FormattedTextTemplate} from './TextTypeTemplate';
import { state } from '.'; import { state } from '.';
import { theme } from '../constants'; import { theme } from '../constants';
import { TextFormat } from 'gift-pegjs'; import { TextFormat } from 'gift-pegjs';
@ -20,7 +20,7 @@ export default function GlobalFeedbackTemplate({ format, text }: GlobalFeedbackO
return (format && text) return (format && text)
? `<div style="${Container}"> ? `<div style="${Container}">
<p>${FormatTextTemplate({format: format, text: text})}</p> <p>${FormattedTextTemplate({format: format, text: text})}</p>
</div>` </div>`
: ``; : ``;
} }

View file

@ -1,7 +1,7 @@
import { TemplateOptions } from './types'; import { TemplateOptions } from './types';
import QuestionContainer from './QuestionContainerTemplate'; import QuestionContainer from './QuestionContainerTemplate';
import Title from './TitleTemplate'; import Title from './TitleTemplate';
import {FormatTextTemplate} from './TextTypeTemplate'; import {FormattedTextTemplate} from './TextTypeTemplate';
import GlobalFeedback from './GlobalFeedbackTemplate'; import GlobalFeedback from './GlobalFeedbackTemplate';
import { ParagraphStyle, SelectStyle } from '../constants'; import { ParagraphStyle, SelectStyle } from '../constants';
import { state } from '.'; import { state } from '.';
@ -67,7 +67,7 @@ function MatchAnswers({ choices }: MatchAnswerOptions): string {
.map(({ formattedSubquestion }) => { .map(({ formattedSubquestion }) => {
return ` return `
<div style="${OptionTable} ${ParagraphStyle(state.theme)}"> <div style="${OptionTable} ${ParagraphStyle(state.theme)}">
${FormatTextTemplate(formattedSubquestion)} ${FormattedTextTemplate(formattedSubquestion)}
</div> </div>
<div> <div>
<select class="gift-select" style="${SelectStyle(state.theme)} ${Dropdown}"> <select class="gift-select" style="${SelectStyle(state.theme)} ${Dropdown}">

View file

@ -1,6 +1,6 @@
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { TemplateOptions } from './types'; import { TemplateOptions } from './types';
import {FormatTextTemplate} from './TextTypeTemplate'; import {FormattedTextTemplate} from './TextTypeTemplate';
import AnswerIcon from './AnswerIconTemplate'; import AnswerIcon from './AnswerIconTemplate';
import { state } from '.'; import { state } from '.';
import { ParagraphStyle, theme } from '../constants'; import { ParagraphStyle, theme } from '../constants';
@ -42,7 +42,7 @@ export default function MultipleChoiceAnswersTemplate({ choices }: MultipleChoic
}" id="${inputId}" name="${id}"> }" id="${inputId}" name="${id}">
${AnswerWeight({ correct: isCorrectOption, weight: weight })} ${AnswerWeight({ correct: isCorrectOption, weight: weight })}
<label style="${CustomLabel} ${ParagraphStyle(state.theme)}" for="${inputId}"> <label style="${CustomLabel} ${ParagraphStyle(state.theme)}" for="${inputId}">
${FormatTextTemplate(formattedText)} ${FormattedTextTemplate(formattedText)}
</label> </label>
${AnswerIcon({ correct: isCorrectOption })} ${AnswerIcon({ correct: isCorrectOption })}
${AnswerFeedback({ formattedFeedback: formattedFeedback })} ${AnswerFeedback({ formattedFeedback: formattedFeedback })}
@ -86,5 +86,5 @@ function AnswerFeedback({ formattedFeedback }: AnswerFeedbackOptions): string {
color: ${theme(state.theme, 'teal700', 'gray700')}; color: ${theme(state.theme, 'teal700', 'gray700')};
`; `;
return formattedFeedback ? `<span style="${Container}">${FormatTextTemplate(formattedFeedback)}</span>` : ``; return formattedFeedback ? `<span style="${Container}">${FormattedTextTemplate(formattedFeedback)}</span>` : ``;
} }

View file

@ -1,7 +1,7 @@
import { TemplateOptions } from './types'; import { TemplateOptions } from './types';
import QuestionContainer from './QuestionContainerTemplate'; import QuestionContainer from './QuestionContainerTemplate';
import Title from './TitleTemplate'; import Title from './TitleTemplate';
import {FormatTextTemplate} from './TextTypeTemplate'; import {FormattedTextTemplate} from './TextTypeTemplate';
import GlobalFeedback from './GlobalFeedbackTemplate'; import GlobalFeedback from './GlobalFeedbackTemplate';
import { ParagraphStyle, InputStyle } from '../constants'; import { ParagraphStyle, InputStyle } from '../constants';
import { state } from './index'; import { state } from './index';
@ -32,7 +32,7 @@ export default function ShortAnswerTemplate({
function Answers({ choices }: AnswerOptions): string { function Answers({ choices }: AnswerOptions): string {
const placeholder = choices const placeholder = choices
.map(({ text }) => FormatTextTemplate({ format: '', text: text })) .map(({ text }) => FormattedTextTemplate({ format: '', text: text }))
.join(', '); .join(', ');
return ` return `
<div> <div>

View file

@ -2,7 +2,7 @@ import { TemplateOptions } from './types';
import { state } from '.'; import { state } from '.';
import { ParagraphStyle } from '../constants'; import { ParagraphStyle } from '../constants';
import { BaseQuestion } from 'gift-pegjs'; import { BaseQuestion } from 'gift-pegjs';
import { FormatTextTemplate } from './TextTypeTemplate'; import { FormattedTextTemplate } from './TextTypeTemplate';
// Type is string to allow for custom question type text (e,g, "Multiple Choice") // Type is string to allow for custom question type text (e,g, "Multiple Choice")
interface StemOptions extends TemplateOptions { interface StemOptions extends TemplateOptions {
@ -18,7 +18,7 @@ export default function StemTemplate({ formattedStem }: StemOptions): string {
<div style="${Container}"> <div style="${Container}">
<span> <span>
<p style="${ParagraphStyle(state.theme)}" class="present-question-stem"> <p style="${ParagraphStyle(state.theme)}" class="present-question-stem">
${FormatTextTemplate(formattedStem)} ${FormattedTextTemplate(formattedStem)}
</p> </p>
</span> </span>
</div> </div>

View file

@ -25,22 +25,27 @@ export function formatLatex(text: string): string {
* @see marked * @see marked
* @see katex * @see katex
*/ */
export function FormatTextTemplate(formattedText: TextFormat): string { export function FormattedTextTemplate(formattedText: TextFormat): string {
const formatText = formatLatex(formattedText.text.trim()); // latex needs pure "&", ">", etc. Must not be escaped const formatText = formatLatex(formattedText.text.trim()); // latex needs pure "&", ">", etc. Must not be escaped
let parsedText = ''; let parsedText = '';
let result = '';
switch (formattedText.format) { switch (formattedText.format) {
case '': case '':
case 'moodle': case 'moodle':
case 'plain': case 'plain':
// Replace newlines with <br> tags // Replace newlines with <br> tags
return DOMPurify.sanitize(formatText.replace(/(?:\r\n|\r|\n)/g, '<br>')); result = formatText.replace(/(?:\r\n|\r|\n)/g, '<br>');
break;
case 'html': case 'html':
// Strip outer paragraph tags (not a great approach with regex) // Strip outer paragraph tags (not a great approach with regex)
return DOMPurify.sanitize(formatText.replace(/(^<p>)(.*?)(<\/p>)$/gm, '$2')); result = formatText.replace(/(^<p>)(.*?)(<\/p>)$/gm, '$2');
break;
case 'markdown': case 'markdown':
parsedText = marked.parse(formatText, { breaks: true }) as string; // https://github.com/markedjs/marked/discussions/3219 parsedText = marked.parse(formatText, { breaks: true, gfm: true }) as string; // <br> for newlines
return DOMPurify.sanitize(parsedText.replace(/(^<p>)(.*?)(<\/p>)$/gm, '$2')); result = parsedText.replace(/(^<p>)(.*?)(<\/p>)$/gm, '$2');
break;
default: default:
throw new Error(`Unsupported text format: ${formattedText.format}`); throw new Error(`Unsupported text format: ${formattedText.format}`);
} }
return DOMPurify.sanitize(result);
} }

View file

@ -2,7 +2,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import '../questionStyle.css'; import '../questionStyle.css';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import { FormatTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate'; import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
import { MultipleChoiceQuestion } from 'gift-pegjs'; import { MultipleChoiceQuestion } from 'gift-pegjs';
interface Props { interface Props {
@ -30,7 +30,7 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
return ( return (
<div className="question-container"> <div className="question-container">
<div className="question content"> <div className="question content">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
<div className="choices-wrapper mb-1"> <div className="choices-wrapper mb-1">
{question.choices.map((choice, i) => { {question.choices.map((choice, i) => {
@ -47,13 +47,13 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
(choice.isCorrect ? '✅' : '❌')} (choice.isCorrect ? '✅' : '❌')}
<div className={`circle ${selected}`}>{alphabet[i]}</div> <div className={`circle ${selected}`}>{alphabet[i]}</div>
<div className={`answer-text ${selected}`}> <div className={`answer-text ${selected}`}>
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(choice.formattedText) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} />
</div> </div>
</Button> </Button>
{choice.formattedFeedback && showAnswer && ( {choice.formattedFeedback && showAnswer && (
<div className="feedback-container mb-1 mt-1/2"> <div className="feedback-container mb-1 mt-1/2">
{choice.isCorrect ? '✅' : '❌'} {choice.isCorrect ? '✅' : '❌'}
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(choice.formattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} />
</div> </div>
)} )}
</div> </div>
@ -62,7 +62,7 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
</div> </div>
{question.formattedGlobalFeedback && showAnswer && ( {question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2"> <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div> </div>
)} )}

View file

@ -2,7 +2,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import '../questionStyle.css'; import '../questionStyle.css';
import { Button, TextField } from '@mui/material'; import { Button, TextField } from '@mui/material';
import { FormatTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate'; import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs'; import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs';
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards'; import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards';
@ -40,13 +40,13 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
return ( return (
<div className="question-wrapper"> <div className="question-wrapper">
<div> <div>
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
{showAnswer ? ( {showAnswer ? (
<> <>
<div className="correct-answer-text mb-2">{correctAnswer}</div> <div className="correct-answer-text mb-2">{correctAnswer}</div>
{question.formattedGlobalFeedback && <div className="global-feedback mb-2"> {question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>} </div>}
</> </>
) : ( ) : (
@ -64,7 +64,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
</div> </div>
{question.formattedGlobalFeedback && showAnswer && ( {question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2"> <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div> </div>
)} )}
{handleOnSubmitAnswer && ( {handleOnSubmitAnswer && (

View file

@ -1,7 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import '../questionStyle.css'; import '../questionStyle.css';
import { Button, TextField } from '@mui/material'; import { Button, TextField } from '@mui/material';
import { FormatTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate'; import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
import { ShortAnswerQuestion } from 'gift-pegjs'; import { ShortAnswerQuestion } from 'gift-pegjs';
interface Props { interface Props {
@ -17,7 +17,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
return ( return (
<div className="question-wrapper"> <div className="question-wrapper">
<div className="question content"> <div className="question content">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
{showAnswer ? ( {showAnswer ? (
<> <>
@ -29,7 +29,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
))} ))}
</div> </div>
{question.formattedGlobalFeedback && <div className="global-feedback mb-2"> {question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>} </div>}
</> </>
) : ( ) : (

View file

@ -3,7 +3,7 @@ import React, { useState, useEffect } from 'react';
import '../questionStyle.css'; import '../questionStyle.css';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import { TrueFalseQuestion } from 'gift-pegjs'; import { TrueFalseQuestion } from 'gift-pegjs';
import { FormatTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate'; import { FormattedTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate';
interface Props { interface Props {
question: TrueFalseQuestion; question: TrueFalseQuestion;
@ -26,7 +26,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
return ( return (
<div className="question-container"> <div className="question-container">
<div className="question content"> <div className="question content">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
<div className="choices-wrapper mb-1"> <div className="choices-wrapper mb-1">
<Button <Button
@ -51,18 +51,18 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
{/* selected TRUE, show True feedback if it exists */} {/* selected TRUE, show True feedback if it exists */}
{showAnswer && answer && question.trueFormattedFeedback && ( {showAnswer && answer && question.trueFormattedFeedback && (
<div className="true-feedback mb-2"> <div className="true-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.trueFormattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} />
</div> </div>
)} )}
{/* selected FALSE, show False feedback if it exists */} {/* selected FALSE, show False feedback if it exists */}
{showAnswer && !answer && question.falseFormattedFeedback && ( {showAnswer && !answer && question.falseFormattedFeedback && (
<div className="false-feedback mb-2"> <div className="false-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.falseFormattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
</div> </div>
)} )}
{question.formattedGlobalFeedback && showAnswer && ( {question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2"> <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormatTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div> </div>
)} )}
{!showAnswer && handleOnSubmitAnswer && ( {!showAnswer && handleOnSubmitAnswer && (