Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MathML #1063

Merged
merged 3 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Thank you for your interest in contributing to MDN Web Docs.
|--> fonts # fonts used by the editor and examples
|--> html-examples
|--> js-examples
|--> mathml-examples
|--> media # media used only by the examples
```

Expand All @@ -45,6 +46,7 @@ Thank you for your interest in contributing to MDN Web Docs.
|----> js # All JS examples
|----> tabbed # All examples using the tabbed UI
|----> wat # WebAssembly examples
|----> mathml # MathML examples
|----> webapi-tabbed # Web API examples (not currently used in production)
```

Expand Down
4 changes: 2 additions & 2 deletions __tests__/puppeteer-tabbed-editor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ describe("Tabbed Editor", () => {
const expectedCSS =
" address { font-variant-caps: small-caps;}a { font-variant: normal;} ";
const expectedHTML =
"<address> James Rockford<br> 2354 Pacific Coast Highway<br> " +
" <address> James Rockford<br> 2354 Pacific Coast Highway<br> " +
"California<br> USA<br> +311-555-2368<br> Email: " +
'<a href="mailto:j.rockford@example.com">j.rockford@example.com</a><br>' +
"</address>";
"</address> ";
queengooborg marked this conversation as resolved.
Show resolved Hide resolved

await page.waitForSelector("#output-iframe");
const outputIframe = await page.$("#output-iframe");
Expand Down
8 changes: 8 additions & 0 deletions editor/css/tabbed-editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,11 @@
height: min-content; /* This value ensures correct calculation of clientHeight in /pages/tabbed/img */
width: fit-content; /* This value moves horizontal scroll bar to the bottom of iframe */
}

#html-output math {
font-size: 1.5rem;
}

#html-output.editor-mathml {
margin: auto;
}
24 changes: 24 additions & 0 deletions editor/js/editor-libs/feature-detector.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,27 @@ export function isDefined(feature) {

return getFeatureObject(feature) !== undefined;
}

export function isMathMLSupported() {
// Test used by MathML polyfill in YARI (https://github.com/mdn/yari/blob/main/client/src/document/mathml-polyfill)
const offscreenContainer = document.createElement("div");
const mathMLNamespace = "http://www.w3.org/1998/Math/MathML";
const mathElement = document.createElementNS(mathMLNamespace, "math");
const mspaceElement = document.createElementNS(mathMLNamespace, "mspace");
mspaceElement.setAttribute("height", "23px");
mspaceElement.setAttribute("width", "77px");
mathElement.append(mspaceElement);
offscreenContainer.append(mathElement);
offscreenContainer.classList.add("offscreen");

const mathMLTestElement = document.body.appendChild(offscreenContainer);
if (!mspaceElement) {
return false;
}
const box = mspaceElement.getBoundingClientRect();
document.body.removeChild(mathMLTestElement);
if (!box) {
return false;
}
return Math.abs(box.height - 23) <= 1 && Math.abs(box.width - 77) <= 1;
}
queengooborg marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 10 additions & 0 deletions editor/js/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as mceEvents from "./editor-libs/events.js";
import * as mceUtils from "./editor-libs/mce-utils.js";
import * as tabby from "./editor-libs/tabby.js";
import { getEditorContent } from "./editor-libs/codemirror-editor.js";
import { isMathMLSupported } from "./editor-libs/feature-detector.js";

import "../css/editor-libs/ui-fonts.css";
import "../css/editor-libs/common.css";
Expand All @@ -24,6 +25,7 @@ import "../css/tabbed-editor.css";
const staticJSCode = jsEditor.querySelector("pre");
const outputIFrame = document.getElementById("output-iframe");
const outputTemplate = getOutputTemplate();
const editorType = editorContainer.dataset.editorType;

let appliedHeightAdjustment = false;
let timer;
Expand Down Expand Up @@ -174,6 +176,14 @@ import "../css/tabbed-editor.css";
timer = setTimeout(() => refreshOutput(), 500);
}

if (editorType === "mathml" && !isMathMLSupported()) {
const notSupportedWarning = document.getElementById(
"warning-mathml-not-supported"
);
notSupportedWarning.classList.remove("hidden");
return;
}

outputIFrame.addEventListener("load", () => onOutputLoaded());

