|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import utils from "./utils"; |
|
import {DocumentFragment} from "./tree"; |
|
import {createClass} from "./domTree"; |
|
import {makeEm} from "./units"; |
|
|
|
import type {VirtualNode} from "./tree"; |
|
|
|
|
|
|
|
|
|
|
|
export type MathNodeType = |
|
"math" | "annotation" | "semantics" | |
|
"mtext" | "mn" | "mo" | "mi" | "mspace" | |
|
"mover" | "munder" | "munderover" | "msup" | "msub" | "msubsup" | |
|
"mfrac" | "mroot" | "msqrt" | |
|
"mtable" | "mtr" | "mtd" | "mlabeledtr" | |
|
"mrow" | "menclose" | |
|
"mstyle" | "mpadded" | "mphantom" | "mglyph"; |
|
|
|
export interface MathDomNode extends VirtualNode { |
|
toText(): string; |
|
} |
|
|
|
export type documentFragment = DocumentFragment<MathDomNode>; |
|
export function newDocumentFragment( |
|
children: $ReadOnlyArray<MathDomNode> |
|
): documentFragment { |
|
return new DocumentFragment(children); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export class MathNode implements MathDomNode { |
|
type: MathNodeType; |
|
attributes: {[string]: string}; |
|
children: $ReadOnlyArray<MathDomNode>; |
|
classes: string[]; |
|
|
|
constructor( |
|
type: MathNodeType, |
|
children?: $ReadOnlyArray<MathDomNode>, |
|
classes?: string[] |
|
) { |
|
this.type = type; |
|
this.attributes = {}; |
|
this.children = children || []; |
|
this.classes = classes || []; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
setAttribute(name: string, value: string) { |
|
this.attributes[name] = value; |
|
} |
|
|
|
|
|
|
|
|
|
getAttribute(name: string): string { |
|
return this.attributes[name]; |
|
} |
|
|
|
|
|
|
|
|
|
toNode(): Node { |
|
const node = document.createElementNS( |
|
"http://www.w3.org/1998/Math/MathML", this.type); |
|
|
|
for (const attr in this.attributes) { |
|
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { |
|
node.setAttribute(attr, this.attributes[attr]); |
|
} |
|
} |
|
|
|
if (this.classes.length > 0) { |
|
node.className = createClass(this.classes); |
|
} |
|
|
|
for (let i = 0; i < this.children.length; i++) { |
|
node.appendChild(this.children[i].toNode()); |
|
} |
|
|
|
return node; |
|
} |
|
|
|
|
|
|
|
|
|
toMarkup(): string { |
|
let markup = "<" + this.type; |
|
|
|
|
|
for (const attr in this.attributes) { |
|
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { |
|
markup += " " + attr + "=\""; |
|
markup += utils.escape(this.attributes[attr]); |
|
markup += "\""; |
|
} |
|
} |
|
|
|
if (this.classes.length > 0) { |
|
markup += ` class ="${utils.escape(createClass(this.classes))}"`; |
|
} |
|
|
|
markup += ">"; |
|
|
|
for (let i = 0; i < this.children.length; i++) { |
|
markup += this.children[i].toMarkup(); |
|
} |
|
|
|
markup += "</" + this.type + ">"; |
|
|
|
return markup; |
|
} |
|
|
|
|
|
|
|
|
|
toText(): string { |
|
return this.children.map(child => child.toText()).join(""); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
export class TextNode implements MathDomNode { |
|
text: string; |
|
|
|
constructor(text: string) { |
|
this.text = text; |
|
} |
|
|
|
|
|
|
|
|
|
toNode(): Node { |
|
return document.createTextNode(this.text); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
toMarkup(): string { |
|
return utils.escape(this.toText()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
toText(): string { |
|
return this.text; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
class SpaceNode implements MathDomNode { |
|
width: number; |
|
character: ?string; |
|
|
|
|
|
|
|
|
|
constructor(width: number) { |
|
this.width = width; |
|
|
|
|
|
|
|
|
|
if (width >= 0.05555 && width <= 0.05556) { |
|
this.character = "\u200a"; |
|
} else if (width >= 0.1666 && width <= 0.1667) { |
|
this.character = "\u2009"; |
|
} else if (width >= 0.2222 && width <= 0.2223) { |
|
this.character = "\u2005"; |
|
} else if (width >= 0.2777 && width <= 0.2778) { |
|
this.character = "\u2005\u200a"; |
|
} else if (width >= -0.05556 && width <= -0.05555) { |
|
this.character = "\u200a\u2063"; |
|
} else if (width >= -0.1667 && width <= -0.1666) { |
|
this.character = "\u2009\u2063"; |
|
} else if (width >= -0.2223 && width <= -0.2222) { |
|
this.character = "\u205f\u2063"; |
|
} else if (width >= -0.2778 && width <= -0.2777) { |
|
this.character = "\u2005\u2063"; |
|
} else { |
|
this.character = null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
toNode(): Node { |
|
if (this.character) { |
|
return document.createTextNode(this.character); |
|
} else { |
|
const node = document.createElementNS( |
|
"http://www.w3.org/1998/Math/MathML", "mspace"); |
|
node.setAttribute("width", makeEm(this.width)); |
|
return node; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
toMarkup(): string { |
|
if (this.character) { |
|
return `<mtext>${this.character}</mtext>`; |
|
} else { |
|
return `<mspace width="${makeEm(this.width)}"/>`; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
toText(): string { |
|
if (this.character) { |
|
return this.character; |
|
} else { |
|
return " "; |
|
} |
|
} |
|
} |
|
|
|
export default { |
|
MathNode, |
|
TextNode, |
|
SpaceNode, |
|
newDocumentFragment, |
|
}; |
|
|