Turn var into const or let
This commit is contained in:
parent
9b565a6375
commit
bd9db332d2
|
@ -35,6 +35,7 @@
|
|||
"no-unreachable": 2,
|
||||
"no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^_*$"}],
|
||||
"no-useless-call": 2,
|
||||
"no-var": 2,
|
||||
"no-with": 2,
|
||||
"one-var": [2, "never"],
|
||||
"prefer-const": 2,
|
||||
|
@ -52,9 +53,6 @@
|
|||
// We've decided explicitly not to care about this.
|
||||
"arrow-parens": 0,
|
||||
// ---------------------------------------
|
||||
// Stuff that's disabled for now, but maybe shouldn't be.
|
||||
// disabled because KaTeX doesn't use ES6
|
||||
"no-var": 0,
|
||||
// TODO(csilvers): enable these if/when community agrees on it.
|
||||
"prefer-arrow-callback": 0,
|
||||
"object-curly-spacing": [0, "always"],
|
||||
|
|
10
cli.js
10
cli.js
|
@ -3,11 +3,11 @@
|
|||
// Reads TeX from stdin, outputs HTML to stdout.
|
||||
/* eslint no-console:0 */
|
||||
|
||||
var katex = require("./");
|
||||
var input = "";
|
||||
const katex = require("./");
|
||||
let input = "";
|
||||
|
||||
// Skip the first two args, which are just "node" and "cli.js"
|
||||
var args = process.argv.slice(2);
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.indexOf("--help") !== -1) {
|
||||
console.log(process.argv[0] + " " + process.argv[1] +
|
||||
|
@ -26,7 +26,7 @@ process.stdin.on("data", function(chunk) {
|
|||
});
|
||||
|
||||
process.stdin.on("end", function() {
|
||||
var options = { displayMode: args.indexOf("--display-mode") !== -1 };
|
||||
var output = katex.renderToString(input, options);
|
||||
const options = { displayMode: args.indexOf("--display-mode") !== -1 };
|
||||
const output = katex.renderToString(input, options);
|
||||
console.log(output);
|
||||
});
|
||||
|
|
|
@ -4,21 +4,21 @@
|
|||
/* global it: false */
|
||||
/* global describe: false */
|
||||
|
||||
var splitAtDelimiters = require("./splitAtDelimiters");
|
||||
const splitAtDelimiters = require("./splitAtDelimiters");
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.addMatchers({
|
||||
toSplitInto: function() {
|
||||
return {
|
||||
compare: function(actual, left, right, result) {
|
||||
var message = {
|
||||
const message = {
|
||||
pass: true,
|
||||
message: "'" + actual + "' split correctly",
|
||||
};
|
||||
|
||||
var startData = [{type: "text", data: actual}];
|
||||
const startData = [{type: "text", data: actual}];
|
||||
|
||||
var split =
|
||||
const split =
|
||||
splitAtDelimiters(startData, left, right, false);
|
||||
|
||||
if (split.length !== result.length) {
|
||||
|
@ -30,12 +30,12 @@ beforeEach(function() {
|
|||
return message;
|
||||
}
|
||||
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
var real = split[i];
|
||||
var correct = result[i];
|
||||
for (let i = 0; i < split.length; i++) {
|
||||
const real = split[i];
|
||||
const correct = result[i];
|
||||
|
||||
var good = true;
|
||||
var diff;
|
||||
let good = true;
|
||||
let diff;
|
||||
|
||||
if (real.type !== correct.type) {
|
||||
good = false;
|
||||
|
@ -189,7 +189,7 @@ describe("A delimiter splitter", function() {
|
|||
});
|
||||
|
||||
it("remembers which delimiters are display-mode", function() {
|
||||
var startData = [{type: "text", data: "hello ( world ) boo"}];
|
||||
const startData = [{type: "text", data: "hello ( world ) boo"}];
|
||||
|
||||
expect(splitAtDelimiters(startData, "(", ")", true)).toEqual(
|
||||
[
|
||||
|
@ -201,7 +201,7 @@ describe("A delimiter splitter", function() {
|
|||
});
|
||||
|
||||
it("works with more than one start datum", function() {
|
||||
var startData = [
|
||||
const startData = [
|
||||
{type: "text", data: "hello ( world ) boo"},
|
||||
{type: "math", data: "math", rawData: "(math)", display: true},
|
||||
{type: "text", data: "hello ( world ) boo"},
|
||||
|
@ -222,7 +222,7 @@ describe("A delimiter splitter", function() {
|
|||
});
|
||||
|
||||
it("doesn't do splitting inside of math nodes", function() {
|
||||
var startData = [
|
||||
const startData = [
|
||||
{type: "text", data: "hello ( world ) boo"},
|
||||
{type: "math", data: "hello ( world ) boo",
|
||||
rawData: "(hello ( world ) boo)", display: true},
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/* eslint no-console:0 */
|
||||
/* global katex */
|
||||
|
||||
var splitAtDelimiters = require("./splitAtDelimiters");
|
||||
const splitAtDelimiters = require("./splitAtDelimiters");
|
||||
|
||||
var splitWithDelimiters = function(text, delimiters) {
|
||||
var data = [{type: "text", data: text}];
|
||||
for (var i = 0; i < delimiters.length; i++) {
|
||||
var delimiter = delimiters[i];
|
||||
const splitWithDelimiters = function(text, delimiters) {
|
||||
let data = [{type: "text", data: text}];
|
||||
for (let i = 0; i < delimiters.length; i++) {
|
||||
const delimiter = delimiters[i];
|
||||
data = splitAtDelimiters(
|
||||
data, delimiter.left, delimiter.right,
|
||||
delimiter.display || false);
|
||||
|
@ -14,17 +14,17 @@ var splitWithDelimiters = function(text, delimiters) {
|
|||
return data;
|
||||
};
|
||||
|
||||
var renderMathInText = function(text, delimiters) {
|
||||
var data = splitWithDelimiters(text, delimiters);
|
||||
const renderMathInText = function(text, delimiters) {
|
||||
const data = splitWithDelimiters(text, delimiters);
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === "text") {
|
||||
fragment.appendChild(document.createTextNode(data[i].data));
|
||||
} else {
|
||||
var span = document.createElement("span");
|
||||
var math = data[i].data;
|
||||
const span = document.createElement("span");
|
||||
const math = data[i].data;
|
||||
try {
|
||||
katex.render(math, span, {
|
||||
displayMode: data[i].display,
|
||||
|
@ -48,17 +48,17 @@ var renderMathInText = function(text, delimiters) {
|
|||
return fragment;
|
||||
};
|
||||
|
||||
var renderElem = function(elem, delimiters, ignoredTags) {
|
||||
for (var i = 0; i < elem.childNodes.length; i++) {
|
||||
var childNode = elem.childNodes[i];
|
||||
const renderElem = function(elem, delimiters, ignoredTags) {
|
||||
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||
const childNode = elem.childNodes[i];
|
||||
if (childNode.nodeType === 3) {
|
||||
// Text node
|
||||
var frag = renderMathInText(childNode.textContent, delimiters);
|
||||
const frag = renderMathInText(childNode.textContent, delimiters);
|
||||
i += frag.childNodes.length - 1;
|
||||
elem.replaceChild(frag, childNode);
|
||||
} else if (childNode.nodeType === 1) {
|
||||
// Element node
|
||||
var shouldRender = ignoredTags.indexOf(
|
||||
const shouldRender = ignoredTags.indexOf(
|
||||
childNode.nodeName.toLowerCase()) === -1;
|
||||
|
||||
if (shouldRender) {
|
||||
|
@ -69,7 +69,7 @@ var renderElem = function(elem, delimiters, ignoredTags) {
|
|||
}
|
||||
};
|
||||
|
||||
var defaultOptions = {
|
||||
const defaultOptions = {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "\\[", right: "\\]", display: true},
|
||||
|
@ -83,11 +83,12 @@ var defaultOptions = {
|
|||
],
|
||||
};
|
||||
|
||||
var extend = function(obj) {
|
||||
const extend = function(obj) {
|
||||
// Adapted from underscore.js' `_.extend`. See LICENSE.txt for license.
|
||||
var source;
|
||||
var prop;
|
||||
for (var i = 1, length = arguments.length; i < length; i++) {
|
||||
let source;
|
||||
let prop;
|
||||
const length = arguments.length;
|
||||
for (let i = 1; i < length; i++) {
|
||||
source = arguments[i];
|
||||
for (prop in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, prop)) {
|
||||
|
@ -98,7 +99,7 @@ var extend = function(obj) {
|
|||
return obj;
|
||||
};
|
||||
|
||||
var renderMathInElement = function(elem, options) {
|
||||
const renderMathInElement = function(elem, options) {
|
||||
if (!elem) {
|
||||
throw new Error("No element provided to render");
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/* eslint no-constant-condition:0 */
|
||||
var findEndOfMath = function(delimiter, text, startIndex) {
|
||||
const findEndOfMath = function(delimiter, text, startIndex) {
|
||||
// Adapted from
|
||||
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||
var index = startIndex;
|
||||
var braceLevel = 0;
|
||||
let index = startIndex;
|
||||
let braceLevel = 0;
|
||||
|
||||
var delimLength = delimiter.length;
|
||||
const delimLength = delimiter.length;
|
||||
|
||||
while (index < text.length) {
|
||||
var character = text[index];
|
||||
const character = text[index];
|
||||
|
||||
if (braceLevel <= 0 &&
|
||||
text.slice(index, index + delimLength) === delimiter) {
|
||||
|
@ -27,16 +27,16 @@ var findEndOfMath = function(delimiter, text, startIndex) {
|
|||
return -1;
|
||||
};
|
||||
|
||||
var splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
var finalData = [];
|
||||
const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
const finalData = [];
|
||||
|
||||
for (var i = 0; i < startData.length; i++) {
|
||||
for (let i = 0; i < startData.length; i++) {
|
||||
if (startData[i].type === "text") {
|
||||
var text = startData[i].data;
|
||||
const text = startData[i].data;
|
||||
|
||||
var lookingForLeft = true;
|
||||
var currIndex = 0;
|
||||
var nextIndex;
|
||||
let lookingForLeft = true;
|
||||
let currIndex = 0;
|
||||
let nextIndex;
|
||||
|
||||
nextIndex = text.indexOf(leftDelim);
|
||||
if (nextIndex !== -1) {
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
/* eslint no-console:0, prefer-spread:0 */
|
||||
"use strict";
|
||||
|
||||
var childProcess = require("child_process");
|
||||
var fs = require("fs");
|
||||
var http = require("http");
|
||||
var jspngopt = require("jspngopt");
|
||||
var net = require("net");
|
||||
var os = require("os");
|
||||
var pako = require("pako");
|
||||
var path = require("path");
|
||||
var selenium = require("selenium-webdriver");
|
||||
var firefox = require("selenium-webdriver/firefox");
|
||||
const childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
const http = require("http");
|
||||
const jspngopt = require("jspngopt");
|
||||
const net = require("net");
|
||||
const os = require("os");
|
||||
const pako = require("pako");
|
||||
const path = require("path");
|
||||
const selenium = require("selenium-webdriver");
|
||||
const firefox = require("selenium-webdriver/firefox");
|
||||
|
||||
var app = require("../../server");
|
||||
var data = require("../../test/screenshotter/ss_data");
|
||||
const app = require("../../server");
|
||||
const data = require("../../test/screenshotter/ss_data");
|
||||
|
||||
var dstDir = path.normalize(
|
||||
const dstDir = path.normalize(
|
||||
path.join(__dirname, "..", "..", "test", "screenshotter", "images"));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Process command line arguments
|
||||
|
||||
var opts = require("nomnom")
|
||||
const opts = require("nomnom")
|
||||
.option("browser", {
|
||||
abbr: "b",
|
||||
"default": "firefox",
|
||||
|
@ -74,25 +74,25 @@ var opts = require("nomnom")
|
|||
})
|
||||
.parse();
|
||||
|
||||
var listOfCases;
|
||||
let listOfCases;
|
||||
if (opts.include) {
|
||||
listOfCases = opts.include.split(",");
|
||||
} else {
|
||||
listOfCases = Object.keys(data);
|
||||
}
|
||||
if (opts.exclude) {
|
||||
var exclude = opts.exclude.split(",");
|
||||
const exclude = opts.exclude.split(",");
|
||||
listOfCases = listOfCases.filter(function(key) {
|
||||
return exclude.indexOf(key) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
var seleniumURL = opts.seleniumURL;
|
||||
var seleniumIP = opts.seleniumIP;
|
||||
var seleniumPort = opts.seleniumPort;
|
||||
var katexURL = opts.katexURL;
|
||||
var katexIP = opts.katexIP;
|
||||
var katexPort = opts.katexPort;
|
||||
let seleniumURL = opts.seleniumURL;
|
||||
let seleniumIP = opts.seleniumIP;
|
||||
let seleniumPort = opts.seleniumPort;
|
||||
let katexURL = opts.katexURL;
|
||||
let katexIP = opts.katexIP;
|
||||
let katexPort = opts.katexPort;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Work out connection to selenium docker container
|
||||
|
@ -107,15 +107,15 @@ function check(err) {
|
|||
}
|
||||
|
||||
function cmd() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var cmd = args.shift();
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
const cmd = args.shift();
|
||||
return childProcess.execFileSync(
|
||||
cmd, args, { encoding: "utf-8" }).replace(/\n$/, "");
|
||||
}
|
||||
|
||||
function guessDockerIPs() {
|
||||
if (process.env.DOCKER_MACHINE_NAME) {
|
||||
var machine = process.env.DOCKER_MACHINE_NAME;
|
||||
const machine = process.env.DOCKER_MACHINE_NAME;
|
||||
seleniumIP = seleniumIP || cmd("docker-machine", "ip", machine);
|
||||
katexIP = katexIP || cmd("docker-machine", "ssh", machine,
|
||||
"echo ${SSH_CONNECTION%% *}");
|
||||
|
@ -124,7 +124,7 @@ function guessDockerIPs() {
|
|||
try {
|
||||
// When using boot2docker, seleniumIP and katexIP are distinct.
|
||||
seleniumIP = seleniumIP || cmd("boot2docker", "ip");
|
||||
var config = cmd("boot2docker", "config");
|
||||
let config = cmd("boot2docker", "config");
|
||||
config = (/^HostIP = "(.*)"$/m).exec(config);
|
||||
if (!config) {
|
||||
console.error("Failed to find HostIP");
|
||||
|
@ -142,7 +142,7 @@ function guessDockerIPs() {
|
|||
return;
|
||||
}
|
||||
// Native Docker on Linux or remote Docker daemon or similar
|
||||
var gatewayIP = cmd("docker", "inspect",
|
||||
const gatewayIP = cmd("docker", "inspect",
|
||||
"-f", "{{.NetworkSettings.Gateway}}", opts.container);
|
||||
seleniumIP = seleniumIP || gatewayIP;
|
||||
katexIP = katexIP || gatewayIP;
|
||||
|
@ -165,22 +165,22 @@ if (seleniumURL) {
|
|||
}
|
||||
|
||||
process.nextTick(startServer);
|
||||
var attempts = 0;
|
||||
let attempts = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start up development server
|
||||
|
||||
var devServer = null;
|
||||
var minPort = 32768;
|
||||
var maxPort = 61000;
|
||||
let devServer = null;
|
||||
const minPort = 32768;
|
||||
const maxPort = 61000;
|
||||
|
||||
function startServer() {
|
||||
if (katexURL || katexPort) {
|
||||
process.nextTick(tryConnect);
|
||||
return;
|
||||
}
|
||||
var port = Math.floor(Math.random() * (maxPort - minPort)) + minPort;
|
||||
var server = http.createServer(app).listen(port);
|
||||
const port = Math.floor(Math.random() * (maxPort - minPort)) + minPort;
|
||||
const server = http.createServer(app).listen(port);
|
||||
server.once("listening", function() {
|
||||
devServer = server;
|
||||
katexPort = port;
|
||||
|
@ -206,7 +206,7 @@ function tryConnect() {
|
|||
process.nextTick(buildDriver);
|
||||
return;
|
||||
}
|
||||
var sock = net.connect({
|
||||
const sock = net.connect({
|
||||
host: seleniumIP,
|
||||
port: +seleniumPort,
|
||||
});
|
||||
|
@ -225,21 +225,21 @@ function tryConnect() {
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Build the web driver
|
||||
|
||||
var driver;
|
||||
let driver;
|
||||
function buildDriver() {
|
||||
var builder = new selenium.Builder().forBrowser(opts.browser);
|
||||
var ffProfile = new firefox.Profile();
|
||||
const builder = new selenium.Builder().forBrowser(opts.browser);
|
||||
const ffProfile = new firefox.Profile();
|
||||
ffProfile.setPreference(
|
||||
"browser.startup.homepage_override.mstone", "ignore");
|
||||
ffProfile.setPreference("browser.startup.page", 0);
|
||||
var ffOptions = new firefox.Options().setProfile(ffProfile);
|
||||
const ffOptions = new firefox.Options().setProfile(ffProfile);
|
||||
builder.setFirefoxOptions(ffOptions);
|
||||
if (seleniumURL) {
|
||||
builder.usingServer(seleniumURL);
|
||||
}
|
||||
driver = builder.build();
|
||||
driver.manage().timeouts().setScriptTimeout(3000).then(function() {
|
||||
var html = '<!DOCTYPE html>' +
|
||||
let html = '<!DOCTYPE html>' +
|
||||
'<html><head><style type="text/css">html,body{' +
|
||||
'width:100%;height:100%;margin:0;padding:0;overflow:hidden;' +
|
||||
'}</style></head><body><p>Test</p></body></html>';
|
||||
|
@ -253,15 +253,15 @@ function buildDriver() {
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Set the screen size
|
||||
|
||||
var targetW = 1024;
|
||||
var targetH = 768;
|
||||
const targetW = 1024;
|
||||
const targetH = 768;
|
||||
function setSize(reqW, reqH) {
|
||||
return driver.manage().window().setSize(reqW, reqH).then(function() {
|
||||
return driver.takeScreenshot();
|
||||
}).then(function(img) {
|
||||
img = imageDimensions(img);
|
||||
var actualW = img.width;
|
||||
var actualH = img.height;
|
||||
const actualW = img.width;
|
||||
const actualH = img.height;
|
||||
if (actualW === targetW && actualH === targetH) {
|
||||
findHostIP();
|
||||
return;
|
||||
|
@ -274,7 +274,7 @@ function setSize(reqW, reqH) {
|
|||
}
|
||||
|
||||
function imageDimensions(img) {
|
||||
var buf = new Buffer(img, "base64");
|
||||
const buf = new Buffer(img, "base64");
|
||||
return {
|
||||
buf: buf,
|
||||
width: buf.readUInt32BE(16),
|
||||
|
@ -312,13 +312,13 @@ function findHostIP() {
|
|||
});
|
||||
|
||||
// Next, enumerate all network addresses
|
||||
var ips = [];
|
||||
var devs = os.networkInterfaces();
|
||||
for (var dev in devs) {
|
||||
const ips = [];
|
||||
const devs = os.networkInterfaces();
|
||||
for (const dev in devs) {
|
||||
if (devs.hasOwnProperty(dev)) {
|
||||
var addrs = devs[dev];
|
||||
for (var i = 0; i < addrs.length; ++i) {
|
||||
var addr = addrs[i].address;
|
||||
const addrs = devs[dev];
|
||||
for (let i = 0; i < addrs.length; ++i) {
|
||||
let addr = addrs[i].address;
|
||||
if (/:/.test(addr)) {
|
||||
addr = "[" + addr + "]";
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ function findHostIP() {
|
|||
console.log("Looking for host IP among " + ips.join(", "));
|
||||
|
||||
// Load a data: URI document which attempts to contact each of these IPs
|
||||
var html = "<!doctype html>\n<html><body>\n";
|
||||
let html = "<!doctype html>\n<html><body>\n";
|
||||
html += ips.map(function(ip) {
|
||||
return '<script src="http://' + ip + ':' + katexPort +
|
||||
'/ss-connect.js?ip=' + encodeURIComponent(ip) +
|
||||
|
@ -343,17 +343,17 @@ function findHostIP() {
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Take the screenshots
|
||||
|
||||
var countdown = listOfCases.length;
|
||||
let countdown = listOfCases.length;
|
||||
|
||||
var exitStatus = 0;
|
||||
var listOfFailed = [];
|
||||
let exitStatus = 0;
|
||||
const listOfFailed = [];
|
||||
|
||||
function takeScreenshots() {
|
||||
listOfCases.forEach(takeScreenshot);
|
||||
}
|
||||
|
||||
function takeScreenshot(key) {
|
||||
var itm = data[key];
|
||||
const itm = data[key];
|
||||
if (!itm) {
|
||||
console.error("Test case " + key + " not known!");
|
||||
listOfFailed.push(key);
|
||||
|
@ -364,14 +364,14 @@ function takeScreenshot(key) {
|
|||
return;
|
||||
}
|
||||
|
||||
var file = path.join(dstDir, key + "-" + opts.browser + ".png");
|
||||
var retry = 0;
|
||||
var loadExpected = null;
|
||||
let file = path.join(dstDir, key + "-" + opts.browser + ".png");
|
||||
let retry = 0;
|
||||
let loadExpected = null;
|
||||
if (opts.verify) {
|
||||
loadExpected = promisify(fs.readFile, file);
|
||||
}
|
||||
|
||||
var url = katexURL + "test/screenshotter/test.html?" + itm.query;
|
||||
const url = katexURL + "test/screenshotter/test.html?" + itm.query;
|
||||
driver.get(url);
|
||||
if (opts.wait) {
|
||||
browserSideWait(1000 * opts.wait);
|
||||
|
@ -398,10 +398,10 @@ function takeScreenshot(key) {
|
|||
loadExpected = promisify(fs.readFile, file);
|
||||
}
|
||||
}
|
||||
var opt = new jspngopt.Optimizer({
|
||||
const opt = new jspngopt.Optimizer({
|
||||
pako: pako,
|
||||
});
|
||||
var buf = opt.bufferSync(img.buf);
|
||||
const buf = opt.bufferSync(img.buf);
|
||||
if (loadExpected) {
|
||||
return loadExpected.then(function(expected) {
|
||||
if (!buf.equals(expected)) {
|
||||
|
@ -451,8 +451,8 @@ function browserSideWait(milliseconds) {
|
|||
// Second and later arguments are passed to the function named in the
|
||||
// first argument, and a callback is added as last argument.
|
||||
function promisify(f) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var deferred = new selenium.promise.Deferred();
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const deferred = new selenium.promise.Deferred();
|
||||
args.push(function(err, val) {
|
||||
if (err) {
|
||||
deferred.reject(err);
|
||||
|
|
|
@ -2,22 +2,22 @@
|
|||
/* eslint-disable no-console */
|
||||
"use strict";
|
||||
|
||||
var childProcess = require("child_process");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var Q = require("q"); // To debug, pass Q_DEBUG=1 in the environment
|
||||
var pngparse = require("pngparse");
|
||||
var fft = require("ndarray-fft");
|
||||
var ndarray = require("ndarray-fft/node_modules/ndarray");
|
||||
const childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const Q = require("q"); // To debug, pass Q_DEBUG=1 in the environment
|
||||
const pngparse = require("pngparse");
|
||||
const fft = require("ndarray-fft");
|
||||
const ndarray = require("ndarray-fft/node_modules/ndarray");
|
||||
|
||||
var data = require("../../test/screenshotter/ss_data");
|
||||
const data = require("../../test/screenshotter/ss_data");
|
||||
|
||||
// Adapt node functions to Q promises
|
||||
var readFile = Q.denodeify(fs.readFile);
|
||||
var writeFile = Q.denodeify(fs.writeFile);
|
||||
var mkdir = Q.denodeify(fs.mkdir);
|
||||
const readFile = Q.denodeify(fs.readFile);
|
||||
const writeFile = Q.denodeify(fs.writeFile);
|
||||
const mkdir = Q.denodeify(fs.mkdir);
|
||||
|
||||
var todo;
|
||||
let todo;
|
||||
if (process.argv.length > 2) {
|
||||
todo = process.argv.slice(2);
|
||||
} else {
|
||||
|
@ -27,23 +27,23 @@ if (process.argv.length > 2) {
|
|||
}
|
||||
|
||||
// Dimensions used when we do the FFT-based alignment computation
|
||||
var alignWidth = 2048; // should be at least twice the width resp. height
|
||||
var alignHeight = 2048; // of the screenshots, and a power of two.
|
||||
const alignWidth = 2048; // should be at least twice the width resp. height
|
||||
const alignHeight = 2048; // of the screenshots, and a power of two.
|
||||
|
||||
// Compute required resolution to match test.html. 16px default font,
|
||||
// scaled to 4em in test.html, and to 1.21em in katex.css. Corresponding
|
||||
// LaTeX font size is 10pt. There are 72.27pt per inch.
|
||||
var pxPerEm = 16 * 4 * 1.21;
|
||||
var pxPerPt = pxPerEm / 10;
|
||||
var dpi = pxPerPt * 72.27;
|
||||
const pxPerEm = 16 * 4 * 1.21;
|
||||
const pxPerPt = pxPerEm / 10;
|
||||
const dpi = pxPerPt * 72.27;
|
||||
|
||||
var tmpDir = "/tmp/texcmp";
|
||||
var ssDir = path.normalize(
|
||||
const tmpDir = "/tmp/texcmp";
|
||||
const ssDir = path.normalize(
|
||||
path.join(__dirname, "..", "..", "test", "screenshotter"));
|
||||
var imagesDir = path.join(ssDir, "images");
|
||||
var teximgDir = path.join(ssDir, "tex");
|
||||
var diffDir = path.join(ssDir, "diff");
|
||||
var template;
|
||||
const imagesDir = path.join(ssDir, "images");
|
||||
const teximgDir = path.join(ssDir, "tex");
|
||||
const diffDir = path.join(ssDir, "diff");
|
||||
let template;
|
||||
|
||||
Q.all([
|
||||
readFile(path.join(ssDir, "test.tex"), "utf-8"),
|
||||
|
@ -58,8 +58,8 @@ Q.all([
|
|||
|
||||
// Process a single test case: rasterize, then create diff
|
||||
function processTestCase(key) {
|
||||
var itm = data[key];
|
||||
var tex = "$" + itm.tex + "$";
|
||||
const itm = data[key];
|
||||
let tex = "$" + itm.tex + "$";
|
||||
if (itm.display) {
|
||||
tex = "\\[" + itm.tex + "\\]";
|
||||
}
|
||||
|
@ -70,14 +70,14 @@ function processTestCase(key) {
|
|||
tex = tex + itm.post.replace("<br>", "\\\\");
|
||||
}
|
||||
tex = template.replace(/\$.*\$/, tex.replace(/\$/g, "$$$$"));
|
||||
var texFile = path.join(tmpDir, key + ".tex");
|
||||
var pdfFile = path.join(tmpDir, key + ".pdf");
|
||||
var pngFile = path.join(teximgDir, key + "-pdflatex.png");
|
||||
var browserFile = path.join(imagesDir, key + "-firefox.png");
|
||||
var diffFile = path.join(diffDir, key + ".png");
|
||||
const texFile = path.join(tmpDir, key + ".tex");
|
||||
const pdfFile = path.join(tmpDir, key + ".pdf");
|
||||
const pngFile = path.join(teximgDir, key + "-pdflatex.png");
|
||||
const browserFile = path.join(imagesDir, key + "-firefox.png");
|
||||
const diffFile = path.join(diffDir, key + ".png");
|
||||
|
||||
// Step 1: write key.tex file
|
||||
var fftLatex = writeFile(texFile, tex).then(function() {
|
||||
const fftLatex = writeFile(texFile, tex).then(function() {
|
||||
// Step 2: call "pdflatex key" to create key.pdf
|
||||
return execFile("pdflatex", [
|
||||
"-interaction", "nonstopmode", key,
|
||||
|
@ -95,24 +95,24 @@ function processTestCase(key) {
|
|||
return readPNG(pngFile).then(fftImage);
|
||||
});
|
||||
// Step 5: apply FFT to reference image as well
|
||||
var fftBrowser = readPNG(browserFile).then(fftImage);
|
||||
const fftBrowser = readPNG(browserFile).then(fftImage);
|
||||
|
||||
return Q.all([fftBrowser, fftLatex]).spread(function(browser, latex) {
|
||||
// Now we have the FFT result from both
|
||||
// Step 6: find alignment which maximizes overlap.
|
||||
// This uses a FFT-based correlation computation.
|
||||
var x;
|
||||
var y;
|
||||
var real = createMatrix();
|
||||
var imag = createMatrix();
|
||||
let x;
|
||||
let y;
|
||||
const real = createMatrix();
|
||||
const imag = createMatrix();
|
||||
|
||||
// Step 6a: (real + i*imag) = latex * conjugate(browser)
|
||||
for (y = 0; y < alignHeight; ++y) {
|
||||
for (x = 0; x < alignWidth; ++x) {
|
||||
var br = browser.real.get(y, x);
|
||||
var bi = browser.imag.get(y, x);
|
||||
var lr = latex.real.get(y, x);
|
||||
var li = latex.imag.get(y, x);
|
||||
const br = browser.real.get(y, x);
|
||||
const bi = browser.imag.get(y, x);
|
||||
const lr = latex.real.get(y, x);
|
||||
const li = latex.imag.get(y, x);
|
||||
real.set(y, x, br * lr + bi * li);
|
||||
imag.set(y, x, br * li - bi * lr);
|
||||
}
|
||||
|
@ -122,14 +122,14 @@ function processTestCase(key) {
|
|||
fft(-1, real, imag);
|
||||
|
||||
// Step 6c: find position where the (squared) absolute value is maximal
|
||||
var offsetX = 0;
|
||||
var offsetY = 0;
|
||||
var maxSquaredNorm = -1; // any result is greater than initial value
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
let maxSquaredNorm = -1; // any result is greater than initial value
|
||||
for (y = 0; y < alignHeight; ++y) {
|
||||
for (x = 0; x < alignWidth; ++x) {
|
||||
var or = real.get(y, x);
|
||||
var oi = imag.get(y, x);
|
||||
var squaredNorm = or * or + oi * oi;
|
||||
const or = real.get(y, x);
|
||||
const oi = imag.get(y, x);
|
||||
const squaredNorm = or * or + oi * oi;
|
||||
if (maxSquaredNorm < squaredNorm) {
|
||||
maxSquaredNorm = squaredNorm;
|
||||
offsetX = x;
|
||||
|
@ -148,12 +148,12 @@ function processTestCase(key) {
|
|||
console.log("Positioned " + key + ": " + offsetX + ", " + offsetY);
|
||||
|
||||
// Step 7: use these offsets to compute difference illustration
|
||||
var bx = Math.max(offsetX, 0); // browser left padding
|
||||
var by = Math.max(offsetY, 0); // browser top padding
|
||||
var lx = Math.max(-offsetX, 0); // latex left padding
|
||||
var ly = Math.max(-offsetY, 0); // latex top padding
|
||||
var uw = Math.max(browser.width + bx, latex.width + lx); // union width
|
||||
var uh = Math.max(browser.height + by, latex.height + ly); // u. height
|
||||
const bx = Math.max(offsetX, 0); // browser left padding
|
||||
const by = Math.max(offsetY, 0); // browser top padding
|
||||
const lx = Math.max(-offsetX, 0); // latex left padding
|
||||
const ly = Math.max(-offsetY, 0); // latex top padding
|
||||
const uw = Math.max(browser.width + bx, latex.width + lx); // union w.
|
||||
const uh = Math.max(browser.height + by, latex.height + ly); // u. h.
|
||||
return execFile("convert", [
|
||||
// First image: latex rendering, converted to grayscale and padded
|
||||
"(", pngFile, "-grayscale", "Rec709Luminance",
|
||||
|
@ -187,7 +187,7 @@ function ensureDir(dir) {
|
|||
// Execute a given command, and return a promise to its output.
|
||||
// Don't denodeify here, since fail branch needs access to stderr.
|
||||
function execFile(cmd, args, opts) {
|
||||
var deferred = Q.defer();
|
||||
const deferred = Q.defer();
|
||||
childProcess.execFile(cmd, args, opts, function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.error("Error executing " + cmd + " " + args.join(" "));
|
||||
|
@ -204,9 +204,9 @@ function execFile(cmd, args, opts) {
|
|||
|
||||
// Read given file and parse it as a PNG file.
|
||||
function readPNG(file) {
|
||||
var deferred = Q.defer();
|
||||
var onerror = deferred.reject.bind(deferred);
|
||||
var stream = fs.createReadStream(file);
|
||||
const deferred = Q.defer();
|
||||
const onerror = deferred.reject.bind(deferred);
|
||||
const stream = fs.createReadStream(file);
|
||||
stream.on("error", onerror);
|
||||
pngparse.parseStream(stream, function(err, image) {
|
||||
if (err) {
|
||||
|
@ -221,20 +221,19 @@ function readPNG(file) {
|
|||
|
||||
// Take a parsed image data structure and apply FFT transformation to it
|
||||
function fftImage(image) {
|
||||
var real = createMatrix();
|
||||
var imag = createMatrix();
|
||||
var idx = 0;
|
||||
var nchan = image.channels;
|
||||
var alphachan = 1 - (nchan % 2);
|
||||
var colorchan = nchan - alphachan;
|
||||
for (var y = 0; y < image.height; ++y) {
|
||||
for (var x = 0; x < image.width; ++x) {
|
||||
var c;
|
||||
var v = 0;
|
||||
for (c = 0; c < colorchan; ++c) {
|
||||
const real = createMatrix();
|
||||
const imag = createMatrix();
|
||||
let idx = 0;
|
||||
const nchan = image.channels;
|
||||
const alphachan = 1 - (nchan % 2);
|
||||
const colorchan = nchan - alphachan;
|
||||
for (let y = 0; y < image.height; ++y) {
|
||||
for (let x = 0; x < image.width; ++x) {
|
||||
let v = 0;
|
||||
for (let c = 0; c < colorchan; ++c) {
|
||||
v += 255 - image.data[idx++];
|
||||
}
|
||||
for (c = 0; c < alphachan; ++c) {
|
||||
for (let c = 0; c < alphachan; ++c) {
|
||||
v += image.data[idx++];
|
||||
}
|
||||
real.set(y, x, v);
|
||||
|
@ -251,6 +250,6 @@ function fftImage(image) {
|
|||
|
||||
// Create a new matrix of preconfigured dimensions, initialized to zero
|
||||
function createMatrix() {
|
||||
var array = new Float64Array(alignWidth * alignHeight);
|
||||
const array = new Float64Array(alignWidth * alignHeight);
|
||||
return new ndarray(array, [alignWidth, alignHeight]);
|
||||
}
|
||||
|
|
28
katex.js
28
katex.js
|
@ -7,24 +7,24 @@
|
|||
* errors in the expression, or errors in javascript handling.
|
||||
*/
|
||||
|
||||
var ParseError = require("./src/ParseError");
|
||||
var Settings = require("./src/Settings");
|
||||
const ParseError = require("./src/ParseError");
|
||||
const Settings = require("./src/Settings");
|
||||
|
||||
var buildTree = require("./src/buildTree");
|
||||
var parseTree = require("./src/parseTree");
|
||||
var utils = require("./src/utils");
|
||||
const buildTree = require("./src/buildTree");
|
||||
const parseTree = require("./src/parseTree");
|
||||
const utils = require("./src/utils");
|
||||
|
||||
/**
|
||||
* Parse and build an expression, and place that expression in the DOM node
|
||||
* given.
|
||||
*/
|
||||
var render = function(expression, baseNode, options) {
|
||||
let render = function(expression, baseNode, options) {
|
||||
utils.clearNode(baseNode);
|
||||
|
||||
var settings = new Settings(options);
|
||||
const settings = new Settings(options);
|
||||
|
||||
var tree = parseTree(expression, settings);
|
||||
var node = buildTree(tree, expression, settings).toNode();
|
||||
const tree = parseTree(expression, settings);
|
||||
const node = buildTree(tree, expression, settings).toNode();
|
||||
|
||||
baseNode.appendChild(node);
|
||||
};
|
||||
|
@ -46,18 +46,18 @@ if (typeof document !== "undefined") {
|
|||
/**
|
||||
* Parse and build an expression, and return the markup for that.
|
||||
*/
|
||||
var renderToString = function(expression, options) {
|
||||
var settings = new Settings(options);
|
||||
const renderToString = function(expression, options) {
|
||||
const settings = new Settings(options);
|
||||
|
||||
var tree = parseTree(expression, settings);
|
||||
const tree = parseTree(expression, settings);
|
||||
return buildTree(tree, expression, settings).toMarkup();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an expression and return the parse tree.
|
||||
*/
|
||||
var generateParseTree = function(expression, options) {
|
||||
var settings = new Settings(options);
|
||||
const generateParseTree = function(expression, options) {
|
||||
const settings = new Settings(options);
|
||||
return parseTree(expression, settings);
|
||||
};
|
||||
|
||||
|
|
28
server.js
28
server.js
|
@ -1,14 +1,14 @@
|
|||
/* eslint no-console:0 */
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
var babelify = require("babelify");
|
||||
var browserify = require("browserify");
|
||||
var express = require("express");
|
||||
var glob = require("glob");
|
||||
var less = require("less");
|
||||
const babelify = require("babelify");
|
||||
const browserify = require("browserify");
|
||||
const express = require("express");
|
||||
const glob = require("glob");
|
||||
const less = require("less");
|
||||
|
||||
var app = express();
|
||||
const app = express();
|
||||
|
||||
if (require.main === module) {
|
||||
app.use(require("morgan")(
|
||||
|
@ -17,7 +17,7 @@ if (require.main === module) {
|
|||
|
||||
var serveBrowserified = function(file, standaloneName) {
|
||||
return function(req, res, next) {
|
||||
var files;
|
||||
let files;
|
||||
if (Array.isArray(file)) {
|
||||
files = file.map(function(f) { return path.join(__dirname, f); });
|
||||
} else if (file.indexOf("*") !== -1) {
|
||||
|
@ -26,16 +26,16 @@ var serveBrowserified = function(file, standaloneName) {
|
|||
files = [path.join(__dirname, file)];
|
||||
}
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
transform: [babelify]
|
||||
};
|
||||
if (standaloneName) {
|
||||
options.standalone = standaloneName;
|
||||
}
|
||||
var b = browserify(files, options);
|
||||
var stream = b.bundle();
|
||||
const b = browserify(files, options);
|
||||
const stream = b.bundle();
|
||||
|
||||
var body = "";
|
||||
let body = "";
|
||||
stream.on("data", function(s) { body += s; });
|
||||
stream.on("error", function(e) { next(e); });
|
||||
stream.on("end", function() {
|
||||
|
@ -59,7 +59,7 @@ app.get("/contrib/auto-render/auto-render.js",
|
|||
"renderMathInElement"));
|
||||
|
||||
app.get("/katex.css", function(req, res, next) {
|
||||
var lessfile = path.join(__dirname, "static", "katex.less");
|
||||
const lessfile = path.join(__dirname, "static", "katex.less");
|
||||
fs.readFile(lessfile, {encoding: "utf8"}, function(err, data) {
|
||||
if (err) {
|
||||
next(err);
|
||||
|
|
18
src/Lexer.js
18
src/Lexer.js
|
@ -11,9 +11,9 @@
|
|||
* kinds.
|
||||
*/
|
||||
|
||||
var matchAt = require("match-at");
|
||||
const matchAt = require("match-at");
|
||||
|
||||
var ParseError = require("./ParseError");
|
||||
const ParseError = require("./ParseError");
|
||||
|
||||
// The main lexer class
|
||||
function Lexer(input) {
|
||||
|
@ -76,7 +76,7 @@ Token.prototype.range = function(endToken, text) {
|
|||
* If there is no matching function or symbol definition, the Parser will
|
||||
* still reject the input.
|
||||
*/
|
||||
var tokenRegex = new RegExp(
|
||||
const tokenRegex = new RegExp(
|
||||
"([ \r\n\t]+)|" + // whitespace
|
||||
"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
||||
"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
|
||||
|
@ -88,21 +88,21 @@ var tokenRegex = new RegExp(
|
|||
* This function lexes a single token.
|
||||
*/
|
||||
Lexer.prototype.lex = function() {
|
||||
var input = this.input;
|
||||
var pos = this.pos;
|
||||
const input = this.input;
|
||||
const pos = this.pos;
|
||||
if (pos === input.length) {
|
||||
return new Token("EOF", pos, pos, this);
|
||||
}
|
||||
var match = matchAt(tokenRegex, input, pos);
|
||||
const match = matchAt(tokenRegex, input, pos);
|
||||
if (match === null) {
|
||||
throw new ParseError(
|
||||
"Unexpected character: '" + input[pos] + "'",
|
||||
new Token(input[pos], pos, pos + 1, this));
|
||||
}
|
||||
var text = match[2] || " ";
|
||||
var start = this.pos;
|
||||
const text = match[2] || " ";
|
||||
const start = this.pos;
|
||||
this.pos += match[0].length;
|
||||
var end = this.pos;
|
||||
const end = this.pos;
|
||||
return new Token(text, start, end, this);
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* until only non-macro tokens remain.
|
||||
*/
|
||||
|
||||
var Lexer = require("./Lexer");
|
||||
const Lexer = require("./Lexer");
|
||||
|
||||
function MacroExpander(input, macros) {
|
||||
this.lexer = new Lexer(input);
|
||||
|
@ -20,16 +20,16 @@ MacroExpander.prototype.nextToken = function() {
|
|||
if (this.stack.length === 0) {
|
||||
this.stack.push(this.lexer.lex());
|
||||
}
|
||||
var topToken = this.stack.pop();
|
||||
var name = topToken.text;
|
||||
const topToken = this.stack.pop();
|
||||
const name = topToken.text;
|
||||
if (!(name.charAt(0) === "\\" && this.macros.hasOwnProperty(name))) {
|
||||
return topToken;
|
||||
}
|
||||
var expansion = this.macros[name];
|
||||
let expansion = this.macros[name];
|
||||
if (typeof expansion === "string") {
|
||||
var bodyLexer = new Lexer(expansion);
|
||||
const bodyLexer = new Lexer(expansion);
|
||||
expansion = [];
|
||||
var tok = bodyLexer.lex();
|
||||
let tok = bodyLexer.lex();
|
||||
while (tok.text !== "EOF") {
|
||||
expansion.push(tok);
|
||||
tok = bodyLexer.lex();
|
||||
|
@ -43,7 +43,7 @@ MacroExpander.prototype.nextToken = function() {
|
|||
|
||||
MacroExpander.prototype.get = function(ignoreSpace) {
|
||||
this.discardedWhiteSpace = [];
|
||||
var token = this.nextToken();
|
||||
let token = this.nextToken();
|
||||
if (ignoreSpace) {
|
||||
while (token.text === " ") {
|
||||
this.discardedWhiteSpace.push(token);
|
||||
|
|
|
@ -39,7 +39,7 @@ function Options(data) {
|
|||
* from "extension" will be copied to the new options object.
|
||||
*/
|
||||
Options.prototype.extend = function(extension) {
|
||||
var data = {
|
||||
const data = {
|
||||
style: this.style,
|
||||
size: this.size,
|
||||
color: this.color,
|
||||
|
@ -49,7 +49,7 @@ Options.prototype.extend = function(extension) {
|
|||
font: this.font,
|
||||
};
|
||||
|
||||
for (var key in extension) {
|
||||
for (const key in extension) {
|
||||
if (extension.hasOwnProperty(key)) {
|
||||
data[key] = extension[key];
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ Options.prototype.reset = function() {
|
|||
* A map of color names to CSS colors.
|
||||
* TODO(emily): Remove this when we have real macros
|
||||
*/
|
||||
var colorMap = {
|
||||
const colorMap = {
|
||||
"katex-blue": "#6495ed",
|
||||
"katex-orange": "#ffa500",
|
||||
"katex-pink": "#ff00af",
|
||||
|
|
|
@ -10,15 +10,15 @@
|
|||
* @param {(Token|ParseNode)=} token An object providing position information
|
||||
*/
|
||||
function ParseError(message, token) {
|
||||
var error = "KaTeX parse error: " + message;
|
||||
var start;
|
||||
var end;
|
||||
let error = "KaTeX parse error: " + message;
|
||||
let start;
|
||||
let end;
|
||||
|
||||
if (token && token.lexer && token.start <= token.end) {
|
||||
// If we have the input and a position, make the error a bit fancier
|
||||
|
||||
// Get the input
|
||||
var input = token.lexer.input;
|
||||
const input = token.lexer.input;
|
||||
|
||||
// Prepend some information
|
||||
start = token.start;
|
||||
|
@ -30,16 +30,16 @@ function ParseError(message, token) {
|
|||
}
|
||||
|
||||
// Underline token in question using combining underscores
|
||||
var underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
|
||||
const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
|
||||
|
||||
// Extract some context from the input and add it to the error
|
||||
var left;
|
||||
let left;
|
||||
if (start > 15) {
|
||||
left = "…" + input.slice(start - 15, start);
|
||||
} else {
|
||||
left = input.slice(0, start);
|
||||
}
|
||||
var right;
|
||||
let right;
|
||||
if (end + 15 < input.length) {
|
||||
right = input.slice(end, end + 15) + "…";
|
||||
} else {
|
||||
|
@ -50,7 +50,7 @@ function ParseError(message, token) {
|
|||
|
||||
// Some hackery to make ParseError a prototype of Error
|
||||
// See http://stackoverflow.com/a/8460753
|
||||
var self = new Error(error);
|
||||
const self = new Error(error);
|
||||
self.name = "ParseError";
|
||||
self.__proto__ = ParseError.prototype;
|
||||
|
||||
|
|
198
src/Parser.js
198
src/Parser.js
|
@ -1,13 +1,13 @@
|
|||
/* eslint no-constant-condition:0 */
|
||||
var functions = require("./functions");
|
||||
var environments = require("./environments");
|
||||
var MacroExpander = require("./MacroExpander");
|
||||
var symbols = require("./symbols");
|
||||
var utils = require("./utils");
|
||||
var cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
const functions = require("./functions");
|
||||
const environments = require("./environments");
|
||||
const MacroExpander = require("./MacroExpander");
|
||||
const symbols = require("./symbols");
|
||||
const utils = require("./utils");
|
||||
const cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
|
||||
var parseData = require("./parseData");
|
||||
var ParseError = require("./ParseError");
|
||||
const parseData = require("./parseData");
|
||||
const ParseError = require("./ParseError");
|
||||
|
||||
/**
|
||||
* This file contains the parser used to parse out a TeX expression from the
|
||||
|
@ -56,7 +56,7 @@ function Parser(input, settings) {
|
|||
this.leftrightDepth = 0;
|
||||
}
|
||||
|
||||
var ParseNode = parseData.ParseNode;
|
||||
const ParseNode = parseData.ParseNode;
|
||||
|
||||
/**
|
||||
* An initial function (without its arguments), or an argument to a function.
|
||||
|
@ -111,7 +111,7 @@ Parser.prototype.parse = function() {
|
|||
// Try to parse the input
|
||||
this.mode = "math";
|
||||
this.consume();
|
||||
var parse = this.parseInput();
|
||||
const parse = this.parseInput();
|
||||
return parse;
|
||||
};
|
||||
|
||||
|
@ -120,13 +120,13 @@ Parser.prototype.parse = function() {
|
|||
*/
|
||||
Parser.prototype.parseInput = function() {
|
||||
// Parse an expression
|
||||
var expression = this.parseExpression(false);
|
||||
const expression = this.parseExpression(false);
|
||||
// If we succeeded, make sure there's an EOF at the end
|
||||
this.expect("EOF", false);
|
||||
return expression;
|
||||
};
|
||||
|
||||
var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
|
||||
const endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
|
||||
|
||||
/**
|
||||
* Parses an "expression", which is a list of atoms.
|
||||
|
@ -142,11 +142,11 @@ var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
|
|||
* @return {ParseNode}
|
||||
*/
|
||||
Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) {
|
||||
var body = [];
|
||||
const body = [];
|
||||
// Keep adding atoms to the body until we can't parse any more atoms (either
|
||||
// we reached the end, a }, or a \right)
|
||||
while (true) {
|
||||
var lex = this.nextToken;
|
||||
const lex = this.nextToken;
|
||||
if (endOfExpression.indexOf(lex.text) !== -1) {
|
||||
break;
|
||||
}
|
||||
|
@ -156,10 +156,10 @@ Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) {
|
|||
if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
|
||||
break;
|
||||
}
|
||||
var atom = this.parseAtom();
|
||||
const atom = this.parseAtom();
|
||||
if (!atom) {
|
||||
if (!this.settings.throwOnError && lex.text[0] === "\\") {
|
||||
var errorNode = this.handleUnsupportedCmd();
|
||||
const errorNode = this.handleUnsupportedCmd();
|
||||
body.push(errorNode);
|
||||
continue;
|
||||
}
|
||||
|
@ -181,11 +181,11 @@ Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) {
|
|||
* @returns {Array}
|
||||
*/
|
||||
Parser.prototype.handleInfixNodes = function(body) {
|
||||
var overIndex = -1;
|
||||
var funcName;
|
||||
let overIndex = -1;
|
||||
let funcName;
|
||||
|
||||
for (var i = 0; i < body.length; i++) {
|
||||
var node = body[i];
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
const node = body[i];
|
||||
if (node.type === "infix") {
|
||||
if (overIndex !== -1) {
|
||||
throw new ParseError(
|
||||
|
@ -198,11 +198,11 @@ Parser.prototype.handleInfixNodes = function(body) {
|
|||
}
|
||||
|
||||
if (overIndex !== -1) {
|
||||
var numerNode;
|
||||
var denomNode;
|
||||
let numerNode;
|
||||
let denomNode;
|
||||
|
||||
var numerBody = body.slice(0, overIndex);
|
||||
var denomBody = body.slice(overIndex + 1);
|
||||
const numerBody = body.slice(0, overIndex);
|
||||
const denomBody = body.slice(overIndex + 1);
|
||||
|
||||
if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
|
||||
numerNode = numerBody[0];
|
||||
|
@ -216,7 +216,7 @@ Parser.prototype.handleInfixNodes = function(body) {
|
|||
denomNode = new ParseNode("ordgroup", denomBody, this.mode);
|
||||
}
|
||||
|
||||
var value = this.callFunction(
|
||||
const value = this.callFunction(
|
||||
funcName, [numerNode, denomNode], null);
|
||||
return [new ParseNode(value.type, value, this.mode)];
|
||||
} else {
|
||||
|
@ -225,16 +225,16 @@ Parser.prototype.handleInfixNodes = function(body) {
|
|||
};
|
||||
|
||||
// The greediness of a superscript or subscript
|
||||
var SUPSUB_GREEDINESS = 1;
|
||||
const SUPSUB_GREEDINESS = 1;
|
||||
|
||||
/**
|
||||
* Handle a subscript or superscript with nice errors.
|
||||
*/
|
||||
Parser.prototype.handleSupSubscript = function(name) {
|
||||
var symbolToken = this.nextToken;
|
||||
var symbol = symbolToken.text;
|
||||
const symbolToken = this.nextToken;
|
||||
const symbol = symbolToken.text;
|
||||
this.consume();
|
||||
var group = this.parseGroup();
|
||||
const group = this.parseGroup();
|
||||
|
||||
if (!group) {
|
||||
if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") {
|
||||
|
@ -248,7 +248,7 @@ Parser.prototype.handleSupSubscript = function(name) {
|
|||
} else if (group.isFunction) {
|
||||
// ^ and _ have a greediness, so handle interactions with functions'
|
||||
// greediness
|
||||
var funcGreediness = functions[group.result].greediness;
|
||||
const funcGreediness = functions[group.result].greediness;
|
||||
if (funcGreediness > SUPSUB_GREEDINESS) {
|
||||
return this.parseFunction(group);
|
||||
} else {
|
||||
|
@ -266,14 +266,14 @@ Parser.prototype.handleSupSubscript = function(name) {
|
|||
* contained within a color node whose color is determined by errorColor
|
||||
*/
|
||||
Parser.prototype.handleUnsupportedCmd = function() {
|
||||
var text = this.nextToken.text;
|
||||
var textordArray = [];
|
||||
const text = this.nextToken.text;
|
||||
const textordArray = [];
|
||||
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
textordArray.push(new ParseNode("textord", text[i], "text"));
|
||||
}
|
||||
|
||||
var textNode = new ParseNode(
|
||||
const textNode = new ParseNode(
|
||||
"text",
|
||||
{
|
||||
body: textordArray,
|
||||
|
@ -281,7 +281,7 @@ Parser.prototype.handleUnsupportedCmd = function() {
|
|||
},
|
||||
this.mode);
|
||||
|
||||
var colorNode = new ParseNode(
|
||||
const colorNode = new ParseNode(
|
||||
"color",
|
||||
{
|
||||
color: this.settings.errorColor,
|
||||
|
@ -302,7 +302,7 @@ Parser.prototype.handleUnsupportedCmd = function() {
|
|||
Parser.prototype.parseAtom = function() {
|
||||
// The body of an atom is an implicit group, so that things like
|
||||
// \left(x\right)^2 work correctly.
|
||||
var base = this.parseImplicitGroup();
|
||||
const base = this.parseImplicitGroup();
|
||||
|
||||
// In text mode, we don't have superscripts or subscripts
|
||||
if (this.mode === "text") {
|
||||
|
@ -311,11 +311,11 @@ Parser.prototype.parseAtom = function() {
|
|||
|
||||
// Note that base may be empty (i.e. null) at this point.
|
||||
|
||||
var superscript;
|
||||
var subscript;
|
||||
let superscript;
|
||||
let subscript;
|
||||
while (true) {
|
||||
// Lex the first token
|
||||
var lex = this.nextToken;
|
||||
const lex = this.nextToken;
|
||||
|
||||
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
||||
// We got a limit control
|
||||
|
@ -324,7 +324,7 @@ Parser.prototype.parseAtom = function() {
|
|||
"Limit controls must follow a math operator",
|
||||
lex);
|
||||
} else {
|
||||
var limits = lex.text === "\\limits";
|
||||
const limits = lex.text === "\\limits";
|
||||
base.value.limits = limits;
|
||||
base.value.alwaysHandleSupSub = true;
|
||||
}
|
||||
|
@ -343,10 +343,10 @@ Parser.prototype.parseAtom = function() {
|
|||
subscript = this.handleSupSubscript("subscript");
|
||||
} else if (lex.text === "'") {
|
||||
// We got a prime
|
||||
var prime = new ParseNode("textord", "\\prime", this.mode);
|
||||
const prime = new ParseNode("textord", "\\prime", this.mode);
|
||||
|
||||
// Many primes can be grouped together, so we handle this here
|
||||
var primes = [prime];
|
||||
const primes = [prime];
|
||||
this.consume();
|
||||
// Keep lexing tokens until we get something that's not a prime
|
||||
while (this.nextToken.text === "'") {
|
||||
|
@ -376,13 +376,13 @@ Parser.prototype.parseAtom = function() {
|
|||
};
|
||||
|
||||
// A list of the size-changing functions, for use in parseImplicitGroup
|
||||
var sizeFuncs = [
|
||||
const sizeFuncs = [
|
||||
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
|
||||
"\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
|
||||
];
|
||||
|
||||
// A list of the style-changing functions, for use in parseImplicitGroup
|
||||
var styleFuncs = [
|
||||
const styleFuncs = [
|
||||
"\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle",
|
||||
];
|
||||
|
||||
|
@ -398,27 +398,26 @@ var styleFuncs = [
|
|||
* @return {?ParseNode}
|
||||
*/
|
||||
Parser.prototype.parseImplicitGroup = function() {
|
||||
var start = this.parseSymbol();
|
||||
const start = this.parseSymbol();
|
||||
|
||||
if (start == null) {
|
||||
// If we didn't get anything we handle, fall back to parseFunction
|
||||
return this.parseFunction();
|
||||
}
|
||||
|
||||
var func = start.result;
|
||||
var body;
|
||||
const func = start.result;
|
||||
|
||||
if (func === "\\left") {
|
||||
// If we see a left:
|
||||
// Parse the entire left function (including the delimiter)
|
||||
var left = this.parseFunction(start);
|
||||
const left = this.parseFunction(start);
|
||||
// Parse out the implicit body
|
||||
++this.leftrightDepth;
|
||||
body = this.parseExpression(false);
|
||||
const body = this.parseExpression(false);
|
||||
--this.leftrightDepth;
|
||||
// Check the next token
|
||||
this.expect("\\right", false);
|
||||
var right = this.parseFunction();
|
||||
const right = this.parseFunction();
|
||||
return new ParseNode("leftright", {
|
||||
body: body,
|
||||
left: left.value.value,
|
||||
|
@ -426,26 +425,26 @@ Parser.prototype.parseImplicitGroup = function() {
|
|||
}, this.mode);
|
||||
} else if (func === "\\begin") {
|
||||
// begin...end is similar to left...right
|
||||
var begin = this.parseFunction(start);
|
||||
var envName = begin.value.name;
|
||||
const begin = this.parseFunction(start);
|
||||
const envName = begin.value.name;
|
||||
if (!environments.hasOwnProperty(envName)) {
|
||||
throw new ParseError(
|
||||
"No such environment: " + envName, begin.value.nameGroup);
|
||||
}
|
||||
// Build the environment object. Arguments and other information will
|
||||
// be made available to the begin and end methods using properties.
|
||||
var env = environments[envName];
|
||||
var args = this.parseArguments("\\begin{" + envName + "}", env);
|
||||
var context = {
|
||||
const env = environments[envName];
|
||||
const args = this.parseArguments("\\begin{" + envName + "}", env);
|
||||
const context = {
|
||||
mode: this.mode,
|
||||
envName: envName,
|
||||
parser: this,
|
||||
positions: args.pop(),
|
||||
};
|
||||
var result = env.handler(context, args);
|
||||
const result = env.handler(context, args);
|
||||
this.expect("\\end", false);
|
||||
var endNameToken = this.nextToken;
|
||||
var end = this.parseFunction();
|
||||
const endNameToken = this.nextToken;
|
||||
const end = this.parseFunction();
|
||||
if (end.value.name !== envName) {
|
||||
throw new ParseError(
|
||||
"Mismatch: \\begin{" + envName + "} matched " +
|
||||
|
@ -456,7 +455,7 @@ Parser.prototype.parseImplicitGroup = function() {
|
|||
return result;
|
||||
} else if (utils.contains(sizeFuncs, func)) {
|
||||
// If we see a sizing function, parse out the implict body
|
||||
body = this.parseExpression(false);
|
||||
const body = this.parseExpression(false);
|
||||
return new ParseNode("sizing", {
|
||||
// Figure out what size to use based on the list of functions above
|
||||
size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
|
||||
|
@ -464,7 +463,7 @@ Parser.prototype.parseImplicitGroup = function() {
|
|||
}, this.mode);
|
||||
} else if (utils.contains(styleFuncs, func)) {
|
||||
// If we see a styling function, parse out the implict body
|
||||
body = this.parseExpression(true);
|
||||
const body = this.parseExpression(true);
|
||||
return new ParseNode("styling", {
|
||||
// Figure out what style to use by pulling out the style from
|
||||
// the function name
|
||||
|
@ -492,17 +491,17 @@ Parser.prototype.parseFunction = function(baseGroup) {
|
|||
|
||||
if (baseGroup) {
|
||||
if (baseGroup.isFunction) {
|
||||
var func = baseGroup.result;
|
||||
var funcData = functions[func];
|
||||
const func = baseGroup.result;
|
||||
const funcData = functions[func];
|
||||
if (this.mode === "text" && !funcData.allowedInText) {
|
||||
throw new ParseError(
|
||||
"Can't use function '" + func + "' in text mode",
|
||||
baseGroup.token);
|
||||
}
|
||||
|
||||
var args = this.parseArguments(func, funcData);
|
||||
var token = baseGroup.token;
|
||||
var result = this.callFunction(func, args, args.pop(), token);
|
||||
const args = this.parseArguments(func, funcData);
|
||||
const token = baseGroup.token;
|
||||
const result = this.callFunction(func, args, args.pop(), token);
|
||||
return new ParseNode(result.type, result, this.mode);
|
||||
} else {
|
||||
return baseGroup.result;
|
||||
|
@ -516,7 +515,7 @@ Parser.prototype.parseFunction = function(baseGroup) {
|
|||
* Call a function handler with a suitable context and arguments.
|
||||
*/
|
||||
Parser.prototype.callFunction = function(name, args, positions, token) {
|
||||
var context = {
|
||||
const context = {
|
||||
funcName: name,
|
||||
parser: this,
|
||||
positions: positions,
|
||||
|
@ -533,19 +532,19 @@ Parser.prototype.callFunction = function(name, args, positions, token) {
|
|||
* @return the array of arguments, with the list of positions as last element
|
||||
*/
|
||||
Parser.prototype.parseArguments = function(func, funcData) {
|
||||
var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
||||
const totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
||||
if (totalArgs === 0) {
|
||||
return [[this.pos]];
|
||||
}
|
||||
|
||||
var baseGreediness = funcData.greediness;
|
||||
var positions = [this.pos];
|
||||
var args = [];
|
||||
const baseGreediness = funcData.greediness;
|
||||
const positions = [this.pos];
|
||||
const args = [];
|
||||
|
||||
for (var i = 0; i < totalArgs; i++) {
|
||||
var nextToken = this.nextToken;
|
||||
var argType = funcData.argTypes && funcData.argTypes[i];
|
||||
var arg;
|
||||
for (let i = 0; i < totalArgs; i++) {
|
||||
const nextToken = this.nextToken;
|
||||
const argType = funcData.argTypes && funcData.argTypes[i];
|
||||
let arg;
|
||||
if (i < funcData.numOptionalArgs) {
|
||||
if (argType) {
|
||||
arg = this.parseGroupOfType(argType, true);
|
||||
|
@ -575,9 +574,9 @@ Parser.prototype.parseArguments = function(func, funcData) {
|
|||
}
|
||||
}
|
||||
}
|
||||
var argNode;
|
||||
let argNode;
|
||||
if (arg.isFunction) {
|
||||
var argGreediness =
|
||||
const argGreediness =
|
||||
functions[arg.result].greediness;
|
||||
if (argGreediness > baseGreediness) {
|
||||
argNode = this.parseFunction(arg);
|
||||
|
@ -605,7 +604,7 @@ Parser.prototype.parseArguments = function(func, funcData) {
|
|||
* @return {?ParseFuncOrArgument}
|
||||
*/
|
||||
Parser.prototype.parseGroupOfType = function(innerMode, optional) {
|
||||
var outerMode = this.mode;
|
||||
const outerMode = this.mode;
|
||||
// Handle `original` argTypes
|
||||
if (innerMode === "original") {
|
||||
innerMode = outerMode;
|
||||
|
@ -628,7 +627,7 @@ Parser.prototype.parseGroupOfType = function(innerMode, optional) {
|
|||
}
|
||||
// By the time we get here, innerMode is one of "text" or "math".
|
||||
// We switch the mode of the parser, recurse, then restore the old mode.
|
||||
var res = this.parseGroup(optional);
|
||||
const res = this.parseGroup(optional);
|
||||
this.switchMode(outerMode);
|
||||
return res;
|
||||
};
|
||||
|
@ -644,12 +643,12 @@ Parser.prototype.parseStringGroup = function(modeName, optional) {
|
|||
if (optional && this.nextToken.text !== "[") {
|
||||
return null;
|
||||
}
|
||||
var outerMode = this.mode;
|
||||
const outerMode = this.mode;
|
||||
this.mode = "text";
|
||||
this.expect(optional ? "[" : "{");
|
||||
var str = "";
|
||||
var firstToken = this.nextToken;
|
||||
var lastToken = firstToken;
|
||||
let str = "";
|
||||
const firstToken = this.nextToken;
|
||||
let lastToken = firstToken;
|
||||
while (this.nextToken.text !== (optional ? "]" : "}")) {
|
||||
if (this.nextToken.text === "EOF") {
|
||||
throw new ParseError(
|
||||
|
@ -674,11 +673,11 @@ Parser.prototype.parseStringGroup = function(modeName, optional) {
|
|||
* @param {string} modeName Used to describe the mode in error messages
|
||||
*/
|
||||
Parser.prototype.parseRegexGroup = function(regex, modeName) {
|
||||
var outerMode = this.mode;
|
||||
const outerMode = this.mode;
|
||||
this.mode = "text";
|
||||
var firstToken = this.nextToken;
|
||||
var lastToken = firstToken;
|
||||
var str = "";
|
||||
const firstToken = this.nextToken;
|
||||
let lastToken = firstToken;
|
||||
let str = "";
|
||||
while (this.nextToken.text !== "EOF"
|
||||
&& regex.test(str + this.nextToken.text)) {
|
||||
lastToken = this.nextToken;
|
||||
|
@ -698,11 +697,11 @@ Parser.prototype.parseRegexGroup = function(regex, modeName) {
|
|||
* Parses a color description.
|
||||
*/
|
||||
Parser.prototype.parseColorGroup = function(optional) {
|
||||
var res = this.parseStringGroup("color", optional);
|
||||
const res = this.parseStringGroup("color", optional);
|
||||
if (!res) {
|
||||
return null;
|
||||
}
|
||||
var match = (/^(#[a-z0-9]+|[a-z]+)$/i).exec(res.text);
|
||||
const match = (/^(#[a-z0-9]+|[a-z]+)$/i).exec(res.text);
|
||||
if (!match) {
|
||||
throw new ParseError("Invalid color: '" + res.text + "'", res);
|
||||
}
|
||||
|
@ -715,7 +714,7 @@ Parser.prototype.parseColorGroup = function(optional) {
|
|||
* Parses a size specification, consisting of magnitude and unit.
|
||||
*/
|
||||
Parser.prototype.parseSizeGroup = function(optional) {
|
||||
var res;
|
||||
let res;
|
||||
if (!optional && this.nextToken.text !== "{") {
|
||||
res = this.parseRegexGroup(
|
||||
/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/, "size");
|
||||
|
@ -725,11 +724,11 @@ Parser.prototype.parseSizeGroup = function(optional) {
|
|||
if (!res) {
|
||||
return null;
|
||||
}
|
||||
var match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(res.text);
|
||||
const match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(res.text);
|
||||
if (!match) {
|
||||
throw new ParseError("Invalid size: '" + res.text + "'", res);
|
||||
}
|
||||
var data = {
|
||||
const data = {
|
||||
number: +(match[1] + match[2]), // sign + magnitude, cast to number
|
||||
unit: match[3],
|
||||
};
|
||||
|
@ -753,13 +752,13 @@ Parser.prototype.parseSizeGroup = function(optional) {
|
|||
* @return {?ParseFuncOrArgument}
|
||||
*/
|
||||
Parser.prototype.parseGroup = function(optional) {
|
||||
var firstToken = this.nextToken;
|
||||
const firstToken = this.nextToken;
|
||||
// Try to parse an open brace
|
||||
if (this.nextToken.text === (optional ? "[" : "{")) {
|
||||
// If we get a brace, parse an expression
|
||||
this.consume();
|
||||
var expression = this.parseExpression(false, optional ? "]" : null);
|
||||
var lastToken = this.nextToken;
|
||||
const expression = this.parseExpression(false, optional ? "]" : null);
|
||||
const lastToken = this.nextToken;
|
||||
// Make sure we get a close brace
|
||||
this.expect(optional ? "]" : "}");
|
||||
if (this.mode === "text") {
|
||||
|
@ -786,11 +785,10 @@ Parser.prototype.parseGroup = function(optional) {
|
|||
* list will be moified in place
|
||||
*/
|
||||
Parser.prototype.formLigatures = function(group) {
|
||||
var i;
|
||||
var n = group.length - 1;
|
||||
for (i = 0; i < n; ++i) {
|
||||
var a = group[i];
|
||||
var v = a.value;
|
||||
let n = group.length - 1;
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const a = group[i];
|
||||
const v = a.value;
|
||||
if (v === "-" && group[i + 1].value === "-") {
|
||||
if (i + 1 < n && group[i + 2].value === "-") {
|
||||
group.splice(i, 3, new ParseNode(
|
||||
|
@ -817,7 +815,7 @@ Parser.prototype.formLigatures = function(group) {
|
|||
* @return {?ParseFuncOrArgument}
|
||||
*/
|
||||
Parser.prototype.parseSymbol = function() {
|
||||
var nucleus = this.nextToken;
|
||||
const nucleus = this.nextToken;
|
||||
|
||||
if (functions[nucleus.text]) {
|
||||
this.consume();
|
||||
|
|
43
src/Style.js
43
src/Style.js
|
@ -6,18 +6,17 @@
|
|||
* information about them.
|
||||
*/
|
||||
|
||||
var sigmas = require("./fontMetrics.js").sigmas;
|
||||
const sigmas = require("./fontMetrics.js").sigmas;
|
||||
|
||||
var metrics = [{}, {}, {}];
|
||||
var i;
|
||||
for (var key in sigmas) {
|
||||
const metrics = [{}, {}, {}];
|
||||
for (const key in sigmas) {
|
||||
if (sigmas.hasOwnProperty(key)) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
metrics[i][key] = sigmas[key][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
metrics[i].emPerEx = sigmas.xHeight[i] / sigmas.quad[i];
|
||||
}
|
||||
|
||||
|
@ -95,17 +94,17 @@ Style.prototype.isTight = function() {
|
|||
};
|
||||
|
||||
// IDs of the different styles
|
||||
var D = 0;
|
||||
var Dc = 1;
|
||||
var T = 2;
|
||||
var Tc = 3;
|
||||
var S = 4;
|
||||
var Sc = 5;
|
||||
var SS = 6;
|
||||
var SSc = 7;
|
||||
const D = 0;
|
||||
const Dc = 1;
|
||||
const T = 2;
|
||||
const Tc = 3;
|
||||
const S = 4;
|
||||
const Sc = 5;
|
||||
const SS = 6;
|
||||
const SSc = 7;
|
||||
|
||||
// String names for the different sizes
|
||||
var sizeNames = [
|
||||
const sizeNames = [
|
||||
"displaystyle textstyle",
|
||||
"textstyle",
|
||||
"scriptstyle",
|
||||
|
@ -113,7 +112,7 @@ var sizeNames = [
|
|||
];
|
||||
|
||||
// Reset names for the different sizes
|
||||
var resetNames = [
|
||||
const resetNames = [
|
||||
"reset-textstyle",
|
||||
"reset-textstyle",
|
||||
"reset-scriptstyle",
|
||||
|
@ -121,7 +120,7 @@ var resetNames = [
|
|||
];
|
||||
|
||||
// Instances of the different styles
|
||||
var styles = [
|
||||
const styles = [
|
||||
new Style(D, 0, 1.0, false),
|
||||
new Style(Dc, 0, 1.0, true),
|
||||
new Style(T, 1, 1.0, false),
|
||||
|
@ -133,11 +132,11 @@ var styles = [
|
|||
];
|
||||
|
||||
// Lookup tables for switching from one style to another
|
||||
var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
|
||||
var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
|
||||
var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
|
||||
var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
|
||||
var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
|
||||
const sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
|
||||
const sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
|
||||
const fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
|
||||
const fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
|
||||
const cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
|
||||
|
||||
// We only export some of the styles. Also, we don't export the `Style` class so
|
||||
// no more styles can be generated.
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* different kinds of domTree nodes in a consistent manner.
|
||||
*/
|
||||
|
||||
var domTree = require("./domTree");
|
||||
var fontMetrics = require("./fontMetrics");
|
||||
var symbols = require("./symbols");
|
||||
var utils = require("./utils");
|
||||
const domTree = require("./domTree");
|
||||
const fontMetrics = require("./fontMetrics");
|
||||
const symbols = require("./symbols");
|
||||
const utils = require("./utils");
|
||||
|
||||
var greekCapitals = [
|
||||
const greekCapitals = [
|
||||
"\\Gamma",
|
||||
"\\Delta",
|
||||
"\\Theta",
|
||||
|
@ -24,7 +24,7 @@ var greekCapitals = [
|
|||
];
|
||||
|
||||
// The following have to be loaded from Main-Italic font, using class mainit
|
||||
var mainitLetters = [
|
||||
const mainitLetters = [
|
||||
"\u0131", // dotless i, \imath
|
||||
"\u0237", // dotless j, \jmath
|
||||
"\u00a3", // \pounds
|
||||
|
@ -39,17 +39,17 @@ var mainitLetters = [
|
|||
* TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
|
||||
* should if present come first in `classes`.
|
||||
*/
|
||||
var makeSymbol = function(value, fontFamily, mode, options, classes) {
|
||||
const makeSymbol = function(value, fontFamily, mode, options, classes) {
|
||||
// Replace the value with its replaced value from symbol.js
|
||||
if (symbols[mode][value] && symbols[mode][value].replace) {
|
||||
value = symbols[mode][value].replace;
|
||||
}
|
||||
|
||||
var metrics = fontMetrics.getCharacterMetrics(value, fontFamily);
|
||||
const metrics = fontMetrics.getCharacterMetrics(value, fontFamily);
|
||||
|
||||
var symbolNode;
|
||||
let symbolNode;
|
||||
if (metrics) {
|
||||
var italic = metrics.italic;
|
||||
let italic = metrics.italic;
|
||||
if (mode === "text") {
|
||||
italic = 0;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ var makeSymbol = function(value, fontFamily, mode, options, classes) {
|
|||
* Makes a symbol in Main-Regular or AMS-Regular.
|
||||
* Used for rel, bin, open, close, inner, and punct.
|
||||
*/
|
||||
var mathsym = function(value, mode, options, classes) {
|
||||
const mathsym = function(value, mode, options, classes) {
|
||||
// Decide what font to render the symbol in by its entry in the symbols
|
||||
// table.
|
||||
// Have a special case for when the value = \ because the \ is used as a
|
||||
|
@ -98,7 +98,7 @@ var mathsym = function(value, mode, options, classes) {
|
|||
/**
|
||||
* Makes a symbol in the default font for mathords and textords.
|
||||
*/
|
||||
var mathDefault = function(value, mode, options, classes, type) {
|
||||
const mathDefault = function(value, mode, options, classes, type) {
|
||||
if (type === "mathord") {
|
||||
return mathit(value, mode, options, classes);
|
||||
} else if (type === "textord") {
|
||||
|
@ -112,7 +112,7 @@ var mathDefault = function(value, mode, options, classes, type) {
|
|||
/**
|
||||
* Makes a symbol in the italic math font.
|
||||
*/
|
||||
var mathit = function(value, mode, options, classes) {
|
||||
const mathit = function(value, mode, options, classes) {
|
||||
if (/[0-9]/.test(value.charAt(0)) ||
|
||||
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
||||
// need to use Main-Italic instead
|
||||
|
@ -129,21 +129,21 @@ var mathit = function(value, mode, options, classes) {
|
|||
/**
|
||||
* Makes either a mathord or textord in the correct font and color.
|
||||
*/
|
||||
var makeOrd = function(group, options, type) {
|
||||
var mode = group.mode;
|
||||
var value = group.value;
|
||||
const makeOrd = function(group, options, type) {
|
||||
const mode = group.mode;
|
||||
let value = group.value;
|
||||
if (symbols[mode][value] && symbols[mode][value].replace) {
|
||||
value = symbols[mode][value].replace;
|
||||
}
|
||||
|
||||
var classes = ["mord"];
|
||||
const classes = ["mord"];
|
||||
|
||||
var font = options.font;
|
||||
const font = options.font;
|
||||
if (font) {
|
||||
if (font === "mathit" || utils.contains(mainitLetters, value)) {
|
||||
return mathit(value, mode, options, classes);
|
||||
} else {
|
||||
var fontName = fontMap[font].fontName;
|
||||
const fontName = fontMap[font].fontName;
|
||||
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
||||
return makeSymbol(
|
||||
value, fontName, mode, options, classes.concat([font]));
|
||||
|
@ -160,13 +160,13 @@ var makeOrd = function(group, options, type) {
|
|||
* Calculate the height, depth, and maxFontSize of an element based on its
|
||||
* children.
|
||||
*/
|
||||
var sizeElementFromChildren = function(elem) {
|
||||
var height = 0;
|
||||
var depth = 0;
|
||||
var maxFontSize = 0;
|
||||
const sizeElementFromChildren = function(elem) {
|
||||
let height = 0;
|
||||
let depth = 0;
|
||||
let maxFontSize = 0;
|
||||
|
||||
if (elem.children) {
|
||||
for (var i = 0; i < elem.children.length; i++) {
|
||||
for (let i = 0; i < elem.children.length; i++) {
|
||||
if (elem.children[i].height > height) {
|
||||
height = elem.children[i].height;
|
||||
}
|
||||
|
@ -192,8 +192,8 @@ var sizeElementFromChildren = function(elem) {
|
|||
* TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
|
||||
* should if present come first in `classes`.
|
||||
*/
|
||||
var makeSpan = function(classes, children, options) {
|
||||
var span = new domTree.span(classes, children, options);
|
||||
const makeSpan = function(classes, children, options) {
|
||||
const span = new domTree.span(classes, children, options);
|
||||
|
||||
sizeElementFromChildren(span);
|
||||
|
||||
|
@ -204,7 +204,7 @@ var makeSpan = function(classes, children, options) {
|
|||
* Prepends the given children to the given span, updating height, depth, and
|
||||
* maxFontSize.
|
||||
*/
|
||||
var prependChildren = function(span, children) {
|
||||
const prependChildren = function(span, children) {
|
||||
span.children = children.concat(span.children);
|
||||
|
||||
sizeElementFromChildren(span);
|
||||
|
@ -213,8 +213,8 @@ var prependChildren = function(span, children) {
|
|||
/**
|
||||
* Makes a document fragment with the given list of children.
|
||||
*/
|
||||
var makeFragment = function(children) {
|
||||
var fragment = new domTree.documentFragment(children);
|
||||
const makeFragment = function(children) {
|
||||
const fragment = new domTree.documentFragment(children);
|
||||
|
||||
sizeElementFromChildren(fragment);
|
||||
|
||||
|
@ -226,12 +226,12 @@ var makeFragment = function(children) {
|
|||
* element has the same max font size. To do this, we create a zero-width space
|
||||
* with the correct font size.
|
||||
*/
|
||||
var makeFontSizer = function(options, fontSize) {
|
||||
var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
|
||||
const makeFontSizer = function(options, fontSize) {
|
||||
const fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
|
||||
fontSizeInner.style.fontSize =
|
||||
(fontSize / options.style.sizeMultiplier) + "em";
|
||||
|
||||
var fontSizer = makeSpan(
|
||||
const fontSizer = makeSpan(
|
||||
["fontsize-ensurer", "reset-" + options.size, "size5"],
|
||||
[fontSizeInner]);
|
||||
|
||||
|
@ -277,12 +277,12 @@ var makeFontSizer = function(options, fontSize) {
|
|||
* - options: An Options object
|
||||
*
|
||||
*/
|
||||
var makeVList = function(children, positionType, positionData, options) {
|
||||
var depth;
|
||||
var currPos;
|
||||
var i;
|
||||
const makeVList = function(children, positionType, positionData, options) {
|
||||
let depth;
|
||||
let currPos;
|
||||
let i;
|
||||
if (positionType === "individualShift") {
|
||||
var oldChildren = children;
|
||||
const oldChildren = children;
|
||||
children = [oldChildren[0]];
|
||||
|
||||
// Add in kerns to the list of children to get each element to be
|
||||
|
@ -290,9 +290,9 @@ var makeVList = function(children, positionType, positionData, options) {
|
|||
depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
|
||||
currPos = depth;
|
||||
for (i = 1; i < oldChildren.length; i++) {
|
||||
var diff = -oldChildren[i].shift - currPos -
|
||||
const diff = -oldChildren[i].shift - currPos -
|
||||
oldChildren[i].elem.depth;
|
||||
var size = diff -
|
||||
const size = diff -
|
||||
(oldChildren[i - 1].elem.height +
|
||||
oldChildren[i - 1].elem.depth);
|
||||
|
||||
|
@ -304,7 +304,7 @@ var makeVList = function(children, positionType, positionData, options) {
|
|||
} else if (positionType === "top") {
|
||||
// We always start at the bottom, so calculate the bottom by adding up
|
||||
// all the sizes
|
||||
var bottom = positionData;
|
||||
let bottom = positionData;
|
||||
for (i = 0; i < children.length; i++) {
|
||||
if (children[i].type === "kern") {
|
||||
bottom -= children[i].size;
|
||||
|
@ -324,27 +324,27 @@ var makeVList = function(children, positionType, positionData, options) {
|
|||
}
|
||||
|
||||
// Make the fontSizer
|
||||
var maxFontSize = 0;
|
||||
let maxFontSize = 0;
|
||||
for (i = 0; i < children.length; i++) {
|
||||
if (children[i].type === "elem") {
|
||||
maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
|
||||
}
|
||||
}
|
||||
var fontSizer = makeFontSizer(options, maxFontSize);
|
||||
const fontSizer = makeFontSizer(options, maxFontSize);
|
||||
|
||||
// Create a new list of actual children at the correct offsets
|
||||
var realChildren = [];
|
||||
const realChildren = [];
|
||||
currPos = depth;
|
||||
for (i = 0; i < children.length; i++) {
|
||||
if (children[i].type === "kern") {
|
||||
currPos += children[i].size;
|
||||
} else {
|
||||
var child = children[i].elem;
|
||||
const child = children[i].elem;
|
||||
|
||||
var shift = -child.depth - currPos;
|
||||
const shift = -child.depth - currPos;
|
||||
currPos += child.height + child.depth;
|
||||
|
||||
var childWrap = makeSpan([], [fontSizer, child]);
|
||||
const childWrap = makeSpan([], [fontSizer, child]);
|
||||
childWrap.height -= shift;
|
||||
childWrap.depth += shift;
|
||||
childWrap.style.top = shift + "em";
|
||||
|
@ -355,11 +355,11 @@ var makeVList = function(children, positionType, positionData, options) {
|
|||
|
||||
// Add in an element at the end with no offset to fix the calculation of
|
||||
// baselines in some browsers (namely IE, sometimes safari)
|
||||
var baselineFix = makeSpan(
|
||||
const baselineFix = makeSpan(
|
||||
["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]);
|
||||
realChildren.push(baselineFix);
|
||||
|
||||
var vlist = makeSpan(["vlist"], realChildren);
|
||||
const vlist = makeSpan(["vlist"], realChildren);
|
||||
// Fix the final height and depth, in case there were kerns at the ends
|
||||
// since the makeSpan calculation won't take that in to account.
|
||||
vlist.height = Math.max(currPos, vlist.height);
|
||||
|
@ -368,7 +368,7 @@ var makeVList = function(children, positionType, positionData, options) {
|
|||
};
|
||||
|
||||
// A table of size -> font size for the different sizing functions
|
||||
var sizingMultiplier = {
|
||||
const sizingMultiplier = {
|
||||
size1: 0.5,
|
||||
size2: 0.7,
|
||||
size3: 0.8,
|
||||
|
@ -383,7 +383,7 @@ var sizingMultiplier = {
|
|||
|
||||
// A map of spacing functions to their attributes, like size and corresponding
|
||||
// CSS class
|
||||
var spacingFunctions = {
|
||||
const spacingFunctions = {
|
||||
"\\qquad": {
|
||||
size: "2em",
|
||||
className: "qquad",
|
||||
|
@ -420,7 +420,7 @@ var spacingFunctions = {
|
|||
* - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
|
||||
*/
|
||||
// A map between tex font commands an MathML mathvariant attribute values
|
||||
var fontMap = {
|
||||
const fontMap = {
|
||||
// styles
|
||||
"mathbf": {
|
||||
variant: "bold",
|
||||
|
|
448
src/buildHTML.js
448
src/buildHTML.js
File diff suppressed because it is too large
Load Diff
|
@ -4,21 +4,21 @@
|
|||
* parser.
|
||||
*/
|
||||
|
||||
var buildCommon = require("./buildCommon");
|
||||
var fontMetrics = require("./fontMetrics");
|
||||
var mathMLTree = require("./mathMLTree");
|
||||
var ParseError = require("./ParseError");
|
||||
var symbols = require("./symbols");
|
||||
var utils = require("./utils");
|
||||
const buildCommon = require("./buildCommon");
|
||||
const fontMetrics = require("./fontMetrics");
|
||||
const mathMLTree = require("./mathMLTree");
|
||||
const ParseError = require("./ParseError");
|
||||
const symbols = require("./symbols");
|
||||
const utils = require("./utils");
|
||||
|
||||
var makeSpan = buildCommon.makeSpan;
|
||||
var fontMap = buildCommon.fontMap;
|
||||
const makeSpan = buildCommon.makeSpan;
|
||||
const fontMap = buildCommon.fontMap;
|
||||
|
||||
/**
|
||||
* Takes a symbol and converts it into a MathML text node after performing
|
||||
* optional replacement from symbols.js.
|
||||
*/
|
||||
var makeText = function(text, mode) {
|
||||
const makeText = function(text, mode) {
|
||||
if (symbols[mode][text] && symbols[mode][text].replace) {
|
||||
text = symbols[mode][text].replace;
|
||||
}
|
||||
|
@ -29,18 +29,18 @@ var makeText = function(text, mode) {
|
|||
/**
|
||||
* Returns the math variant as a string or null if none is required.
|
||||
*/
|
||||
var getVariant = function(group, options) {
|
||||
var font = options.font;
|
||||
const getVariant = function(group, options) {
|
||||
const font = options.font;
|
||||
if (!font) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var mode = group.mode;
|
||||
const mode = group.mode;
|
||||
if (font === "mathit") {
|
||||
return "italic";
|
||||
}
|
||||
|
||||
var value = group.value;
|
||||
let value = group.value;
|
||||
if (utils.contains(["\\imath", "\\jmath"], value)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ var getVariant = function(group, options) {
|
|||
value = symbols[mode][value].replace;
|
||||
}
|
||||
|
||||
var fontName = fontMap[font].fontName;
|
||||
const fontName = fontMap[font].fontName;
|
||||
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
||||
return fontMap[options.font].variant;
|
||||
}
|
||||
|
@ -61,14 +61,14 @@ var getVariant = function(group, options) {
|
|||
* Functions for handling the different types of groups found in the parse
|
||||
* tree. Each function should take a parse group and return a MathML node.
|
||||
*/
|
||||
var groupTypes = {};
|
||||
const groupTypes = {};
|
||||
|
||||
groupTypes.mathord = function(group, options) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mi",
|
||||
[makeText(group.value, group.mode)]);
|
||||
|
||||
var variant = getVariant(group, options);
|
||||
const variant = getVariant(group, options);
|
||||
if (variant) {
|
||||
node.setAttribute("mathvariant", variant);
|
||||
}
|
||||
|
@ -76,11 +76,11 @@ groupTypes.mathord = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.textord = function(group, options) {
|
||||
var text = makeText(group.value, group.mode);
|
||||
const text = makeText(group.value, group.mode);
|
||||
|
||||
var variant = getVariant(group, options) || "normal";
|
||||
const variant = getVariant(group, options) || "normal";
|
||||
|
||||
var node;
|
||||
let node;
|
||||
if (/[0-9]/.test(group.value)) {
|
||||
// TODO(kevinb) merge adjacent <mn> nodes
|
||||
// do it as a post processing step
|
||||
|
@ -97,42 +97,42 @@ groupTypes.textord = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.bin = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.rel = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.open = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.close = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.inner = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.punct = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value, group.mode)]);
|
||||
|
||||
node.setAttribute("separator", "true");
|
||||
|
@ -141,25 +141,25 @@ groupTypes.punct = function(group) {
|
|||
};
|
||||
|
||||
groupTypes.ordgroup = function(group, options) {
|
||||
var inner = buildExpression(group.value, options);
|
||||
const inner = buildExpression(group.value, options);
|
||||
|
||||
var node = new mathMLTree.MathNode("mrow", inner);
|
||||
const node = new mathMLTree.MathNode("mrow", inner);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.text = function(group, options) {
|
||||
var inner = buildExpression(group.value.body, options);
|
||||
const inner = buildExpression(group.value.body, options);
|
||||
|
||||
var node = new mathMLTree.MathNode("mtext", inner);
|
||||
const node = new mathMLTree.MathNode("mtext", inner);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.color = function(group, options) {
|
||||
var inner = buildExpression(group.value.value, options);
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
|
||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
node.setAttribute("mathcolor", group.value.color);
|
||||
|
||||
|
@ -167,7 +167,7 @@ groupTypes.color = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.supsub = function(group, options) {
|
||||
var children = [buildGroup(group.value.base, options)];
|
||||
const children = [buildGroup(group.value.base, options)];
|
||||
|
||||
if (group.value.sub) {
|
||||
children.push(buildGroup(group.value.sub, options));
|
||||
|
@ -177,7 +177,7 @@ groupTypes.supsub = function(group, options) {
|
|||
children.push(buildGroup(group.value.sup, options));
|
||||
}
|
||||
|
||||
var nodeType;
|
||||
let nodeType;
|
||||
if (!group.value.sub) {
|
||||
nodeType = "msup";
|
||||
} else if (!group.value.sup) {
|
||||
|
@ -186,13 +186,13 @@ groupTypes.supsub = function(group, options) {
|
|||
nodeType = "msubsup";
|
||||
}
|
||||
|
||||
var node = new mathMLTree.MathNode(nodeType, children);
|
||||
const node = new mathMLTree.MathNode(nodeType, children);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.genfrac = function(group, options) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mfrac",
|
||||
[
|
||||
buildGroup(group.value.numer, options),
|
||||
|
@ -204,10 +204,10 @@ groupTypes.genfrac = function(group, options) {
|
|||
}
|
||||
|
||||
if (group.value.leftDelim != null || group.value.rightDelim != null) {
|
||||
var withDelims = [];
|
||||
const withDelims = [];
|
||||
|
||||
if (group.value.leftDelim != null) {
|
||||
var leftOp = new mathMLTree.MathNode(
|
||||
const leftOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
|
||||
|
||||
leftOp.setAttribute("fence", "true");
|
||||
|
@ -218,7 +218,7 @@ groupTypes.genfrac = function(group, options) {
|
|||
withDelims.push(node);
|
||||
|
||||
if (group.value.rightDelim != null) {
|
||||
var rightOp = new mathMLTree.MathNode(
|
||||
const rightOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
|
||||
|
||||
rightOp.setAttribute("fence", "true");
|
||||
|
@ -226,7 +226,7 @@ groupTypes.genfrac = function(group, options) {
|
|||
withDelims.push(rightOp);
|
||||
}
|
||||
|
||||
var outerNode = new mathMLTree.MathNode("mrow", withDelims);
|
||||
const outerNode = new mathMLTree.MathNode("mrow", withDelims);
|
||||
|
||||
return outerNode;
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ groupTypes.array = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.sqrt = function(group, options) {
|
||||
var node;
|
||||
let node;
|
||||
if (group.value.index) {
|
||||
node = new mathMLTree.MathNode(
|
||||
"mroot", [
|
||||
|
@ -262,10 +262,10 @@ groupTypes.sqrt = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.leftright = function(group, options) {
|
||||
var inner = buildExpression(group.value.body, options);
|
||||
const inner = buildExpression(group.value.body, options);
|
||||
|
||||
if (group.value.left !== ".") {
|
||||
var leftNode = new mathMLTree.MathNode(
|
||||
const leftNode = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value.left, group.mode)]);
|
||||
|
||||
leftNode.setAttribute("fence", "true");
|
||||
|
@ -274,7 +274,7 @@ groupTypes.leftright = function(group, options) {
|
|||
}
|
||||
|
||||
if (group.value.right !== ".") {
|
||||
var rightNode = new mathMLTree.MathNode(
|
||||
const rightNode = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value.right, group.mode)]);
|
||||
|
||||
rightNode.setAttribute("fence", "true");
|
||||
|
@ -282,23 +282,23 @@ groupTypes.leftright = function(group, options) {
|
|||
inner.push(rightNode);
|
||||
}
|
||||
|
||||
var outerNode = new mathMLTree.MathNode("mrow", inner);
|
||||
const outerNode = new mathMLTree.MathNode("mrow", inner);
|
||||
|
||||
return outerNode;
|
||||
};
|
||||
|
||||
groupTypes.middle = function(group, options) {
|
||||
var middleNode = new mathMLTree.MathNode(
|
||||
const middleNode = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value.middle, group.mode)]);
|
||||
middleNode.setAttribute("fence", "true");
|
||||
return middleNode;
|
||||
};
|
||||
|
||||
groupTypes.accent = function(group, options) {
|
||||
var accentNode = new mathMLTree.MathNode(
|
||||
const accentNode = new mathMLTree.MathNode(
|
||||
"mo", [makeText(group.value.accent, group.mode)]);
|
||||
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mover",
|
||||
[buildGroup(group.value.base, options), accentNode]);
|
||||
|
||||
|
@ -308,7 +308,7 @@ groupTypes.accent = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.spacing = function(group) {
|
||||
var node;
|
||||
let node;
|
||||
|
||||
if (group.value === "\\ " || group.value === "\\space" ||
|
||||
group.value === " " || group.value === "~") {
|
||||
|
@ -325,7 +325,7 @@ groupTypes.spacing = function(group) {
|
|||
};
|
||||
|
||||
groupTypes.op = function(group, options) {
|
||||
var node;
|
||||
let node;
|
||||
|
||||
// TODO(emily): handle big operators using the `largeop` attribute
|
||||
|
||||
|
@ -350,7 +350,7 @@ groupTypes.op = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.mod = function(group, options) {
|
||||
var inner = [];
|
||||
let inner = [];
|
||||
|
||||
if (group.value.modType === "pod" || group.value.modType === "pmod") {
|
||||
inner.push(new mathMLTree.MathNode(
|
||||
|
@ -361,7 +361,7 @@ groupTypes.mod = function(group, options) {
|
|||
"mo", [makeText("mod", group.mode)]));
|
||||
}
|
||||
if (group.value.value) {
|
||||
var space = new mathMLTree.MathNode("mspace");
|
||||
const space = new mathMLTree.MathNode("mspace");
|
||||
space.setAttribute("width", "0.333333em");
|
||||
inner.push(space);
|
||||
inner = inner.concat(buildExpression(group.value.value, options));
|
||||
|
@ -375,25 +375,25 @@ groupTypes.mod = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.katex = function(group) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mtext", [new mathMLTree.TextNode("KaTeX")]);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.font = function(group, options) {
|
||||
var font = group.value.font;
|
||||
const font = group.value.font;
|
||||
return buildGroup(group.value.body, options.withFont(font));
|
||||
};
|
||||
|
||||
groupTypes.delimsizing = function(group) {
|
||||
var children = [];
|
||||
const children = [];
|
||||
|
||||
if (group.value.value !== ".") {
|
||||
children.push(makeText(group.value.value, group.mode));
|
||||
}
|
||||
|
||||
var node = new mathMLTree.MathNode("mo", children);
|
||||
const node = new mathMLTree.MathNode("mo", children);
|
||||
|
||||
if (group.value.mclass === "mopen" ||
|
||||
group.value.mclass === "mclose") {
|
||||
|
@ -410,18 +410,18 @@ groupTypes.delimsizing = function(group) {
|
|||
};
|
||||
|
||||
groupTypes.styling = function(group, options) {
|
||||
var inner = buildExpression(group.value.value, options);
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
|
||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
var styleAttributes = {
|
||||
const styleAttributes = {
|
||||
"display": ["0", "true"],
|
||||
"text": ["0", "false"],
|
||||
"script": ["1", "false"],
|
||||
"scriptscript": ["2", "false"],
|
||||
};
|
||||
|
||||
var attr = styleAttributes[group.value.style];
|
||||
const attr = styleAttributes[group.value.style];
|
||||
|
||||
node.setAttribute("scriptlevel", attr[0]);
|
||||
node.setAttribute("displaystyle", attr[1]);
|
||||
|
@ -430,9 +430,9 @@ groupTypes.styling = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.sizing = function(group, options) {
|
||||
var inner = buildExpression(group.value.value, options);
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
|
||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
// TODO(emily): This doesn't produce the correct size for nested size
|
||||
// changes, because we don't keep state of what style we're currently
|
||||
|
@ -446,11 +446,11 @@ groupTypes.sizing = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.overline = function(group, options) {
|
||||
var operator = new mathMLTree.MathNode(
|
||||
const operator = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode("\u203e")]);
|
||||
operator.setAttribute("stretchy", "true");
|
||||
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mover",
|
||||
[buildGroup(group.value.body, options), operator]);
|
||||
node.setAttribute("accent", "true");
|
||||
|
@ -459,11 +459,11 @@ groupTypes.overline = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.underline = function(group, options) {
|
||||
var operator = new mathMLTree.MathNode(
|
||||
const operator = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode("\u203e")]);
|
||||
operator.setAttribute("stretchy", "true");
|
||||
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"munder",
|
||||
[buildGroup(group.value.body, options), operator]);
|
||||
node.setAttribute("accentunder", "true");
|
||||
|
@ -474,20 +474,20 @@ groupTypes.underline = function(group, options) {
|
|||
groupTypes.rule = function(group) {
|
||||
// TODO(emily): Figure out if there's an actual way to draw black boxes
|
||||
// in MathML.
|
||||
var node = new mathMLTree.MathNode("mrow");
|
||||
const node = new mathMLTree.MathNode("mrow");
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.kern = function(group) {
|
||||
// TODO(kevin): Figure out if there's a way to add space in MathML
|
||||
var node = new mathMLTree.MathNode("mrow");
|
||||
const node = new mathMLTree.MathNode("mrow");
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.llap = function(group, options) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [buildGroup(group.value.body, options)]);
|
||||
|
||||
node.setAttribute("lspace", "-1width");
|
||||
|
@ -497,7 +497,7 @@ groupTypes.llap = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.rlap = function(group, options) {
|
||||
var node = new mathMLTree.MathNode(
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [buildGroup(group.value.body, options)]);
|
||||
|
||||
node.setAttribute("width", "0px");
|
||||
|
@ -506,12 +506,12 @@ groupTypes.rlap = function(group, options) {
|
|||
};
|
||||
|
||||
groupTypes.phantom = function(group, options) {
|
||||
var inner = buildExpression(group.value.value, options);
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
return new mathMLTree.MathNode("mphantom", inner);
|
||||
};
|
||||
|
||||
groupTypes.mclass = function(group, options) {
|
||||
var inner = buildExpression(group.value.value, options);
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
return new mathMLTree.MathNode("mstyle", inner);
|
||||
};
|
||||
|
||||
|
@ -520,10 +520,10 @@ groupTypes.mclass = function(group, options) {
|
|||
* MathML nodes. A little simpler than the HTML version because we don't do any
|
||||
* previous-node handling.
|
||||
*/
|
||||
var buildExpression = function(expression, options) {
|
||||
var groups = [];
|
||||
for (var i = 0; i < expression.length; i++) {
|
||||
var group = expression[i];
|
||||
const buildExpression = function(expression, options) {
|
||||
const groups = [];
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const group = expression[i];
|
||||
groups.push(buildGroup(group, options));
|
||||
}
|
||||
return groups;
|
||||
|
@ -533,7 +533,7 @@ var buildExpression = function(expression, options) {
|
|||
* Takes a group from the parser and calls the appropriate groupTypes function
|
||||
* on it to produce a MathML node.
|
||||
*/
|
||||
var buildGroup = function(group, options) {
|
||||
const buildGroup = function(group, options) {
|
||||
if (!group) {
|
||||
return new mathMLTree.MathNode("mrow");
|
||||
}
|
||||
|
@ -555,23 +555,23 @@ var buildGroup = function(group, options) {
|
|||
* Note that we actually return a domTree element with a `<math>` inside it so
|
||||
* we can do appropriate styling.
|
||||
*/
|
||||
var buildMathML = function(tree, texExpression, options) {
|
||||
var expression = buildExpression(tree, options);
|
||||
const buildMathML = function(tree, texExpression, options) {
|
||||
const expression = buildExpression(tree, options);
|
||||
|
||||
// Wrap up the expression in an mrow so it is presented in the semantics
|
||||
// tag correctly.
|
||||
var wrapper = new mathMLTree.MathNode("mrow", expression);
|
||||
const wrapper = new mathMLTree.MathNode("mrow", expression);
|
||||
|
||||
// Build a TeX annotation of the source
|
||||
var annotation = new mathMLTree.MathNode(
|
||||
const annotation = new mathMLTree.MathNode(
|
||||
"annotation", [new mathMLTree.TextNode(texExpression)]);
|
||||
|
||||
annotation.setAttribute("encoding", "application/x-tex");
|
||||
|
||||
var semantics = new mathMLTree.MathNode(
|
||||
const semantics = new mathMLTree.MathNode(
|
||||
"semantics", [wrapper, annotation]);
|
||||
|
||||
var math = new mathMLTree.MathNode("math", [semantics]);
|
||||
const math = new mathMLTree.MathNode("math", [semantics]);
|
||||
|
||||
// You can't style <math> nodes, so we wrap the node in a span.
|
||||
return makeSpan(["katex-mathml"], [math]);
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
var buildHTML = require("./buildHTML");
|
||||
var buildMathML = require("./buildMathML");
|
||||
var buildCommon = require("./buildCommon");
|
||||
var Options = require("./Options");
|
||||
var Settings = require("./Settings");
|
||||
var Style = require("./Style");
|
||||
const buildHTML = require("./buildHTML");
|
||||
const buildMathML = require("./buildMathML");
|
||||
const buildCommon = require("./buildCommon");
|
||||
const Options = require("./Options");
|
||||
const Settings = require("./Settings");
|
||||
const Style = require("./Style");
|
||||
|
||||
var makeSpan = buildCommon.makeSpan;
|
||||
const makeSpan = buildCommon.makeSpan;
|
||||
|
||||
var buildTree = function(tree, expression, settings) {
|
||||
const buildTree = function(tree, expression, settings) {
|
||||
settings = settings || new Settings({});
|
||||
|
||||
var startStyle = Style.TEXT;
|
||||
let startStyle = Style.TEXT;
|
||||
if (settings.displayMode) {
|
||||
startStyle = Style.DISPLAY;
|
||||
}
|
||||
|
||||
// Setup the default options
|
||||
var options = new Options({
|
||||
const options = new Options({
|
||||
style: startStyle,
|
||||
size: "size5",
|
||||
});
|
||||
|
||||
// `buildHTML` sometimes messes with the parse tree (like turning bins ->
|
||||
// ords), so we build the MathML version first.
|
||||
var mathMLNode = buildMathML(tree, expression, options);
|
||||
var htmlNode = buildHTML(tree, options);
|
||||
const mathMLNode = buildMathML(tree, expression, options);
|
||||
const htmlNode = buildHTML(tree, options);
|
||||
|
||||
var katexNode = makeSpan(["katex"], [
|
||||
const katexNode = makeSpan(["katex"], [
|
||||
mathMLNode, htmlNode,
|
||||
]);
|
||||
|
||||
|
|
143
src/delimiter.js
143
src/delimiter.js
|
@ -20,21 +20,21 @@
|
|||
* used in `\left` and `\right`.
|
||||
*/
|
||||
|
||||
var ParseError = require("./ParseError");
|
||||
var Style = require("./Style");
|
||||
const ParseError = require("./ParseError");
|
||||
const Style = require("./Style");
|
||||
|
||||
var buildCommon = require("./buildCommon");
|
||||
var fontMetrics = require("./fontMetrics");
|
||||
var symbols = require("./symbols");
|
||||
var utils = require("./utils");
|
||||
const buildCommon = require("./buildCommon");
|
||||
const fontMetrics = require("./fontMetrics");
|
||||
const symbols = require("./symbols");
|
||||
const utils = require("./utils");
|
||||
|
||||
var makeSpan = buildCommon.makeSpan;
|
||||
const makeSpan = buildCommon.makeSpan;
|
||||
|
||||
/**
|
||||
* Get the metrics for a given symbol and font, after transformation (i.e.
|
||||
* after following replacement from symbols.js)
|
||||
*/
|
||||
var getMetrics = function(symbol, font) {
|
||||
const getMetrics = function(symbol, font) {
|
||||
if (symbols.math[symbol] && symbols.math[symbol].replace) {
|
||||
return fontMetrics.getCharacterMetrics(
|
||||
symbols.math[symbol].replace, font);
|
||||
|
@ -47,7 +47,7 @@ var getMetrics = function(symbol, font) {
|
|||
/**
|
||||
* Builds a symbol in the given font size (note size is an integer)
|
||||
*/
|
||||
var mathrmSize = function(value, size, mode, options) {
|
||||
const mathrmSize = function(value, size, mode, options) {
|
||||
return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
|
||||
mode, options);
|
||||
};
|
||||
|
@ -56,13 +56,13 @@ var mathrmSize = function(value, size, mode, options) {
|
|||
* Puts a delimiter span in a given style, and adds appropriate height, depth,
|
||||
* and maxFontSizes.
|
||||
*/
|
||||
var styleWrap = function(delim, toStyle, options, classes) {
|
||||
const styleWrap = function(delim, toStyle, options, classes) {
|
||||
classes = classes || [];
|
||||
var span = makeSpan(
|
||||
const span = makeSpan(
|
||||
classes.concat(["style-wrap", options.style.reset(), toStyle.cls()]),
|
||||
[delim], options);
|
||||
|
||||
var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
|
||||
const multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
|
||||
|
||||
span.height *= multiplier;
|
||||
span.depth *= multiplier;
|
||||
|
@ -76,13 +76,13 @@ var styleWrap = function(delim, toStyle, options, classes) {
|
|||
* font, but is restyled to either be in textstyle, scriptstyle, or
|
||||
* scriptscriptstyle.
|
||||
*/
|
||||
var makeSmallDelim = function(delim, style, center, options, mode, classes) {
|
||||
var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
|
||||
const makeSmallDelim = function(delim, style, center, options, mode, classes) {
|
||||
const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
|
||||
|
||||
var span = styleWrap(text, style, options, classes);
|
||||
const span = styleWrap(text, style, options, classes);
|
||||
|
||||
if (center) {
|
||||
var shift =
|
||||
const shift =
|
||||
(1 - options.style.sizeMultiplier / style.sizeMultiplier) *
|
||||
options.style.metrics.axisHeight;
|
||||
|
||||
|
@ -98,15 +98,15 @@ var makeSmallDelim = function(delim, style, center, options, mode, classes) {
|
|||
* Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
|
||||
* Size3, or Size4 fonts. It is always rendered in textstyle.
|
||||
*/
|
||||
var makeLargeDelim = function(delim, size, center, options, mode, classes) {
|
||||
var inner = mathrmSize(delim, size, mode, options);
|
||||
const makeLargeDelim = function(delim, size, center, options, mode, classes) {
|
||||
const inner = mathrmSize(delim, size, mode, options);
|
||||
|
||||
var span = styleWrap(
|
||||
const span = styleWrap(
|
||||
makeSpan(["delimsizing", "size" + size], [inner], options),
|
||||
Style.TEXT, options, classes);
|
||||
|
||||
if (center) {
|
||||
var shift = (1 - options.style.sizeMultiplier) *
|
||||
const shift = (1 - options.style.sizeMultiplier) *
|
||||
options.style.metrics.axisHeight;
|
||||
|
||||
span.style.top = shift + "em";
|
||||
|
@ -121,8 +121,8 @@ var makeLargeDelim = function(delim, size, center, options, mode, classes) {
|
|||
* Make an inner span with the given offset and in the given font. This is used
|
||||
* in `makeStackedDelim` to make the stacking pieces for the delimiter.
|
||||
*/
|
||||
var makeInner = function(symbol, font, mode) {
|
||||
var sizeClass;
|
||||
const makeInner = function(symbol, font, mode) {
|
||||
let sizeClass;
|
||||
// Apply the correct CSS class to choose the right font.
|
||||
if (font === "Size1-Regular") {
|
||||
sizeClass = "delim-size1";
|
||||
|
@ -130,7 +130,7 @@ var makeInner = function(symbol, font, mode) {
|
|||
sizeClass = "delim-size4";
|
||||
}
|
||||
|
||||
var inner = makeSpan(
|
||||
const inner = makeSpan(
|
||||
["delimsizinginner", sizeClass],
|
||||
[makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]);
|
||||
|
||||
|
@ -143,18 +143,18 @@ var makeInner = function(symbol, font, mode) {
|
|||
* Make a stacked delimiter out of a given delimiter, with the total height at
|
||||
* least `heightTotal`. This routine is mentioned on page 442 of the TeXbook.
|
||||
*/
|
||||
var makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
||||
const makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
||||
classes) {
|
||||
// There are four parts, the top, an optional middle, a repeated part, and a
|
||||
// bottom.
|
||||
var top;
|
||||
var middle;
|
||||
var repeat;
|
||||
var bottom;
|
||||
let top;
|
||||
let middle;
|
||||
let repeat;
|
||||
let bottom;
|
||||
top = repeat = bottom = delim;
|
||||
middle = null;
|
||||
// Also keep track of what font the delimiters are in
|
||||
var font = "Size1-Regular";
|
||||
let font = "Size1-Regular";
|
||||
|
||||
// We set the parts and font based on the symbol. Note that we use
|
||||
// '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
|
||||
|
@ -251,65 +251,64 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
|||
}
|
||||
|
||||
// Get the metrics of the four sections
|
||||
var topMetrics = getMetrics(top, font);
|
||||
var topHeightTotal = topMetrics.height + topMetrics.depth;
|
||||
var repeatMetrics = getMetrics(repeat, font);
|
||||
var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
|
||||
var bottomMetrics = getMetrics(bottom, font);
|
||||
var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
|
||||
var middleHeightTotal = 0;
|
||||
var middleFactor = 1;
|
||||
const topMetrics = getMetrics(top, font);
|
||||
const topHeightTotal = topMetrics.height + topMetrics.depth;
|
||||
const repeatMetrics = getMetrics(repeat, font);
|
||||
const repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
|
||||
const bottomMetrics = getMetrics(bottom, font);
|
||||
const bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
|
||||
let middleHeightTotal = 0;
|
||||
let middleFactor = 1;
|
||||
if (middle !== null) {
|
||||
var middleMetrics = getMetrics(middle, font);
|
||||
const middleMetrics = getMetrics(middle, font);
|
||||
middleHeightTotal = middleMetrics.height + middleMetrics.depth;
|
||||
middleFactor = 2; // repeat symmetrically above and below middle
|
||||
}
|
||||
|
||||
// Calcuate the minimal height that the delimiter can have.
|
||||
// It is at least the size of the top, bottom, and optional middle combined.
|
||||
var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
|
||||
const minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
|
||||
|
||||
// Compute the number of copies of the repeat symbol we will need
|
||||
var repeatCount = Math.ceil(
|
||||
const repeatCount = Math.ceil(
|
||||
(heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
|
||||
|
||||
// Compute the total height of the delimiter including all the symbols
|
||||
var realHeightTotal =
|
||||
const realHeightTotal =
|
||||
minHeight + repeatCount * middleFactor * repeatHeightTotal;
|
||||
|
||||
// The center of the delimiter is placed at the center of the axis. Note
|
||||
// that in this context, "center" means that the delimiter should be
|
||||
// centered around the axis in the current style, while normally it is
|
||||
// centered around the axis in textstyle.
|
||||
var axisHeight = options.style.metrics.axisHeight;
|
||||
let axisHeight = options.style.metrics.axisHeight;
|
||||
if (center) {
|
||||
axisHeight *= options.style.sizeMultiplier;
|
||||
}
|
||||
// Calculate the depth
|
||||
var depth = realHeightTotal / 2 - axisHeight;
|
||||
const depth = realHeightTotal / 2 - axisHeight;
|
||||
|
||||
// Now, we start building the pieces that will go into the vlist
|
||||
|
||||
// Keep a list of the inner pieces
|
||||
var inners = [];
|
||||
const inners = [];
|
||||
|
||||
// Add the bottom symbol
|
||||
inners.push(makeInner(bottom, font, mode));
|
||||
|
||||
var i;
|
||||
if (middle === null) {
|
||||
// Add that many symbols
|
||||
for (i = 0; i < repeatCount; i++) {
|
||||
for (let i = 0; i < repeatCount; i++) {
|
||||
inners.push(makeInner(repeat, font, mode));
|
||||
}
|
||||
} else {
|
||||
// When there is a middle bit, we need the middle part and two repeated
|
||||
// sections
|
||||
for (i = 0; i < repeatCount; i++) {
|
||||
for (let i = 0; i < repeatCount; i++) {
|
||||
inners.push(makeInner(repeat, font, mode));
|
||||
}
|
||||
inners.push(makeInner(middle, font, mode));
|
||||
for (i = 0; i < repeatCount; i++) {
|
||||
for (let i = 0; i < repeatCount; i++) {
|
||||
inners.push(makeInner(repeat, font, mode));
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +317,7 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
|||
inners.push(makeInner(top, font, mode));
|
||||
|
||||
// Finally, build the vlist
|
||||
var inner = buildCommon.makeVList(inners, "bottom", depth, options);
|
||||
const inner = buildCommon.makeVList(inners, "bottom", depth, options);
|
||||
|
||||
return styleWrap(
|
||||
makeSpan(["delimsizing", "mult"], [inner], options),
|
||||
|
@ -327,7 +326,7 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
|||
|
||||
// There are three kinds of delimiters, delimiters that stack when they become
|
||||
// too large
|
||||
var stackLargeDelimiters = [
|
||||
const stackLargeDelimiters = [
|
||||
"(", ")", "[", "\\lbrack", "]", "\\rbrack",
|
||||
"\\{", "\\lbrace", "\\}", "\\rbrace",
|
||||
"\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
|
||||
|
@ -335,7 +334,7 @@ var stackLargeDelimiters = [
|
|||
];
|
||||
|
||||
// delimiters that always stack
|
||||
var stackAlwaysDelimiters = [
|
||||
const stackAlwaysDelimiters = [
|
||||
"\\uparrow", "\\downarrow", "\\updownarrow",
|
||||
"\\Uparrow", "\\Downarrow", "\\Updownarrow",
|
||||
"|", "\\|", "\\vert", "\\Vert",
|
||||
|
@ -344,19 +343,19 @@ var stackAlwaysDelimiters = [
|
|||
];
|
||||
|
||||
// and delimiters that never stack
|
||||
var stackNeverDelimiters = [
|
||||
const stackNeverDelimiters = [
|
||||
"<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt",
|
||||
];
|
||||
|
||||
// Metrics of the different sizes. Found by looking at TeX's output of
|
||||
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
||||
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|
||||
var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
||||
const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
||||
|
||||
/**
|
||||
* Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4.
|
||||
*/
|
||||
var makeSizedDelim = function(delim, size, options, mode, classes) {
|
||||
const makeSizedDelim = function(delim, size, options, mode, classes) {
|
||||
// < and > turn into \langle and \rangle in delimiters
|
||||
if (delim === "<" || delim === "\\lt") {
|
||||
delim = "\\langle";
|
||||
|
@ -389,7 +388,7 @@ var makeSizedDelim = function(delim, size, options, mode, classes) {
|
|||
*/
|
||||
|
||||
// Delimiters that never stack try small delimiters and large delimiters only
|
||||
var stackNeverDelimiterSequence = [
|
||||
const stackNeverDelimiterSequence = [
|
||||
{type: "small", style: Style.SCRIPTSCRIPT},
|
||||
{type: "small", style: Style.SCRIPT},
|
||||
{type: "small", style: Style.TEXT},
|
||||
|
@ -400,7 +399,7 @@ var stackNeverDelimiterSequence = [
|
|||
];
|
||||
|
||||
// Delimiters that always stack try the small delimiters first, then stack
|
||||
var stackAlwaysDelimiterSequence = [
|
||||
const stackAlwaysDelimiterSequence = [
|
||||
{type: "small", style: Style.SCRIPTSCRIPT},
|
||||
{type: "small", style: Style.SCRIPT},
|
||||
{type: "small", style: Style.TEXT},
|
||||
|
@ -409,7 +408,7 @@ var stackAlwaysDelimiterSequence = [
|
|||
|
||||
// Delimiters that stack when large try the small and then large delimiters, and
|
||||
// stack afterwards
|
||||
var stackLargeDelimiterSequence = [
|
||||
const stackLargeDelimiterSequence = [
|
||||
{type: "small", style: Style.SCRIPTSCRIPT},
|
||||
{type: "small", style: Style.SCRIPT},
|
||||
{type: "small", style: Style.TEXT},
|
||||
|
@ -423,7 +422,7 @@ var stackLargeDelimiterSequence = [
|
|||
/**
|
||||
* Get the font used in a delimiter based on what kind of delimiter it is.
|
||||
*/
|
||||
var delimTypeToFont = function(type) {
|
||||
const delimTypeToFont = function(type) {
|
||||
if (type.type === "small") {
|
||||
return "Main-Regular";
|
||||
} else if (type.type === "large") {
|
||||
|
@ -437,20 +436,20 @@ var delimTypeToFont = function(type) {
|
|||
* Traverse a sequence of types of delimiters to decide what kind of delimiter
|
||||
* should be used to create a delimiter of the given height+depth.
|
||||
*/
|
||||
var traverseSequence = function(delim, height, sequence, options) {
|
||||
const traverseSequence = function(delim, height, sequence, options) {
|
||||
// Here, we choose the index we should start at in the sequences. In smaller
|
||||
// sizes (which correspond to larger numbers in style.size) we start earlier
|
||||
// in the sequence. Thus, scriptscript starts at index 3-3=0, script starts
|
||||
// at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2
|
||||
var start = Math.min(2, 3 - options.style.size);
|
||||
for (var i = start; i < sequence.length; i++) {
|
||||
const start = Math.min(2, 3 - options.style.size);
|
||||
for (let i = start; i < sequence.length; i++) {
|
||||
if (sequence[i].type === "stack") {
|
||||
// This is always the last delimiter, so we just break the loop now.
|
||||
break;
|
||||
}
|
||||
|
||||
var metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
|
||||
var heightDepth = metrics.height + metrics.depth;
|
||||
const metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
|
||||
let heightDepth = metrics.height + metrics.depth;
|
||||
|
||||
// Small delimiters are scaled down versions of the same font, so we
|
||||
// account for the style change size.
|
||||
|
@ -473,7 +472,7 @@ var traverseSequence = function(delim, height, sequence, options) {
|
|||
* Make a delimiter of a given height+depth, with optional centering. Here, we
|
||||
* traverse the sequences, and create a delimiter that the sequence tells us to.
|
||||
*/
|
||||
var makeCustomSizedDelim = function(delim, height, center, options, mode,
|
||||
const makeCustomSizedDelim = function(delim, height, center, options, mode,
|
||||
classes) {
|
||||
if (delim === "<" || delim === "\\lt") {
|
||||
delim = "\\langle";
|
||||
|
@ -482,7 +481,7 @@ var makeCustomSizedDelim = function(delim, height, center, options, mode,
|
|||
}
|
||||
|
||||
// Decide what sequence to use
|
||||
var sequence;
|
||||
let sequence;
|
||||
if (utils.contains(stackNeverDelimiters, delim)) {
|
||||
sequence = stackNeverDelimiterSequence;
|
||||
} else if (utils.contains(stackLargeDelimiters, delim)) {
|
||||
|
@ -492,7 +491,7 @@ var makeCustomSizedDelim = function(delim, height, center, options, mode,
|
|||
}
|
||||
|
||||
// Look through the sequence
|
||||
var delimType = traverseSequence(delim, height, sequence, options);
|
||||
const delimType = traverseSequence(delim, height, sequence, options);
|
||||
|
||||
// Depending on the sequence element we decided on, call the appropriate
|
||||
// function.
|
||||
|
@ -511,20 +510,20 @@ var makeCustomSizedDelim = function(delim, height, center, options, mode,
|
|||
* Make a delimiter for use with `\left` and `\right`, given a height and depth
|
||||
* of an expression that the delimiters surround.
|
||||
*/
|
||||
var makeLeftRightDelim = function(delim, height, depth, options, mode,
|
||||
const makeLeftRightDelim = function(delim, height, depth, options, mode,
|
||||
classes) {
|
||||
// We always center \left/\right delimiters, so the axis is always shifted
|
||||
var axisHeight =
|
||||
const axisHeight =
|
||||
options.style.metrics.axisHeight * options.style.sizeMultiplier;
|
||||
|
||||
// Taken from TeX source, tex.web, function make_left_right
|
||||
var delimiterFactor = 901;
|
||||
var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
|
||||
const delimiterFactor = 901;
|
||||
const delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
|
||||
|
||||
var maxDistFromAxis = Math.max(
|
||||
const maxDistFromAxis = Math.max(
|
||||
height - axisHeight, depth + axisHeight);
|
||||
|
||||
var totalHeight = Math.max(
|
||||
const totalHeight = Math.max(
|
||||
// In real TeX, calculations are done using integral values which are
|
||||
// 65536 per pt, or 655360 per em. So, the division here truncates in
|
||||
// TeX but doesn't here, producing different results. If we wanted to
|
||||
|
|
|
@ -7,16 +7,16 @@
|
|||
*
|
||||
* Similar functions for working with MathML nodes exist in mathMLTree.js.
|
||||
*/
|
||||
var unicodeRegexes = require("./unicodeRegexes");
|
||||
var utils = require("./utils");
|
||||
const unicodeRegexes = require("./unicodeRegexes");
|
||||
const utils = require("./utils");
|
||||
|
||||
/**
|
||||
* Create an HTML className based on a list of classes. In addition to joining
|
||||
* with spaces, we also remove null or empty classes.
|
||||
*/
|
||||
var createClass = function(classes) {
|
||||
const createClass = function(classes) {
|
||||
classes = classes.slice();
|
||||
for (var i = classes.length - 1; i >= 0; i--) {
|
||||
for (let i = classes.length - 1; i >= 0; i--) {
|
||||
if (!classes[i]) {
|
||||
classes.splice(i, 1);
|
||||
}
|
||||
|
@ -65,27 +65,27 @@ span.prototype.tryCombine = function(sibling) {
|
|||
* Convert the span into an HTML node
|
||||
*/
|
||||
span.prototype.toNode = function() {
|
||||
var span = document.createElement("span");
|
||||
const span = document.createElement("span");
|
||||
|
||||
// Apply the class
|
||||
span.className = createClass(this.classes);
|
||||
|
||||
// Apply inline styles
|
||||
for (var style in this.style) {
|
||||
for (const style in this.style) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.style, style)) {
|
||||
span.style[style] = this.style[style];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply attributes
|
||||
for (var attr in this.attributes) {
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
span.setAttribute(attr, this.attributes[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
// Append the children, also as HTML nodes
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
span.appendChild(this.children[i].toNode());
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ span.prototype.toNode = function() {
|
|||
* Convert the span into an HTML markup string
|
||||
*/
|
||||
span.prototype.toMarkup = function() {
|
||||
var markup = "<span";
|
||||
let markup = "<span";
|
||||
|
||||
// Add the class
|
||||
if (this.classes.length) {
|
||||
|
@ -105,10 +105,10 @@ span.prototype.toMarkup = function() {
|
|||
markup += "\"";
|
||||
}
|
||||
|
||||
var styles = "";
|
||||
let styles = "";
|
||||
|
||||
// Add the styles, after hyphenation
|
||||
for (var style in this.style) {
|
||||
for (const style in this.style) {
|
||||
if (this.style.hasOwnProperty(style)) {
|
||||
styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ span.prototype.toMarkup = function() {
|
|||
}
|
||||
|
||||
// Add the attributes
|
||||
for (var attr in this.attributes) {
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
markup += " " + attr + "=\"";
|
||||
markup += utils.escape(this.attributes[attr]);
|
||||
|
@ -130,7 +130,7 @@ span.prototype.toMarkup = function() {
|
|||
markup += ">";
|
||||
|
||||
// Add the markup of the children, also as markup
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
markup += this.children[i].toMarkup();
|
||||
}
|
||||
|
||||
|
@ -157,10 +157,10 @@ function documentFragment(children) {
|
|||
*/
|
||||
documentFragment.prototype.toNode = function() {
|
||||
// Create a fragment
|
||||
var frag = document.createDocumentFragment();
|
||||
const frag = document.createDocumentFragment();
|
||||
|
||||
// Append the children
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
frag.appendChild(this.children[i].toNode());
|
||||
}
|
||||
|
||||
|
@ -171,17 +171,17 @@ documentFragment.prototype.toNode = function() {
|
|||
* Convert the fragment into HTML markup
|
||||
*/
|
||||
documentFragment.prototype.toMarkup = function() {
|
||||
var markup = "";
|
||||
let markup = "";
|
||||
|
||||
// Simply concatenate the markup for the children together
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
markup += this.children[i].toMarkup();
|
||||
}
|
||||
|
||||
return markup;
|
||||
};
|
||||
|
||||
var iCombinations = {
|
||||
const iCombinations = {
|
||||
'î': '\u0131\u0302',
|
||||
'ï': '\u0131\u0308',
|
||||
'í': '\u0131\u0301',
|
||||
|
@ -233,13 +233,13 @@ symbolNode.prototype.tryCombine = function(sibling) {
|
|||
|| this.maxFontSize !== sibling.maxFontSize) {
|
||||
return false;
|
||||
}
|
||||
for (var style in this.style) {
|
||||
for (const style in this.style) {
|
||||
if (this.style.hasOwnProperty(style)
|
||||
&& this.style[style] !== sibling.style[style]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (style in sibling.style) {
|
||||
for (const style in sibling.style) {
|
||||
if (sibling.style.hasOwnProperty(style)
|
||||
&& this.style[style] !== sibling.style[style]) {
|
||||
return false;
|
||||
|
@ -257,8 +257,8 @@ symbolNode.prototype.tryCombine = function(sibling) {
|
|||
* created if it is needed.
|
||||
*/
|
||||
symbolNode.prototype.toNode = function() {
|
||||
var node = document.createTextNode(this.value);
|
||||
var span = null;
|
||||
const node = document.createTextNode(this.value);
|
||||
let span = null;
|
||||
|
||||
if (this.italic > 0) {
|
||||
span = document.createElement("span");
|
||||
|
@ -270,7 +270,7 @@ symbolNode.prototype.toNode = function() {
|
|||
span.className = createClass(this.classes);
|
||||
}
|
||||
|
||||
for (var style in this.style) {
|
||||
for (const style in this.style) {
|
||||
if (this.style.hasOwnProperty(style)) {
|
||||
span = span || document.createElement("span");
|
||||
span.style[style] = this.style[style];
|
||||
|
@ -291,9 +291,9 @@ symbolNode.prototype.toNode = function() {
|
|||
symbolNode.prototype.toMarkup = function() {
|
||||
// TODO(alpert): More duplication than I'd like from
|
||||
// span.prototype.toMarkup and symbolNode.prototype.toNode...
|
||||
var needsSpan = false;
|
||||
let needsSpan = false;
|
||||
|
||||
var markup = "<span";
|
||||
let markup = "<span";
|
||||
|
||||
if (this.classes.length) {
|
||||
needsSpan = true;
|
||||
|
@ -302,12 +302,12 @@ symbolNode.prototype.toMarkup = function() {
|
|||
markup += "\"";
|
||||
}
|
||||
|
||||
var styles = "";
|
||||
let styles = "";
|
||||
|
||||
if (this.italic > 0) {
|
||||
styles += "margin-right:" + this.italic + "em;";
|
||||
}
|
||||
for (var style in this.style) {
|
||||
for (const style in this.style) {
|
||||
if (this.style.hasOwnProperty(style)) {
|
||||
styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ symbolNode.prototype.toMarkup = function() {
|
|||
markup += " style=\"" + utils.escape(styles) + "\"";
|
||||
}
|
||||
|
||||
var escaped = utils.escape(this.value);
|
||||
const escaped = utils.escape(this.value);
|
||||
if (needsSpan) {
|
||||
markup += ">";
|
||||
markup += escaped;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* eslint no-constant-condition:0 */
|
||||
var parseData = require("./parseData");
|
||||
var ParseError = require("./ParseError");
|
||||
var Style = require("./Style");
|
||||
const parseData = require("./parseData");
|
||||
const ParseError = require("./ParseError");
|
||||
const Style = require("./Style");
|
||||
|
||||
var ParseNode = parseData.ParseNode;
|
||||
const ParseNode = parseData.ParseNode;
|
||||
|
||||
/**
|
||||
* Parse the body of the environment, with rows delimited by \\ and
|
||||
|
@ -11,19 +11,19 @@ var ParseNode = parseData.ParseNode;
|
|||
* with one group per cell.
|
||||
*/
|
||||
function parseArray(parser, result) {
|
||||
var row = [];
|
||||
var body = [row];
|
||||
var rowGaps = [];
|
||||
let row = [];
|
||||
const body = [row];
|
||||
const rowGaps = [];
|
||||
while (true) {
|
||||
var cell = parser.parseExpression(false, null);
|
||||
const cell = parser.parseExpression(false, null);
|
||||
row.push(new ParseNode("ordgroup", cell, parser.mode));
|
||||
var next = parser.nextToken.text;
|
||||
const next = parser.nextToken.text;
|
||||
if (next === "&") {
|
||||
parser.consume();
|
||||
} else if (next === "\\end") {
|
||||
break;
|
||||
} else if (next === "\\\\" || next === "\\cr") {
|
||||
var cr = parser.parseFunction();
|
||||
const cr = parser.parseFunction();
|
||||
rowGaps.push(cr.value.size);
|
||||
row = [];
|
||||
body.push(row);
|
||||
|
@ -69,7 +69,7 @@ function defineEnvironment(names, props, handler) {
|
|||
props = { numArgs: props };
|
||||
}
|
||||
// Set default values of environments
|
||||
var data = {
|
||||
const data = {
|
||||
numArgs: props.numArgs || 0,
|
||||
argTypes: props.argTypes,
|
||||
greediness: 1,
|
||||
|
@ -77,7 +77,7 @@ function defineEnvironment(names, props, handler) {
|
|||
numOptionalArgs: props.numOptionalArgs || 0,
|
||||
handler: handler,
|
||||
};
|
||||
for (var i = 0; i < names.length; ++i) {
|
||||
for (let i = 0; i < names.length; ++i) {
|
||||
module.exports[names[i]] = data;
|
||||
}
|
||||
}
|
||||
|
@ -87,10 +87,10 @@ function defineEnvironment(names, props, handler) {
|
|||
defineEnvironment("array", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var colalign = args[0];
|
||||
let colalign = args[0];
|
||||
colalign = colalign.value.map ? colalign.value : [colalign];
|
||||
var cols = colalign.map(function(node) {
|
||||
var ca = node.value;
|
||||
const cols = colalign.map(function(node) {
|
||||
const ca = node.value;
|
||||
if ("lcr".indexOf(ca) !== -1) {
|
||||
return {
|
||||
type: "align",
|
||||
|
@ -106,7 +106,7 @@ defineEnvironment("array", {
|
|||
"Unknown column alignment: " + node.value,
|
||||
node);
|
||||
});
|
||||
var res = {
|
||||
let res = {
|
||||
type: "array",
|
||||
cols: cols,
|
||||
hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
|
||||
|
@ -126,7 +126,7 @@ defineEnvironment([
|
|||
"Vmatrix",
|
||||
], {
|
||||
}, function(context) {
|
||||
var delimiters = {
|
||||
const delimiters = {
|
||||
"matrix": null,
|
||||
"pmatrix": ["(", ")"],
|
||||
"bmatrix": ["[", "]"],
|
||||
|
@ -134,7 +134,7 @@ defineEnvironment([
|
|||
"vmatrix": ["|", "|"],
|
||||
"Vmatrix": ["\\Vert", "\\Vert"],
|
||||
}[context.envName];
|
||||
var res = {
|
||||
let res = {
|
||||
type: "array",
|
||||
hskipBeforeAndAfter: false, // \hskip -\arraycolsep in amsmath
|
||||
};
|
||||
|
@ -154,7 +154,7 @@ defineEnvironment([
|
|||
// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
|
||||
defineEnvironment("cases", {
|
||||
}, function(context) {
|
||||
var res = {
|
||||
let res = {
|
||||
type: "array",
|
||||
arraystretch: 1.2,
|
||||
cols: [{
|
||||
|
@ -188,25 +188,24 @@ defineEnvironment("cases", {
|
|||
// so that \strut@ is the same as \strut.
|
||||
defineEnvironment("aligned", {
|
||||
}, function(context) {
|
||||
var res = {
|
||||
let res = {
|
||||
type: "array",
|
||||
cols: [],
|
||||
};
|
||||
res = parseArray(context.parser, res);
|
||||
var emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
||||
var numCols = 0;
|
||||
const emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
||||
let numCols = 0;
|
||||
res.value.body.forEach(function(row) {
|
||||
var i;
|
||||
for (i = 1; i < row.length; i += 2) {
|
||||
for (let i = 1; i < row.length; i += 2) {
|
||||
row[i].value.unshift(emptyGroup);
|
||||
}
|
||||
if (numCols < row.length) {
|
||||
numCols = row.length;
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < numCols; ++i) {
|
||||
var align = "r";
|
||||
var pregap = 0;
|
||||
for (let i = 0; i < numCols; ++i) {
|
||||
let align = "r";
|
||||
let pregap = 0;
|
||||
if (i % 2 === 1) {
|
||||
align = "l";
|
||||
} else if (i > 0) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint no-unused-vars:0 */
|
||||
|
||||
var Style = require("./Style");
|
||||
var cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
const Style = require("./Style");
|
||||
const cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
|
||||
/**
|
||||
* This file contains metrics regarding fonts and individual symbols. The sigma
|
||||
|
@ -32,7 +32,7 @@ var cjkRegex = require("./unicodeRegexes").cjkRegex;
|
|||
//
|
||||
// The output of each of these commands is quite lengthy. The only part we
|
||||
// care about is the FONTDIMEN section. Each value is measured in EMs.
|
||||
var sigmas = {
|
||||
const sigmas = {
|
||||
slant: [0.250, 0.250, 0.250], // sigma1
|
||||
space: [0.000, 0.000, 0.000], // sigma2
|
||||
stretch: [0.000, 0.000, 0.000], // sigma3
|
||||
|
@ -62,34 +62,34 @@ var sigmas = {
|
|||
// \showthe\fontdimenX\a
|
||||
// where X is the corresponding variable number. These correspond to the font
|
||||
// parameters of the extension fonts (family 3). See the TeXbook, page 441.
|
||||
var xi1 = 0;
|
||||
var xi2 = 0;
|
||||
var xi3 = 0;
|
||||
var xi4 = 0;
|
||||
var xi5 = 0.431;
|
||||
var xi6 = 1;
|
||||
var xi7 = 0;
|
||||
var xi8 = 0.04;
|
||||
var xi9 = 0.111;
|
||||
var xi10 = 0.166;
|
||||
var xi11 = 0.2;
|
||||
var xi12 = 0.6;
|
||||
var xi13 = 0.1;
|
||||
const xi1 = 0;
|
||||
const xi2 = 0;
|
||||
const xi3 = 0;
|
||||
const xi4 = 0;
|
||||
const xi5 = 0.431;
|
||||
const xi6 = 1;
|
||||
const xi7 = 0;
|
||||
const xi8 = 0.04;
|
||||
const xi9 = 0.111;
|
||||
const xi10 = 0.166;
|
||||
const xi11 = 0.2;
|
||||
const xi12 = 0.6;
|
||||
const xi13 = 0.1;
|
||||
|
||||
// This value determines how large a pt is, for metrics which are defined in
|
||||
// terms of pts.
|
||||
// This value is also used in katex.less; if you change it make sure the values
|
||||
// match.
|
||||
var ptPerEm = 10.0;
|
||||
const ptPerEm = 10.0;
|
||||
|
||||
// The space between adjacent `|` columns in an array definition. From
|
||||
// `\showthe\doublerulesep` in LaTeX.
|
||||
var doubleRuleSep = 2.0 / ptPerEm;
|
||||
const doubleRuleSep = 2.0 / ptPerEm;
|
||||
|
||||
/**
|
||||
* This is just a mapping from common names to real metrics
|
||||
*/
|
||||
var metrics = {
|
||||
const metrics = {
|
||||
defaultRuleThickness: xi8,
|
||||
bigOpSpacing1: xi9,
|
||||
bigOpSpacing2: xi10,
|
||||
|
@ -104,7 +104,7 @@ var metrics = {
|
|||
// metrics, including height, depth, italic correction, and skew (kern from the
|
||||
// character to the corresponding \skewchar)
|
||||
// This map is generated via `make metrics`. It should not be changed manually.
|
||||
var metricMap = require("./fontMetricsData");
|
||||
const metricMap = require("./fontMetricsData");
|
||||
|
||||
// These are very rough approximations. We default to Times New Roman which
|
||||
// should have Latin-1 and Cyrillic characters, but may not depending on the
|
||||
|
@ -113,7 +113,7 @@ var metricMap = require("./fontMetricsData");
|
|||
// descenders we prefer approximations with ascenders, primarily to prevent
|
||||
// the fraction bar or root line from intersecting the glyph.
|
||||
// TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
|
||||
var extraCharacterMap = {
|
||||
const extraCharacterMap = {
|
||||
// Latin-1
|
||||
'À': 'A',
|
||||
'Á': 'A',
|
||||
|
@ -252,14 +252,14 @@ var extraCharacterMap = {
|
|||
* Note: the `width` property may be undefined if fontMetricsData.js wasn't
|
||||
* built using `Make extended_metrics`.
|
||||
*/
|
||||
var getCharacterMetrics = function(character, style) {
|
||||
var ch = character.charCodeAt(0);
|
||||
const getCharacterMetrics = function(character, style) {
|
||||
let ch = character.charCodeAt(0);
|
||||
if (character[0] in extraCharacterMap) {
|
||||
ch = extraCharacterMap[character[0]].charCodeAt(0);
|
||||
} else if (cjkRegex.test(character[0])) {
|
||||
ch = 'M'.charCodeAt(0);
|
||||
}
|
||||
var metrics = metricMap[style][ch];
|
||||
const metrics = metricMap[style][ch];
|
||||
if (metrics) {
|
||||
return {
|
||||
depth: metrics[0],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
var utils = require("./utils");
|
||||
var ParseError = require("./ParseError");
|
||||
var parseData = require("./parseData");
|
||||
var ParseNode = parseData.ParseNode;
|
||||
const utils = require("./utils");
|
||||
const ParseError = require("./ParseError");
|
||||
const parseData = require("./parseData");
|
||||
const ParseNode = parseData.ParseNode;
|
||||
|
||||
/* This file contains a list of functions that we parse, identified by
|
||||
* the calls to defineFunction.
|
||||
|
@ -88,7 +88,7 @@ function defineFunction(names, props, handler) {
|
|||
props = { numArgs: props };
|
||||
}
|
||||
// Set default values of functions
|
||||
var data = {
|
||||
const data = {
|
||||
numArgs: props.numArgs,
|
||||
argTypes: props.argTypes,
|
||||
greediness: (props.greediness === undefined) ? 1 : props.greediness,
|
||||
|
@ -97,14 +97,14 @@ function defineFunction(names, props, handler) {
|
|||
infix: !!props.infix,
|
||||
handler: handler,
|
||||
};
|
||||
for (var i = 0; i < names.length; ++i) {
|
||||
for (let i = 0; i < names.length; ++i) {
|
||||
module.exports[names[i]] = data;
|
||||
}
|
||||
}
|
||||
|
||||
// Since the corresponding buildHTML/buildMathML function expects a
|
||||
// list of elements, we normalize for different kinds of arguments
|
||||
var ordargument = function(arg) {
|
||||
const ordargument = function(arg) {
|
||||
if (arg.type === "ordgroup") {
|
||||
return arg.value;
|
||||
} else {
|
||||
|
@ -117,8 +117,8 @@ defineFunction("\\sqrt", {
|
|||
numArgs: 1,
|
||||
numOptionalArgs: 1,
|
||||
}, function(context, args) {
|
||||
var index = args[0];
|
||||
var body = args[1];
|
||||
const index = args[0];
|
||||
const body = args[1];
|
||||
return {
|
||||
type: "sqrt",
|
||||
body: body,
|
||||
|
@ -127,7 +127,7 @@ defineFunction("\\sqrt", {
|
|||
});
|
||||
|
||||
// Non-mathy text, possibly in a font
|
||||
var textFunctionStyles = {
|
||||
const textFunctionStyles = {
|
||||
"\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
|
||||
"\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
|
||||
"\\textit": "textit",
|
||||
|
@ -142,7 +142,7 @@ defineFunction([
|
|||
greediness: 2,
|
||||
allowedInText: true,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "text",
|
||||
body: ordargument(body),
|
||||
|
@ -157,8 +157,8 @@ defineFunction("\\color", {
|
|||
greediness: 3,
|
||||
argTypes: ["color", "original"],
|
||||
}, function(context, args) {
|
||||
var color = args[0];
|
||||
var body = args[1];
|
||||
const color = args[0];
|
||||
const body = args[1];
|
||||
return {
|
||||
type: "color",
|
||||
color: color.value,
|
||||
|
@ -170,7 +170,7 @@ defineFunction("\\color", {
|
|||
defineFunction("\\overline", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "overline",
|
||||
body: body,
|
||||
|
@ -181,7 +181,7 @@ defineFunction("\\overline", {
|
|||
defineFunction("\\underline", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "underline",
|
||||
body: body,
|
||||
|
@ -194,9 +194,9 @@ defineFunction("\\rule", {
|
|||
numOptionalArgs: 1,
|
||||
argTypes: ["size", "size", "size"],
|
||||
}, function(context, args) {
|
||||
var shift = args[0];
|
||||
var width = args[1];
|
||||
var height = args[2];
|
||||
const shift = args[0];
|
||||
const width = args[1];
|
||||
const height = args[2];
|
||||
return {
|
||||
type: "rule",
|
||||
shift: shift && shift.value,
|
||||
|
@ -229,7 +229,7 @@ defineFunction("\\KaTeX", {
|
|||
defineFunction("\\phantom", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "phantom",
|
||||
value: ordargument(body),
|
||||
|
@ -243,7 +243,7 @@ defineFunction([
|
|||
], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "mclass",
|
||||
mclass: "m" + context.funcName.substr(5),
|
||||
|
@ -255,10 +255,10 @@ defineFunction([
|
|||
defineFunction("\\stackrel", {
|
||||
numArgs: 2,
|
||||
}, function(context, args) {
|
||||
var top = args[0];
|
||||
var bottom = args[1];
|
||||
const top = args[0];
|
||||
const bottom = args[1];
|
||||
|
||||
var bottomop = new ParseNode("op", {
|
||||
const bottomop = new ParseNode("op", {
|
||||
type: "op",
|
||||
limits: true,
|
||||
alwaysHandleSupSub: true,
|
||||
|
@ -266,7 +266,7 @@ defineFunction("\\stackrel", {
|
|||
value: ordargument(bottom),
|
||||
}, bottom.mode);
|
||||
|
||||
var supsub = new ParseNode("supsub", {
|
||||
const supsub = new ParseNode("supsub", {
|
||||
base: bottomop,
|
||||
sup: top,
|
||||
sub: null,
|
||||
|
@ -293,7 +293,7 @@ defineFunction("\\bmod", {
|
|||
defineFunction(["\\pod", "\\pmod", "\\mod"], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "mod",
|
||||
modType: context.funcName.substr(1),
|
||||
|
@ -302,7 +302,7 @@ defineFunction(["\\pod", "\\pmod", "\\mod"], {
|
|||
});
|
||||
|
||||
// Extra data needed for the delimiter handler down below
|
||||
var delimiterSizes = {
|
||||
const delimiterSizes = {
|
||||
"\\bigl" : {mclass: "mopen", size: 1},
|
||||
"\\Bigl" : {mclass: "mopen", size: 2},
|
||||
"\\biggl": {mclass: "mopen", size: 3},
|
||||
|
@ -321,7 +321,7 @@ var delimiterSizes = {
|
|||
"\\Bigg" : {mclass: "mord", size: 4},
|
||||
};
|
||||
|
||||
var delimiters = [
|
||||
const delimiters = [
|
||||
"(", ")", "[", "\\lbrack", "]", "\\rbrack",
|
||||
"\\{", "\\lbrace", "\\}", "\\rbrace",
|
||||
"\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
|
||||
|
@ -336,7 +336,7 @@ var delimiters = [
|
|||
".",
|
||||
];
|
||||
|
||||
var fontAliases = {
|
||||
const fontAliases = {
|
||||
"\\Bbb": "\\mathbb",
|
||||
"\\bold": "\\mathbf",
|
||||
"\\frak": "\\mathfrak",
|
||||
|
@ -362,7 +362,7 @@ defineFunction([
|
|||
allowedInText: true,
|
||||
greediness: 3,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "color",
|
||||
color: "katex-" + context.funcName.slice(1),
|
||||
|
@ -440,7 +440,7 @@ defineFunction([
|
|||
defineFunction("\\mathop", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "op",
|
||||
limits: false,
|
||||
|
@ -458,12 +458,12 @@ defineFunction([
|
|||
numArgs: 2,
|
||||
greediness: 2,
|
||||
}, function(context, args) {
|
||||
var numer = args[0];
|
||||
var denom = args[1];
|
||||
var hasBarLine;
|
||||
var leftDelim = null;
|
||||
var rightDelim = null;
|
||||
var size = "auto";
|
||||
const numer = args[0];
|
||||
const denom = args[1];
|
||||
let hasBarLine;
|
||||
let leftDelim = null;
|
||||
let rightDelim = null;
|
||||
let size = "auto";
|
||||
|
||||
switch (context.funcName) {
|
||||
case "\\dfrac":
|
||||
|
@ -512,7 +512,7 @@ defineFunction(["\\llap", "\\rlap"], {
|
|||
numArgs: 1,
|
||||
allowedInText: true,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: context.funcName.slice(1),
|
||||
body: body,
|
||||
|
@ -520,7 +520,7 @@ defineFunction(["\\llap", "\\rlap"], {
|
|||
});
|
||||
|
||||
// Delimiter functions
|
||||
var checkDelimiter = function(delim, context) {
|
||||
const checkDelimiter = function(delim, context) {
|
||||
if (utils.contains(delimiters, delim.value)) {
|
||||
return delim;
|
||||
} else {
|
||||
|
@ -538,7 +538,7 @@ defineFunction([
|
|||
], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var delim = checkDelimiter(args[0], context);
|
||||
const delim = checkDelimiter(args[0], context);
|
||||
|
||||
return {
|
||||
type: "delimsizing",
|
||||
|
@ -553,7 +553,7 @@ defineFunction([
|
|||
], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var delim = checkDelimiter(args[0], context);
|
||||
const delim = checkDelimiter(args[0], context);
|
||||
|
||||
// \left and \right are caught somewhere in Parser.js, which is
|
||||
// why this data doesn't match what is in buildHTML.
|
||||
|
@ -566,7 +566,7 @@ defineFunction([
|
|||
defineFunction("\\middle", {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var delim = checkDelimiter(args[0], context);
|
||||
const delim = checkDelimiter(args[0], context);
|
||||
if (!context.parser.leftrightDepth) {
|
||||
throw new ParseError("\\middle without preceding \\left", delim);
|
||||
}
|
||||
|
@ -604,8 +604,8 @@ defineFunction([
|
|||
numArgs: 1,
|
||||
greediness: 2,
|
||||
}, function(context, args) {
|
||||
var body = args[0];
|
||||
var func = context.funcName;
|
||||
const body = args[0];
|
||||
let func = context.funcName;
|
||||
if (func in fontAliases) {
|
||||
func = fontAliases[func];
|
||||
}
|
||||
|
@ -625,7 +625,7 @@ defineFunction([
|
|||
], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
var base = args[0];
|
||||
const base = args[0];
|
||||
return {
|
||||
type: "accent",
|
||||
accent: context.funcName,
|
||||
|
@ -638,7 +638,7 @@ defineFunction(["\\over", "\\choose", "\\atop"], {
|
|||
numArgs: 0,
|
||||
infix: true,
|
||||
}, function(context) {
|
||||
var replaceWith;
|
||||
let replaceWith;
|
||||
switch (context.funcName) {
|
||||
case "\\over":
|
||||
replaceWith = "\\frac";
|
||||
|
@ -665,7 +665,7 @@ defineFunction(["\\\\", "\\cr"], {
|
|||
numOptionalArgs: 1,
|
||||
argTypes: ["size"],
|
||||
}, function(context, args) {
|
||||
var size = args[0];
|
||||
const size = args[0];
|
||||
return {
|
||||
type: "cr",
|
||||
size: size,
|
||||
|
@ -677,12 +677,12 @@ defineFunction(["\\begin", "\\end"], {
|
|||
numArgs: 1,
|
||||
argTypes: ["text"],
|
||||
}, function(context, args) {
|
||||
var nameGroup = args[0];
|
||||
const nameGroup = args[0];
|
||||
if (nameGroup.type !== "ordgroup") {
|
||||
throw new ParseError("Invalid environment name", nameGroup);
|
||||
}
|
||||
var name = "";
|
||||
for (var i = 0; i < nameGroup.value.length; ++i) {
|
||||
let name = "";
|
||||
for (let i = 0; i < nameGroup.value.length; ++i) {
|
||||
name += nameGroup.value[i].value;
|
||||
}
|
||||
return {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
|
||||
*/
|
||||
|
||||
var utils = require("./utils");
|
||||
const utils = require("./utils");
|
||||
|
||||
/**
|
||||
* This node represents a general purpose MathML node of any type. The
|
||||
|
@ -33,16 +33,16 @@ MathNode.prototype.setAttribute = function(name, value) {
|
|||
* Converts the math node into a MathML-namespaced DOM element.
|
||||
*/
|
||||
MathNode.prototype.toNode = function() {
|
||||
var node = document.createElementNS(
|
||||
const node = document.createElementNS(
|
||||
"http://www.w3.org/1998/Math/MathML", this.type);
|
||||
|
||||
for (var attr in this.attributes) {
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
node.setAttribute(attr, this.attributes[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
node.appendChild(this.children[i].toNode());
|
||||
}
|
||||
|
||||
|
@ -53,10 +53,10 @@ MathNode.prototype.toNode = function() {
|
|||
* Converts the math node into an HTML markup string.
|
||||
*/
|
||||
MathNode.prototype.toMarkup = function() {
|
||||
var markup = "<" + this.type;
|
||||
let markup = "<" + this.type;
|
||||
|
||||
// Add the attributes
|
||||
for (var attr in this.attributes) {
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
markup += " " + attr + "=\"";
|
||||
markup += utils.escape(this.attributes[attr]);
|
||||
|
@ -66,7 +66,7 @@ MathNode.prototype.toMarkup = function() {
|
|||
|
||||
markup += ">";
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
markup += this.children[i].toMarkup();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* TODO(emily): Remove this
|
||||
*/
|
||||
|
||||
var Parser = require("./Parser");
|
||||
const Parser = require("./Parser");
|
||||
|
||||
/**
|
||||
* Parses an expression using a Parser, then returns the parsed result.
|
||||
*/
|
||||
var parseTree = function(toParse, settings) {
|
||||
const parseTree = function(toParse, settings) {
|
||||
if (!(typeof toParse === 'string' || toParse instanceof String)) {
|
||||
throw new TypeError('KaTeX can only parse string typed expression');
|
||||
}
|
||||
var parser = new Parser(toParse, settings);
|
||||
const parser = new Parser(toParse, settings);
|
||||
|
||||
return parser.parse();
|
||||
};
|
||||
|
|
|
@ -33,25 +33,25 @@ function defineSymbol(mode, font, group, replace, name) {
|
|||
// This helps minify the code, and also spotting typos using jshint.
|
||||
|
||||
// modes:
|
||||
var math = "math";
|
||||
var text = "text";
|
||||
const math = "math";
|
||||
const text = "text";
|
||||
|
||||
// fonts:
|
||||
var main = "main";
|
||||
var ams = "ams";
|
||||
const main = "main";
|
||||
const ams = "ams";
|
||||
|
||||
// groups:
|
||||
var accent = "accent";
|
||||
var bin = "bin";
|
||||
var close = "close";
|
||||
var inner = "inner";
|
||||
var mathord = "mathord";
|
||||
var op = "op";
|
||||
var open = "open";
|
||||
var punct = "punct";
|
||||
var rel = "rel";
|
||||
var spacing = "spacing";
|
||||
var textord = "textord";
|
||||
const accent = "accent";
|
||||
const bin = "bin";
|
||||
const close = "close";
|
||||
const inner = "inner";
|
||||
const mathord = "mathord";
|
||||
const op = "op";
|
||||
const open = "open";
|
||||
const punct = "punct";
|
||||
const rel = "rel";
|
||||
const spacing = "spacing";
|
||||
const textord = "textord";
|
||||
|
||||
// Now comes the symbol table
|
||||
|
||||
|
@ -616,50 +616,48 @@ defineSymbol(text, main, spacing, "\u00a0", " ");
|
|||
defineSymbol(text, main, spacing, "\u00a0", "~");
|
||||
|
||||
// There are lots of symbols which are the same, so we add them in afterwards.
|
||||
var i;
|
||||
var ch;
|
||||
|
||||
// All of these are textords in math mode
|
||||
var mathTextSymbols = "0123456789/@.\"";
|
||||
for (i = 0; i < mathTextSymbols.length; i++) {
|
||||
ch = mathTextSymbols.charAt(i);
|
||||
const mathTextSymbols = "0123456789/@.\"";
|
||||
for (let i = 0; i < mathTextSymbols.length; i++) {
|
||||
const ch = mathTextSymbols.charAt(i);
|
||||
defineSymbol(math, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
// All of these are textords in text mode
|
||||
var textSymbols = "0123456789!@*()-=+[]\";:?/.,";
|
||||
for (i = 0; i < textSymbols.length; i++) {
|
||||
ch = textSymbols.charAt(i);
|
||||
const textSymbols = "0123456789!@*()-=+[]\";:?/.,";
|
||||
for (let i = 0; i < textSymbols.length; i++) {
|
||||
const ch = textSymbols.charAt(i);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
// All of these are textords in text mode, and mathords in math mode
|
||||
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (i = 0; i < letters.length; i++) {
|
||||
ch = letters.charAt(i);
|
||||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (let i = 0; i < letters.length; i++) {
|
||||
const ch = letters.charAt(i);
|
||||
defineSymbol(math, main, mathord, ch, ch);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
// Latin-1 letters
|
||||
for (i = 0x00C0; i <= 0x00D6; i++) {
|
||||
ch = String.fromCharCode(i);
|
||||
for (let i = 0x00C0; i <= 0x00D6; i++) {
|
||||
const ch = String.fromCharCode(i);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
for (i = 0x00D8; i <= 0x00F6; i++) {
|
||||
ch = String.fromCharCode(i);
|
||||
for (let i = 0x00D8; i <= 0x00F6; i++) {
|
||||
const ch = String.fromCharCode(i);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
for (i = 0x00F8; i <= 0x00FF; i++) {
|
||||
ch = String.fromCharCode(i);
|
||||
for (let i = 0x00F8; i <= 0x00FF; i++) {
|
||||
const ch = String.fromCharCode(i);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
// Cyrillic
|
||||
for (i = 0x0410; i <= 0x044F; i++) {
|
||||
ch = String.fromCharCode(i);
|
||||
for (let i = 0x0410; i <= 0x044F; i++) {
|
||||
const ch = String.fromCharCode(i);
|
||||
defineSymbol(text, main, textord, ch, ch);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var hangulRegex = /[\uAC00-\uD7AF]/;
|
||||
const hangulRegex = /[\uAC00-\uD7AF]/;
|
||||
|
||||
// This regex combines
|
||||
// - Hiragana: [\u3040-\u309F]
|
||||
|
@ -6,7 +6,7 @@ var hangulRegex = /[\uAC00-\uD7AF]/;
|
|||
// - CJK ideograms: [\u4E00-\u9FAF]
|
||||
// - Hangul syllables: [\uAC00-\uD7AF]
|
||||
// Notably missing are halfwidth Katakana and Romanji glyphs.
|
||||
var cjkRegex =
|
||||
const cjkRegex =
|
||||
/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/;
|
||||
|
||||
module.exports = {
|
||||
|
|
25
src/utils.js
25
src/utils.js
|
@ -7,17 +7,16 @@
|
|||
* Provide an `indexOf` function which works in IE8, but defers to native if
|
||||
* possible.
|
||||
*/
|
||||
var nativeIndexOf = Array.prototype.indexOf;
|
||||
var indexOf = function(list, elem) {
|
||||
const nativeIndexOf = Array.prototype.indexOf;
|
||||
const indexOf = function(list, elem) {
|
||||
if (list == null) {
|
||||
return -1;
|
||||
}
|
||||
if (nativeIndexOf && list.indexOf === nativeIndexOf) {
|
||||
return list.indexOf(elem);
|
||||
}
|
||||
var i = 0;
|
||||
var l = list.length;
|
||||
for (; i < l; i++) {
|
||||
const l = list.length;
|
||||
for (let i = 0; i < l; i++) {
|
||||
if (list[i] === elem) {
|
||||
return i;
|
||||
}
|
||||
|
@ -28,25 +27,25 @@ var indexOf = function(list, elem) {
|
|||
/**
|
||||
* Return whether an element is contained in a list
|
||||
*/
|
||||
var contains = function(list, elem) {
|
||||
const contains = function(list, elem) {
|
||||
return indexOf(list, elem) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide a default value if a setting is undefined
|
||||
*/
|
||||
var deflt = function(setting, defaultIfUndefined) {
|
||||
const deflt = function(setting, defaultIfUndefined) {
|
||||
return setting === undefined ? defaultIfUndefined : setting;
|
||||
};
|
||||
|
||||
// hyphenate and escape adapted from Facebook's React under Apache 2 license
|
||||
|
||||
var uppercase = /([A-Z])/g;
|
||||
var hyphenate = function(str) {
|
||||
const uppercase = /([A-Z])/g;
|
||||
const hyphenate = function(str) {
|
||||
return str.replace(uppercase, "-$1").toLowerCase();
|
||||
};
|
||||
|
||||
var ESCAPE_LOOKUP = {
|
||||
const ESCAPE_LOOKUP = {
|
||||
"&": "&",
|
||||
">": ">",
|
||||
"<": "<",
|
||||
|
@ -54,7 +53,7 @@ var ESCAPE_LOOKUP = {
|
|||
"'": "'",
|
||||
};
|
||||
|
||||
var ESCAPE_REGEX = /[&><"']/g;
|
||||
const ESCAPE_REGEX = /[&><"']/g;
|
||||
|
||||
function escaper(match) {
|
||||
return ESCAPE_LOOKUP[match];
|
||||
|
@ -74,9 +73,9 @@ function escape(text) {
|
|||
* A function to set the text content of a DOM element in all supported
|
||||
* browsers. Note that we don't define this if there is no document.
|
||||
*/
|
||||
var setTextContent;
|
||||
let setTextContent;
|
||||
if (typeof document !== "undefined") {
|
||||
var testNode = document.createElement("span");
|
||||
const testNode = document.createElement("span");
|
||||
if ("textContent" in testNode) {
|
||||
setTextContent = function(node, text) {
|
||||
node.textContent = text;
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
/* global it: false */
|
||||
/* global describe: false */
|
||||
|
||||
var parseTree = require("../src/parseTree");
|
||||
var Settings = require("../src/Settings");
|
||||
const parseTree = require("../src/parseTree");
|
||||
const Settings = require("../src/Settings");
|
||||
|
||||
var defaultSettings = new Settings({});
|
||||
const defaultSettings = new Settings({});
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.addMatchers({
|
||||
toFailWithParseError: function(util, customEqualityTesters) {
|
||||
var prefix = "KaTeX parse error: ";
|
||||
const prefix = "KaTeX parse error: ";
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
try {
|
||||
|
@ -28,8 +28,8 @@ beforeEach(function() {
|
|||
message: "'" + actual + "' parsed with error",
|
||||
};
|
||||
}
|
||||
var msg = e.message;
|
||||
var exp = prefix + expected;
|
||||
const msg = e.message;
|
||||
const exp = prefix + expected;
|
||||
if (msg === exp) {
|
||||
return {
|
||||
pass: true,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,20 @@
|
|||
/* eslint no-console:0 */
|
||||
"use strict";
|
||||
|
||||
var fs = require("fs");
|
||||
var childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
const childProcess = require("child_process");
|
||||
|
||||
var opts = require("nomnom")
|
||||
const opts = require("nomnom")
|
||||
.option("spacing", {
|
||||
flag: true,
|
||||
help: "Print mismatches involving spacing commands",
|
||||
})
|
||||
.parse();
|
||||
|
||||
var symbols = require("../src/symbols");
|
||||
var keys = Object.keys(symbols.math);
|
||||
const symbols = require("../src/symbols");
|
||||
const keys = Object.keys(symbols.math);
|
||||
keys.sort();
|
||||
var types = [
|
||||
const types = [
|
||||
"mathord", "op", "bin", "rel", "open", "close", "punct", "inner",
|
||||
"spacing", "accent", "textord",
|
||||
];
|
||||
|
@ -22,22 +22,22 @@ var types = [
|
|||
process.nextTick(writeTexFile);
|
||||
|
||||
function writeTexFile() {
|
||||
var tex = fs.createWriteStream("symgroups.tex");
|
||||
const tex = fs.createWriteStream("symgroups.tex");
|
||||
tex.on("finish", typeset);
|
||||
tex.write("\\documentclass{article}\n" +
|
||||
"\\usepackage{textcomp,amsmath,amssymb,gensymb}\n" +
|
||||
"\\begin{document}\n" +
|
||||
"\\showboxbreadth=\\maxdimen\\showboxdepth=\\maxdimen\n\n");
|
||||
keys.forEach(function(key, idx) {
|
||||
var sym = symbols.math[key];
|
||||
var type = types.indexOf(sym.group) + 1;
|
||||
const sym = symbols.math[key];
|
||||
const type = types.indexOf(sym.group) + 1;
|
||||
tex.write("$" + idx + "+" + key + "+" + type + "\\showlists$\n\n");
|
||||
});
|
||||
tex.end("\\end{document}\n");
|
||||
}
|
||||
|
||||
function typeset() {
|
||||
var proc = childProcess.spawn(
|
||||
const proc = childProcess.spawn(
|
||||
"pdflatex", ["--interaction=nonstopmode", "symgroups"],
|
||||
{stdio: "ignore"});
|
||||
proc.on("exit", function(code, signal) {
|
||||
|
@ -76,29 +76,29 @@ function typeset() {
|
|||
*/
|
||||
|
||||
// Extract individual blocks, from switch to math mode up to switch back.
|
||||
var reMM = /^### math mode entered.*\n([^]*?)###/mg;
|
||||
const reMM = /^### math mode entered.*\n([^]*?)###/mg;
|
||||
|
||||
// Identify the parts separated by the plus signs
|
||||
var reParts = /([^]*^\.\\fam0 \+\n)([^]+)(\\mathbin\n\.+\\fam0 \+[^]*)/m;
|
||||
const reParts = /([^]*^\.\\fam0 \+\n)([^]+)(\\mathbin\n\.+\\fam0 \+[^]*)/m;
|
||||
|
||||
// Variation of the above in case we have nothing between the plus signs
|
||||
var reEmpty = /^\.\\fam0 \+\n\\mathbin\n\.\\fam0 \+/m;
|
||||
const reEmpty = /^\.\\fam0 \+\n\\mathbin\n\.\\fam0 \+/m;
|
||||
|
||||
// Match any printed digit in the first or last of these parts
|
||||
var reDigit = /^\.\\fam0 ([0-9])/mg;
|
||||
const reDigit = /^\.\\fam0 ([0-9])/mg;
|
||||
|
||||
// Match the atom type, i.e. "\mathrel" in the above example
|
||||
var reAtom = /\\([a-z]+)/;
|
||||
const reAtom = /\\([a-z]+)/;
|
||||
|
||||
function evaluate(err, log) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var match;
|
||||
var nextIndex = 0;
|
||||
let match;
|
||||
let nextIndex = 0;
|
||||
while ((match = reMM.exec(log)) !== null) {
|
||||
var list = match[1];
|
||||
const list = match[1];
|
||||
match = reParts.exec(list);
|
||||
if (!match) {
|
||||
match = reEmpty.exec(list);
|
||||
|
@ -113,9 +113,9 @@ function evaluate(err, log) {
|
|||
console.error(list);
|
||||
process.exit(2);
|
||||
}
|
||||
var idx = extractDigits(match[1]);
|
||||
var atom = match[2];
|
||||
var katexType = types[extractDigits(match[3]) - 1] || "???";
|
||||
const idx = extractDigits(match[1]);
|
||||
const atom = match[2];
|
||||
const katexType = types[extractDigits(match[3]) - 1] || "???";
|
||||
match = reAtom.exec(atom);
|
||||
if (!match) {
|
||||
console.error("Failed to find atom type");
|
||||
|
@ -123,7 +123,7 @@ function evaluate(err, log) {
|
|||
console.error(list);
|
||||
process.exit(3);
|
||||
}
|
||||
var latexType = match[1];
|
||||
const latexType = match[1];
|
||||
if (katexType !== latexType && "math" + katexType !== latexType &&
|
||||
(katexType !== "textord" || latexType !== "mathord") &&
|
||||
(katexType !== "spacing" || opts.spacing)) {
|
||||
|
@ -145,8 +145,8 @@ function evaluate(err, log) {
|
|||
}
|
||||
|
||||
function extractDigits(str) {
|
||||
var match;
|
||||
var res = "";
|
||||
let match;
|
||||
let res = "";
|
||||
while ((match = reDigit.exec(str)) !== null) {
|
||||
res += match[1];
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
/* global expect: false */
|
||||
/* global it: false */
|
||||
/* global describe: false */
|
||||
var ParseError = require("../src/ParseError");
|
||||
var parseTree = require("../src/parseTree");
|
||||
var Settings = require("../src/Settings");
|
||||
const ParseError = require("../src/ParseError");
|
||||
const parseTree = require("../src/parseTree");
|
||||
const Settings = require("../src/Settings");
|
||||
|
||||
var defaultSettings = new Settings({});
|
||||
const defaultSettings = new Settings({});
|
||||
|
||||
var parseAndSetResult = function(expr, result, settings) {
|
||||
const parseAndSetResult = function(expr, result, settings) {
|
||||
try {
|
||||
return parseTree(expr, settings || defaultSettings);
|
||||
} catch (e) {
|
||||
|
@ -32,9 +32,9 @@ describe("unicode", function() {
|
|||
toParse: function() {
|
||||
return {
|
||||
compare: function(actual, settings) {
|
||||
var usedSettings = settings ? settings : defaultSettings;
|
||||
const usedSettings = settings ? settings : defaultSettings;
|
||||
|
||||
var result = {
|
||||
const result = {
|
||||
pass: true,
|
||||
message: "'" + actual + "' succeeded parsing",
|
||||
};
|
||||
|
@ -47,9 +47,9 @@ describe("unicode", function() {
|
|||
toNotParse: function() {
|
||||
return {
|
||||
compare: function(actual, settings) {
|
||||
var usedSettings = settings ? settings : defaultSettings;
|
||||
const usedSettings = settings ? settings : defaultSettings;
|
||||
|
||||
var result = {
|
||||
const result = {
|
||||
pass: false,
|
||||
message: "Expected '" + actual + "' to fail " +
|
||||
"parsing, but it succeeded",
|
||||
|
|
Loading…
Reference in New Issue
Block a user