Skip to content

Commit

Permalink
improve API for tabbability
Browse files Browse the repository at this point in the history
* update value through the config method
* change from "tabbable" to "tabindex", to match all of html's capabilities
  • Loading branch information
eluberoff committed Feb 3, 2025
1 parent 66f776f commit cdfa690
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 51 deletions.
4 changes: 0 additions & 4 deletions docs/Api_Methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,6 @@ mathField.typedText('x=-b\\pm \\sqrt b^2 -4ac');

Specify an [ARIA label][`aria-label`] for this field, for screen readers. The actual [`aria-label`] includes this label followed by the math content of the field as speech. Default: `'Math Input'`

## .setTabbable(tabbable)

Specify whether this field should be in the tab order.

## .getAriaLabel()

Returns the [ARIA label][`aria-label`] for this field, for screen readers. If no ARIA label has been specified, `'Math Input'` is returned.
Expand Down
7 changes: 4 additions & 3 deletions docs/Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,12 @@ You can also specify a speech-friendly representation of the operator name by su
`substituteTextarea` is a function that creates a focusable DOM element that is called when setting up a math field. Overwriting this may be useful for hacks like suppressing built-in virtual keyboards. It defaults to `<textarea autocorrect=off .../>`.
For example, [Desmos](https://www.desmos.com/calculator) substitutes `<textarea inputmode=none />` to suppress the native virtual keyboard in favor of a custom math keypad that calls the MathQuill API. On old iOS versions that don't support `inputmode=none`, it uses `<span tabindex=0></span>` to suppress the native virtual keyboard, at the cost of bluetooth keyboards not working.

## tabbable
## tabindex

For static and editable math fields, when `tabbable` is false, the math field is not part of the page's tab order. Despite that, the math field can still be focused when selected by a mouse.
Sets a tabindex on the field, following the standard spec. When tabindex is -1,
the math field is not part of the page's tab order. Despite that, the math field can still be focused when selected by a mouse.

Static math fields default to `tabbable: false`, Editable math fields default to `tabbable:true`.
Static math fields default to `tabindex: -1`, Editable math fields default to `tabindex: 1`.

## disableAutoSubstitutionInSubscripts

Expand Down
3 changes: 1 addition & 2 deletions src/mathquill.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ declare namespace MathQuill {
latex(latex: string): this;
latex(): string;
setAriaLabel(str: string): this;
setTabbable(tabbable: boolean): this;
blur(): this;
focus(): this;
select(): this;
Expand Down Expand Up @@ -109,7 +108,7 @@ declare namespace MathQuill {
typingSlashWritesDivisionSymbol?: boolean;
typingPercentWritesPercentOf?: boolean;
resetCursorOnBlur?: boolean | undefined;
tabbable?: boolean;
tabindex?: number;
leftRightIntoCmdGoes?: 'up' | 'down';
enableDigitGrouping?: boolean;
tripleDotsAreEllipsis?: boolean;
Expand Down
9 changes: 4 additions & 5 deletions src/publicapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class Options {
leftRightIntoCmdGoes?: 'up' | 'down';
enableDigitGrouping?: boolean;
tripleDotsAreEllipsis?: boolean;
tabbable?: boolean;
tabindex?: number;
mouseEvents?: boolean;
maxDepth?: number;
disableCopyPaste?: boolean;
Expand Down Expand Up @@ -310,12 +310,11 @@ function getInterface(v: number): MathQuill.v3.API | MathQuill.v1.API {
getAriaLabel() {
return this.__controller.getAriaLabel();
}
setTabbable(tabbable: boolean) {
this.__controller.setTabbable(tabbable);
return this;
}
config(opts: ConfigOptions) {
config(this.__options, opts);
if (opts.tabindex !== undefined) {
this.__controller.setTabindex(opts.tabindex);
}
return this;
}
el() {
Expand Down
33 changes: 14 additions & 19 deletions src/services/textarea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Options.prototype.substituteKeyboardEvents = defaultSubstituteKeyboardEvents;
class Controller extends Controller_scrollHoriz {
selectFn: (text: string) => void = noop;

wasTabbable: boolean | undefined;
previousTabindex: number | undefined;

createTextarea() {
this.textareaSpan = h('span', { class: 'mq-textarea' });
Expand Down Expand Up @@ -60,34 +60,29 @@ class Controller extends Controller_scrollHoriz {
ctrlr.selectionChanged();
};

const tabbable =
this.options.tabbable !== undefined
? this.options.tabbable
: this.KIND_OF_MQ !== 'StaticMath';
const tabindex =
this.options.tabindex !== undefined
? this.options.tabindex
: this.KIND_OF_MQ === 'StaticMath'
? -1
: 0;

if (!this.options.tabbable && this.KIND_OF_MQ === 'StaticMath') {
// aria-hide noninteractive textarea element for static math
textarea.setAttribute('aria-hidden', 'true');
}
if (tabbable && this.mathspeakSpan) {
this.mathspeakSpan.setAttribute('aria-hidden', 'true');
}
this.setTabbable(tabbable);
this.setTabindex(tabindex);
}

setTabbable(tabbable: boolean) {
if (tabbable === this.wasTabbable) return;
this.wasTabbable = tabbable;
setTabindex(tabindex: number) {
if (tabindex === this.previousTabindex || !this.textarea) return;
this.previousTabindex = tabindex;

this.textarea?.setAttribute('tabindex', tabbable ? '0' : '-1');
this.textarea?.setAttribute('tabindex', '' + tabindex);

if (!tabbable && this.KIND_OF_MQ === 'StaticMath') {
if (tabindex < 0 && this.KIND_OF_MQ === 'StaticMath') {
this.textarea?.setAttribute('aria-hidden', 'true');
} else {
this.textarea?.removeAttribute('aria-hidden');
}

if (tabbable) {
if (tabindex >= 0) {
this.mathspeakSpan?.setAttribute('aria-hidden', 'true');
} else {
this.mathspeakSpan?.removeAttribute('aria-hidden');
Expand Down
3 changes: 2 additions & 1 deletion test/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ <h1>
});
});
var mq = MQ.MathField($('#basic')[0], {
tabbable: false,
tabindex: -1,
autoSubscriptNumerals: true,
autoCommands:
'alpha beta sqrt theta phi pi tau nthroot cbrt prod int ans percent mid square',
Expand All @@ -58,6 +58,7 @@ <h1>
}
});
latex.val(mq.latex());
mq.config({ tabindex: 0 });
</script>
</body>
</html>
8 changes: 4 additions & 4 deletions test/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ <h1>
</p>

<p>
On the other hand, you can make static math tabbable to appear in the
tab order despite being non-editable. The entire range is selected when
tabbed into:
On the other hand, you can make static math appear in the tab order
despite being non-editable by providing a tabindex. The entire range is
selected when tabbed into:
<span class="static-math-tabbable">1.234\times 10^{8}</span>.
</p>

Expand Down Expand Up @@ -169,7 +169,7 @@ <h1>
MQ.StaticMath(this, { mouseEvents: false });
});
$('.static-math-tabbable').each(function () {
MQ.StaticMath(this, { tabbable: true });
MQ.StaticMath(this, { tabindex: 0 });
});
$('.mathquill-math-field').each(function () {
MQ.MathField(this);
Expand Down
6 changes: 3 additions & 3 deletions test/unit/aria.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ suite('aria', function () {
'aria-hidden is set on mq-root-block'
);

staticMath.setTabbable(true);
staticMath.config({ tabindex: 0 });
var ariaHiddenChildren = $(container).find('[aria-hidden]="true"');
assert.equal(ariaHiddenChildren.length, 2, '2 aria-hidden elements');
assert.equal(
Expand All @@ -47,7 +47,7 @@ suite('aria', function () {
'aria-hidden is set on mathspeak span when tabbable'
);

staticMath.setTabbable(false);
staticMath.config({ tabindex: -1 });
var ariaHiddenChildren = $(container).find('[aria-hidden]="true"');
assert.equal(
ariaHiddenChildren[0].nodeName,
Expand All @@ -57,7 +57,7 @@ suite('aria', function () {
});

test('Tabbable static math aria-hidden', function () {
var staticMath = MQ.StaticMath(container, { tabbable: true });
var staticMath = MQ.StaticMath(container, { tabindex: 0 });
staticMath.latex('1+\\frac{1}{x}');
var ariaHiddenChildren = $(container).find('[aria-hidden]="true"');
// There will be two hidden children: the raw text of the field, and its mathspeak representation.
Expand Down
20 changes: 10 additions & 10 deletions test/unit/focusBlur.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ suite('focusBlur', function () {
test('full range selected on focusing tabbable static math', function () {
var mq = MQ.StaticMath(
$('<span>1234\\times 10^{23}</span>').appendTo('#mock')[0],
{ tabbable: true }
{ tabindex: 0 }
);

mq.focus();
Expand All @@ -119,18 +119,18 @@ suite('focusBlur', function () {
);

assert.equal($(document.activeElement).attr('tabindex'), '0');
mq.setTabbable(false);
mq.config({ tabindex: -1 });
assert.equal(
$(document.activeElement).attr('tabindex'),
'-1',
'tab index updated when setTabbable:false called'
'tab index updated when tabindex is set to -1'
);

mq.setTabbable(true);
mq.config({ tabindex: 0 });
assert.equal(
$(document.activeElement).attr('tabindex'),
'0',
'tab index restored when setTabbable:true called'
'tab index restored when tabindex is set to 0'
);

mq.blur();
Expand All @@ -139,7 +139,7 @@ suite('focusBlur', function () {

test('tabindex for editable math', function () {
var mq = MQ.MathField($('<span></span>').appendTo('#mock')[0], {
tabbable: false
tabindex: -1
});

mq.focus();
Expand All @@ -149,18 +149,18 @@ suite('focusBlur', function () {
assert.equal(mq.latex(), '1+1', 'latex populated');

assert.equal($(document.activeElement).attr('tabindex'), '-1');
mq.setTabbable(true);
mq.config({ tabindex: 0 });
assert.equal(
$(document.activeElement).attr('tabindex'),
'0',
'tab index updated when setTabbable:true called'
'tab index updated tabindex is set to 0'
);

mq.setTabbable(false);
mq.config({ tabindex: -1 });
assert.equal(
$(document.activeElement).attr('tabindex'),
'-1',
'tab index restored when setTabbable:false called'
'tab index restored when tabindex is set to -1'
);

mq.blur();
Expand Down

0 comments on commit cdfa690

Please sign in to comment.