header.addEventListener("click", (event) => {
Expand Down
11 changes: 9 additions & 2 deletions editor/tmpl/live-tabbed-tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ <h4 class="output-heading">%title%</h4>
</header>
<noscript>
<div id="warning-no-script" class="warning">
Interactive example cannot be shown because JavaScript is disabled.
The interactive example cannot be shown because JavaScript is disabled.
</div>
</noscript>
<div id="warning-mathml-not-supported" class="warning hidden">
The interactive example cannot be shown because MathML is not supported by
your browser.
</div>
<div
id="editor-container"
class="editor-container %editor-height% hidden"
%active-tabs%
%default-tab%
data-editor-type="%editor-type%"
>
<section id="tab-container" class="tabs">
<div class="tab-list" id="tablist" role="tablist">
Expand Down Expand Up @@ -133,7 +138,9 @@ <h4 class="console-label">Console Output</h4>
</style>
</template>
<template id="output-body">
<div id="html-output" class="output">%html-content%</div>
<div id="html-output" class="output editor-%editor-type%">
%html-content%
</div>

<script>
function executeExample() {
Expand Down
94 changes: 50 additions & 44 deletions lib/pageBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function build(pages, selfVersion = "") {
const type = currentPage.type;
let tmpl = pageBuilderUtils.getPageTmpl(type);
let outputHTML = "";
let exampleCode;

const outputPath =
config.pagesDir + currentPage.type + "/" + currentPage.fileName;
Expand All @@ -45,53 +46,58 @@ function build(pages, selfVersion = "") {
tmpl = pageBuilderUtils.setCacheBuster(`?v=${selfVersion}`, tmpl);

// handle both standard and webapi tabbed examples
if (type.indexOf("tabbed") > -1) {
fse.outputFileSync(
outputPath,
tabbedPageBuilder.buildTabbedExample(tmpl, currentPage)
);
} else if (type === "wat") {
// set main title
tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);

const exampleCode = processor.processWat(
currentPage.watExampleCode,
currentPage.jsExampleCode
);

outputHTML = tmpl.replace("%example-code%", () => exampleCode);

fse.outputFileSync(outputPath, outputHTML);
} else {
// is there a linked CSS file
if (cssSource) {
// inject the link tag into the source
tmpl = processor.processInclude("css", tmpl, cssSource);
} else {
// clear out the template string
tmpl = tmpl.replace("%example-css-src%", "");
}

// is there a linked JS file
if (jsSource) {
// inject the script tag into the source
tmpl = processor.processInclude("js", tmpl, jsSource);
} else {
// clear out the template string
tmpl = tmpl.replace("%example-js-src%", "");
}

// set main title
tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);
switch (type) {
case "tabbed":
case "webapi-tabbed":
case "mathml":
fse.outputFileSync(
outputPath,
tabbedPageBuilder.buildTabbedExample(tmpl, currentPage)
);
break;
case "wat":
// set main title
tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);

exampleCode = processor.processWat(
currentPage.watExampleCode,
currentPage.jsExampleCode
);

const exampleCode = processor.processExampleCode(
currentPage.type,
currentPage.exampleCode
);
outputHTML = tmpl.replace("%example-code%", () => exampleCode);
break;
case "css":
case "js":
// is there a linked CSS file
if (cssSource) {
// inject the link tag into the source
tmpl = processor.processInclude("css", tmpl, cssSource);
} else {
// clear out the template string
tmpl = tmpl.replace("%example-css-src%", "");
}

// is there a linked JS file
if (jsSource) {
// inject the script tag into the source
tmpl = processor.processInclude("js", tmpl, jsSource);
} else {
// clear out the template string
tmpl = tmpl.replace("%example-js-src%", "");
}

// set main title
tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);

exampleCode = processor.processExampleCode(
currentPage.type,
currentPage.exampleCode
);

outputHTML = tmpl.replace("%example-code%", () => exampleCode);
outputHTML = tmpl.replace("%example-code%", () => exampleCode);

fse.outputFileSync(outputPath, outputHTML);
fse.outputFileSync(outputPath, outputHTML);
break;
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions lib/pageBuilderUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function getPageTmpl(tmplType) {
break;
case "tabbed":
case "webapi-tabbed":
case "mathml":
try {
return fse.readFileSync(
path.join(__dirname, "../editor/tmpl/live-tabbed-tmpl.html"),
Expand Down Expand Up @@ -164,3 +165,9 @@ export function setCacheBuster(string, tmpl) {
const regex = /%cache-buster%/g;
return tmpl.replace(regex, string);
}

export function setEditorType(currentPage, tmpl) {
const regex = /%editor-type%/g;

return tmpl.replace(regex, currentPage.type);
}
10 changes: 2 additions & 8 deletions lib/tabbedPageBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,16 @@ function addJS(currentPage, tmpl) {
* @returns {String} The HTML for a tabbed example
*/
export function buildTabbedExample(tmpl, currentPage) {
// set main title
tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl);
// set the height of the editor container
tmpl = pageBuilderUtils.setEditorHeight(currentPage, tmpl);
// set the active tabs to show
tmpl = pageBuilderUtils.setActiveTabs(currentPage, tmpl);
// set the default tab to open
tmpl = pageBuilderUtils.setDefaultTab(currentPage, tmpl);
// set the console state
tmpl = pageBuilderUtils.setConsoleState(currentPage, tmpl);
tmpl = pageBuilderUtils.setEditorType(currentPage, tmpl);

// add the example CSS
// add example code
tmpl = addCSS(currentPage, tmpl);
// add the example HTML
tmpl = addHTML(currentPage, tmpl);
// add the example JS
tmpl = addJS(currentPage, tmpl);
return tmpl;
}
23 changes: 23 additions & 0 deletions live-examples/mathml-examples/elements/math.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<math display="block">
<mrow>
<munderover>
<mo>∑</mo>
<mrow>
<mi>n</mi>
<mo>=</mo>
<mn>1</mn>
</mrow>
<mrow>
<mo>+</mo>
<mn>∞</mn>
</mrow>
</munderover>
<mfrac>
<mn>1</mn>
<msup>
<mi>n</mi>
<mn>2</mn>
</msup>
</mfrac>
</mrow>
</math>
20 changes: 20 additions & 0 deletions live-examples/mathml-examples/elements/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"pages": {
"math": {
"exampleCode": "./live-examples/mathml-examples/elements/math.html",
"fileName": "math.html",
"title": "MathML Demo: <math>",
"type": "mathml",
"height": "tabbed-taller",
"tabs": "html"
},
"mi": {
"exampleCode": "./live-examples/mathml-examples/elements/mi.html",
"fileName": "mi.html",
"title": "MathML Demo: <mi>",
"type": "mathml",
"height": "tabbed-standard",
"tabs": "html"
}
}
}
11 changes: 11 additions & 0 deletions live-examples/mathml-examples/elements/mi.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<math display="block">
<mi>sin</mi>
</math>

<math display="block">
<mi>y</mi>
</math>

<math display="block">
<mi mathvariant="normal">F</mi>
</math>