diff --git a/ts/input/tex/DimensionUtil.ts b/ts/input/tex/DimensionUtil.ts new file mode 100644 index 000000000..cf6a4f99b --- /dev/null +++ b/ts/input/tex/DimensionUtil.ts @@ -0,0 +1,97 @@ +/************************************************************* + * + * Copyright (c) 2009-2021 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +namespace DimensionUtil { + // TODO (VS): Combine some of this with lengths in util. + const emPerInch = 7.2; + const pxPerInch = 72; + // Note, the following are TeX CM font values. + const UNIT_CASES: { [key: string]: (m: number) => number } = { + em: (m) => m, + ex: (m) => m * 0.43, + pt: (m) => m / 10, // 10 pt to an em + pc: (m) => m * 1.2, // 12 pt to a pc + px: (m) => (m * emPerInch) / pxPerInch, + in: (m) => m * emPerInch, + cm: (m) => (m * emPerInch) / 2.54, // 2.54 cm to an inch + mm: (m) => (m * emPerInch) / 25.4, // 10 mm to a cm + mu: (m) => m / 18, + }; + const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))'; + const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)'; + const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$'); + const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?'); + /** + * Matches for a dimension argument. + * @param {string} dim The argument. + * @param {boolean} rest Allow for trailing garbage in the dimension string. + * @return {[string, string, number]} The match result as (Anglosaxon) value, + * unit name, length of matched string. The latter is interesting in the + * case of trailing garbage. + */ + export function matchDimen( + dim: string, + rest: boolean = false + ): [string, string, number] { + let match = dim.match(rest ? dimenRest : dimenEnd); + return match + ? muReplace([match[1].replace(/,/, '.'), match[4], match[0].length]) + : [null, null, 0]; + } + + /** + * Convert a dimension string into standard em dimension. + * @param {string} dim The attribute string. + * @return {number} The numerical value. + */ + export function dimen2em(dim: string): number { + let [value, unit] = matchDimen(dim); + let m = parseFloat(value || '1'); + let func = UNIT_CASES[unit]; + return func ? func(m) : 0; + } + + /** + * Transforms mu dimension to em if necessary. + * @param {[string, string, number]} [value, unit, length] The dimension triple. + * @return {[string, string, number]} [value, unit, length] The transformed triple. + */ + function muReplace([value, unit, length]: [string, string, number]): [ + string, + string, + number + ] { + if (unit !== 'mu') { + return [value, unit, length]; + } + let em = Em(UNIT_CASES[unit](parseFloat(value || '1'))); + return [em.slice(0, -2), 'em', length]; + } + + /** + * Turns a number into an em value. + * @param {number} m The number. + * @return {string} The em dimension string. + */ + export function Em(m: number): string { + if (Math.abs(m) < 0.0006) { + return '0em'; + } + return m.toFixed(3).replace(/\.?0+$/, '') + 'em'; + } +} + +export default DimensionUtil; diff --git a/ts/input/tex/ParseUtil.ts b/ts/input/tex/ParseUtil.ts index 9bd3427c0..d7a3ec82d 100644 --- a/ts/input/tex/ParseUtil.ts +++ b/ts/input/tex/ParseUtil.ts @@ -31,87 +31,15 @@ import TexParser from './TexParser.js'; import TexError from './TexError.js'; import {entities} from '../../util/Entities.js'; import {MmlMunderover} from '../../core/MmlTree/MmlNodes/munderover.js'; - +import DimensionUtil from './DimensionUtil'; namespace ParseUtil { - // TODO (VS): Combine some of this with lengths in util. - const emPerInch = 7.2; - const pxPerInch = 72; - // Note, the following are TeX CM font values. - const UNIT_CASES: {[key: string]: ((m: number) => number)} = { - 'em': m => m, - 'ex': m => m * .43, - 'pt': m => m / 10, // 10 pt to an em - 'pc': m => m * 1.2, // 12 pt to a pc - 'px': m => m * emPerInch / pxPerInch, - 'in': m => m * emPerInch, - 'cm': m => m * emPerInch / 2.54, // 2.54 cm to an inch - 'mm': m => m * emPerInch / 25.4, // 10 mm to a cm - 'mu': m => m / 18, - }; - const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))'; - const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)'; - const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$'); - const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?'); - - - /** - * Matches for a dimension argument. - * @param {string} dim The argument. - * @param {boolean} rest Allow for trailing garbage in the dimension string. - * @return {[string, string, number]} The match result as (Anglosaxon) value, - * unit name, length of matched string. The latter is interesting in the - * case of trailing garbage. - */ - export function matchDimen( - dim: string, rest: boolean = false): [string, string, number] { - let match = dim.match(rest ? dimenRest : dimenEnd); - return match ? - muReplace([match[1].replace(/,/, '.'), match[4], match[0].length]) : - [null, null, 0]; - } - - - /** - * Transforms mu dimension to em if necessary. - * @param {[string, string, number]} [value, unit, length] The dimension triple. - * @return {[string, string, number]} [value, unit, length] The transformed triple. - */ - function muReplace([value, unit, length]: [string, string, number]): [string, string, number] { - if (unit !== 'mu') { - return [value, unit, length]; - } - let em = Em(UNIT_CASES[unit](parseFloat(value || '1'))); - return [em.slice(0, -2), 'em', length]; - } - - - /** - * Convert a dimension string into standard em dimension. - * @param {string} dim The attribute string. - * @return {number} The numerical value. - */ - export function dimen2em(dim: string): number { - let [value, unit] = matchDimen(dim); - let m = parseFloat(value || '1'); - let func = UNIT_CASES[unit]; - return func ? func(m) : 0; - } - - - /** - * Turns a number into an em value. - * @param {number} m The number. - * @return {string} The em dimension string. - */ - export function Em(m: number): string { - if (Math.abs(m) < .0006) { - return '0em'; - } - return m.toFixed(3).replace(/\.?0+$/, '') + 'em'; - } + export const matchDimen = DimensionUtil.matchDimen; + export const dimen2em = DimensionUtil.dimen2em; + + export const Em = DimensionUtil.Em; /** * Takes an array of numbers and returns a space-separated string of em values. diff --git a/ts/input/tex/StringUtil.ts b/ts/input/tex/StringUtil.ts new file mode 100644 index 000000000..fac519978 --- /dev/null +++ b/ts/input/tex/StringUtil.ts @@ -0,0 +1,34 @@ +/************************************************************* + * + * Copyright (c) 2009-2021 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +namespace StringUtil { + /** + * Trim spaces from a string. + * @param {string} text The string to clean. + * @return {string} The string with leading and trailing whitespace removed. + */ + export function trimSpaces(text: string): string { + if (typeof text !== 'string') { + return text; + } + let TEXT = text.trim(); + if (TEXT.match(/\\$/) && text.match(/ $/)) { + TEXT += ' '; + } + return TEXT; + } +} +export default StringUtil; diff --git a/ts/input/tex/TexParser.ts b/ts/input/tex/TexParser.ts index f8706c57f..0346e96d6 100644 --- a/ts/input/tex/TexParser.ts +++ b/ts/input/tex/TexParser.ts @@ -23,7 +23,8 @@ * @author v.sorge@mathjax.org (Volker Sorge) */ -import ParseUtil from './ParseUtil.js'; +import DimensionUtil from './DimensionUtil'; +import StringUtil from './StringUtil'; import {HandlerType} from './MapHandler.js'; import Stack from './Stack.js'; import StackItemFactory from './StackItemFactory.js'; @@ -392,7 +393,7 @@ export default class TexParser { public GetDimen(name: string): string { if (this.GetNext() === '{') { let dimen = this.GetArgument(name); - let [value, unit] = ParseUtil.matchDimen(dimen); + let [value, unit] = DimensionUtil.matchDimen(dimen); if (value) { // @test Raise In Line, Lower 2, (Raise|Lower) Negative return value + unit; @@ -400,7 +401,7 @@ export default class TexParser { } else { // @test Above, Raise, Lower, Modulo, Above With Delims let dimen = this.string.slice(this.i); - let [value, unit, length] = ParseUtil.matchDimen(dimen, true); + let [value, unit, length] = DimensionUtil.matchDimen(dimen, true); if (value) { this.i += length; return value + unit; @@ -475,7 +476,7 @@ export default class TexParser { * @return {string} The delimiter. */ public GetDelimiterArg(name: string): string { - let c = ParseUtil.trimSpaces(this.GetArgument(name)); + let c = StringUtil.trimSpaces(this.GetArgument(name)); if (c === '') { return null; }