From 07cb37723de3abef3fbd6ad5ec08add311295b6b Mon Sep 17 00:00:00 2001 From: Jared Hughes Date: Tue, 21 Apr 2026 15:23:34 -0700 Subject: [PATCH] Fix scanning for "and" in mixed fractions --- src/commands/math/commands.ts | 27 ++++++++++++++++----------- test/unit/aria.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/commands/math/commands.ts b/src/commands/math/commands.ts index 67d4a71c8..395515cfb 100644 --- a/src/commands/math/commands.ts +++ b/src/commands/math/commands.ts @@ -966,22 +966,27 @@ var Fraction = // Handle the case of an integer followed by a simplified fraction such as 1\frac{1}{2}. // Such combinations should be spoken aloud as "1 and 1 half." // Start at the left sibling of the fraction and continue leftward until something other than a digit or whitespace is found. - var precededByInteger = false; + let sawDigit = false; + + let sibling; + // Scan until you see something other than a digit or space for ( - var sibling: NodeRef | undefined = this[L]; - sibling && sibling[L] !== undefined; + sibling = this[L]; + sibling && + sibling.ctrlSeq && + (sibling.ctrlSeq === '\\ ' || intRgx.test(sibling.ctrlSeq ?? '')); sibling = sibling[L] ) { - // Ignore whitespace - if (sibling.ctrlSeq === '\\ ') { - continue; - } else if (intRgx.test(sibling.ctrlSeq || '')) { - precededByInteger = true; - } else { - precededByInteger = false; - break; + if (intRgx.test(sibling.ctrlSeq)) { + sawDigit = true; } } + const lastNodeSeen = sibling; + + // `precededByInteger` is true if everything we saw while scanning is digits and spaces, and + // we saw at least one digit. + const precededByInteger = + sawDigit && !(lastNodeSeen && lastNodeSeen.ctrlSeq === '.'); if (precededByInteger) { output += 'and '; } diff --git a/test/unit/aria.test.js b/test/unit/aria.test.js index 012eb2ae2..e14d47243 100644 --- a/test/unit/aria.test.js +++ b/test/unit/aria.test.js @@ -255,6 +255,36 @@ suite('aria', function () { assertAriaEqual('left parenthesis'); }); + test('testing mathspeak for mixed fractions', function () { + const mq = mathField; + mq.latex('1+2\\frac{3}{4}'); + mq.select(); + assert.equal(mq.mathspeak().trim(), '1 plus 2 and 3 fourths'); + + mq.latex('1.2\\frac{3}{4}'); + mq.select(); + assert.equal(mq.mathspeak().trim(), '1.2 3 fourths'); + + mq.latex('a\\frac{3}{4}'); + mq.select(); + assert.equal(mq.mathspeak().trim(), '"a" 3 fourths'); + + mq.latex('a1\\frac{3}{4}'); + mq.select(); + assert.equal(mq.mathspeak().trim(), '"a" 1 and 3 fourths'); + + mq.latex('1\\left(x\\right)\\frac{3}{4}'); + mq.select(); + assert.equal( + mq.mathspeak().trim(), + '1 left parenthesis, "x" , right parenthesis 3 fourths' + ); + + mq.latex('1+2\\ \\ \\frac{3}{4}'); + mq.select(); + assert.equal(mq.mathspeak().trim(), '1 plus 2 and 3 fourths'); + }); + test('testing beginning and end alerts', function () { mathField.typedText('sqrt(x)'); mathField.keystroke('Home');