123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /*************************************************************
- *
- * Copyright (c) 2018-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 computes complexity of the internal MathML
- * and optionally marks collapsible items
- *
- * @author dpvc@mathjax.org (Davide Cervone)
- */
- import {Handler} from '../core/Handler.js';
- import {MathDocumentConstructor} from '../core/MathDocument.js';
- import {STATE, newState} from '../core/MathItem.js';
- import {MathML} from '../input/mathml.js';
- import {MmlNode} from '../core/MmlTree/MmlNode.js';
- import {EnrichHandler, EnrichedMathItem, EnrichedMathDocument} from './semantic-enrich.js';
- import {ComplexityVisitor} from './complexity/visitor.js';
- import {OptionList, selectOptionsFromKeys, expandable} from '../util/Options.js';
- /**
- * Generic constructor for Mixins
- */
- export type Constructor<T> = new(...args: any[]) => T;
- /**
- * Shorthands for constructors
- */
- export type EMItemC<N, T, D> = Constructor<EnrichedMathItem<N, T, D>>;
- export type CMItemC<N, T, D> = Constructor<ComplexityMathItem<N, T, D>>;
- export type EMDocC<N, T, D> = MathDocumentConstructor<EnrichedMathDocument<N, T, D>>;
- export type CMDocC<N, T, D> = Constructor<ComplexityMathDocument<N, T, D>>;
- /*==========================================================================*/
- /**
- * Add STATE value for having complexity added (after ENRICHED and before TYPESET)
- */
- newState('COMPLEXITY', 40);
- /**
- * The functions added to MathItem for complexity
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- */
- export interface ComplexityMathItem<N, T, D> extends EnrichedMathItem<N, T, D> {
- /**
- * @param {ComplexityMathDocument} document The MathDocument for the MathItem
- * @param {boolean} force True to force the computation even if enableComplexity is false
- */
- complexity(document: ComplexityMathDocument<N, T, D>, force?: boolean): void;
- }
- /**
- * The mixin for adding complexity to MathItems
- *
- * @param {B} BaseMathItem The MathItem class to be extended
- * @param {function(MmlNode): void} computeComplexity Method of complexity computation.
- * @return {ComplexityMathItem} The complexity MathItem class
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- * @template B The MathItem class to extend
- */
- export function ComplexityMathItemMixin<N, T, D, B extends
- EMItemC<N, T, D>>(BaseMathItem: B, computeComplexity: (node: MmlNode) => void): CMItemC<N, T, D> & B {
- return class extends BaseMathItem {
- /**
- * @param {ComplexityMathDocument} document The MathDocument for the MathItem
- * @param {boolean} force True to force the computation even if enableComplexity is false
- */
- public complexity(document: ComplexityMathDocument<N, T, D>, force: boolean = false) {
- if (this.state() >= STATE.COMPLEXITY) return;
- if (!this.isEscaped && (document.options.enableComplexity || force)) {
- this.enrich(document, true);
- computeComplexity(this.root);
- }
- this.state(STATE.COMPLEXITY);
- }
- };
- }
- /*==========================================================================*/
- /**
- * The functions added to MathDocument for complexity
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- */
- export interface ComplexityMathDocument<N, T, D> extends EnrichedMathDocument<N, T, D> {
- /**
- * Perform complexity computations on the MathItems in the MathDocument
- *
- * @return {ComplexityMathDocument} The MathDocument (so calls can be chained)
- */
- complexity(): ComplexityMathDocument<N, T, D>;
- }
- /**
- * The mixin for adding complexity to MathDocuments
- *
- * @param {B} BaseDocument The MathDocument class to be extended
- * @return {EnrichedMathDocument} The enriched MathDocument class
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- * @template B The MathDocument class to extend
- */
- export function ComplexityMathDocumentMixin<N, T, D, B extends
- EMDocC<N, T, D>>(BaseDocument: B): CMDocC<N, T, D> & B {
- return class extends BaseDocument {
- /**
- * The options for this type of document
- */
- public static OPTIONS: OptionList = {
- ...BaseDocument.OPTIONS,
- ...ComplexityVisitor.OPTIONS,
- enableComplexity: true,
- ComplexityVisitor: ComplexityVisitor,
- renderActions: expandable({
- ...BaseDocument.OPTIONS.renderActions,
- complexity: [STATE.COMPLEXITY]
- })
- };
- /**
- * The visitor that computes complexities
- */
- protected complexityVisitor: ComplexityVisitor;
- /**
- * Extend the MathItem class used for this MathDocument
- *
- * @override
- * @constructor
- */
- constructor(...args: any[]) {
- super(...args);
- const ProcessBits = (this.constructor as typeof BaseDocument).ProcessBits;
- if (!ProcessBits.has('complexity')) {
- ProcessBits.allocate('complexity');
- }
- const visitorOptions = selectOptionsFromKeys(this.options, this.options.ComplexityVisitor.OPTIONS);
- this.complexityVisitor = new this.options.ComplexityVisitor(this.mmlFactory, visitorOptions);
- const computeComplexity = ((node: MmlNode) => this.complexityVisitor.visitTree(node));
- this.options.MathItem =
- ComplexityMathItemMixin<N, T, D, EMItemC<N, T, D>>(
- this.options.MathItem, computeComplexity
- );
- }
- /**
- * Compute the complexity the MathItems in this MathDocument
- */
- public complexity() {
- if (!this.processed.isSet('complexity')) {
- if (this.options.enableComplexity) {
- for (const math of this.math) {
- (math as ComplexityMathItem<N, T, D>).complexity(this);
- }
- }
- this.processed.set('complexity');
- }
- return this;
- }
- /**
- * @override
- */
- public state(state: number, restore: boolean = false) {
- super.state(state, restore);
- if (state < STATE.COMPLEXITY) {
- this.processed.clear('complexity');
- }
- return this;
- }
- };
- }
- /*==========================================================================*/
- /**
- * Add complexity computations a Handler instance
- *
- * @param {Handler} handler The Handler instance to enhance
- * @param {MathML} MmlJax The MathML input jax to use for reading the enriched MathML
- * @return {Handler} The handler that was modified (for purposes of chainging extensions)
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- */
- export function ComplexityHandler<N, T, D>(
- handler: Handler<N, T, D>,
- MmlJax: MathML<N, T, D> = null
- ): Handler<N, T, D> {
- if (!handler.documentClass.prototype.enrich && MmlJax) {
- handler = EnrichHandler(handler, MmlJax);
- }
- handler.documentClass = ComplexityMathDocumentMixin<N, T, D, EMDocC<N, T, D>>(handler.documentClass as any);
- return handler;
- }
|