Skip to content

Conversation

@dpvc
Copy link
Member

@dpvc dpvc commented Nov 17, 2025

Overview

This PR moves the handling of the explorer colors into CSS. Initially, this was to allow the info icon to use the same color, but it also make it possible to simplify the highlighters, which can now use CSS to control the colors, rather than setting them on the nodes themselves. That means you don't have to store and restore the colors, but can just use CSS to determine the colors. There are also several other issues that cropped up while working on this, with the biggest one being that the magnifier didn't handle the extra nodes that we now enclose in the explorer. That is taken care of here.

The main changes:

  • The explorer colors are now stored in CSS variables (separate for foreground/background and primary and secondary explorers) rather than in the nodes styles attribute.
  • The info icon and the display regions now use CSS to add their colors.
  • The magnification region now handles multi-node enclosures properly.
  • Magnification can now be used without speech/Braille generation (it used to throw errors).
  • The SRE attributes for collapsed sub-expressions are not set on the proper output nodes rather than on the background rect in SVG output.
  • Menu changes in foreground/background colors now affect flame highlighting immediately.
  • Some edxplorer CSS has been moved out of the output jax into the region's style definitions.

The Details

The changes in complexity/collapse.ts are to mark the mtext node used for collapsed sub-expressions with data-mjx-collapsed for easier reference in the highlighter and regions code.

The explorer.ts change makes the info icon have the correct background color.

In ExplorerPool.ts, we add a new parameter to distinguish the primary and secondary highlighters, since they need to know which CSS color variables to use. This does make things slightly less general than before, but it is still possible to have multiple additional highlighters if you wanted.

The Highlighter.ts file has significant changes. The type that I added earlier to the NamedColored has been removed (we now pass the type directly to the color functions). Since we are using CSS variables for the colors, getColorString() is no longer needed. The default colors no longer need the types, and the default background now has the correct alpha value.

A new ATTR object is used to hold the various attribute names needed for the highlighting, to make it easier and less likely to have typos.

Since the colors are now in CSS, the foreground() and background() methods are not needed, and nether are the _foreground and _background properties.

The getMactionNodes() method is added to the interface, since it is public.

The Highlight interface is no longer needed, since we don't have to store the old colors any longer (the CSS overrides them instead). Hightlight has been replaced by HTMLElement throughout as a result.

We don't need the counter, since the attributes are now based on the primary/secondary value (saved as the new property priority). [The diff gets a little out of sync here, as it gets confused about which properties are old one with slight changes and which are new ones. Sorry about that]

The currentHighlights is now just a list of lists of DOM nodes, since that is all that is needed anymore.

The constructor() now gets a priority (1 = primary, 2 = secondary, and you could add more if needed) and constructs the ATTR property from that.

The highlight() method now simplifies since we don't need to create info objects. The loop in highlightAll() is simplified to use for (const ... of ...) rather than a loop counter.

A new setColorCSS() method calls the LiveRegion.setColor() method to adjust the CSS for the given color type and priority (since the stylesheet holding the CSS for the colors is part of the LiveRegion class). The setColor() method now just calls the setColorCSS() for the foreground and background colors.

The getMactionNodes() and isMactionNode() methods are made abstract since they are overridden in both output highlighters (the original code for these was never used). The mactionName getter is removed since it is not used int he abstract class, and the individual output classes can just use the name they need explicitly.

The removal of the ATTR.ENCLOSED attribute is moves to unsetHightlighted() as it is logically part of that function.

The SVG and CHTML highlighters no longer need to set up mactionName, and instead just use the explicit name (no need to waste space storing a pointer to it for every equation on the page).

The SVG highlightNode() method is now simplified since we don't have to worry about saving foreground and background colors. All we need to do is decide if we need to make a colored background rect or not. Similarly, unhighlightNode() is simpler, since we don't have to replace colors. We just have to decide whether to remove a temporary rect or not.

For CHTML, highlightnode() doesn't need to do anything (the CSS already handles it), and unhighlighting just checks if a temporary enclosure needs to be removed.

