Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save answer on equation change #623

Merged
merged 2 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion playwright/editor.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,45 @@ 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 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', () => {
test.beforeEach(async ({ page }) => {
await page.keyboard.press('A')
Expand Down Expand Up @@ -677,7 +716,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')
Expand Down
13 changes: 7 additions & 6 deletions src/app/state/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export function EditorStateProvider({

function onChange(latex: string) {
equationEditorHistory.write(latex)
onAnswerChange(false, false)
}

function onEnter(latex: string) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}

Expand Down
3 changes: 1 addition & 2 deletions src/app/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down