0.90.0 2023-03-19
Breaking Changes
This release contains several breaking changes. As much as possible I try to
avoid introducing breaking changes, but there was an accumulation of issues that
required some breaking change and I figured I would introduce them all at once:
- the use case where a page had several mathfields was not handled well. Several
configuration options were effectively shared, yet each mathfield had its own
idea of what the setting was. There were also several duplicate ways of
configuring a mathfield, which was confusing.
- the virtual keyboard was awkward to use and configure with multiple
mathfields. The virtual keyboard API was also attached to mathfield instances,
instead of the virtual keyboard being its own entity.
- Fill-in-the-blank is a popular feature, but its current implementation had
some limitations. Thanks to a contributed new implementation, those
limitations have been removed, and the API to handle fill-in-the-blank has
been adjusted accordingly.
Fill-in-the-blank
-
New implementation of the \placeholder{}
command for "fill-in-the-blank"
feature. Thank you to James Mullen (https://github.com/wildyellowfin) for this
contribution.
Previously, each placeholder was an embedded mathfield inside a "root"
mathfield. The placeholders are now special editable regions of a read-only
mathfield.
This improves their layout (for example a placeholder numerator is now
displayed at the correct size) and simplify their interaction. When used as a
"fill-in-the-blank", set the mathfield to readonly, and specify an ID with the
placeholder, i.e. \placeholder[id]{value}
. In this situation these
placeholders are called "prompts".
-
The mf.getPlaceholderField()
function has been replaced with
mf.getPromptValue()
-
Use mf.setPromptValue()
to change the content of a prompt.
-
Use mf.getPrompts()
to get an array of the ids of all the prompts in the
expression.
-
Prompts can be either in a correct, incorrect or indeterminate state. In
correct or incorrect state, their appearance changes to reflect their state.
Use mf.setPromptState()
to flag a prompt as being correct or incorrect.
mf.setPromptState()
can also be used to mark a prompt as no longer being
editable.
Virtual Keyboard
-
Previously the virtual keyboard was shared amongst mathfield instances if the
makeSharedVirtualKeyboard()
function was called or the
use-shared-virtual-keyboard
attribute was set on a mathfield. Otherwise a
virtual keyboard instance was created for each mathfield in the document.
The virtual keyboard is now always shared.
The virtual keyboard global instance can be accessed as
window.mathVirtualKeyboard
or just mathVirtualKeyboard
. Its value
implements VirtualKeyboardInterface
instance, same as was previously
returned by makeSharedVirtualKeyboard()
.
-
The options related to the virtual keyboard should now be set on the global
shared virtual keyboard, using window.mathVirtualKeyboard
instead of on
mathfield instances.
-
The MathLive virtual keyboard API (offered by the window.mathVirtualKeyboard
property) has changed to be consistent with the
W3C Virtual Keyboard API.
This includes adding a show()
and hide()
functions, and a boundingRect
property to VirtualKeyboardInterface
.
A geometrychange
event is dispatched when the size of the keyboard changes.
In addition, the MathfieldElement.virtualKeyboardMode
property is now called
MathfieldElement.mathVirtualKeyboardPolicy
and can take a value of "auto"
or "manual"
.
A value of "manual"
corresponds to the previous virtualKeyboardMode
value
of "off"
, that is the virtual keyboard is not displayed automatically and
must be displayed programmatically.
The value "onfocus"
is no longer supported. To implement the behavior
previously provided by this value:
mf.addEventListener('focusin', () => mathVirtualKeyboard.show());
If mathVirtualKeyboardPolicy
is set to "auto"
the virtual keyboard is
displayed automatically when a mathfield is focused on a touch-enabled device.
-
The virtual keyboard customization API has been simplified.
Before:
const MINIMAL_LAYER = [
minimal: {
rows: [
[
{latex: "+"}, {latex: "-"}, {latex: "\\times"},
{latex: "\\frac{#@}{#?}"}, {latex: "="}, {latex: "."},
{latex: "("}, {latex: ")"}, {latex: "\\sqrt{#0}"},
{latex: "#@^{#?}"}
],
[
{latex: "1"}, {latex: "2"}, {latex: "3"}, {latex: "4"},
{latex: "5"}, {latex: "6"}, {latex: "7"}, {latex: "8"},
{latex: "9"}, {latex: "0"},
]
]
}];
const MINIMAL_KEYBOARD = {
'minimal': {
label: 'Minimal',
layer: 'minimal',
},
};
mf.setOptions({
customVirtualKeyboardLayers: MINIMAL_LAYER,
customVirtualKeyboards: MINIMAL_KEYBOARD,
virtualKeyboards: 'minimal',
});
Now:
mathVirtualKeyboard.layouts = {
rows: [
[
'+',
'-',
'\\times',
'\\frac{#@}{#?}',
'=',
'.',
'(',
')',
'\\sqrt{#0}',
'#@^{#?}',
],
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
],
};
To change the alphabetic layout:
Before:
mf.setOptions({ virtualKeyboardLayout: 'azerty' });
Now:
mathVirtualKeyboard.alphabeticLayout = 'azerty';
-
The "roman"
virtual keyboard is now called "alphabetic"
-
The virtualKeyboardToolbar
option is now mathVirtualKeyboard.actionToolbar
-
The virtualKeyboardContainer
option is now mathVirtualKeyboard.container
-
The virtual keyboard toggle glyph can no longer be customized.
-
The virtual keyboard toggle button is displayed by default if the content of
mathfield can be modified.
The display of the toggle button is independent of the
mathVirtualKeyboardPolicy
.
Using the math-field::part(virtual-keyboard-toggle)
CSS selector, a
display: none
CSS attribute can be used to hide the virtual keyboard toggle
if desired. To replicate the previous default behavior, where the toggle was
displayed on touch-enabled devices, use:
@media not (pointer: coarse) {
math-field::part(virtual-keyboard-toggle) {
display: none;
}
}
-
The "alt-keys" of the virtual keyboard are now called "variants". The
data-alt-keys
attribute is now data-variants
Options
Previously all the options to configure a mathfield could be changed using
mf.setOptions({...})
. Some of these options affected a specific mathfield
instance, while others affected all mathfields on the page.
The options that affect all mathfields are now static properties of the
MathfieldElement
global. The options that affect the virtual keyboard are
properties of the mathVirtualKeyboard
global singleton. The options specific
to a mathfield are now properties or attribute of this element.
For example:
Before:
mf.setOptions({ soundsDirectory: null });
Now:
MathfieldElement.soundsDirectory = null;
| Before | Now |
| :-------------------------------------------------- | :--------------------------------------------------------------------------- |
| mf.setOptions({defaultMode: ...})
| mf.defaultMode = ...
|
| mf.setOptions({letterShapeStyle: ...})
| mf.letterShapeStyle = ...
|
| mf.setOptions({horizontalSpacingScale: ...})
| Removed. Use "thinmuskip"
, "medmuskip"
, and "thickmuskip"
registers ', |
| mf.setOptions({macros: ...})
| mf.macros = ...
|
| mf.setOptions({registers: ...})
| mf.registers = ...
|
| mf.setOptions({backgroundColorMap: ...})
| mf.backgroundColorMap = ...
|
| mf.setOptions({colorMap: ...})
| mf.colorMap = ...
|
| mf.setOptions({enablePopover: ...})
| mf.popoverPolicy = ...
|
| mf.setOptions({mathModeSpace: ...})
| mf.mathModeSpace = ...
|
| mf.setOptions({placeholderSymbol: ...})
| mf.placeholderSymbol = ...
|
| mf.setOptions({readOnly: ...})
| mf.readOnly = ...
|
| mf.setOptions({removeExtraneousParentheses: ...})
| mf.removeExtraneousParentheses = ...
|
| mf.setOptions({scriptDepth: ...})
| mf.scriptDepth = ...
|
| mf.setOptions({smartFence: ...})
| mf.smartFence = ...
|
| mf.setOptions({smartMode: ...})
| mf.smartMode = ...
|
| mf.setOptions({smartSuperscript: ...})
| mf.smartSuperscript = ...
|
| mf.setOptions({inlineShortcutTimeout: ...})
| mf.inlineShortcutTimeout = ...
|
| mf.setOptions({inlineShortcuts: ...})
| mf.inlineShortcuts = ...
|
| mf.setOptions({keybindings: ...})
| mf.keybindings = ...
|
| mf.setOptions({virtualKeyboardMode: ...})
| mf.mathVirtualKeyboardPolicy = ...
|
| mf.setOptions({customVirtualKeyboardLayers: ...})
| mathVirtualKeyboard.layouts.layers = ...
|
| mf.setOptions({customVirtualKeyboards: ...})
| mathVirtualKeyboard.layouts = ...
|
| mf.setOptions({keypressSound: ...})
| mathVirtualKeyboard.keypressSound = ...
|
| mf.setOptions({keypressVibration: ...})
| mathVirtualKeyboard.keypressVibration = ...
|
| mf.setOptions({plonkSound: ...})
| mathVirtualKeyboard.plonkSound = ...
|
| mf.setOptions({virtualKeyboardContainer: ...})
| mathVirtualKeyboard.container = ...
|
| mf.setOptions({virtualKeyboardLayout: ...})
| mathVirtualKeyboard.alphabeticLayout = ...
|
| mf.setOptions({virtualKeyboardTheme: ...})
| No longer supported |
| mf.setOptions({virtualKeyboardToggleGlyph: ...})
| No longer supported |
| mf.setOptions({virtualKeyboardToolbar: ...})
| mathVirtualKeyboard.actionToolbar = ...
|
| mf.setOptions({virtualKeyboards: ...})
| Use mathVirtualKeyboard.layouts
|
| mf.setOptions({speechEngine: ...})
| MathfieldElement.speechEngine
|
| mf.setOptions({speechEngineRate: ...})
| MathfieldElement.speechEngineRate
|
| mf.setOptions({speechEngineVoice: ...})
| MathfieldElement.speechEngineVoice
|
| mf.setOptions({textToSpeechMarkup: ...})
| MathfieldElement.textToSpeechMarkup
|
| mf.setOptions({textToSpeechRules: ...})
| MathfieldElement.textToSpeechRules
|
| mf.setOptions({textToSpeechRulesOptions: ...})
| MathfieldElement.textToSpeechRulesOptions
|
| mf.setOptions({readAloudHook: ...})
| MathfieldElement.readAloudHook
|
| mf.setOptions({speakHook: ...})
| MathfieldElement.speakHook
|
| mf.setOptions({computeEngine: ...})
| MathfieldElement.computeEngine
|
| mf.setOptions({fontsDirectory: ...})
| MathfieldElement.fontsDirectory
|
| mf.setOptions({soundsDirectory: ...})
| MathfieldElement.soundsDirectory
|
| mf.setOptions({createHTML: ...})
| MathfieldElement.createHTML
|
| mf.setOptions({onExport: ...})
| MathfieldElement.onExport
|
| mf.setOptions({onInlineShortcut: ...})
| MathfieldElement.onInlineShortcut
|
| mf.setOptions({locale: ...})
| MathfieldElement.locale = ...
|
| mf.setOptions({strings: ...})
| MathfieldElement.strings = ...
|
| mf.setOptions({decimalSeparator: ...})
| MathfieldElement.decimalSeparator = ...
|
| mf.setOptions({fractionNavigationOrder: ...})
| MathfieldElement.fractionNavigationOrder = ...
|
Miscellaneous Breaking Changes
- For consistency with
<textarea>
the <math-field>
tag now has a default
display style of "inline". You can change the display style to "block" using a
CSS rule. - The
<math-field>
tag now has some default styling, including a background
and border, consistent with a <textarea>
element. You can override this
styling by defining CSS rules for the math-field
selector. - The previously deprecated option
horizontalSpacingScale
has been removed. It
is replaced by the standard TeX registers\thinmuskip
, \medmuskip
and
\thickmuskip
. - It was previously possible to specify a set of options for a mathfield as a
<script>
tag inside the mathfield, as JSON data structure. This is no longer
supported. - It was previously possible to supply a custom style sheet to be applied inside
the shadow DOM by using a
<style>
tag inside the mathfield. This is no
longer supported. Use custom CSS variables or part
selectors to apply custom
styling to the mathfield.
Improvements
- #1854 Attempt to solve multiple reading of field content by screen readers
on focus
- #1855 Updated support for more recent versions of SRE (Speech Rule Engine)
- Improved interaction with some screen readers
- #843, #1845 Smarter smart-fence: fewer fence combinations are now
valid, resulting in more correct results
- #1859 In math mode, after pressing the SPACE key, the variant style
(upright, italic, etc...) from neighboring atoms is not adopted by subsequent
characters.
- The
disabled
and readonly
attributes and the user-select
CSS property
are now consistent with <textarea>
:
- a
readonly
mathfield is still focusable - a
disabled
mathfield is not focusable - The content of a
readonly
or disabled
mathfield can be selected, unless
the contenteditable
attribute is set to "false"
and the user-select
CSS property is set to "none"
. (fixes #1136)
- A mathfield can be used inline, for example inside a
<p>
element. - For consistency with a
<textarea>
, click
events are not dispatched when a
disabled <math-element>
is clicked. - #1722 The theme applied to the keyboard can be set programmatically by
apply a
theme
attribute to the container of the keyboard, for example
<body theme="dark">
or <body theme="light">
. - When a mathfield contains placeholders (or prompts), tabbing at the last
placeholder will move to the next focusable element on the page (previously,
it would circularly stay inside the current mathfield, with no possibility of
escape).
Issues Resolved
- #1850 When multiple
\char
commands were in an expression, they would all
have the same argument when serialized - #1691 Inserting a left parenthesis to the left of a right parenthesis
caused the expression to be incorrectly balanced
- #1858 The spoken representation of the
\pm
command was incorrect - #1856 Displaying the virtual keyboard in a custom container was broken
- #1877 Setting options on read-only field was not working
- #1771 Incorrect layout of fill-in-the-blank
- #1770
mf.setValue()
did not affect fill-in-the-blank sections - #1736 Layout issues with fill-in-the-blank
- #1048 Virtual keyboard inside a custom container is now displayed
correctly.