The remaining changes in this file are to handle the new priority value.

The changes in KeyExplorer.ts are mostly to allow the magnifier to work without speech or Braille rendering. In the past, that would cause the addSpeech() method to crash, so we check whether speech or Braille is enabled and skip that function if not. We move the setting of the tabIndex and the Update() call that would have been performed there to the setCurrent() function, where addSpeech() is called, so that they are sure to be performed. Similarly, we check for speech and Braille in the Update() function.

The Region.Show() functions no longer need the highlighter (as we will see below), as the colors are handled through CSS. This is also true in MouseExplorer.ts.

The Region.ts file also has significant changes. First, the getHighlighter isn't needed (it was a redundant call that is removed below). Also, the highlighter no longer needs to be passed to the Show() method, since the colors are set by CSS, so the region colors don't have to be updated explicitly.

A new styleSheet() getter is added to get the stylesheet using its ID, for convenience.

The highlight methods are removed as no longer needed (it is automatic with the CSS).

The style selectors are now created using `...` strings.

A priority object is used to make priority names (primary and secondary) to their priority numbers.

The fg and bg numbers for the two priorities are added to the CSS variable list, along with their alpha values.

The LiveRegion styles now include a rule for setting the background color of the region's display automatically, and new rules for adding the foreground and background colors to the selected nodes during expression exploration. The primary rules are a bit complicated so as not to set the foreground color for collapsed sub-expressions, and not to set the background for magnified items (data-mjx-clone-container) since the magnification region already has the background color

The setAlpha() function is now a more general setColor() method that sets the color and alpha values for a given type and priority.

The HoverRegion gets CSS to set its background color automatically, as well, and we override the display margins so there isn't excessive space above and below the magnified sub-expression in displayed equations.

Again, the hightlight() method is no longer needed, since the colors are added by CSS.

The main changes to the HoverRegion are in the cloneNode() method, which now has to handle the extra enclosed nodes, when needed. The method has been refactored to move the SVG and CHTML-specific code into separate functions. Some extra work is done move past the selection box (mjx-bbox node in CHTML), and to handle the extra enclosed items, if any. The cloned mjx-container is marked using data-mjx-clone-container for use in the CSS selectors.

For CHTML output, the extra enclosed nodes are just cloned into the container (with the assumption that they follow it in the expression).

For SVG, we not only have to clone the nodes, but need to figure out their positions within the enclosure. A new xy() method does that, and we use the values from that to set the element's transform attribute to move it into the correct place. When there are extra nodes, we set the bounding box information from the enclosure node, not the selected one. Finally, we set up the SVG attributes to get the size and viewport correct.

The xy() method transforms the node's coordinate system's origin to the SVG's coordinate system, so we can tell how it was placed, even if it is not in the same g element as the currently selected node.

The change in WebWorker.ts is so that the SRE attributes are applied to an maction's content, not the rect used for its hit-box for clicking.

The change in HTMLMathItem.ts is to prevent an error that sometimes occurs in the lab when the expression has been removed before it is typeset. It checks that the parent item is available before trying to replace it with the newly typeset DOM nodes.

The maction CSS for giving the collapsed nodes the blue color is simplified (now that we mark the collapsed node by data-mjx-collapsed attributes).

Finally, the Menu.ts code is modified to have changes to the colors update the color CSS so that any flame highlighting will update immediately. (This probably means that we don't need to set the colors every time a new node is selected, as is currently being done. But the LiveRegion.setColor() checks that the CSS has changed before updating it, so there won't be CSS updates most of the time anyway.)

Also, the explorer doesn't need to be loaded when collapsing is enabled, so that has been removed.

Finally, the MathJax.startup value doesn't have to be cached in the rerender() function, since it is only used once.

@dpvc dpvc requested a review from zorkow November 17, 2025 09:00
@dpvc dpvc added this to the v4.1.0 milestone Nov 17, 2025
Base automatically changed from feature/draggable-dialogs to develop November 20, 2025 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants