Skip to content

Commit 8c5a4a4

Browse files
Merge pull request #1672 from lifeart/basic-mathml-support
Feature: Basic mathml support
2 parents c7f8e59 + 622f1d7 commit 8c5a4a4

File tree

2 files changed

+97
-4
lines changed

2 files changed

+97
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import type { Namespace } from '@glimmer/interfaces';
2+
import { NS_HTML, NS_MATHML, NS_SVG } from '@glimmer/constants';
3+
4+
import { defineComponent, jitSuite, RenderTest, test } from '..';
5+
6+
class MathElementTest extends RenderTest {
7+
static suiteName = '<math>';
8+
query(selector: string) {
9+
let el = (s: string) => (this.element as unknown as HTMLElement).querySelector(s);
10+
return el(selector) as Element;
11+
}
12+
assertNamespace(selector: string, ns: Namespace) {
13+
this.assert.strictEqual(
14+
this.query(selector).namespaceURI,
15+
ns,
16+
`Expecting "${ns}" namespace for tag "${selector}"`
17+
);
18+
}
19+
20+
@test
21+
'<math> element can render'() {
22+
const Bar = defineComponent({}, '<math><msqrt><mi>x</mi></msqrt></math>');
23+
24+
this.renderComponent(Bar);
25+
26+
this.assertNamespace('math', NS_MATHML);
27+
this.assertNamespace('msqrt', NS_MATHML);
28+
this.assertNamespace('mi', NS_MATHML);
29+
}
30+
31+
@test
32+
'HTML and <math> element can render together'() {
33+
const Bar = defineComponent(
34+
{},
35+
'<div><p>Math inside:</p><math><msqrt><mi>x</mi></msqrt></math></div>'
36+
);
37+
38+
this.renderComponent(Bar);
39+
40+
this.assertNamespace('div', NS_HTML);
41+
this.assertNamespace('p', NS_HTML);
42+
this.assertNamespace('math', NS_MATHML);
43+
this.assertNamespace('msqrt', NS_MATHML);
44+
this.assertNamespace('mi', NS_MATHML);
45+
}
46+
47+
@test
48+
'SVG and <math> element can render together'() {
49+
const Bar = defineComponent(
50+
{},
51+
'<svg><circle cx="50" cy="50" r="40" /></svg><math><msqrt><mi>x</mi></msqrt></math>'
52+
);
53+
54+
this.renderComponent(Bar);
55+
56+
this.assertNamespace('svg', NS_SVG);
57+
this.assertNamespace('circle', NS_SVG);
58+
this.assertNamespace('math', NS_MATHML);
59+
this.assertNamespace('msqrt', NS_MATHML);
60+
this.assertNamespace('mi', NS_MATHML);
61+
}
62+
63+
@test
64+
'HTML, SVG, and <math> element can render together'() {
65+
const Bar = defineComponent(
66+
{},
67+
'<div><p>Math and SVG inside:</p><svg><circle cx="50" cy="50" r="40" /></svg><math><msqrt><mi>x</mi></msqrt></math></div>'
68+
);
69+
70+
this.renderComponent(Bar);
71+
72+
this.assertNamespace('div', NS_HTML);
73+
this.assertNamespace('p', NS_HTML);
74+
this.assertNamespace('svg', NS_SVG);
75+
this.assertNamespace('circle', NS_SVG);
76+
this.assertNamespace('math', NS_MATHML);
77+
this.assertNamespace('msqrt', NS_MATHML);
78+
this.assertNamespace('mi', NS_MATHML);
79+
}
80+
}
81+
82+
jitSuite(MathElementTest);

packages/@glimmer/runtime/lib/dom/operations.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import type {
22
Bounds,
33
Dict,
4+
Namespace,
45
Nullable,
56
SimpleComment,
67
SimpleDocument,
78
SimpleElement,
89
SimpleNode,
910
SimpleText,
1011
} from '@glimmer/interfaces';
11-
import { INSERT_BEFORE_BEGIN, INSERT_BEFORE_END, NS_SVG } from '@glimmer/constants';
12+
import { INSERT_BEFORE_BEGIN, INSERT_BEFORE_END, NS_MATHML, NS_SVG } from '@glimmer/constants';
1213
import { expect } from '@glimmer/debug-util';
1314

1415
import { ConcreteBounds } from '../bounds';
@@ -39,25 +40,35 @@ export class DOMOperations {
3940
}
4041

4142
createElement(tag: string, context?: SimpleElement): SimpleElement {
42-
let isElementInSVGNamespace: boolean, isHTMLIntegrationPoint: boolean;
43+
let isElementInSVGNamespace: boolean,
44+
isHTMLIntegrationPoint: boolean,
45+
isElementInMathMlNamespace: boolean,
46+
ns: Namespace;
4347

4448
if (context) {
4549
isElementInSVGNamespace = context.namespaceURI === NS_SVG || tag === 'svg';
50+
isElementInMathMlNamespace = context.namespaceURI === NS_MATHML || tag === 'math';
4651
isHTMLIntegrationPoint = !!(SVG_INTEGRATION_POINTS as Dict<number>)[context.tagName];
4752
} else {
4853
isElementInSVGNamespace = tag === 'svg';
54+
isElementInMathMlNamespace = tag === 'math';
4955
isHTMLIntegrationPoint = false;
5056
}
5157

52-
if (isElementInSVGNamespace && !isHTMLIntegrationPoint) {
58+
if ((isElementInMathMlNamespace || isElementInSVGNamespace) && !isHTMLIntegrationPoint) {
5359
// FIXME: This does not properly handle <font> with color, face, or
5460
// size attributes, which is also disallowed by the spec. We should fix
5561
// this.
5662
if (BLACKLIST_TABLE[tag]) {
5763
throw new Error(`Cannot create a ${tag} inside an SVG context`);
5864
}
65+
if (isElementInMathMlNamespace) {
66+
ns = NS_MATHML;
67+
} else {
68+
ns = NS_SVG;
69+
}
5970

60-
return this.document.createElementNS(NS_SVG, tag);
71+
return this.document.createElementNS(ns, tag);
6172
} else {
6273
return this.document.createElement(tag);
6374
}

0 commit comments

Comments
 (0)