diff --git a/ts/components/startup.ts b/ts/components/startup.ts index 3cac215a8..12321c5ae 100644 --- a/ts/components/startup.ts +++ b/ts/components/startup.ts @@ -342,12 +342,13 @@ export abstract class Startup { public static typesetPromise(elements: any[]): Promise { Startup.document.options.elements = elements; Startup.document.reset(); - return Startup.mathjax.handleRetriesFor(() => { + Startup.rerenderPromise = Startup.promise = Startup.mathjax.handleRetriesFor(() => { Startup.document.render(); const promise = Promise.all(Startup.document.renderPromises); Startup.document.renderPromises = []; return promise; }); + return Startup.promise; } /** diff --git a/ts/output/common.ts b/ts/output/common.ts index dd6134848..7accf974f 100644 --- a/ts/output/common.ts +++ b/ts/output/common.ts @@ -404,13 +404,13 @@ export abstract class CommonOutputJax< if (linebreak) { this.getLinebreakWidth(); } - if ( - this.options.linebreaks.inline && - !math.display && - !math.outputData.inlineMarked - ) { + const inlineMarked = !!math.root.getProperty('inlineMarked'); + if (this.options.linebreaks.inline && !math.display && !inlineMarked) { this.markInlineBreaks(math.root.childNodes?.[0]); - math.outputData.inlineMarked = true; + math.root.setProperty('inlineMarked', true); + } else if (!this.options.linebreaks.inline && inlineMarked) { + this.unmarkInlineBreaks(math.root); + math.root.setProperty('inlineMarked', false); } math.root.setTeXclass(null); const wrapper = this.factory.wrap(math.root); @@ -588,6 +588,21 @@ export abstract class CommonOutputJax< return marked; } + /** + * @param {MmlNode} node The node where inline breaks are to be removed + */ + public unmarkInlineBreaks(node: MmlNode) { + if (!node) return; + node.removeProperty('forcebreak'); + node.removeProperty('breakable'); + if (node.getProperty('process-breaks')) { + node.removeProperty('process-breaks'); + for (const child of node.childNodes) { + this.unmarkInlineBreaks(child); + } + } + } + /** * @override */ diff --git a/ts/output/common/Wrapper.ts b/ts/output/common/Wrapper.ts index 95b1ac4d8..2504e55dd 100644 --- a/ts/output/common/Wrapper.ts +++ b/ts/output/common/Wrapper.ts @@ -1220,12 +1220,12 @@ export class CommonWrapper< return ['left', 0]; } if (!align || align === 'auto') { - align = this.jax.math.outputData.inlineMarked + align = this.jax.math.root.getProperty('inlineMarked') ? 'left' : this.jax.options.displayAlign; } if (!shift || shift === 'auto') { - shift = this.jax.math.outputData.inlineMarked + shift = this.jax.math.root.getProperty('inlineMarked') ? '0' : this.jax.options.displayIndent; } diff --git a/ts/ui/menu/MJContextMenu.ts b/ts/ui/menu/MJContextMenu.ts index 5a5aa31bb..e35c11988 100644 --- a/ts/ui/menu/MJContextMenu.ts +++ b/ts/ui/menu/MJContextMenu.ts @@ -55,6 +55,11 @@ export class MJContextMenu extends ContextMenu { */ public mathItem: MathItem = null; + /** + * True when the menu is posted while the explorer is in operation + */ + public refocus: boolean = false; + /** * The document options */ @@ -80,6 +85,8 @@ export class MJContextMenu extends ContextMenu { */ public post(x?: any, y?: number) { if (this.mathItem) { + this.refocus = + document.activeElement.nodeName.toLowerCase() !== 'mjx-container'; if (y !== undefined) { this.getOriginalMenu(); this.getSemanticsMenu(); @@ -99,9 +106,20 @@ export class MJContextMenu extends ContextMenu { * @override */ public unpost() { - super.unpost(); - this.mathItem?.typesetRoot?.blur(); this.mathItem = null; + if (this.refocus) { + super.unpost(); + return; + } + // + // Prevent store.active.focus() from refocusing the menu in super.unpost() + // (no pretty way to do it without making changes to mj-context-menu) + // + const store = this.store; + const active = store.active; + (store as any)._active = document.body; + super.unpost(); + store.active = active; } /*======================================================================*/ diff --git a/ts/ui/menu/Menu.ts b/ts/ui/menu/Menu.ts index dd7b2db21..93463170d 100644 --- a/ts/ui/menu/Menu.ts +++ b/ts/ui/menu/Menu.ts @@ -499,11 +499,15 @@ export class Menu { this.jax[jax.name] = jax; this.settings.renderer = jax.name; this.settings.scale = jax.options.scale; - this.defaultSettings = Object.assign({}, this.settings); this.settings.overflow = jax.options.displayOverflow.substring(0, 1).toUpperCase() + jax.options.displayOverflow.substring(1).toLowerCase(); this.settings.breakInline = jax.options.linebreaks.inline; + this.defaultSettings = Object.assign( + {}, + this.document.options.a11y, + this.settings + ); } /** @@ -1019,7 +1023,9 @@ export class Menu { */ protected setOverflow(overflow: string) { this.document.outputJax.options.displayOverflow = overflow.toLowerCase(); - this.document.rerender(); + if (!Menu.loading) { + this.document.rerender(); + } } /** @@ -1027,7 +1033,9 @@ export class Menu { */ protected setInlineBreaks(breaks: boolean) { this.document.outputJax.options.linebreaks.inline = breaks; - this.document.rerender(); + if (!Menu.loading) { + this.document.rerender(); + } } /** @@ -1035,7 +1043,9 @@ export class Menu { */ protected setScale(scale: string) { this.document.outputJax.options.scale = parseFloat(scale); - this.document.rerender(); + if (!Menu.loading) { + this.document.rerender(); + } } /** @@ -1277,15 +1287,17 @@ export class Menu { Menu.loading++; // pretend we're loading, to suppress rerendering for each variable change const pool = this.menu.pool; const settings = this.defaultSettings; - for (const name of Object.keys(this.settings) as (keyof MenuSettings)[]) { + for (const name of Object.keys(settings) as (keyof MenuSettings)[]) { const variable = pool.lookup(name); if (variable) { - variable.setValue(settings[name] as string | boolean); - const item = (variable as any).items[0]; - if (item) { - item.executeCallbacks_(); + if (variable.getValue() !== settings[name]) { + variable.setValue(settings[name] as string | boolean); + const item = (variable as any).items[0]; + if (item) { + item.executeCallbacks_(); + } } - } else { + } else if (Object.hasOwn(this.settings, name)) { (this.settings as any)[name] = settings[name]; } } @@ -1366,6 +1378,12 @@ export class Menu { this.document = startup.document = startup.getDocument(); this.document.menu = this; this.setA11y(this.settings); + this.defaultSettings = Object.assign( + {}, + this.document.options.a11y, + MathJax.config?.options?.a11y || {}, + this.defaultSettings + ); this.document.outputJax.reset(); this.transferMathList(document); this.document.processed = document.processed; @@ -1468,11 +1486,8 @@ export class Menu { math.root = root.copy(true); math.root.setInheritedAttributes({}, math.display, 0, false); if (breaks) { - math.root.walkTree((n) => { - n.removeProperty('process-breaks'); - n.removeProperty('forcebreak'); - n.removeProperty('breakable'); - }); + jax.unmarkInlineBreaks(math.root); + math.root.setProperty('inlineMarked', false); } const promise = mathjax.handleRetriesFor(() => { jax.toDOM(math, div, jax.document); @@ -1554,6 +1569,7 @@ export class Menu { * @param {number=} start The state at which to start rerendering */ protected rerender(start: number = STATE.TYPESET) { + this.menu.refocus = false; this.rerenderStart = Math.min(start, this.rerenderStart); const startup = MathJax.startup; if (!Menu.loading && startup.rerenderPromise) { diff --git a/ts/ui/menu/MenuUtil.ts b/ts/ui/menu/MenuUtil.ts index 5cccdbfd7..3c672d38b 100644 --- a/ts/ui/menu/MenuUtil.ts +++ b/ts/ui/menu/MenuUtil.ts @@ -21,12 +21,13 @@ * @author dpvc@mathjax.org (Davide Cervone) */ -import {context} from '../../util/context.js'; +import { context } from '../../util/context.js'; /** * True when platform is a Mac (so we can enable CMD menu item for zoom trigger) */ -export const isMac = context.window?.navigator?.platform?.substring(0, 3) === 'Mac'; +export const isMac = + context.window?.navigator?.platform?.substring(0, 3) === 'Mac'; /** * @param {string} text The text to be copied to the clipboard