From f54b8e31f382028b9a9e990ffca74fc750952a03 Mon Sep 17 00:00:00 2001 From: Jere Nurminen Date: Mon, 2 Dec 2024 15:52:30 +0200 Subject: [PATCH 1/2] Save answer when equation changes --- playwright/editor.spec.tsx | 13 ++++++++++++- src/app/state/index.tsx | 13 +++++++------ src/app/utility.ts | 3 +-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/playwright/editor.spec.tsx b/playwright/editor.spec.tsx index 4ce2cbbd..2afb3f69 100644 --- a/playwright/editor.spec.tsx +++ b/playwright/editor.spec.tsx @@ -610,6 +610,17 @@ test.describe('Rich text editor', () => { }) }) + test('updates the answer when equation is changed', async ({ page }) => { + await page.keyboard.press('1') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) + await page.keyboard.press('2') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('12') }) + await page.keyboard.press('Control+z') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) + await page.keyboard.press('Escape') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) + }) + test.describe('when multiple equation editors in answer', () => { test.beforeEach(async ({ page }) => { await page.keyboard.press('A') @@ -677,7 +688,7 @@ test.describe('Rich text editor', () => { test('after editor with Tab in Latex field', async ({ page }) => { await expect(page.getByRole('img').last()).toBeVisible() await page.getByRole('img').last().click() - // first TAb to focus latex-field + // first Tab to focus latex-field await page.keyboard.press('Tab') await page.keyboard.press('Tab') await page.keyboard.type('XX') diff --git a/src/app/state/index.tsx b/src/app/state/index.tsx index 64632a50..2ccaa9ac 100644 --- a/src/app/state/index.tsx +++ b/src/app/state/index.tsx @@ -169,6 +169,7 @@ export function EditorStateProvider({ function onChange(latex: string) { equationEditorHistory.write(latex) + onAnswerChange(false, false) } function onEnter(latex: string) { @@ -276,12 +277,6 @@ export function EditorStateProvider({ * @param shouldUpdateHistoryImmediately - Whether to update the answer history immediately, without debouncing (defaults to false) */ function onAnswerChange(shouldUpdateHistory: boolean = true, shouldUpdateHistoryImmediately: boolean = false) { - /** This 0ms timeout is crucial - it essentially moves the callback into the next event loop, - * after pending DOM changes have been made in the current loop (in practice, - * this is needed because closing a math editor changes the HTML of the answer, - * but doesn't trigger the text area's onInput event. With this hack we can get the answer HTML with - * the changes already included.) - */ const fn = () => { const content = mainTextAreaRef.current?.innerHTML if (content !== undefined) { @@ -297,6 +292,12 @@ export function EditorStateProvider({ } } } + /** This 0ms timeout is crucial - it essentially moves the callback into the next event loop, + * after pending DOM changes have been made in the current loop (in practice, + * this is needed because closing a math editor changes the HTML of the answer, + * but doesn't trigger the text area's onInput event. With this hack we can get the answer HTML with + * the changes already included.) + */ setTimeout(fn, 0) } diff --git a/src/app/utility.ts b/src/app/utility.ts index efffe3cb..898da50a 100644 --- a/src/app/utility.ts +++ b/src/app/utility.ts @@ -89,9 +89,8 @@ export const getAnswer = (html: string) => { transformTags: { img: (tagName: string, attribs: Attributes) => attribs.src ? { tagName, attribs } : { tagName: '', attribs: {} }, - span: (tagName: string, attribs: Attributes) => - attribs.class !== MATH_EDITOR_CLASS ? { tagName, attribs } : { tagName: '', attribs: {} }, }, + exclusiveFilter: (frame) => frame.tag === 'span' && frame.attribs?.class === MATH_EDITOR_CLASS, }) const answer = new DOMParser().parseFromString(answerHtml, 'text/html').body const answerText = Array.from(answer.childNodes) From fe2ef436a3413d2d2eb0bce4d457105f2d4868dd Mon Sep 17 00:00:00 2001 From: Jere Nurminen Date: Mon, 2 Dec 2024 17:46:44 +0200 Subject: [PATCH 2/2] Add more tests for saving answer on equation edit --- playwright/editor.spec.tsx | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/playwright/editor.spec.tsx b/playwright/editor.spec.tsx index 2afb3f69..9e4862c2 100644 --- a/playwright/editor.spec.tsx +++ b/playwright/editor.spec.tsx @@ -615,10 +615,38 @@ test.describe('Rich text editor', () => { assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) await page.keyboard.press('2') assertAnswerContent(answer, { answerHtml: getLatexImgTag('12') }) - await page.keyboard.press('Control+z') - assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) - await page.keyboard.press('Escape') - assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) + + await test.step('updates on undo', async () => { + await page.keyboard.press('Control+z') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('1') }) + }) + + await test.step('updates with long text', async () => { + await page.keyboard.type('testing that this works when there is a lot of text as well') + assertAnswerContent(answer, { + answerHtml: getLatexImgTag( + '1testing\\ that\\ this\\ works\\ when\\ there\\ is\\ a\\ lot\\ of\\ text\\ as\\ well', + ), + }) + await selectAll(page) + await page.keyboard.press('Backspace') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('') }) + }) + + await test.step('updates when latex command is inserted', async () => { + await inputLatexCommandFromToolbar(page, specialCharacters.sqrt[0]) + assertAnswerContent(answer, { answerHtml: getLatexImgTag('\\sqrt{ }') }) + await page.keyboard.type('123') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('\\sqrt{123}') }) + }) + + await test.step('updates when re-opnening an equation', async () => { + await page.keyboard.press('Escape') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('\\sqrt{123}') }) + await getEditorLocator(page).getByRole('img').first().click() + await page.keyboard.type('abc') + assertAnswerContent(answer, { answerHtml: getLatexImgTag('\\sqrt{123}abc') }) + }) }) test.describe('when multiple equation editors in answer', () => {