123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- /*************************************************************
- *
- * Copyright (c) 2019-2022 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview Mixin that adds a context-menu to MathJax output
- *
- * @author dpvc@mathjax.org (Davide Cervone)
- */
- import {mathjax} from '../../mathjax.js';
- import {STATE, newState} from '../../core/MathItem.js';
- import {MathDocumentConstructor} from '../../core/MathDocument.js';
- import {Handler} from '../../core/Handler.js';
- import {ComplexityMathDocument, ComplexityMathItem} from '../../a11y/complexity.js';
- import {ExplorerMathDocument, ExplorerMathItem} from '../../a11y/explorer.js';
- import {AssistiveMmlMathDocument, AssistiveMmlMathItem} from '../../a11y/assistive-mml.js';
- import {expandable} from '../../util/Options.js';
- import {Menu} from './Menu.js';
- /*==========================================================================*/
- /**
- * Generic constructor for Mixins
- */
- export type Constructor<T> = new(...args: any[]) => T;
- /**
- * Constructor for base MathItem for MenuMathItem
- */
- export type A11yMathItemConstructor = {
- new(...args: any[]): ComplexityMathItem<HTMLElement, Text, Document> &
- ExplorerMathItem & AssistiveMmlMathItem<HTMLElement, Text, Document>;
- };
- /**
- * Constructor for base document for MenuMathDocument
- */
- export type A11yDocumentConstructor =
- MathDocumentConstructor<ComplexityMathDocument<HTMLElement, Text, Document> &
- ExplorerMathDocument & AssistiveMmlMathDocument<HTMLElement, Text, Document>>;
- /*==========================================================================*/
- /**
- * Add STATE value for menus being added (after TYPESET and before INSERTED)
- */
- newState('CONTEXT_MENU', 170);
- /**
- * The new function for MathItem that adds the context menu
- */
- export interface MenuMathItem extends ComplexityMathItem<HTMLElement, Text, Document> {
- /**
- * @param {MenuMathDocument} document The document where the menu is being added
- * @param {boolean} force True if menu should be added even if enableMenu is false
- */
- addMenu(document: MenuMathDocument, force?: boolean): void;
- /**
- * @param {MenuMathDocument} document The document to check for if anything is being loaded
- */
- checkLoading(document: MenuMathDocument): void;
- }
- /**
- * The mixin for adding context menus to MathItems
- *
- * @param {B} BaseMathItem The MathItem class to be extended
- * @return {MathMathItem} The extended MathItem class
- *
- * @template B The MathItem class to extend
- */
- export function MenuMathItemMixin<B extends A11yMathItemConstructor>(
- BaseMathItem: B
- ): Constructor<MenuMathItem> & B {
- return class extends BaseMathItem {
- /**
- * @param {MenuMathDocument} document The document where the menu is being added
- * @param {boolean} force True if menu should be added even if enableMenu is false
- */
- public addMenu(document: MenuMathDocument, force: boolean = false) {
- if (this.state() >= STATE.CONTEXT_MENU) return;
- if (!this.isEscaped && (document.options.enableMenu || force)) {
- document.menu.addMenu(this);
- }
- this.state(STATE.CONTEXT_MENU);
- }
- /**
- * @param {MenuMathDocument} document The document to check for if anything is being loaded
- */
- public checkLoading(document: MenuMathDocument) {
- document.checkLoading();
- }
- };
- }
- /*==========================================================================*/
- /**
- * The properties needed in the MathDocument for context menus
- */
- export interface MenuMathDocument extends ComplexityMathDocument<HTMLElement, Text, Document> {
- /**
- * The menu associated with this document
- */
- menu: Menu;
- /**
- * Add context menus to the MathItems in the MathDocument
- *
- * @return {MenuMathDocument} The MathDocument (so calls can be chained)
- */
- addMenu(): MenuMathDocument;
- /**
- * Checks if there are files being loaded by the menu, and restarts the typesetting if so
- *
- * @return {MenuMathDocument} The MathDocument (so calls can be chained)
- */
- checkLoading(): MenuMathDocument;
- }
- /**
- * The mixin for adding context menus to MathDocuments
- *
- * @param {B} BaseDocument The MathDocument class to be extended
- * @return {MenuMathDocument} The extended MathDocument class
- *
- * @template B The MathDocument class to extend
- */
- export function MenuMathDocumentMixin<B extends A11yDocumentConstructor>(
- BaseDocument: B
- ): Constructor<MenuMathDocument> & B {
- return class extends BaseDocument {
- /**
- * @override
- */
- public static OPTIONS = {
- //
- // These options are from the a11y extensions, which may not be loaded
- // initially, and so would cause "undefined option" error messages
- // if a user tries to configure them. So we include them here.
- // They are overridden by the options from the extensions when
- // those are loaded (via ...BaseDocument.OPTIONS).
- //
- enableEnrichment: true,
- enableComplexity: true,
- enableExplorer: true,
- enrichSpeech: 'none',
- enrichError: (_doc: MenuMathDocument, _math: MenuMathItem, err: Error) =>
- console.warn('Enrichment Error:', err),
- ...BaseDocument.OPTIONS,
- MenuClass: Menu,
- menuOptions: Menu.OPTIONS,
- enableMenu: true,
- sre: (BaseDocument.OPTIONS.sre || expandable({})),
- a11y: (BaseDocument.OPTIONS.a11y || expandable({})),
- renderActions: expandable({
- ...BaseDocument.OPTIONS.renderActions,
- addMenu: [STATE.CONTEXT_MENU],
- checkLoading: [STATE.UNPROCESSED + 1]
- })
- };
- /**
- * The menu associated with this document
- */
- public menu: Menu;
- /**
- * Extend the MathItem class used for this MathDocument
- *
- * @override
- * @constructor
- */
- constructor(...args: any[]) {
- super(...args);
- this.menu = new this.options.MenuClass(this, this.options.menuOptions);
- const ProcessBits = (this.constructor as typeof BaseDocument).ProcessBits;
- if (!ProcessBits.has('context-menu')) {
- ProcessBits.allocate('context-menu');
- }
- this.options.MathItem = MenuMathItemMixin<A11yMathItemConstructor>(this.options.MathItem);
- }
- /**
- * Add context menus to the MathItems in the MathDocument
- *
- * @return {MenuMathDocument} The MathDocument (so calls can be chained)
- */
- public addMenu(): MenuMathDocument {
- if (!this.processed.isSet('context-menu')) {
- for (const math of this.math) {
- (math as MenuMathItem).addMenu(this);
- }
- this.processed.set('context-menu');
- }
- return this;
- }
- /**
- * Checks if there are files being loaded by the menu, and restarts the typesetting if so
- *
- * @return {MenuMathDocument} The MathDocument (so calls can be chained)
- */
- public checkLoading(): MenuMathDocument {
- if (this.menu.isLoading) {
- mathjax.retryAfter(this.menu.loadingPromise.catch((err) => console.log(err)));
- }
- const settings = this.menu.settings;
- if (settings.collapsible) {
- this.options.enableComplexity = true;
- this.menu.checkComponent('a11y/complexity');
- }
- if (settings.explorer) {
- this.options.enableEnrichment = true;
- this.options.enableExplorer = true;
- this.menu.checkComponent('a11y/explorer');
- }
- return this;
- }
- /**
- * @override
- */
- public state(state: number, restore: boolean = false) {
- super.state(state, restore);
- if (state < STATE.CONTEXT_MENU) {
- this.processed.clear('context-menu');
- }
- return this;
- }
- /**
- * @override
- */
- public updateDocument() {
- super.updateDocument();
- (this.menu.menu.store as any).sort();
- return this;
- }
- };
- }
- /*==========================================================================*/
- /**
- * Add context-menu support to a Handler instance
- *
- * @param {Handler} handler The Handler instance to enhance
- * @return {Handler} The handler that was modified (for purposes of chaining extensions)
- */
- export function MenuHandler(handler: Handler<HTMLElement, Text, Document>): Handler<HTMLElement, Text, Document> {
- handler.documentClass = MenuMathDocumentMixin<A11yDocumentConstructor>(handler.documentClass as any);
- return handler;
- }
|