Comparing version 0.33.2 to 0.34.0
@@ -0,1 +1,26 @@ | ||
## | ||
### Bug Fixes | ||
- Fix #364: Some expressions containing placeholders, when inserted, would not have the placeholder selected. For example, when using the "differentialD" key in the virtual keyboard. | ||
- Fix #349: | ||
- 'latex-expanded' format no longer returns `\mleft` and `\mright`. This | ||
format is intended for inter-exchange with other TeX-compatible renderers | ||
and the `\mleft` and `\mright` commands are not widely deployed. | ||
- The content exported to the clipboard is now surrounded by `$$` to more | ||
clearly indicate that the content is using TeX format. | ||
- When pasting content that begins/ends with `$` or `$$`, assume LaTeX format | ||
- Fix keyboard shortcuts, e.g. "alt+(" or "alt+v" | ||
- Fix #354: The argument of `\operatorname` is of type 'math', not 'text'. This means that using the '\text' command inside the argument is valid and that spaces should be ignored by default (but the `~` character can be used to insert a space in that context). | ||
- Fix #282: Some keys from the virtual keyboards ('e', 'i') produce an incorrect input. | ||
- Fix #227: An operator (`\sin`) following some text is incorrectly considered | ||
to be part of the text. | ||
### Features / Improvements | ||
- Documented `suppressChangeNotifications` options for `$insert()` | ||
- Document `config.smartMode` (#312) | ||
- The 'surd' (root) and 'leftright' (fences) elements now change color when the caret is inside their body. This helps distinguish the case where the caret position may be ambiguous, for example when it is either after the last element of the body of a 'surd' or the first element after the 'surd'. | ||
- #339: Read-only mode. Set the mode to read-only with `mf.$setConfig({readOnly: true})`. When this mode is activated, the formula can be selected (so it can be copied), but it cannot be modified by the user. Progammatic modification is still possible. | ||
## 0.33 (December 16, 2019) | ||
@@ -227,3 +252,3 @@ | ||
config.inlineShortcuts = { | ||
in: "\\in" | ||
in: '\\in', | ||
}; | ||
@@ -237,6 +262,6 @@ ``` | ||
in: { | ||
mode: "math", | ||
after: "space+letter+digit+symbol+fence", | ||
value: "\\in" | ||
} | ||
mode: 'math', | ||
after: 'space+letter+digit+symbol+fence', | ||
value: '\\in', | ||
}, | ||
}; | ||
@@ -297,3 +322,3 @@ ``` | ||
- #132: Support for smart fence with `{}`, and `\langle`. | ||
- Pressing the spacebar next to a closing smartfence will close it. Useful | ||
- Pressing the spacebar next to a closing smartFence will close it. Useful | ||
for semi-open fences. | ||
@@ -389,6 +414,6 @@ - Improved rendering performance by 8% | ||
```javascript | ||
MathLive.makeMathField("input", { | ||
MathLive.makeMathField('input', { | ||
onContentDidChange: mf => { | ||
document.getElementById("output").innerHTML = mf.latex(); | ||
} | ||
document.getElementById('output').innerHTML = mf.latex(); | ||
}, | ||
}); | ||
@@ -434,3 +459,3 @@ ``` | ||
<script type="module"> | ||
import MathLive from "../../dist/mathlive.mjs"; | ||
import MathLive from '../../dist/mathlive.mjs'; | ||
</script> | ||
@@ -470,3 +495,3 @@ ``` | ||
```javascript | ||
import MathLive from "../../dist/src/mathlive.js"; | ||
import MathLive from '../../dist/src/mathlive.js'; | ||
MathLive.makeMathField(/*...*/); | ||
@@ -473,0 +498,0 @@ ``` |
@@ -41,2 +41,3 @@ /** | ||
@property {string} plonkSound? | ||
@property {boolean} readOnly? | ||
@property {"mathlive" | "sre"} textToSpeechRules? | ||
@@ -103,2 +104,3 @@ @property {"ssml" | "mac"} textToSpeechMarkup? | ||
plonkSound?: string; | ||
readOnly?: boolean; | ||
textToSpeechRules?: "mathlive" | "sre"; | ||
@@ -461,2 +463,4 @@ textToSpeechMarkup?: "ssml" | "mac"; | ||
* | ||
* @param {object} options.style | ||
* | ||
* @param {boolean} options.resetStyle - If true, the style after the insertion | ||
@@ -466,2 +470,9 @@ * is the same as the style before. If false, the style after the | ||
* | ||
* @param {boolean} options.smartFence - If true, promote plain fences, e.g. `(`, | ||
* as `\left...\right` or `\mleft...\mright` | ||
* | ||
* @param {boolean} options.suppressChangeNotifications - If true, the | ||
* handlers for the contentWillChange, contentDidChange, selectionWillChange and | ||
* selectionDidChange notifications will not be invoked. Default `false`. | ||
* | ||
* @category Changing the Content | ||
@@ -477,3 +488,6 @@ * @method MathField#$insert | ||
mode: "text" | "math" | ""; | ||
style: any; | ||
resetStyle: boolean; | ||
smartFence: boolean; | ||
suppressChangeNotifications: boolean; | ||
}): void; | ||
@@ -787,3 +801,3 @@ /** | ||
* used at the end of repeating digits. **Default** = `"}"` | ||
* | ||
* | ||
* @return {string} The LaTeX representation of the Abstract Syntax Tree, if valid. | ||
@@ -790,0 +804,0 @@ * @category Converting |
@@ -16,4 +16,6 @@ /* eslint no-console:0 */ | ||
if (braceLevel <= 0 && | ||
text.slice(index, index + delimLength) === delimiter) { | ||
if ( | ||
braceLevel <= 0 && | ||
text.slice(index, index + delimLength) === delimiter | ||
) { | ||
return index; | ||
@@ -51,3 +53,3 @@ } else if (character === '\\') { | ||
type: 'text', | ||
data: text.slice(0, currIndex) | ||
data: text.slice(0, currIndex), | ||
}); | ||
@@ -68,3 +70,3 @@ } | ||
type: 'text', | ||
data: text.slice(currIndex, nextIndex) | ||
data: text.slice(currIndex, nextIndex), | ||
}); | ||
@@ -78,3 +80,4 @@ } | ||
text, | ||
currIndex + leftDelim.length); | ||
currIndex + leftDelim.length | ||
); | ||
if (nextIndex === -1) { | ||
@@ -89,7 +92,9 @@ done = true; | ||
currIndex + leftDelim.length, | ||
nextIndex), | ||
nextIndex | ||
), | ||
rawData: text.slice( | ||
currIndex, | ||
nextIndex + rightDelim.length), | ||
mathstyle: mathstyle | ||
nextIndex + rightDelim.length | ||
), | ||
mathstyle: mathstyle, | ||
}); | ||
@@ -105,3 +110,3 @@ | ||
type: 'text', | ||
data: text.slice(currIndex) | ||
data: text.slice(currIndex), | ||
}); | ||
@@ -118,7 +123,6 @@ } | ||
function splitWithDelimiters(text, delimiters) { | ||
let data = [{type: 'text', data: text}]; | ||
let data = [{ type: 'text', data: text }]; | ||
for (let i = 0; i < delimiters.inline.length; i++) { | ||
const delimiter = delimiters.inline[i]; | ||
data = splitAtDelimiters( | ||
data, delimiter[0], delimiter[1], 'textstyle'); | ||
data = splitAtDelimiters(data, delimiter[0], delimiter[1], 'textstyle'); | ||
} | ||
@@ -128,3 +132,7 @@ for (let i = 0; i < delimiters.display.length; i++) { | ||
data = splitAtDelimiters( | ||
data, delimiter[0], delimiter[1], 'displaystyle'); | ||
data, | ||
delimiter[0], | ||
delimiter[1], | ||
'displaystyle' | ||
); | ||
} | ||
@@ -135,3 +143,2 @@ | ||
function createMathMLNode(latex, options) { | ||
@@ -142,7 +149,8 @@ // Create a node for AT (Assistive Technology, e.g. screen reader) to speak, etc. | ||
try { | ||
span.innerHTML = "<math xmlns='http://www.w3.org/1998/Math/MathML'>" + | ||
options.renderToMathML(latex, options) + | ||
"</math>"; | ||
span.innerHTML = | ||
"<math xmlns='http://www.w3.org/1998/Math/MathML'>" + | ||
options.renderToMathML(latex, options) + | ||
'</math>'; | ||
} catch (e) { | ||
console.error( 'Could not convert\'' + latex + '\' to MathML with ', e ); | ||
console.error("Could not convert'" + latex + "' to MathML with ", e); | ||
span.textContent = latex; | ||
@@ -161,7 +169,13 @@ } | ||
let span = document.createElement('span'); | ||
span.setAttribute('aria-hidden','true'); | ||
span.setAttribute('aria-hidden', 'true'); | ||
if (options.preserveOriginalContent) { | ||
span.setAttribute('data-' + options.namespace + 'original-content', text); | ||
span.setAttribute( | ||
'data-' + options.namespace + 'original-content', | ||
text | ||
); | ||
if (mathstyle) { | ||
span.setAttribute('data-' + options.namespace + 'original-mathstyle', mathstyle); | ||
span.setAttribute( | ||
'data-' + options.namespace + 'original-mathstyle', | ||
mathstyle | ||
); | ||
} | ||
@@ -171,5 +185,10 @@ } | ||
try { | ||
span.innerHTML = options.renderToMarkup(text, mathstyle || 'displaystyle', 'html', options.macros); | ||
} catch (e) { | ||
console.error( 'Could not parse\'' + text + '\' with ', e ); | ||
span.innerHTML = options.renderToMarkup( | ||
text, | ||
mathstyle || 'displaystyle', | ||
'html', | ||
options.macros | ||
); | ||
} catch (e) { | ||
console.error("Could not parse'" + text + "' with ", e); | ||
if (createNodeOnFailure) { | ||
@@ -184,16 +203,35 @@ span = document.createTextNode(text); | ||
function createAccessibleMarkupPair(text, mathstyle, options, createNodeOnFailure) { | ||
function createAccessibleMarkupPair( | ||
text, | ||
mathstyle, | ||
options, | ||
createNodeOnFailure | ||
) { | ||
// Create a math node (a span with an accessible component and a visual component) | ||
// If there is an error in parsing the latex, 'createNodeOnFailure' controls whether | ||
// 'null' is returned or an accessible node with the text used. | ||
const markupNode = createMarkupNode(text, options, mathstyle, createNodeOnFailure); | ||
const markupNode = createMarkupNode( | ||
text, | ||
options, | ||
mathstyle, | ||
createNodeOnFailure | ||
); | ||
if (markupNode && /\b(mathml|speakable-text)\b/i.test(options.renderAccessibleContent)) { | ||
if ( | ||
markupNode && | ||
/\b(mathml|speakable-text)\b/i.test(options.renderAccessibleContent) | ||
) { | ||
const fragment = document.createDocumentFragment(); | ||
if (/\bmathml\b/i.test(options.renderAccessibleContent) && options.renderToMathML) { | ||
if ( | ||
/\bmathml\b/i.test(options.renderAccessibleContent) && | ||
options.renderToMathML | ||
) { | ||
fragment.appendChild(createMathMLNode(text, options)); | ||
} | ||
if (/\bspeakable-text\b/i.test(options.renderAccessibleContent) && options.renderToSpeakableText) { | ||
if ( | ||
/\bspeakable-text\b/i.test(options.renderAccessibleContent) && | ||
options.renderToSpeakableText | ||
) { | ||
const span = document.createElement('span'); | ||
span.innerHTML = options.renderToSpeakableText(text, options); | ||
span.innerHTML = options.renderToSpeakableText(text, options); | ||
span.className = 'sr-only'; | ||
@@ -215,3 +253,5 @@ fragment.appendChild(span); | ||
fragment = document.createDocumentFragment(); | ||
fragment.appendChild(createAccessibleMarkupPair(text, undefined, options, true)); | ||
fragment.appendChild( | ||
createAccessibleMarkupPair(text, undefined, options, true) | ||
); | ||
} else { | ||
@@ -229,3 +269,10 @@ const data = splitWithDelimiters(text, options.TeX.delimiters); | ||
} else { | ||
fragment.appendChild(createAccessibleMarkupPair(data[i].data, data[i].mathstyle, options, true)); | ||
fragment.appendChild( | ||
createAccessibleMarkupPair( | ||
data[i].data, | ||
data[i].mathstyle, | ||
options, | ||
true | ||
) | ||
); | ||
} | ||
@@ -238,7 +285,15 @@ } | ||
function scanElement(elem, options) { | ||
const originalContent = elem.getAttribute('data-' + options.namespace + | ||
'original-content'); | ||
const originalContent = elem.getAttribute( | ||
'data-' + options.namespace + 'original-content' | ||
); | ||
if (originalContent) { | ||
const mathstyle = elem.getAttribute('data-' + options.namespace + 'mathstyle'); | ||
const span = createAccessibleMarkupPair(originalContent, mathstyle, options, false); | ||
const mathstyle = elem.getAttribute( | ||
'data-' + options.namespace + 'mathstyle' | ||
); | ||
const span = createAccessibleMarkupPair( | ||
originalContent, | ||
mathstyle, | ||
options, | ||
false | ||
); | ||
if (span != null) { | ||
@@ -251,3 +306,2 @@ elem.textContent = ''; | ||
if (elem.childNodes.length === 1 && elem.childNodes[0].nodeType === 3) { | ||
@@ -259,3 +313,5 @@ // This is a node with textual content only. Perhaps an opportunity | ||
elem.textContent = ''; | ||
elem.appendChild( createAccessibleMarkupPair(text, undefined, options, true) ); | ||
elem.appendChild( | ||
createAccessibleMarkupPair(text, undefined, options, true) | ||
); | ||
return; | ||
@@ -269,3 +325,10 @@ } | ||
elem.textContent = ''; | ||
elem.appendChild( createAccessibleMarkupPair(data[0].data, data[0].mathstyle, options, true) ); | ||
elem.appendChild( | ||
createAccessibleMarkupPair( | ||
data[0].data, | ||
data[0].mathstyle, | ||
options, | ||
true | ||
) | ||
); | ||
return; | ||
@@ -292,6 +355,8 @@ } else if (data.length === 1 && data[0].type === 'text') { | ||
const tag = childNode.nodeName.toLowerCase(); | ||
if (tag === 'script' && | ||
options.processScriptTypePattern.test(childNode.type)) { | ||
if ( | ||
tag === 'script' && | ||
options.processScriptTypePattern.test(childNode.type) | ||
) { | ||
let style = 'displaystyle'; | ||
for (const l of childNode.type.split(';')) { | ||
for (const l of childNode.type.split(';')) { | ||
const v = l.split('='); | ||
@@ -304,8 +369,11 @@ if (v[0].toLowerCase() === 'mode') { | ||
} | ||
} | ||
} | ||
const span = createAccessibleMarkupPair(childNode.textContent, | ||
style, options, true) | ||
const span = createAccessibleMarkupPair( | ||
childNode.textContent, | ||
style, | ||
options, | ||
true | ||
); | ||
childNode.parentNode.replaceChild(span, childNode); | ||
@@ -316,4 +384,6 @@ } else { | ||
options.processClassPattern.test(childNode.className) || | ||
!(options.skipTags.includes(tag) || | ||
options.ignoreClassPattern.test(childNode.className)); | ||
!( | ||
options.skipTags.includes(tag) || | ||
options.ignoreClassPattern.test(childNode.className) | ||
); | ||
@@ -334,15 +404,22 @@ if (shouldRender) { | ||
// Name of tags whose content will not be scanned for math delimiters | ||
skipTags: ['noscript', 'style', 'textarea', 'pre', 'code', | ||
'annotation', 'annotation-xml'], | ||
skipTags: [ | ||
'noscript', | ||
'style', | ||
'textarea', | ||
'pre', | ||
'code', | ||
'annotation', | ||
'annotation-xml', | ||
], | ||
// <script> tags of the following types will be processed. Others, ignored. | ||
processScriptType: "math/tex", | ||
processScriptType: 'math/tex', | ||
// Regex pattern of the class name of elements whose contents should not | ||
// be processed | ||
ignoreClass: "tex2jax_ignore", | ||
ignoreClass: 'tex2jax_ignore', | ||
// Regex pattern of the class name of elements whose contents should | ||
// be processed when they appear inside ones that are ignored. | ||
processClass: "tex2jax_process", | ||
processClass: 'tex2jax_process', | ||
@@ -358,9 +435,12 @@ // Indicate whether to preserve or discard the original content of the | ||
disabled: false, | ||
processEnvironments : true, | ||
processEnvironments: true, | ||
delimiters: { | ||
inline: [['\\(','\\)']], | ||
display: [['$$', '$$'], ['\\[', '\\]']], | ||
} | ||
} | ||
} | ||
inline: [['\\(', '\\)']], | ||
display: [ | ||
['$$', '$$'], | ||
['\\[', '\\]'], | ||
], | ||
}, | ||
}, | ||
}; | ||
@@ -372,3 +452,5 @@ function renderMathInElement(elem, options) { | ||
options.processClassPattern = new RegExp(options.processClass); | ||
options.processScriptTypePattern = new RegExp(options.processScriptType); | ||
options.processScriptTypePattern = new RegExp( | ||
options.processScriptType | ||
); | ||
options.macros = Definitions.MACROS; | ||
@@ -379,6 +461,8 @@ | ||
if (!/^[a-z]+[-]?$/.test(options.namespace)) { | ||
throw Error('options.namespace must be a string of lowercase characters only'); | ||
throw Error( | ||
'options.namespace must be a string of lowercase characters only' | ||
); | ||
} | ||
if (!/-$/.test(options.namespace)) { | ||
options.namespace += '-'; | ||
options.namespace += '-'; | ||
} | ||
@@ -388,7 +472,10 @@ } | ||
scanElement(elem, options); | ||
} catch(e) { | ||
} catch (e) { | ||
if (e instanceof Error) { | ||
console.error('renderMathInElement(): ' + e.message); | ||
} else { | ||
console.error('renderMathInElement(): Could not render math for element ' + elem); | ||
console.error( | ||
'renderMathInElement(): Could not render math for element ' + | ||
elem | ||
); | ||
} | ||
@@ -398,5 +485,4 @@ } | ||
export default { | ||
renderMathInElement, | ||
} | ||
export default { | ||
renderMathInElement, | ||
}; |
@@ -19,3 +19,7 @@ /** | ||
const mathlist = ParserModule.parseTokens( | ||
Lexer.tokenize(latex), mode, null, null); | ||
Lexer.tokenize(latex), | ||
mode, | ||
null, | ||
null | ||
); | ||
@@ -26,3 +30,3 @@ return toASCIIMath(mathlist); | ||
export function asciiMathToLatex(ascii) { | ||
return parseMathString(ascii, {format: 'ASCIIMath'}); | ||
return parseMathString(ascii, { format: 'ASCIIMath' }); | ||
} | ||
@@ -44,4 +48,4 @@ | ||
if (Array.isArray(symbol)) { | ||
childSymbol = symbol.slice(); // Clone the array | ||
symbol = childSymbol.shift(); // Get the first element and remove it from the array | ||
childSymbol = symbol.slice(); // Clone the array | ||
symbol = childSymbol.shift(); // Get the first element and remove it from the array | ||
} | ||
@@ -85,3 +89,3 @@ | ||
* @private | ||
*/ | ||
*/ | ||
function getType(spans, symbol) { | ||
@@ -99,3 +103,3 @@ const s = getSymbol(spans, symbol); | ||
* @private | ||
*/ | ||
*/ | ||
function getTag(spans, symbol) { | ||
@@ -107,3 +111,2 @@ const s = getSymbol(spans, symbol); | ||
function getStyle(spans, symbol, prop) { | ||
@@ -121,3 +124,2 @@ const s = getSymbol(spans, symbol); | ||
function hasClass(spans, symbol, cls) { | ||
@@ -172,3 +174,4 @@ let classes = getClasses(spans, symbol); | ||
if (span.children && span.children.length > 0) { | ||
result += indent + 'children:' + spanToString(span.children, indent); | ||
result += | ||
indent + 'children:' + spanToString(span.children, indent); | ||
} | ||
@@ -189,3 +192,5 @@ result += indent + '}'; | ||
} else if (Array.isArray(value)) { | ||
return indent + prop + ':' + mathlistToString(value, indent + '\t') + ',\n'; | ||
return ( | ||
indent + prop + ':' + mathlistToString(value, indent + '\t') + ',\n' | ||
); | ||
} | ||
@@ -272,3 +277,4 @@ return ''; | ||
if (span.classes && span.classes.length > 0) { | ||
result += ' <span class="classes">' + span.classes + '</span>'; | ||
result += | ||
' <span class="classes">' + span.classes + '</span>'; | ||
} | ||
@@ -285,4 +291,8 @@ if (span.isTight) { | ||
if (Object.prototype.hasOwnProperty.call(span.style, s)) { | ||
result += ' <span class="styleprop">' + s + ':</span>'; | ||
result += '<span class="stylevalue"> ' + span.style[s] + '</span>; '; | ||
result += | ||
' <span class="styleprop">' + s + ':</span>'; | ||
result += | ||
'<span class="stylevalue"> ' + | ||
span.style[s] + | ||
'</span>; '; | ||
} | ||
@@ -296,6 +306,13 @@ } | ||
} else if (span) { | ||
result += '<br>' + indent + 'table ' + span.array[0].length + '×' + span.array.length; | ||
result += | ||
'<br>' + | ||
indent + | ||
'table ' + | ||
span.array[0].length + | ||
'×' + | ||
span.array.length; | ||
for (let i = 0; i < span.array.length; i++) { | ||
for (let j = 0; j < span.array[i].length; j++) { | ||
result += '<br>' + indent + '[' + (i + 1) + ', ' + (j + 1) + '] '; | ||
result += | ||
'<br>' + indent + '[' + (i + 1) + ', ' + (j + 1) + '] '; | ||
result += spanToMarkup(span.array[i][j], ''); | ||
@@ -312,3 +329,6 @@ } | ||
result += '<span class="styleprop">' + propname + '=</span>'; | ||
result += '<span style="font-size:2em;vertical-align:middle;color:' + mathlist[propname] + '">■</span>'; | ||
result += | ||
'<span style="font-size:2em;vertical-align:middle;color:' + | ||
mathlist[propname] + | ||
'">■</span>'; | ||
result += '<span class="stylevalue">'; | ||
@@ -326,3 +346,3 @@ result += mathlist[propname]; | ||
result += '<span class="stylevalue">'; | ||
result += mathlist[propname] | ||
result += mathlist[propname]; | ||
result += '</span>" '; | ||
@@ -348,4 +368,7 @@ } | ||
result += mathlist.caret ? ' caret' : ''; | ||
result += '">' + mathlist.type + | ||
(mathlist.caret ? ' caret ' : '') + '</span>'; | ||
result += | ||
'">' + | ||
mathlist.type + | ||
(mathlist.caret ? ' caret ' : '') + | ||
'</span>'; | ||
} | ||
@@ -355,6 +378,11 @@ if (typeof mathlist.body === 'string' && mathlist.body.length > 0) { | ||
result += mathlist.body; | ||
if (mathlist.body.charCodeAt(0) < 32 | ||
|| mathlist.body.charCodeAt(0) > 127) { | ||
result += ' U+' + ('000000' + | ||
mathlist.body.charCodeAt(0).toString(16)).substr(-6); | ||
if ( | ||
mathlist.body.charCodeAt(0) < 32 || | ||
mathlist.body.charCodeAt(0) > 127 | ||
) { | ||
result += | ||
' U+' + | ||
( | ||
'000000' + mathlist.body.charCodeAt(0).toString(16) | ||
).substr(-6); | ||
} | ||
@@ -398,3 +426,3 @@ result += '</span> '; | ||
result += mathListPropToMarkup(mathlist, 'position'); | ||
// Type 'overunder' | ||
@@ -412,5 +440,14 @@ result += mathlistToMarkup(mathlist.overscript, indent + '↑'); | ||
for (let i = 0; i < mathlist.array.length; i++) { | ||
result += '<br>' + indent + '\u2317 row ' + (i + 1) + '/' + mathlist.array.length; | ||
result += | ||
'<br>' + | ||
indent + | ||
'\u2317 row ' + | ||
(i + 1) + | ||
'/' + | ||
mathlist.array.length; | ||
for (let j = 0; j < mathlist.array[i].length; j++) { | ||
result += mathlistToMarkup(mathlist.array[i][j], indent + '\u2317\u232A'); | ||
result += mathlistToMarkup( | ||
mathlist.array[i][j], | ||
indent + '\u2317\u232A' | ||
); | ||
} | ||
@@ -423,7 +460,2 @@ } | ||
// Export the public interface for this module | ||
@@ -436,3 +468,3 @@ export default { | ||
spanToString, | ||
hasClass, | ||
@@ -447,5 +479,2 @@ getClasses, | ||
asciiMathToLatex, | ||
} | ||
}; |
@@ -17,10 +17,18 @@ /** | ||
while (atoms[i]) { | ||
if (atoms[i].type !== 'mop' && | ||
(atoms[i].fontFamily || atoms[i].baseFontFamily) !== value) break | ||
if ( | ||
atoms[i].type !== 'mop' && | ||
(atoms[i].fontFamily || atoms[i].baseFontFamily) !== value | ||
) { | ||
break; | ||
} | ||
i++; | ||
} | ||
} else if (property === 'mode') { | ||
while (atoms[i]) { | ||
if (atoms[i][property] !== value) break; | ||
i++; | ||
} | ||
} else { | ||
while (atoms[i]) { | ||
if (atoms[i].type !== 'mop' && | ||
atoms[i][property] !== value) break | ||
if (atoms[i].type !== 'mop' && atoms[i][property] !== value) break; | ||
i++; | ||
@@ -54,3 +62,5 @@ } | ||
let propValue = atoms[0][prop]; | ||
if (prop === 'fontFamily') propValue = atoms[0].fontFamily || atoms[0].baseFontFamily; | ||
if (prop === 'fontFamily') { | ||
propValue = atoms[0].fontFamily || atoms[0].baseFontFamily; | ||
} | ||
@@ -62,12 +72,12 @@ const i = findLongestRun(atoms, prop, propValue); | ||
if (atoms[0].fontShape === 'it') { | ||
prefix = '\\textit{' | ||
prefix = '\\textit{'; | ||
suffix = '}'; | ||
} else if (atoms[0].fontShape === 'sl') { | ||
prefix = '\\textsl{' | ||
prefix = '\\textsl{'; | ||
suffix = '}'; | ||
} else if (atoms[0].fontShape === 'sc') { | ||
prefix = '\\textsc{' | ||
prefix = '\\textsc{'; | ||
suffix = '}'; | ||
} else if (atoms[0].fontShape === 'n') { | ||
prefix = '\\textup{' | ||
prefix = '\\textup{'; | ||
suffix = '}'; | ||
@@ -80,9 +90,9 @@ } else { | ||
if (atoms[0].fontSeries === 'b') { | ||
prefix = '\\textbf{' | ||
prefix = '\\textbf{'; | ||
suffix = '}'; | ||
} else if (atoms[0].fontSeries === 'l') { | ||
prefix = '\\textlf{' | ||
prefix = '\\textlf{'; | ||
suffix = '}'; | ||
} else if (atoms[0].fontSeries === 'm') { | ||
prefix = '\\textmd{' | ||
prefix = '\\textmd{'; | ||
suffix = '}'; | ||
@@ -96,6 +106,8 @@ } else { | ||
for (let j = 0; j < i; j++) { | ||
if (!atoms[j].fontSeries && | ||
if ( | ||
!atoms[j].fontSeries && | ||
!atoms[j].fontShape && | ||
!atoms[j].fontFamily && | ||
!atoms[j].baseFontFamily) { | ||
!atoms[j].baseFontFamily | ||
) { | ||
allAtomsHaveShapeOrSeriesOrFontFamily = false; | ||
@@ -113,26 +125,32 @@ break; | ||
} else if (prop === 'fontSize' && atoms[0].fontSize) { | ||
const command = { | ||
'size1': 'tiny', | ||
'size2': 'scriptsize', | ||
'size3': 'footnotesize', | ||
'size4': 'small', | ||
'size5': 'normalsize', | ||
'size6': 'large', | ||
'size7': 'Large', | ||
'size8': 'LARGE', | ||
'size9': 'huge', | ||
'size10': 'Huge' | ||
}[atoms[0].fontSize] || ''; | ||
const command = | ||
{ | ||
size1: 'tiny', | ||
size2: 'scriptsize', | ||
size3: 'footnotesize', | ||
size4: 'small', | ||
size5: 'normalsize', | ||
size6: 'large', | ||
size7: 'Large', | ||
size8: 'LARGE', | ||
size9: 'huge', | ||
size10: 'Huge', | ||
}[atoms[0].fontSize] || ''; | ||
prefix = '{\\' + command + ' '; | ||
suffix = '}'; | ||
} else if (prop === 'fontFamily' && | ||
(atoms[0].fontFamily || atoms[0].baseFontFamily)) { | ||
const command = { | ||
'cmr': 'textrm', | ||
'cmtt': 'texttt', | ||
'cmss': 'textsf' | ||
}[atoms[0].fontFamily || atoms[0].baseFontFamily] || ''; | ||
} else if ( | ||
prop === 'fontFamily' && | ||
(atoms[0].fontFamily || atoms[0].baseFontFamily) | ||
) { | ||
const command = | ||
{ | ||
cmr: 'textrm', | ||
cmtt: 'texttt', | ||
cmss: 'textsf', | ||
}[atoms[0].fontFamily || atoms[0].baseFontFamily] || ''; | ||
if (!command) { | ||
prefix += '{\\fontfamily{' + (atoms[0].fontFamily || atoms[0].baseFontFamily) + '}'; | ||
prefix += | ||
'{\\fontfamily{' + | ||
(atoms[0].fontFamily || atoms[0].baseFontFamily) + | ||
'}'; | ||
suffix = '}'; | ||
@@ -164,30 +182,30 @@ } else { | ||
} | ||
} else if (prop === 'fontSize' && atoms[0].fontSize) { | ||
const command = { | ||
'size1': 'tiny', | ||
'size2': 'scriptsize', | ||
'size3': 'footnotesize', | ||
'size4': 'small', | ||
'size5': 'normalsize', | ||
'size6': 'large', | ||
'size7': 'Large', | ||
'size8': 'LARGE', | ||
'size9': 'huge', | ||
'size10': 'Huge' | ||
}[atoms[0].fontSize] || ''; | ||
const command = | ||
{ | ||
size1: 'tiny', | ||
size2: 'scriptsize', | ||
size3: 'footnotesize', | ||
size4: 'small', | ||
size5: 'normalsize', | ||
size6: 'large', | ||
size7: 'Large', | ||
size8: 'LARGE', | ||
size9: 'huge', | ||
size10: 'Huge', | ||
}[atoms[0].fontSize] || ''; | ||
prefix = '{\\' + command + ' '; | ||
suffix = '}'; | ||
} else if (prop === 'fontFamily' && atoms[0].fontFamily) { | ||
if (!/^(math|main)$/.test(atoms[0].fontFamily)) { | ||
const command = { | ||
'cal': 'mathcal', | ||
'frak': 'mathfrak', | ||
'bb': 'mathbb', | ||
'scr': 'mathscr', | ||
'cmr': 'mathrm', | ||
'cmtt': 'mathtt', | ||
'cmss': 'mathsf' | ||
}[atoms[0].fontFamily] || ''; | ||
const command = | ||
{ | ||
cal: 'mathcal', | ||
frak: 'mathfrak', | ||
bb: 'mathbb', | ||
scr: 'mathscr', | ||
cmr: 'mathrm', | ||
cmtt: 'mathtt', | ||
cmss: 'mathsf', | ||
}[atoms[0].fontFamily] || ''; | ||
if (!command) { | ||
@@ -198,3 +216,11 @@ prefix += '{\\fontfamily{' + atoms[0].fontFamily + '}'; | ||
if (/^\\operatorname{/.test(atoms[0].latex)) { | ||
return atoms[0].latex + latexifyArray(parent, properties, atoms.slice(i), expandMacro); | ||
return ( | ||
atoms[0].latex + | ||
latexifyArray( | ||
parent, | ||
properties, | ||
atoms.slice(i), | ||
expandMacro | ||
) | ||
); | ||
} | ||
@@ -216,11 +242,12 @@ if (!atoms[0].isFunction) { | ||
} else { | ||
const command = { | ||
'cal': 'mathcal', | ||
'frak': 'mathfrak', | ||
'bb': 'mathbb', | ||
'scr': 'mathscr', | ||
'cmr': 'mathrm', | ||
'cmtt': 'mathtt', | ||
'cmss': 'mathsf' | ||
}[atoms[0].baseFontFamily] || ''; | ||
const command = | ||
{ | ||
cal: 'mathcal', | ||
frak: 'mathfrak', | ||
bb: 'mathbb', | ||
scr: 'mathscr', | ||
cmr: 'mathrm', | ||
cmtt: 'mathtt', | ||
cmss: 'mathsf', | ||
}[atoms[0].baseFontFamily] || ''; | ||
if (command) { | ||
@@ -234,5 +261,8 @@ prefix = '\\' + command + '{'; | ||
if (prop === 'color' && atoms[0].color && | ||
atoms[0].color !== 'none' && | ||
(!parent || parent.color !== atoms[0].color)) { | ||
if ( | ||
prop === 'color' && | ||
atoms[0].color && | ||
atoms[0].color !== 'none' && | ||
(!parent || parent.color !== atoms[0].color) | ||
) { | ||
prefix = '\\textcolor{' + Color.colorToString(atoms[0].color) + '}{'; | ||
@@ -242,6 +272,12 @@ suffix = '}'; | ||
if (prop === 'backgroundColor' && atoms[0].backgroundColor && | ||
atoms[0].backgroundColor !== 'none' && | ||
(!parent || parent.backgroundColor !== atoms[0].backgroundColor)) { | ||
prefix = '\\colorbox{' + Color.colorToString(atoms[0].backgroundColor) + '}{'; | ||
if ( | ||
prop === 'backgroundColor' && | ||
atoms[0].backgroundColor && | ||
atoms[0].backgroundColor !== 'none' && | ||
(!parent || parent.backgroundColor !== atoms[0].backgroundColor) | ||
) { | ||
prefix = | ||
'\\colorbox{' + | ||
Color.colorToString(atoms[0].backgroundColor) + | ||
'}{'; | ||
suffix = '}'; | ||
@@ -252,6 +288,8 @@ } | ||
result += latexifyArray(parent, | ||
result += latexifyArray( | ||
parent, | ||
properties.slice(1), | ||
atoms.slice(0, i), | ||
expandMacro); | ||
expandMacro | ||
); | ||
@@ -266,4 +304,2 @@ result += suffix; | ||
/** | ||
@@ -284,15 +320,19 @@ * Given an atom or an array of atoms, return a LaTeX string representation | ||
result = latexifyArray(parent, [ | ||
'mode', | ||
'color', | ||
'backgroundColor', | ||
'fontSize', | ||
'fontFamily', | ||
'fontShape', | ||
'fontSeries', | ||
], value, expandMacro); | ||
result = latexifyArray( | ||
parent, | ||
[ | ||
'mode', | ||
'color', | ||
'backgroundColor', | ||
'fontSize', | ||
'fontFamily', | ||
'fontShape', | ||
'fontSeries', | ||
], | ||
value, | ||
expandMacro | ||
); | ||
// if (result.startsWith('{') && result.endsWith('}')) { | ||
// result = result.slice(1, result.length - 1); | ||
// } | ||
} else if (typeof value === 'number' || typeof value === 'boolean') { | ||
@@ -308,4 +348,2 @@ result = value.toString(); | ||
/** | ||
@@ -324,3 +362,4 @@ * Return a LaTeX representation of the atom. | ||
let result = ''; | ||
let col, row = 0; | ||
let col, | ||
row = 0; | ||
let i = 0; | ||
@@ -331,5 +370,6 @@ const m = !this.latex ? null : this.latex.match(/^(\\[^{\s0-9]+)/); | ||
// this.mode=='text' is handled in the switch by looking at this.type==='' | ||
switch(this.type) { | ||
switch (this.type) { | ||
case 'group': | ||
result += this.latexOpen || ((this.cssId || this.cssClass) ? '' : '{'); | ||
result += | ||
this.latexOpen || (this.cssId || this.cssClass ? '' : '{'); | ||
@@ -339,8 +379,10 @@ if (this.cssId) result += '\\cssId{' + this.cssId + '}{'; | ||
if (this.cssClass === 'ML__emph') { | ||
result += '\\emph{' + latexify(this, this.body, expandMacro) + '}'; | ||
result += | ||
'\\emph{' + latexify(this, this.body, expandMacro) + '}'; | ||
} else { | ||
if (this.cssClass) result += '\\class{' + this.cssClass + '}{'; | ||
result += expandMacro ? latexify(this, this.body, true) : | ||
(this.latex || latexify(this, this.body, false)); | ||
result += expandMacro | ||
? latexify(this, this.body, true) | ||
: this.latex || latexify(this, this.body, false); | ||
@@ -351,3 +393,4 @@ if (this.cssClass) result += '}'; | ||
result += this.latexClose || ((this.cssId || this.cssClass) ? '' : '}'); | ||
result += | ||
this.latexClose || (this.cssId || this.cssClass ? '' : '}'); | ||
break; | ||
@@ -391,3 +434,3 @@ | ||
result += '{'; | ||
result += latexify(this, this.numer, expandMacro) | ||
result += latexify(this, this.numer, expandMacro); | ||
result += '\\' + this.body + ' '; | ||
@@ -399,3 +442,7 @@ result += latexify(this, this.denom, expandMacro); | ||
result += command; | ||
result += `{${latexify(this, this.numer, expandMacro)}}{${latexify(this, this.denom, expandMacro)}}`; | ||
result += `{${latexify( | ||
this, | ||
this.numer, | ||
expandMacro | ||
)}}{${latexify(this, this.denom, expandMacro)}}`; | ||
} | ||
@@ -420,9 +467,28 @@ break; | ||
result += '\\right' + (this.rightDelim || '.'); | ||
if (this.rightDelim && this.rightDelim.length > 1) result += ' '; | ||
if (this.rightDelim && this.rightDelim.length > 1) { | ||
result += ' '; | ||
} | ||
} else { | ||
result += '\\mleft' + (this.leftDelim || '.'); | ||
if (this.leftDelim && this.leftDelim.length > 1) result += ' '; | ||
result += latexify(this, this.body, expandMacro); | ||
result += '\\mright' + (this.rightDelim || '.'); | ||
if (this.rightDelim && this.rightDelim.length > 1) result += ' '; | ||
if ( | ||
expandMacro && | ||
this.leftDelim === '(' && | ||
this.rightDelim === ')' | ||
) { | ||
// If we're in 'expandMacro' mode (i.e. interchange format | ||
// used, e.g., on the clipboard for maximum compatibility | ||
// with other LaTeX renderers), drop the `\mleft(` and `\mright`) | ||
// commands | ||
result += | ||
'(' + latexify(this, this.body, expandMacro) + ')'; | ||
} else { | ||
result += '\\mleft' + (this.leftDelim || '.'); | ||
if (this.leftDelim && this.leftDelim.length > 1) { | ||
result += ' '; | ||
} | ||
result += latexify(this, this.body, expandMacro); | ||
result += '\\mright' + (this.rightDelim || '.'); | ||
if (this.rightDelim && this.rightDelim.length > 1) { | ||
result += ' '; | ||
} | ||
} | ||
} | ||
@@ -441,3 +507,7 @@ break; | ||
} | ||
result += `{${latexify(this, this.width, expandMacro)}em}{${latexify(this, this.height, expandMacro)}em}`; | ||
result += `{${latexify( | ||
this, | ||
this.width, | ||
expandMacro | ||
)}em}{${latexify(this, this.height, expandMacro)}em}`; | ||
break; | ||
@@ -452,3 +522,7 @@ | ||
case 'overunder': | ||
result += `${command}{${latexify(this, this.overscript || this.underscript, expandMacro)}}{${latexify(parent, this.body, expandMacro)}}`; | ||
result += `${command}{${latexify( | ||
this, | ||
this.overscript || this.underscript, | ||
expandMacro | ||
)}}{${latexify(parent, this.body, expandMacro)}}`; | ||
break; | ||
@@ -464,5 +538,13 @@ | ||
case 'textord': | ||
case '': // mode = text | ||
if (/^\\(mathbin|mathrel|mathopen|mathclose|mathpunct|mathord|mathinner)/.test(command)) { | ||
result += command + '{' + latexify(this, this.body, expandMacro) + '}'; | ||
case '': // mode = text | ||
if ( | ||
/^\\(mathbin|mathrel|mathopen|mathclose|mathpunct|mathord|mathinner)/.test( | ||
command | ||
) | ||
) { | ||
result += | ||
command + | ||
'{' + | ||
latexify(this, this.body, expandMacro) + | ||
'}'; | ||
} else if (command === '\\char"') { | ||
@@ -472,3 +554,5 @@ result += this.latex + ' '; | ||
result += '\\unicode{"'; | ||
result += ('000000' + this.body.charCodeAt(0).toString(16)).toUpperCase().substr(-6); | ||
result += ('000000' + this.body.charCodeAt(0).toString(16)) | ||
.toUpperCase() | ||
.substr(-6); | ||
result += '}'; | ||
@@ -485,3 +569,4 @@ } else if (this.latex || typeof this.body === 'string') { | ||
} else { | ||
result += this.body !== '\u200b' ? (this.latex || this.body) : ''; | ||
result += | ||
this.body !== '\u200b' ? this.latex || this.body : ''; | ||
} | ||
@@ -496,6 +581,14 @@ } | ||
// The argument to mathop is math, therefor this.body can be an expression | ||
result += command + '{' + latexify(this, this.body, expandMacro) + '}'; | ||
result += | ||
command + | ||
'{' + | ||
latexify(this, this.body, expandMacro) + | ||
'}'; | ||
} else if (command === '\\operatorname') { | ||
// The argument to operator name is text, therefore this.body is a string | ||
result += command + '{' + this.body + '}'; | ||
// The argument to `\operatorname` is 'math' and needs to be latexified | ||
result += | ||
command + | ||
'{' + | ||
latexify(this, this.body, expandMacro) + | ||
'}'; | ||
} else { | ||
@@ -510,3 +603,6 @@ if (this.latex && this.latex[0] === '\\') { | ||
} else { | ||
result += this.body !== '\u200b' ? (this.latex || this.body) : ''; | ||
result += | ||
this.body !== '\u200b' | ||
? this.latex || this.body | ||
: ''; | ||
} | ||
@@ -521,12 +617,15 @@ } | ||
case 'box': | ||
if (command === '\\bbox') { | ||
result += command; | ||
if (isFinite(this.padding) || | ||
if ( | ||
isFinite(this.padding) || | ||
typeof this.border !== 'undefined' || | ||
typeof this.backgroundcolor !== 'undefined') { | ||
typeof this.backgroundcolor !== 'undefined' | ||
) { | ||
const bboxParams = []; | ||
if (isFinite(this.padding)) { | ||
bboxParams.push(Math.floor(1e2 * this.padding) / 1e2 + 'em') | ||
bboxParams.push( | ||
Math.floor(1e2 * this.padding) / 1e2 + 'em' | ||
); | ||
} | ||
@@ -537,3 +636,5 @@ if (this.border) { | ||
if (this.backgroundcolor) { | ||
bboxParams.push(Color.colorToString(this.backgroundcolor)); | ||
bboxParams.push( | ||
Color.colorToString(this.backgroundcolor) | ||
); | ||
} | ||
@@ -569,3 +670,3 @@ result += `[${bboxParams.join(',')}]`; | ||
} else { | ||
result += '0em' | ||
result += '0em'; | ||
} | ||
@@ -580,3 +681,2 @@ result += '}'; | ||
break; | ||
@@ -590,4 +690,9 @@ | ||
for (const notation in this.notation) { | ||
if (Object.prototype.hasOwnProperty.call(this.notation, notation) && | ||
this.notation[notation]) { | ||
if ( | ||
Object.prototype.hasOwnProperty.call( | ||
this.notation, | ||
notation | ||
) && | ||
this.notation[notation] | ||
) { | ||
result += sep + notation; | ||
@@ -602,4 +707,11 @@ sep = ' '; | ||
sep = ''; | ||
if (this.backgroundcolor && this.backgroundcolor !== 'transparent') { | ||
style += sep + 'mathbackground="' + Color.colorToString(this.backgroundcolor) + '"'; | ||
if ( | ||
this.backgroundcolor && | ||
this.backgroundcolor !== 'transparent' | ||
) { | ||
style += | ||
sep + | ||
'mathbackground="' + | ||
Color.colorToString(this.backgroundcolor) + | ||
'"'; | ||
sep = ','; | ||
@@ -614,8 +726,14 @@ } | ||
sep = ','; | ||
} else if (this.strokeColor && this.strokeColor !== 'currentColor') { | ||
style += sep + 'mathcolor="' + Color.colorToString(this.strokeColor) + '"'; | ||
} else if ( | ||
this.strokeColor && | ||
this.strokeColor !== 'currentColor' | ||
) { | ||
style += | ||
sep + | ||
'mathcolor="' + | ||
Color.colorToString(this.strokeColor) + | ||
'"'; | ||
sep = ','; | ||
} | ||
if (style) { | ||
@@ -649,8 +767,11 @@ result += `[${style}]`; | ||
default: | ||
console.warn('Unexpected atom type "' + this.type + | ||
'" in "' + (this.latex || this.value) + '"'); | ||
console.warn( | ||
'Unexpected atom type "' + | ||
this.type + | ||
'" in "' + | ||
(this.latex || this.value) + | ||
'"' | ||
); | ||
break; | ||
} | ||
@@ -660,5 +781,7 @@ if (this.superscript) { | ||
if (sup.length === 1) { | ||
if (sup === '\u2032') { // PRIME | ||
if (sup === '\u2032') { | ||
// PRIME | ||
sup = '\\prime '; | ||
} else if (sup === '\u2033') { // DOUBLE-PRIME | ||
} else if (sup === '\u2033') { | ||
// DOUBLE-PRIME | ||
sup = '\\doubleprime '; | ||
@@ -680,10 +803,5 @@ } | ||
return result; | ||
} | ||
}; | ||
// Export the public interface for this module | ||
export default { | ||
} | ||
export default {}; |
@@ -14,3 +14,2 @@ /** | ||
const SPECIAL_OPERATORS = { | ||
@@ -41,13 +40,14 @@ '\\pm': '±', | ||
'\\check': 'ˇ', | ||
'\\hat': '^' | ||
'\\hat': '^', | ||
}; | ||
function xmlEscape(str) { | ||
return str | ||
// .replace(/&/g, '&') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, ''') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>'); | ||
return ( | ||
str | ||
// .replace(/&/g, '&') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, ''') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
); | ||
} | ||
@@ -62,3 +62,2 @@ | ||
function scanIdentifier(stream, final, options) { | ||
@@ -73,5 +72,7 @@ let result = false; | ||
if (stream.index < final && | ||
if ( | ||
stream.index < final && | ||
(atom.type === 'mord' || atom.type === 'textord') && | ||
'0123456789,.'.indexOf(atom.body) < 0) { | ||
'0123456789,.'.indexOf(atom.body) < 0 | ||
) { | ||
body = atom.toMathML(options); | ||
@@ -102,4 +103,10 @@ if (atom.superscript) { | ||
mathML = '<msubsup>' + body; | ||
mathML += toMathML(stream.atoms[subscript].subscript, 0, 0, options).mathML; | ||
mathML += toMathML(stream.atoms[superscript].superscript, 0, 0, options).mathML; | ||
mathML += toMathML(stream.atoms[subscript].subscript, 0, 0, options) | ||
.mathML; | ||
mathML += toMathML( | ||
stream.atoms[superscript].superscript, | ||
0, | ||
0, | ||
options | ||
).mathML; | ||
mathML += '</msubsup>'; | ||
@@ -110,9 +117,25 @@ } else if (superscript >= 0) { | ||
// There's another superscript after this one. Maybe double-prime? | ||
const sup = toMathML(stream.atoms[superscript].superscript, 0, 0, options).mathML; | ||
const sup = toMathML( | ||
stream.atoms[superscript].superscript, | ||
0, | ||
0, | ||
options | ||
).mathML; | ||
const sup2 = toMathML(stream.atoms[superscript + 1].superscript, 0, 0, options).mathML; | ||
if ((sup === '<mi>\u2032</mi>' || sup === '<mi>′</mi>') && | ||
(sup2 === '<mi>\u2032</mi>' || sup2 === '<mi>′</mi>')) { | ||
const sup2 = toMathML( | ||
stream.atoms[superscript + 1].superscript, | ||
0, | ||
0, | ||
options | ||
).mathML; | ||
if ( | ||
(sup === '<mi>\u2032</mi>' || | ||
sup === '<mi>′</mi>') && | ||
(sup2 === '<mi>\u2032</mi>' || sup2 === '<mi>′</mi>') | ||
) { | ||
mathML += '<mi>″</mi>'; | ||
} else if (sup === '<mi>\u2032</mi>' || sup === '<mi>′</mi>') { | ||
} else if ( | ||
sup === '<mi>\u2032</mi>' || | ||
sup === '<mi>′</mi>' | ||
) { | ||
mathML += '<mi>′</mi>'; | ||
@@ -122,5 +145,9 @@ } else { | ||
} | ||
} else { | ||
mathML += toMathML(stream.atoms[superscript].superscript, 0, 0, options).mathML; | ||
mathML += toMathML( | ||
stream.atoms[superscript].superscript, | ||
0, | ||
0, | ||
options | ||
).mathML; | ||
} | ||
@@ -130,3 +157,4 @@ mathML += '</msup>'; | ||
mathML = '<msub>' + body; | ||
mathML += toMathML(stream.atoms[subscript].subscript, 0, 0, options).mathML; | ||
mathML += toMathML(stream.atoms[subscript].subscript, 0, 0, options) | ||
.mathML; | ||
mathML += '</msub>'; | ||
@@ -137,7 +165,9 @@ } else { | ||
if ((stream.lastType === 'mi' || | ||
stream.lastType === 'mn' || | ||
stream.lastType === 'mtext' || | ||
stream.lastType === 'fence') && | ||
!/^<mo>(.*)<\/mo>$/.test(mathML)) { | ||
if ( | ||
(stream.lastType === 'mi' || | ||
stream.lastType === 'mn' || | ||
stream.lastType === 'mtext' || | ||
stream.lastType === 'fence') && | ||
!/^<mo>(.*)<\/mo>$/.test(mathML) | ||
) { | ||
mathML = '<mo>⁢</mo>' + mathML; | ||
@@ -159,4 +189,2 @@ } | ||
/** | ||
@@ -171,19 +199,18 @@ * Return true if the current atom is a standalone superscript atom | ||
function isSuperscriptAtom(stream) { | ||
return stream.index < stream.atoms.length && | ||
return ( | ||
stream.index < stream.atoms.length && | ||
stream.atoms[stream.index].superscript && | ||
stream.atoms[stream.index].type === 'msubsup' | ||
); | ||
} | ||
function isSubscriptAtom(stream) { | ||
return stream.index < stream.atoms.length && | ||
return ( | ||
stream.index < stream.atoms.length && | ||
stream.atoms[stream.index].subscript && | ||
stream.atoms[stream.index].type === 'msubsup' | ||
); | ||
} | ||
function indexOfSuperscriptInNumber(stream) { | ||
let result = -1; | ||
@@ -194,6 +221,7 @@ let i = stream.index; | ||
while (i < stream.atoms.length && !done && !found) { | ||
done = stream.atoms[i].type !== 'mord' || | ||
done = | ||
stream.atoms[i].type !== 'mord' || | ||
'0123456789,.'.indexOf(stream.atoms[i].body) < 0; | ||
found = !done && stream.atoms[i].superscript; | ||
i++ | ||
i++; | ||
} | ||
@@ -208,4 +236,2 @@ | ||
function parseSubsup(base, stream, options) { | ||
@@ -249,3 +275,2 @@ let result = false; | ||
function scanText(stream, final, options) { | ||
@@ -256,6 +281,6 @@ let result = false; | ||
let mathML = ''; | ||
while (stream.index < final && | ||
stream.atoms[stream.index].mode === 'text' | ||
) { | ||
mathML += stream.atoms[stream.index].body ? stream.atoms[stream.index].body : ' '; | ||
while (stream.index < final && stream.atoms[stream.index].mode === 'text') { | ||
mathML += stream.atoms[stream.index].body | ||
? stream.atoms[stream.index].body | ||
: ' '; | ||
stream.index += 1; | ||
@@ -266,3 +291,8 @@ } | ||
result = true; | ||
mathML = '<mtext' + makeID(stream.atoms[initial].id, options) + '>' + mathML + '</mtext>'; | ||
mathML = | ||
'<mtext' + | ||
makeID(stream.atoms[initial].id, options) + | ||
'>' + | ||
mathML + | ||
'</mtext>'; | ||
@@ -287,3 +317,4 @@ stream.mathML += mathML; | ||
while (stream.index < final && | ||
while ( | ||
stream.index < final && | ||
stream.atoms[stream.index].type === 'mord' && | ||
@@ -296,6 +327,10 @@ '0123456789,.'.indexOf(stream.atoms[stream.index].body) >= 0 | ||
if (mathML.length > 0) { | ||
result = true; | ||
mathML = '<mn' + makeID(stream.atoms[initial].id, options) + '>' + mathML + '</mn>'; | ||
mathML = | ||
'<mn' + | ||
makeID(stream.atoms[initial].id, options) + | ||
'>' + | ||
mathML + | ||
'</mn>'; | ||
@@ -309,3 +344,8 @@ if (superscript < 0 && isSuperscriptAtom(stream)) { | ||
mathML = '<msup>' + mathML; | ||
mathML += toMathML(stream.atoms[superscript].superscript, 0, 0, options).mathML; | ||
mathML += toMathML( | ||
stream.atoms[superscript].superscript, | ||
0, | ||
0, | ||
options | ||
).mathML; | ||
mathML += '</msup>'; | ||
@@ -327,4 +367,3 @@ } | ||
if (stream.index < final && | ||
stream.atoms[stream.index].type === 'mopen') { | ||
if (stream.index < final && stream.atoms[stream.index].type === 'mopen') { | ||
let found = false; | ||
@@ -352,3 +391,4 @@ let depth = 0; | ||
mathML += toMathML(stream.atoms, openIndex + 1, closeIndex, options).mathML; | ||
mathML += toMathML(stream.atoms, openIndex + 1, closeIndex, options) | ||
.mathML; | ||
@@ -359,6 +399,8 @@ // TODO: could add attribute indicating it's a fence (fence=true) | ||
if (stream.lastType === 'mi' || | ||
if ( | ||
stream.lastType === 'mi' || | ||
stream.lastType === 'mn' || | ||
stream.lastType === 'mfrac' || | ||
stream.lastType === 'fence') { | ||
stream.lastType === 'fence' | ||
) { | ||
mathML = '<mo>⁢</mo>' + mathML; | ||
@@ -394,4 +436,6 @@ } | ||
if (stream.index < final && ( | ||
atom.type === 'mbin' || atom.type === 'mrel')) { | ||
if ( | ||
stream.index < final && | ||
(atom.type === 'mbin' || atom.type === 'mrel') | ||
) { | ||
mathML += stream.atoms[stream.index].toMathML(options); | ||
@@ -403,3 +447,3 @@ stream.index += 1; | ||
if ((atom.limits === 'limits') && (atom.superscript || atom.subscript)) { | ||
if (atom.limits === 'limits' && (atom.superscript || atom.subscript)) { | ||
// Operator with limits, e.g. \sum | ||
@@ -409,25 +453,34 @@ const op = toMo(atom, options); | ||
// Both superscript and subscript | ||
mathML += (atom.limits !== 'nolimits' ? '<munderover>' : '<msubsup>') + op; | ||
mathML += | ||
(atom.limits !== 'nolimits' | ||
? '<munderover>' | ||
: '<msubsup>') + op; | ||
mathML += toMathML(atom.subscript, 0, 0, options).mathML; | ||
mathML += toMathML(atom.superscript, 0, 0, options).mathML; | ||
mathML += (atom.limits !== 'nolimits' ? '</munderover>' : '</msubsup>'); | ||
mathML += | ||
atom.limits !== 'nolimits' ? '</munderover>' : '</msubsup>'; | ||
} else if (atom.superscript) { | ||
// Superscript only | ||
mathML += (atom.limits !== 'nolimits' ? '<mover>' : '<msup>') + op; | ||
mathML += | ||
(atom.limits !== 'nolimits' ? '<mover>' : '<msup>') + op; | ||
mathML += toMathML(atom.superscript, 0, 0, options).mathML; | ||
mathML += (atom.limits !== 'nolimits' ? '</mover>' : '</msup>'); | ||
mathML += atom.limits !== 'nolimits' ? '</mover>' : '</msup>'; | ||
} else { | ||
// Subscript only | ||
mathML += (atom.limits !== 'nolimits' ? '<munder>' : '<msub>') + op; | ||
mathML += | ||
(atom.limits !== 'nolimits' ? '<munder>' : '<msub>') + op; | ||
mathML += toMathML(atom.subscript, 0, 0, options).mathML; | ||
mathML += (atom.limits !== 'nolimits' ? '</munder>' : '</msub>'); | ||
mathML += atom.limits !== 'nolimits' ? '</munder>' : '</msub>'; | ||
} | ||
lastType = 'mo'; | ||
} else { | ||
const atom = stream.atoms[stream.index]; | ||
const isUnit = atom.latex.indexOf('\\operatorname') === 0; | ||
const op = isUnit ? | ||
'<mi class="MathML-Unit"' + makeID(atom.id, options) + '>' + toString(atom.body) + '</mi>' : | ||
toMo(atom, options); | ||
const op = isUnit | ||
? '<mi class="MathML-Unit"' + | ||
makeID(atom.id, options) + | ||
'>' + | ||
toString(atom.body) + | ||
'</mi>' | ||
: toMo(atom, options); | ||
mathML += op; | ||
@@ -442,3 +495,3 @@ stream.index += 1; | ||
if (!isUnit && !/^<mo>(.*)<\/mo>$/.test(op)) { | ||
mathML += '<mo>⁡</mo>'; // APPLY FUNCTION | ||
mathML += '<mo>⁡</mo>'; // APPLY FUNCTION | ||
// mathML += scanArgument(stream); | ||
@@ -452,4 +505,6 @@ lastType = 'applyfunction'; | ||
if ((stream.lastType === 'mi' || stream.lastType === 'mn') && | ||
!/^<mo>(.*)<\/mo>$/.test(mathML)) { | ||
if ( | ||
(stream.lastType === 'mi' || stream.lastType === 'mn') && | ||
!/^<mo>(.*)<\/mo>$/.test(mathML) | ||
) { | ||
mathML = '<mo>⁢</mo>' + mathML; | ||
@@ -469,3 +524,2 @@ } | ||
/** | ||
@@ -485,3 +539,3 @@ * Given an atom or an array of atoms, return their MathML representation as | ||
mathML: '', | ||
lastType: '' | ||
lastType: '', | ||
}; | ||
@@ -500,12 +554,17 @@ final = final || (input ? input.length : 0); | ||
while (result.index < final) { | ||
if (scanText(result, final, options) || | ||
if ( | ||
scanText(result, final, options) || | ||
scanNumber(result, final, options) || | ||
scanIdentifier(result, final, options) || | ||
scanOperator(result, final, options) || | ||
scanFence(result, final, options)) { | ||
count += 1; | ||
scanFence(result, final, options) | ||
) { | ||
count += 1; | ||
} else if (result.index < final) { | ||
let mathML = result.atoms[result.index].toMathML(options); | ||
if (result.lastType === 'mn' && mathML.length > 0 && | ||
result.atoms[result.index].type === 'genfrac') { | ||
if ( | ||
result.lastType === 'mn' && | ||
mathML.length > 0 && | ||
result.atoms[result.index].type === 'genfrac' | ||
) { | ||
// If this is a fraction preceded by a number (e.g. 2 1/2), | ||
@@ -561,3 +620,2 @@ // add an "invisible plus" (U+0264) character in front of it | ||
/** | ||
@@ -577,4 +635,4 @@ * Return a MathML fragment representation of a single atom | ||
'\\pi': 'π', | ||
'\\infty' : '∞', | ||
'\\forall' : '∀', | ||
'\\infty': '∞', | ||
'\\forall': '∀', | ||
'\\nexists': '∄', | ||
@@ -589,23 +647,23 @@ '\\exists': '∃', | ||
'\\ldotp': '\u002e', | ||
// TODO: include all the 'textord' that are identifiers, not operators. | ||
// TODO: include all the 'textord' that are identifiers, not operators. | ||
}; | ||
const MATH_VARIANTS = { | ||
'cal': 'script', | ||
'frak': 'fraktur', | ||
'bb': 'double-struck', | ||
'scr': 'script', | ||
'cmtt': 'monospace', | ||
'cmss': 'sans-serif' | ||
cal: 'script', | ||
frak: 'fraktur', | ||
bb: 'double-struck', | ||
scr: 'script', | ||
cmtt: 'monospace', | ||
cmss: 'sans-serif', | ||
}; | ||
const SPACING = { | ||
'\\!': -3 / 18, | ||
'\\ ': 6 / 18, | ||
'\\,': 3 / 18, | ||
'\\:': 4 / 18, | ||
'\\;': 5 / 18, | ||
'\\enspace': .5, | ||
'\\quad': 1, | ||
'\\qquad': 2, | ||
'\\enskip': .5, | ||
'\\!': -3 / 18, | ||
'\\ ': 6 / 18, | ||
'\\,': 3 / 18, | ||
'\\:': 4 / 18, | ||
'\\;': 5 / 18, | ||
'\\enspace': 0.5, | ||
'\\quad': 1, | ||
'\\qquad': 2, | ||
'\\enskip': 0.5, | ||
}; | ||
@@ -626,5 +684,5 @@ | ||
} else { | ||
switch(this.type) { | ||
switch (this.type) { | ||
case 'first': | ||
break; // nothing to do | ||
break; // nothing to do | ||
case 'group': | ||
@@ -634,9 +692,14 @@ case 'root': | ||
break; | ||
case 'array': | ||
if ((this.lFence && this.lFence !== '.') || | ||
(this.rFence && this.rFence !== '.')) { | ||
if ( | ||
(this.lFence && this.lFence !== '.') || | ||
(this.rFence && this.rFence !== '.') | ||
) { | ||
result += '<mrow>'; | ||
if ((this.lFence && this.lFence !== '.')) { | ||
result += '<mo>' + (SPECIAL_OPERATORS[this.lFence] || this.lFence) + '</mo>'; | ||
if (this.lFence && this.lFence !== '.') { | ||
result += | ||
'<mo>' + | ||
(SPECIAL_OPERATORS[this.lFence] || this.lFence) + | ||
'</mo>'; | ||
} | ||
@@ -649,3 +712,6 @@ } | ||
if (this.colFormat[i].align) { | ||
result += {l:'left', c:'center', r:'right'}[this.colFormat[i].align] + ' '; | ||
result += | ||
{ l: 'left', c: 'center', r: 'right' }[ | ||
this.colFormat[i].align | ||
] + ' '; | ||
} | ||
@@ -655,3 +721,3 @@ } | ||
} | ||
result += '>'; | ||
@@ -661,13 +727,22 @@ for (row = 0; row < this.array.length; row++) { | ||
for (col = 0; col < this.array[row].length; col++) { | ||
result += '<mtd>' + toMathML(this.array[row][col], 0, 0, options).mathML + '</mtd>'; | ||
result += | ||
'<mtd>' + | ||
toMathML(this.array[row][col], 0, 0, options) | ||
.mathML + | ||
'</mtd>'; | ||
} | ||
result += '</mtr>'; | ||
} | ||
result += '</mtable>'; | ||
if ((this.lFence && this.lFence !== '.') || | ||
(this.rFence && this.rFence !== '.')) { | ||
if ((this.rFence && this.rFence !== '.')) { | ||
result += '<mo>' + (SPECIAL_OPERATORS[this.lFence] || this.rFence) + '</mo>'; | ||
if ( | ||
(this.lFence && this.lFence !== '.') || | ||
(this.rFence && this.rFence !== '.') | ||
) { | ||
if (this.rFence && this.rFence !== '.') { | ||
result += | ||
'<mo>' + | ||
(SPECIAL_OPERATORS[this.lFence] || this.rFence) + | ||
'</mo>'; | ||
} | ||
@@ -677,3 +752,3 @@ result += '</mrow>'; | ||
break; | ||
case 'genfrac': | ||
@@ -684,8 +759,17 @@ if (this.leftDelim || this.rightDelim) { | ||
if (this.leftDelim && this.leftDelim !== '.') { | ||
result += '<mo' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[this.leftDelim] || this.leftDelim) + '</mo>'; | ||
result += | ||
'<mo' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[this.leftDelim] || this.leftDelim) + | ||
'</mo>'; | ||
} | ||
if (this.hasBarLine) { | ||
result += '<mfrac>'; | ||
result += toMathML(this.numer, 0, 0, options).mathML || '<mi> </mi>'; | ||
result += toMathML(this.denom, 0, 0, options).mathML || '<mi> </mi>'; | ||
result += | ||
toMathML(this.numer, 0, 0, options).mathML || | ||
'<mi> </mi>'; | ||
result += | ||
toMathML(this.denom, 0, 0, options).mathML || | ||
'<mi> </mi>'; | ||
result += '</mfrac>'; | ||
@@ -695,8 +779,20 @@ } else { | ||
result += '<mtable' + makeID(this.id, options) + '>'; | ||
result += '<mtr>' + toMathML(this.numer, 0, 0, options).mathML + '</mtr>'; | ||
result += '<mtr>' + toMathML(this.denom, 0, 0, options).mathML + '</mtr>'; | ||
result += | ||
'<mtr>' + | ||
toMathML(this.numer, 0, 0, options).mathML + | ||
'</mtr>'; | ||
result += | ||
'<mtr>' + | ||
toMathML(this.denom, 0, 0, options).mathML + | ||
'</mtr>'; | ||
result += '</mtable>'; | ||
} | ||
if (this.rightDelim && this.rightDelim !== '.') { | ||
result += '<mo' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[this.rightDelim] || this.rightDelim) + '</mo>'; | ||
result += | ||
'<mo' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[this.rightDelim] || | ||
this.rightDelim) + | ||
'</mo>'; | ||
} | ||
@@ -706,4 +802,4 @@ if (this.leftDelim || this.rightDelim) { | ||
} | ||
break; | ||
break; | ||
case 'surd': | ||
@@ -721,3 +817,3 @@ if (this.index) { | ||
break; | ||
case 'leftright': | ||
@@ -727,28 +823,48 @@ // TODO: could add fence=true attribute | ||
if (this.leftDelim && this.leftDelim !== '.') { | ||
result += '<mo' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[this.leftDelim] || this.leftDelim) + '</mo>'; | ||
result += | ||
'<mo' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[this.leftDelim] || this.leftDelim) + | ||
'</mo>'; | ||
} | ||
if (this.body) result += toMathML(this.body, 0, 0, options).mathML; | ||
if (this.body) | ||
result += toMathML(this.body, 0, 0, options).mathML; | ||
if (this.rightDelim && this.rightDelim !== '.') { | ||
result += '<mo' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[this.rightDelim] || this.rightDelim) + '</mo>'; | ||
result += | ||
'<mo' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[this.rightDelim] || | ||
this.rightDelim) + | ||
'</mo>'; | ||
} | ||
result += '</mrow>'; | ||
break; | ||
case 'sizeddelim': | ||
case 'delim': | ||
result += '<mo separator="true"' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[this.delim] || this.delim) + '</mo>'; | ||
result += | ||
'<mo separator="true"' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[this.delim] || this.delim) + | ||
'</mo>'; | ||
break; | ||
case 'accent': | ||
result += '<mover accent="true"' + makeID(this.id, options) + '>'; | ||
result += | ||
'<mover accent="true"' + makeID(this.id, options) + '>'; | ||
result += toMathML(this.body, 0, 0, options).mathML; | ||
result += '<mo>' + (SPECIAL_OPERATORS[command] || this.accent) + '</mo>'; | ||
result += '</mover>' | ||
result += | ||
'<mo>' + | ||
(SPECIAL_OPERATORS[command] || this.accent) + | ||
'</mo>'; | ||
result += '</mover>'; | ||
break; | ||
case 'line': | ||
case 'overlap': | ||
break; | ||
case 'overunder': | ||
@@ -764,3 +880,8 @@ overscript = this.overscript; | ||
body = this.body[0].body; | ||
} else if (this.body[0] && this.body[0].type === 'first' && this.body[1] && this.body[1].underscript) { | ||
} else if ( | ||
this.body[0] && | ||
this.body[0].type === 'first' && | ||
this.body[1] && | ||
this.body[1].underscript | ||
) { | ||
underscript = this.body[1].underscript; | ||
@@ -774,3 +895,8 @@ body = this.body[1].body; | ||
body = this.body[0].body; | ||
} else if (this.body[0] && this.body[0].type === 'first' && this.body[1] && this.body[1].overscript) { | ||
} else if ( | ||
this.body[0] && | ||
this.body[0].type === 'first' && | ||
this.body[1] && | ||
this.body[1].overscript | ||
) { | ||
overscript = this.body[1].overscript; | ||
@@ -780,5 +906,10 @@ body = this.body[1].body; | ||
} | ||
if (overscript && underscript) { | ||
result += '<munderover' + variant + makeID(this.id, options) + '>' + toMathML(body, 0, 0, options).mathML; | ||
result += | ||
'<munderover' + | ||
variant + | ||
makeID(this.id, options) + | ||
'>' + | ||
toMathML(body, 0, 0, options).mathML; | ||
result += toMathML(underscript, 0, 0, options).mathML; | ||
@@ -788,7 +919,17 @@ result += toMathML(overscript, 0, 0, options).mathML; | ||
} else if (overscript) { | ||
result += '<mover' + variant + makeID(this.id, options) + '>' + toMathML(body, 0, 0, options).mathML; | ||
result += | ||
'<mover' + | ||
variant + | ||
makeID(this.id, options) + | ||
'>' + | ||
toMathML(body, 0, 0, options).mathML; | ||
result += toMathML(overscript, 0, 0, options).mathML; | ||
result += '</mover>'; | ||
} else if (underscript) { | ||
result += '<munder' + variant + makeID(this.id, options) + '>' + toMathML(body, 0, 0, options).mathML; | ||
result += | ||
'<munder' + | ||
variant + | ||
makeID(this.id, options) + | ||
'>' + | ||
toMathML(body, 0, 0, options).mathML; | ||
result += toMathML(underscript, 0, 0, options).mathML; | ||
@@ -798,16 +939,28 @@ result += '</munder>'; | ||
break; | ||
case 'placeholder': // no real equivalent in MathML -- will generate a '?'qq | ||
case 'placeholder': // no real equivalent in MathML -- will generate a '?'qq | ||
case 'mord': { | ||
result = SPECIAL_IDENTIFIERS[command] || command || (typeof this.body === 'string' ? this.body : ''); | ||
const m = command ? command.match(/[{]?\\char"([0-9abcdefABCDEF]*)[}]?/) : null; | ||
result = | ||
SPECIAL_IDENTIFIERS[command] || | ||
command || | ||
(typeof this.body === 'string' ? this.body : ''); | ||
const m = command | ||
? command.match(/[{]?\\char"([0-9abcdefABCDEF]*)[}]?/) | ||
: null; | ||
if (m) { | ||
// It's a \char command | ||
result = '&#x' + m[1] + ';' | ||
result = '&#x' + m[1] + ';'; | ||
} else if (result.length > 0 && result.charAt(0) === '\\') { | ||
// This is an identifier with no special handling. Use the | ||
// Unicode value | ||
if (typeof this.body === 'string' && this.body.charCodeAt(0) > 255) { | ||
result = '&#x' + ('000000' + | ||
this.body.charCodeAt(0).toString(16)).substr(-4) + ';'; | ||
if ( | ||
typeof this.body === 'string' && | ||
this.body.charCodeAt(0) > 255 | ||
) { | ||
result = | ||
'&#x' + | ||
( | ||
'000000' + this.body.charCodeAt(0).toString(16) | ||
).substr(-4) + | ||
';'; | ||
} else if (typeof this.body === 'string') { | ||
@@ -820,3 +973,12 @@ result = this.body.charAt(0); | ||
const tag = /\d/.test(result) ? 'mn' : 'mi'; | ||
result = '<' + tag + variant + makeID(this.id, options) + '>' + xmlEscape(result) + '</' + tag + '>'; | ||
result = | ||
'<' + | ||
tag + | ||
variant + | ||
makeID(this.id, options) + | ||
'>' + | ||
xmlEscape(result) + | ||
'</' + | ||
tag + | ||
'>'; | ||
break; | ||
@@ -830,5 +992,15 @@ } | ||
// Some 'textord' are actually identifiers. Check them here. | ||
result = '<mi' + makeID(this.id, options) + '>' + SPECIAL_IDENTIFIERS[command] + '</mi>'; | ||
result = | ||
'<mi' + | ||
makeID(this.id, options) + | ||
'>' + | ||
SPECIAL_IDENTIFIERS[command] + | ||
'</mi>'; | ||
} else if (command && SPECIAL_OPERATORS[command]) { | ||
result = '<mo' + makeID(this.id, options) + '>' + SPECIAL_OPERATORS[command] + '</mo>'; | ||
result = | ||
'<mo' + | ||
makeID(this.id, options) + | ||
'>' + | ||
SPECIAL_OPERATORS[command] + | ||
'</mo>'; | ||
} else { | ||
@@ -838,7 +1010,12 @@ result = toMo(this, options); | ||
break; | ||
case 'mpunct': | ||
result = '<mo separator="true"' + makeID(this.id, options) + '>' + (SPECIAL_OPERATORS[command] || command) + '</mo>'; | ||
result = | ||
'<mo separator="true"' + | ||
makeID(this.id, options) + | ||
'>' + | ||
(SPECIAL_OPERATORS[command] || command) + | ||
'</mo>'; | ||
break; | ||
case 'mop': | ||
@@ -856,3 +1033,3 @@ if (this.body !== '\u200b') { | ||
break; | ||
case 'mathstyle': | ||
@@ -868,20 +1045,32 @@ // TODO: mathstyle is a switch. Need to figure out its scope to properly wrap it around a <mstyle> tag | ||
break; | ||
case 'box': | ||
result = '<menclose notation="box"'; | ||
if (this.backgroundcolor) { | ||
result += ' mathbackground="' + Color.stringToColor(this.backgroundcolor) + '"'; | ||
result += | ||
' mathbackground="' + | ||
Color.stringToColor(this.backgroundcolor) + | ||
'"'; | ||
} | ||
result += makeID(this.id, options) + '>' + toMathML(this.body, 0, 0, options).mathML + '</menclose>'; | ||
result += | ||
makeID(this.id, options) + | ||
'>' + | ||
toMathML(this.body, 0, 0, options).mathML + | ||
'</menclose>'; | ||
break; | ||
case 'spacing': | ||
result += '<mspace width="' + (SPACING[command] || 0) + 'em"/>'; | ||
break; | ||
case 'enclose': | ||
result = '<menclose notation="'; | ||
for (const notation in this.notation) { | ||
if (Object.prototype.hasOwnProperty.call(this.notation, notation) && | ||
this.notation[notation]) { | ||
if ( | ||
Object.prototype.hasOwnProperty.call( | ||
this.notation, | ||
notation | ||
) && | ||
this.notation[notation] | ||
) { | ||
result += sep + notation; | ||
@@ -891,26 +1080,26 @@ sep = ' '; | ||
} | ||
result += makeID(this.id, options) + '">' + toMathML(this.body, 0, 0, options).mathML + '</menclose>'; | ||
result += | ||
makeID(this.id, options) + | ||
'">' + | ||
toMathML(this.body, 0, 0, options).mathML + | ||
'</menclose>'; | ||
break; | ||
case 'space': | ||
result += ' ' | ||
result += ' '; | ||
break; | ||
default: | ||
console.log("In conversion to MathML, unknown type : " + this.type); | ||
console.log( | ||
'In conversion to MathML, unknown type : ' + this.type | ||
); | ||
} | ||
} | ||
return result; | ||
} | ||
}; | ||
MathAtom.toMathML = function(atoms, options) { | ||
return toMathML(atoms, 0, 0, options).mathML; | ||
} | ||
}; | ||
// Export the public interface for this module | ||
export default { | ||
} | ||
export default {}; |
@@ -25,87 +25,92 @@ import MathAtom from '../core/mathAtom.js'; | ||
const PRONUNCIATION = { | ||
'\\alpha': 'alpha ', | ||
'\\mu': 'mew ', | ||
'\\sigma': 'sigma ', | ||
'\\pi': 'pie ', | ||
'\\alpha': 'alpha ', | ||
'\\mu': 'mew ', | ||
'\\sigma': 'sigma ', | ||
'\\pi': 'pie ', | ||
'\\imaginaryI': 'eye ', | ||
'\\sum': 'Summation ', | ||
'\\prod': 'Product ', | ||
'\\sum': 'Summation ', | ||
'\\prod': 'Product ', | ||
'a': '<phoneme alphabet="ipa" ph="eɪ">a</phoneme>', | ||
'A': 'capital <phoneme alphabet="ipa" ph="eɪ">A</phoneme>', | ||
'+': 'plus ', | ||
'-': 'minus ', | ||
';': '<break time="150ms"/> semi-colon <break time="150ms"/>', | ||
',': '<break time="150ms"/> comma <break time="150ms"/>', | ||
'|': '<break time="150ms"/>Vertical bar<break time="150ms"/>', | ||
'(': '<break time="150ms"/>Open paren. <break time="150ms"/>', | ||
')': '<break time="150ms"/> Close paren. <break time="150ms"/>', | ||
'=': 'equals ', | ||
'<': 'is less than ', | ||
'\\lt': 'is less than ', | ||
'<=': 'is less than or equal to ', | ||
'\\le': 'is less than or equal to ', | ||
'\\gt': 'is greater than ', | ||
'>': 'is greater than ', | ||
'\\ge': 'is greater than or equal to ', | ||
'\\geq': 'is greater than or equal to ', | ||
'\\leq': 'is less than or equal to ', | ||
'!': 'factorial ', | ||
'\\sin': 'sine ', | ||
'\\cos': 'cosine ', | ||
'\u200b': '', | ||
'\u2212': 'minus ', | ||
':': '<break time="150ms"/> such that <break time="200ms"/> ', | ||
'\\colon': '<break time="150ms"/> such that <break time="200ms"/> ', | ||
'\\hbar': 'etch bar ', | ||
'\\iff': '<break time="200ms"/>if, and only if, <break time="200ms"/>', | ||
'\\Longleftrightarrow': '<break time="200ms"/>if, and only if, <break time="200ms"/>', | ||
'\\land': 'and ', | ||
'\\lor': 'or ', | ||
'\\neg': 'not ', | ||
'\\div': 'divided by ', | ||
a: '<phoneme alphabet="ipa" ph="eɪ">a</phoneme>', | ||
A: 'capital <phoneme alphabet="ipa" ph="eɪ">A</phoneme>', | ||
'+': 'plus ', | ||
'-': 'minus ', | ||
';': '<break time="150ms"/> semi-colon <break time="150ms"/>', | ||
',': '<break time="150ms"/> comma <break time="150ms"/>', | ||
'|': '<break time="150ms"/>Vertical bar<break time="150ms"/>', | ||
'(': '<break time="150ms"/>Open paren. <break time="150ms"/>', | ||
')': '<break time="150ms"/> Close paren. <break time="150ms"/>', | ||
'=': 'equals ', | ||
'<': 'is less than ', | ||
'\\lt': 'is less than ', | ||
'<=': 'is less than or equal to ', | ||
'\\le': 'is less than or equal to ', | ||
'\\gt': 'is greater than ', | ||
'>': 'is greater than ', | ||
'\\ge': 'is greater than or equal to ', | ||
'\\geq': 'is greater than or equal to ', | ||
'\\leq': 'is less than or equal to ', | ||
'!': 'factorial ', | ||
'\\sin': 'sine ', | ||
'\\cos': 'cosine ', | ||
'\u200b': '', | ||
'\u2212': 'minus ', | ||
':': '<break time="150ms"/> such that <break time="200ms"/> ', | ||
'\\colon': '<break time="150ms"/> such that <break time="200ms"/> ', | ||
'\\hbar': 'etch bar ', | ||
'\\iff': '<break time="200ms"/>if, and only if, <break time="200ms"/>', | ||
'\\Longleftrightarrow': | ||
'<break time="200ms"/>if, and only if, <break time="200ms"/>', | ||
'\\land': 'and ', | ||
'\\lor': 'or ', | ||
'\\neg': 'not ', | ||
'\\div': 'divided by ', | ||
'\\forall': 'for all ', | ||
'\\exists': 'there exists ', | ||
'\\nexists': 'there does not exists ', | ||
'\\forall': 'for all ', | ||
'\\exists': 'there exists ', | ||
'\\nexists': 'there does not exists ', | ||
'\\in': 'element of ', | ||
'\\in': 'element of ', | ||
'\\N': 'the set <break time="150ms"/><say-as interpret-as="character">n</say-as>', | ||
'\\C': 'the set <break time="150ms"/><say-as interpret-as="character">c</say-as>', | ||
'\\Z': 'the set <break time="150ms"/><say-as interpret-as="character">z</say-as>', | ||
'\\Q': 'the set <break time="150ms"/><say-as interpret-as="character">q</say-as>', | ||
'\\N': | ||
'the set <break time="150ms"/><say-as interpret-as="character">n</say-as>', | ||
'\\C': | ||
'the set <break time="150ms"/><say-as interpret-as="character">c</say-as>', | ||
'\\Z': | ||
'the set <break time="150ms"/><say-as interpret-as="character">z</say-as>', | ||
'\\Q': | ||
'the set <break time="150ms"/><say-as interpret-as="character">q</say-as>', | ||
'\\infty': 'infinity ', | ||
'\\infty': 'infinity ', | ||
'\\nabla': 'nabla ', | ||
'\\nabla': 'nabla ', | ||
'\\partial': 'partial derivative of ', | ||
'\\partial': 'partial derivative of ', | ||
'\\cdots': 'dot dot dot ', | ||
'\\cdots': 'dot dot dot ', | ||
'\\Rightarrow': 'implies ', | ||
'\\lbrace': '<break time="150ms"/>open brace<break time="150ms"/>', | ||
'\\{': '<break time="150ms"/>open brace<break time="150ms"/>', | ||
'\\rbrace': '<break time="150ms"/>close brace<break time="150ms"/>', | ||
'\\}': '<break time="150ms"/>close brace<break time="150ms"/>', | ||
'\\langle': '<break time="150ms"/>left angle bracket<break time="150ms"/>', | ||
'\\rangle': '<break time="150ms"/>right angle bracket<break time="150ms"/>', | ||
'\\lfloor': '<break time="150ms"/>open floor<break time="150ms"/>', | ||
'\\rfloor': '<break time="150ms"/>close floor<break time="150ms"/>', | ||
'\\lceil': '<break time="150ms"/>open ceiling<break time="150ms"/>', | ||
'\\rceil': '<break time="150ms"/>close ceiling<break time="150ms"/>', | ||
'\\vert': '<break time="150ms"/>vertical bar<break time="150ms"/>', | ||
'\\mvert': '<break time="150ms"/>divides<break time="150ms"/>', | ||
'\\lvert': '<break time="150ms"/>left vertical bar<break time="150ms"/>', | ||
'\\rvert': '<break time="150ms"/>right vertical bar<break time="150ms"/>', | ||
'\\lbrace': '<break time="150ms"/>open brace<break time="150ms"/>', | ||
'\\{': '<break time="150ms"/>open brace<break time="150ms"/>', | ||
'\\rbrace': '<break time="150ms"/>close brace<break time="150ms"/>', | ||
'\\}': '<break time="150ms"/>close brace<break time="150ms"/>', | ||
'\\langle': '<break time="150ms"/>left angle bracket<break time="150ms"/>', | ||
'\\rangle': '<break time="150ms"/>right angle bracket<break time="150ms"/>', | ||
'\\lfloor': '<break time="150ms"/>open floor<break time="150ms"/>', | ||
'\\rfloor': '<break time="150ms"/>close floor<break time="150ms"/>', | ||
'\\lceil': '<break time="150ms"/>open ceiling<break time="150ms"/>', | ||
'\\rceil': '<break time="150ms"/>close ceiling<break time="150ms"/>', | ||
'\\vert': '<break time="150ms"/>vertical bar<break time="150ms"/>', | ||
'\\mvert': '<break time="150ms"/>divides<break time="150ms"/>', | ||
'\\lvert': '<break time="150ms"/>left vertical bar<break time="150ms"/>', | ||
'\\rvert': '<break time="150ms"/>right vertical bar<break time="150ms"/>', | ||
// '\\lbrack': 'left bracket', | ||
// '\\rbrack': 'right bracket', | ||
'\\lbrack': '<break time="150ms"/> open square bracket <break time="150ms"/>', | ||
'\\rbrack': '<break time="150ms"/> close square bracket <break time="150ms"/>', | ||
'\\lbrack': | ||
'<break time="150ms"/> open square bracket <break time="150ms"/>', | ||
'\\rbrack': | ||
'<break time="150ms"/> close square bracket <break time="150ms"/>', | ||
@@ -116,9 +121,8 @@ // need to add code to detect singluar/plural. Until then spoken as plural since that is vastly more common | ||
// note: need to do this for <msup> | ||
'mm': 'millimeters', | ||
'cm': 'centimeters', | ||
'km': 'kilometers', | ||
'kg': 'kilograms', | ||
} | ||
mm: 'millimeters', | ||
cm: 'centimeters', | ||
km: 'kilometers', | ||
kg: 'kilograms', | ||
}; | ||
function getSpokenName(latex) { | ||
@@ -139,3 +143,2 @@ let result = Popover.NOTES[latex]; | ||
function platform(p) { | ||
@@ -150,5 +153,7 @@ let result = 'other'; | ||
result = 'android'; | ||
} else if (/(iphone)/i.test(navigator.userAgent) || | ||
/(ipod)/i.test(navigator.userAgent) || | ||
/(ipad)/i.test(navigator.userAgent)) { | ||
} else if ( | ||
/(iphone)/i.test(navigator.userAgent) || | ||
/(ipod)/i.test(navigator.userAgent) || | ||
/(ipad)/i.test(navigator.userAgent) | ||
) { | ||
result = 'ios'; | ||
@@ -163,3 +168,2 @@ } else if (/\bCrOS\b/i.test(navigator.userAgent)) { | ||
function isAtomic(mathlist) { | ||
@@ -200,6 +204,2 @@ let count = 0; | ||
MathAtom.toSpeakableFragment = function(atom, options) { | ||
@@ -218,3 +218,4 @@ function letter(c) { | ||
if (/[a-z]/.test(c)) { | ||
result += ' <say-as interpret-as="character">' + c + '</say-as>'; | ||
result += | ||
' <say-as interpret-as="character">' + c + '</say-as>'; | ||
} else if (/[A-Z]/.test(c)) { | ||
@@ -242,17 +243,34 @@ result += 'capital ' + c.toLowerCase() + ''; | ||
if (Array.isArray(atom)) { | ||
let isInDigitRun = false; // need to group sequence of digits | ||
let isInDigitRun = false; // need to group sequence of digits | ||
let isInTextRun = false; // need to group text | ||
for (let i = 0; i < atom.length; i++) { | ||
if (i < atom.length - 2 && | ||
if (atom[i].mode !== 'text') { | ||
isInTextRun = false; | ||
} | ||
if ( | ||
i < atom.length - 2 && | ||
atom[i].type === 'mopen' && | ||
atom[i + 2].type === 'mclose' && | ||
atom[i + 1].type === 'mord') { | ||
atom[i + 1].type === 'mord' | ||
) { | ||
result += ' of '; | ||
result += emph(MathAtom.toSpeakableFragment(atom[i + 1], options)); | ||
result += emph( | ||
MathAtom.toSpeakableFragment(atom[i + 1], options) | ||
); | ||
i += 2; | ||
// '.' and ',' should only be allowed if prev/next entry is a digit | ||
// However, if that isn't the case, this still works because 'toSpeakableFragment' is called in either case. | ||
} else if (atom[i].mode === 'text') { | ||
result += atom[i].body ? atom[i].body : ' '; | ||
} else if (atom[i].type === 'mord' && /[0123456789,.]/.test(atom[i].body)) { | ||
if (isInDigitRun) { | ||
} else if (atom[i].mode === 'text') { | ||
if (isInTextRun) { | ||
result += atom[i].body ? atom[i].body : ' '; | ||
} else { | ||
isInTextRun = true; | ||
result += MathAtom.toSpeakableFragment(atom[i], options); | ||
} | ||
// '.' and ',' should only be allowed if prev/next entry is a digit | ||
// However, if that isn't the case, this still works because 'toSpeakableFragment' is called in either case. | ||
// Note: the first char in a digit/text run potentially needs to have a 'mark', hence the call to 'toSpeakableFragment' | ||
} else if ( | ||
atom[i].type === 'mord' && | ||
/[0123456789,.]/.test(atom[i].body) | ||
) { | ||
if (isInDigitRun) { | ||
result += atom[i].body; | ||
@@ -264,3 +282,3 @@ } else { | ||
} else { | ||
isInDigitRun = false | ||
isInDigitRun = false; | ||
result += MathAtom.toSpeakableFragment(atom[i], options); | ||
@@ -270,3 +288,3 @@ } | ||
} else if (atom.mode === 'text') { | ||
result = atom.body; | ||
result += atom.body; | ||
} else { | ||
@@ -277,3 +295,3 @@ let numer = ''; | ||
let supsubHandled = false; | ||
switch(atom.type) { | ||
switch (atom.type) { | ||
case 'group': | ||
@@ -289,23 +307,23 @@ case 'root': | ||
const COMMON_FRACTIONS = { | ||
'1/2': ' half ', | ||
'1/3': ' one third ', | ||
'2/3': ' two third', | ||
'1/4': ' one quarter ', | ||
'3/4': ' three quarter ', | ||
'1/5': ' one fifth ', | ||
'2/5': ' two fifths ', | ||
'3/5': ' three fifths ', | ||
'4/5': ' four fifths ', | ||
'1/6': ' one sixth ', | ||
'5/6': ' five sixths ', | ||
'1/8': ' one eight ', | ||
'3/8': ' three eights ', | ||
'5/8': ' five eights ', | ||
'7/8': ' seven eights ', | ||
'1/9': ' one ninth ', | ||
'2/9': ' two ninths ', | ||
'4/9': ' four ninths ', | ||
'5/9': ' five ninths ', | ||
'7/9': ' seven ninths ', | ||
'8/9': ' eight ninths ', | ||
'1/2': ' half ', | ||
'1/3': ' one third ', | ||
'2/3': ' two third', | ||
'1/4': ' one quarter ', | ||
'3/4': ' three quarter ', | ||
'1/5': ' one fifth ', | ||
'2/5': ' two fifths ', | ||
'3/5': ' three fifths ', | ||
'4/5': ' four fifths ', | ||
'1/6': ' one sixth ', | ||
'5/6': ' five sixths ', | ||
'1/8': ' one eight ', | ||
'3/8': ' three eights ', | ||
'5/8': ' five eights ', | ||
'7/8': ' seven eights ', | ||
'1/9': ' one ninth ', | ||
'2/9': ' two ninths ', | ||
'4/9': ' four ninths ', | ||
'5/9': ' five ninths ', | ||
'7/9': ' seven ninths ', | ||
'8/9': ' eight ninths ', | ||
// '1/10': ' one tenth ', | ||
@@ -315,4 +333,8 @@ // '1/12': ' one twelfth ', | ||
}; | ||
const commonFraction = COMMON_FRACTIONS[ | ||
atomicValue(atom.numer) + '/' + atomicValue(atom.denom)]; | ||
const commonFraction = | ||
COMMON_FRACTIONS[ | ||
atomicValue(atom.numer) + | ||
'/' + | ||
atomicValue(atom.denom) | ||
]; | ||
if (commonFraction) { | ||
@@ -324,3 +346,8 @@ result = commonFraction; | ||
} else { | ||
result += ' the fraction <break time="150ms"/>' + numer + ', over <break time="150ms"/>' + denom + '.<break time="150ms"/> End fraction.<break time="150ms"/>'; | ||
result += | ||
' the fraction <break time="150ms"/>' + | ||
numer + | ||
', over <break time="150ms"/>' + | ||
denom + | ||
'.<break time="150ms"/> End fraction.<break time="150ms"/>'; | ||
} | ||
@@ -336,14 +363,31 @@ | ||
} else { | ||
result += ' the square root of <break time="200ms"/>' + body + '. <break time="200ms"/> End square root'; | ||
result += | ||
' the square root of <break time="200ms"/>' + | ||
body + | ||
'. <break time="200ms"/> End square root'; | ||
} | ||
} else { | ||
let index = MathAtom.toSpeakableFragment(atom.index, options); | ||
let index = MathAtom.toSpeakableFragment( | ||
atom.index, | ||
options | ||
); | ||
index = index.trim(); | ||
const index2 = index.replace(/<mark([^/]*)\/>/g, '') | ||
const index2 = index.replace(/<mark([^/]*)\/>/g, ''); | ||
if (index2 === '3') { | ||
result += ' the cube root of <break time="200ms"/>' + body + '. <break time="200ms"/> End cube root'; | ||
result += | ||
' the cube root of <break time="200ms"/>' + | ||
body + | ||
'. <break time="200ms"/> End cube root'; | ||
} else if (index2 === 'n') { | ||
result += ' the nth root of <break time="200ms"/>' + body + '. <break time="200ms"/> End root'; | ||
result += | ||
' the nth root of <break time="200ms"/>' + | ||
body + | ||
'. <break time="200ms"/> End root'; | ||
} else { | ||
result += ' the root with index: <break time="200ms"/>' + index + ', of <break time="200ms"/>' + body + '. <break time="200ms"/> End root'; | ||
result += | ||
' the root with index: <break time="200ms"/>' + | ||
index + | ||
', of <break time="200ms"/>' + | ||
body + | ||
'. <break time="200ms"/> End root'; | ||
} | ||
@@ -383,9 +427,13 @@ } | ||
case 'mclose': | ||
case 'textord': | ||
{ | ||
const command = atom.latex ? atom.latex.trim() : '' ; | ||
if (command === '\\mathbin' || command === '\\mathrel' || | ||
command === '\\mathopen' || command === '\\mathclose' || | ||
command === '\\mathpunct' || command === '\\mathord' || | ||
command === '\\mathinner') { | ||
case 'textord': { | ||
const command = atom.latex ? atom.latex.trim() : ''; | ||
if ( | ||
command === '\\mathbin' || | ||
command === '\\mathrel' || | ||
command === '\\mathopen' || | ||
command === '\\mathclose' || | ||
command === '\\mathpunct' || | ||
command === '\\mathord' || | ||
command === '\\mathinner' | ||
) { | ||
result = MathAtom.toSpeakableFragment(atom.body, options); | ||
@@ -408,14 +456,23 @@ break; | ||
if (atomValue) { | ||
const value = PRONUNCIATION[atomValue] || | ||
(latexValue ? PRONUNCIATION[latexValue.trim()] : ''); | ||
const value = | ||
PRONUNCIATION[atomValue] || | ||
(latexValue | ||
? PRONUNCIATION[latexValue.trim()] | ||
: ''); | ||
if (value) { | ||
result += ' ' + value; | ||
} else { | ||
const spokenName = latexValue ? | ||
getSpokenName(latexValue.trim()) : ''; | ||
const spokenName = latexValue | ||
? getSpokenName(latexValue.trim()) | ||
: ''; | ||
result += spokenName ? spokenName : letter(atomValue); | ||
result += spokenName | ||
? spokenName | ||
: letter(atomValue); | ||
} | ||
} else { | ||
result += MathAtom.toSpeakableFragment(atom.body, options); | ||
result += MathAtom.toSpeakableFragment( | ||
atom.body, | ||
options | ||
); | ||
} | ||
@@ -429,18 +486,35 @@ if (atom.type === 'mbin') { | ||
case 'mop': | ||
// @todo | ||
// @todo | ||
if (atom.body !== '\u200b') { | ||
// Not ZERO-WIDTH | ||
const trimLatex = atom.latex ? atom.latex.trim() : '' ; | ||
const trimLatex = atom.latex ? atom.latex.trim() : ''; | ||
if (trimLatex === '\\sum') { | ||
if (atom.superscript && atom.subscript) { | ||
let sup = MathAtom.toSpeakableFragment(atom.superscript, options); | ||
let sup = MathAtom.toSpeakableFragment( | ||
atom.superscript, | ||
options | ||
); | ||
sup = sup.trim(); | ||
let sub = MathAtom.toSpeakableFragment(atom.subscript, options); | ||
let sub = MathAtom.toSpeakableFragment( | ||
atom.subscript, | ||
options | ||
); | ||
sub = sub.trim(); | ||
result += ' the summation from <break time="200ms"/>' + sub + '<break time="200ms"/> to <break time="200ms"/>' + sup + '<break time="200ms"/> of <break time="150ms"/>'; | ||
result += | ||
' the summation from <break time="200ms"/>' + | ||
sub + | ||
'<break time="200ms"/> to <break time="200ms"/>' + | ||
sup + | ||
'<break time="200ms"/> of <break time="150ms"/>'; | ||
supsubHandled = true; | ||
} else if (atom.subscript) { | ||
let sub = MathAtom.toSpeakableFragment(atom.subscript, options); | ||
} else if (atom.subscript) { | ||
let sub = MathAtom.toSpeakableFragment( | ||
atom.subscript, | ||
options | ||
); | ||
sub = sub.trim(); | ||
result += ' the summation from <break time="200ms"/>' + sub + '<break time="200ms"/> of <break time="150ms"/>'; | ||
result += | ||
' the summation from <break time="200ms"/>' + | ||
sub + | ||
'<break time="200ms"/> of <break time="150ms"/>'; | ||
supsubHandled = true; | ||
@@ -452,12 +526,29 @@ } else { | ||
if (atom.superscript && atom.subscript) { | ||
let sup = MathAtom.toSpeakableFragment(atom.superscript, options); | ||
let sup = MathAtom.toSpeakableFragment( | ||
atom.superscript, | ||
options | ||
); | ||
sup = sup.trim(); | ||
let sub = MathAtom.toSpeakableFragment(atom.subscript, options); | ||
let sub = MathAtom.toSpeakableFragment( | ||
atom.subscript, | ||
options | ||
); | ||
sub = sub.trim(); | ||
result += ' the product from <break time="200ms"/>' + sub + '<break time="200ms"/> to <break time="200ms"/>' + sup + '<break time="200ms"/> of <break time="150ms"/>'; | ||
result += | ||
' the product from <break time="200ms"/>' + | ||
sub + | ||
'<break time="200ms"/> to <break time="200ms"/>' + | ||
sup + | ||
'<break time="200ms"/> of <break time="150ms"/>'; | ||
supsubHandled = true; | ||
} else if (atom.subscript) { | ||
let sub = MathAtom.toSpeakableFragment(atom.subscript, options); | ||
let sub = MathAtom.toSpeakableFragment( | ||
atom.subscript, | ||
options | ||
); | ||
sub = sub.trim(); | ||
result += ' the product from <break time="200ms"/>' + sub + '<break time="200ms"/> of <break time="150ms"/>'; | ||
result += | ||
' the product from <break time="200ms"/>' + | ||
sub + | ||
'<break time="200ms"/> of <break time="150ms"/>'; | ||
supsubHandled = true; | ||
@@ -469,7 +560,18 @@ } else { | ||
if (atom.superscript && atom.subscript) { | ||
let sup = MathAtom.toSpeakableFragment(atom.superscript, options); | ||
let sup = MathAtom.toSpeakableFragment( | ||
atom.superscript, | ||
options | ||
); | ||
sup = sup.trim(); | ||
let sub = MathAtom.toSpeakableFragment(atom.subscript, options); | ||
let sub = MathAtom.toSpeakableFragment( | ||
atom.subscript, | ||
options | ||
); | ||
sub = sub.trim(); | ||
result += ' the integral from <break time="200ms"/>' + emph(sub) + '<break time="200ms"/> to <break time="200ms"/>' + emph(sup) + ' <break time="200ms"/> of '; | ||
result += | ||
' the integral from <break time="200ms"/>' + | ||
emph(sub) + | ||
'<break time="200ms"/> to <break time="200ms"/>' + | ||
emph(sup) + | ||
' <break time="200ms"/> of '; | ||
supsubHandled = true; | ||
@@ -480,3 +582,4 @@ } else { | ||
} else if (typeof atom.body === 'string') { | ||
const value = PRONUNCIATION[atom.body] || | ||
const value = | ||
PRONUNCIATION[atom.body] || | ||
PRONUNCIATION[atom.latex.trim()]; | ||
@@ -514,6 +617,4 @@ if (value) { | ||
break; | ||
} | ||
if (!supsubHandled && atom.superscript) { | ||
let sup = MathAtom.toSpeakableFragment(atom.superscript, options); | ||
@@ -538,3 +639,6 @@ sup = sup.trim(); | ||
} else { | ||
result += ' to the <say-as interpret-as="ordinal">' + sup2 + '</say-as> power; '; | ||
result += | ||
' to the <say-as interpret-as="ordinal">' + | ||
sup2 + | ||
'</say-as> power; '; | ||
} | ||
@@ -545,3 +649,6 @@ } else { | ||
} else { | ||
result += ' raised to the <say-as interpret-as="ordinal">' + sup2 + '</say-as> power; '; | ||
result += | ||
' raised to the <say-as interpret-as="ordinal">' + | ||
sup2 + | ||
'</say-as> power; '; | ||
} | ||
@@ -561,7 +668,5 @@ } | ||
return result; | ||
} | ||
}; | ||
/** | ||
@@ -572,8 +677,10 @@ * @param {MathAtom[]} atoms The atoms to represent as speakable text. | ||
* @private | ||
*/ | ||
*/ | ||
MathAtom.toSpeakableText = function(atoms, speechOptions) { | ||
const options = speechOptions ? JSON.parse(JSON.stringify(speechOptions)) : { | ||
textToSpeechMarkup: '', // no markup | ||
textToSpeechRules: 'mathlive' | ||
}; | ||
const options = speechOptions | ||
? JSON.parse(JSON.stringify(speechOptions)) | ||
: { | ||
textToSpeechMarkup: '', // no markup | ||
textToSpeechRules: 'mathlive', | ||
}; | ||
options.speechMode = 'math'; | ||
@@ -586,11 +693,16 @@ | ||
if (options.textToSpeechMarkup) { | ||
options.textToSpeechRulesOptions = options.textToSpeechRulesOptions || {}; | ||
options.textToSpeechRulesOptions.markup = options.textToSpeechMarkup; | ||
options.textToSpeechRulesOptions = | ||
options.textToSpeechRulesOptions || {}; | ||
options.textToSpeechRulesOptions.markup = | ||
options.textToSpeechMarkup; | ||
if (options.textToSpeechRulesOptions.markup === 'ssml') { | ||
options.textToSpeechRulesOptions.markup = 'ssml_step'; | ||
} | ||
options.textToSpeechRulesOptions.rate = options.speechEngineRate; | ||
options.textToSpeechRulesOptions.rate = | ||
options.speechEngineRate; | ||
} | ||
if (options.textToSpeechRulesOptions) { | ||
window.sre.System.getInstance().setupEngine(options.textToSpeechRulesOptions); | ||
window.sre.System.getInstance().setupEngine( | ||
options.textToSpeechRulesOptions | ||
); | ||
} | ||
@@ -607,16 +719,21 @@ return window.sre.System.getInstance().toSpeech(mathML); | ||
if (options.speechEngineRate) { | ||
prosody = '<prosody rate="' + options.speechEngineRate + '">' | ||
prosody = '<prosody rate="' + options.speechEngineRate + '">'; | ||
} | ||
result = `<?xml version="1.0"?><speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">` + | ||
'<amazon:auto-breaths>' + | ||
prosody + | ||
'<p><s>' + | ||
result + | ||
'</s></p>' + | ||
(prosody ? '</prosody>' : '') + | ||
'</amazon:auto-breaths>' + | ||
'</speak>'; | ||
} else if (options.textToSpeechMarkup === 'mac' && platform('mac') === 'mac') { | ||
result = | ||
`<?xml version="1.0"?><speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">` + | ||
'<amazon:auto-breaths>' + | ||
prosody + | ||
'<p><s>' + | ||
result + | ||
'</s></p>' + | ||
(prosody ? '</prosody>' : '') + | ||
'</amazon:auto-breaths>' + | ||
'</speak>'; | ||
} else if ( | ||
options.textToSpeechMarkup === 'mac' && | ||
platform('mac') === 'mac' | ||
) { | ||
// Convert SSML to Mac markup | ||
result = result.replace(/<mark([^/]*)\/>/g, '') | ||
result = result | ||
.replace(/<mark([^/]*)\/>/g, '') | ||
.replace(/<emphasis>/g, '[[emph+]]') | ||
@@ -631,11 +748,8 @@ .replace(/<\/emphasis>/g, '') | ||
// Strip out the SSML markup | ||
result = result.replace(/<[^>]*>/g, '') | ||
.replace(/\s{2,}/g, ' '); | ||
result = result.replace(/<[^>]*>/g, '').replace(/\s{2,}/g, ' '); | ||
} | ||
return result; | ||
}; | ||
} | ||
// Export the public interface for this module | ||
export default {} | ||
export default {}; |
@@ -1,3 +0,1 @@ | ||
/** | ||
@@ -11,3 +9,2 @@ * This module contains some color dictionaries and algorithms to | ||
/* | ||
@@ -27,66 +24,65 @@ {\color{apricot}\blacksquare}{\color{aquamarine}\blacksquare}{\color{bittersweet}\blacksquare}{\color{black}\blacksquare}{\color{blue}\blacksquare}{\color{blueGreen}\blacksquare}{\color{blueviolet}\blacksquare}{\color{brickred}\blacksquare}{\color{brown}\blacksquare}{\color{burntorange}\blacksquare}{\color{cadetblue}\blacksquare}{\color{carnationpink}\blacksquare}{\color{cerulean}\blacksquare}{\color{cornflowerblue}\blacksquare}{\color{cyan}\blacksquare}{\color{dandelion}\blacksquare}{\color{darkorchid}\blacksquare}{\color{emerald}\blacksquare}{\color{forestgreen}\blacksquare}{\color{fuchsia}\blacksquare}{\color{goldenrod}\blacksquare}{\color{gray}\blacksquare}{\color{green}\blacksquare}{\color{greenyellow}\blacksquare}{\color{junglegreen}\blacksquare}{\color{lavender}\blacksquare}{\color{limegreen}\blacksquare}{\color{magenta}\blacksquare}{\color{mahogany}\blacksquare}{\color{maroon}\blacksquare}{\color{melon}\blacksquare}{\color{midnightblue}\blacksquare}{\color{mulberry}\blacksquare}{\color{navyblue}\blacksquare}{\color{olivegreen}\blacksquare}{\color{orange}\blacksquare}{\color{orangered}\blacksquare}{\color{orchid}\blacksquare}{\color{peach}\blacksquare}{\color{periwinkle}\blacksquare}{\color{pinegreen}\blacksquare}{\color{plum}\blacksquare}{\color{processblue}\blacksquare}{\color{purple}\blacksquare}{\color{rawsienna}\blacksquare}{\color{red}\blacksquare}{\color{redorange}\blacksquare}{\color{redviolet}\blacksquare}{\color{rhodamine}\blacksquare}{\color{royalblue}\blacksquare}{\color{royalpurple}\blacksquare}{\color{rubinered}\blacksquare}{\color{salmon}\blacksquare}{\color{seagreen}\blacksquare}{\color{sepia}\blacksquare}{\color{skyblue}\blacksquare}{\color{springgreen}\blacksquare}{\color{tan}\blacksquare}{\color{tealblue}\blacksquare}{\color{thistle}\blacksquare}{\color{turquoise}\blacksquare}{\color{violet}\blacksquare}{\color{violetred}\blacksquare}{\color{white}\blacksquare}{\color{wildstrawberry}\blacksquare}{\color{yellow}\blacksquare}{\color{yellowgreen}\blacksquare}{\color{yelloworange}\blacksquare} | ||
const MATHEMATICA_COLORS = { | ||
'm0': '#3f3d99', // strong blue | ||
'm1': '#993d71', // strong cerise | ||
'm2': '#998b3d', // strong gold | ||
'm3': '#3d9956', // malachite green | ||
'm4': '#3d5a99', // strong cobalt blue | ||
'm5': '#993d90', // strong orchid | ||
'm6': '#996d3d', // strong orange | ||
'm7': '#43993d', // strong sap green | ||
'm8': '#3d7999', // cornflower blue | ||
'm9': '#843d99' // mulberry | ||
} | ||
// ColorData97 (Mathematica standard lines) | ||
// rgb(0.368417, 0.506779, 0.709798), #5e81b5 | ||
// rgb(0.880722, 0.611041, 0.142051), | ||
// rgb(0.560181, 0.691569, 0.194885), | ||
// rgb(0.922526, 0.385626, 0.209179), | ||
// rgb(0.528488, 0.470624, 0.701351), | ||
// rgb(0.772079, 0.431554, 0.102387), | ||
// rgb(0.363898, 0.618501, 0.782349), | ||
// rgb(1, 0.75, 0), | ||
// rgb(0.647624, 0.37816, 0.614037), | ||
// rgb(0.571589, 0.586483, 0.), | ||
// rgb(0.915, 0.3325, 0.2125), | ||
// rgb(0.40082222609352647, 0.5220066643438841, 0.85), | ||
// rgb(0.9728288904374106, 0.621644452187053, 0.07336199581899142), | ||
// rgb(0.736782672705901, 0.358, 0.5030266573755369), | ||
// rgb(0.28026441037696703, 0.715, 0.4292089322474965) | ||
m0: '#3f3d99', // strong blue | ||
m1: '#993d71', // strong cerise | ||
m2: '#998b3d', // strong gold | ||
m3: '#3d9956', // malachite green | ||
m4: '#3d5a99', // strong cobalt blue | ||
m5: '#993d90', // strong orchid | ||
m6: '#996d3d', // strong orange | ||
m7: '#43993d', // strong sap green | ||
m8: '#3d7999', // cornflower blue | ||
m9: '#843d99', // mulberry | ||
}; | ||
// ColorData97 (Mathematica standard lines) | ||
// rgb(0.368417, 0.506779, 0.709798), #5e81b5 | ||
// rgb(0.880722, 0.611041, 0.142051), | ||
// rgb(0.560181, 0.691569, 0.194885), | ||
// rgb(0.922526, 0.385626, 0.209179), | ||
// rgb(0.528488, 0.470624, 0.701351), | ||
// rgb(0.772079, 0.431554, 0.102387), | ||
// rgb(0.363898, 0.618501, 0.782349), | ||
// rgb(1, 0.75, 0), | ||
// rgb(0.647624, 0.37816, 0.614037), | ||
// rgb(0.571589, 0.586483, 0.), | ||
// rgb(0.915, 0.3325, 0.2125), | ||
// rgb(0.40082222609352647, 0.5220066643438841, 0.85), | ||
// rgb(0.9728288904374106, 0.621644452187053, 0.07336199581899142), | ||
// rgb(0.736782672705901, 0.358, 0.5030266573755369), | ||
// rgb(0.28026441037696703, 0.715, 0.4292089322474965) | ||
// MathLab colors | ||
// '#0072bd' // [0, 0.4470, 0.7410] blue | ||
// '#d95319' // [0.8500, 0.3250, 0.0980] orange | ||
// '#edb120', // [0.9290, 0.6940, 0.1250] yellow | ||
// '#7e2f8e', // [0.4940, 0.1840, 0.5560] purple | ||
// '#77ac30', // [0.4660, 0.6740, 0.1880] green | ||
// '#4dbeee', // [0.3010, 0.7450, 0.9330] cyan | ||
// '#a2142f' // [0.6350, 0.0780, 0.1840] dark red | ||
// MathLab colors | ||
// '#0072bd' // [0, 0.4470, 0.7410] blue | ||
// '#d95319' // [0.8500, 0.3250, 0.0980] orange | ||
// '#edb120', // [0.9290, 0.6940, 0.1250] yellow | ||
// '#7e2f8e', // [0.4940, 0.1840, 0.5560] purple | ||
// '#77ac30', // [0.4660, 0.6740, 0.1880] green | ||
// '#4dbeee', // [0.3010, 0.7450, 0.9330] cyan | ||
// '#a2142f' // [0.6350, 0.0780, 0.1840] dark red | ||
/* Area colors are most appropriate to color a large area */ | ||
const AREA_COLORS = [ | ||
'#d35d60', // red | ||
'#7293cb', // cobalt blue | ||
'#e1974d', // orange | ||
'#84bb5d', // pistachio | ||
'#9066a7', // purple | ||
'#aD6a58', // vermilion | ||
'#f5a4ce', // pale rose | ||
'#fff590', // pale gold | ||
'#212121', // Black | ||
'#818787', // dark grey | ||
'#d4d5d2', // light grey | ||
'#ffffff' // white | ||
] | ||
'#d35d60', // red | ||
'#7293cb', // cobalt blue | ||
'#e1974d', // orange | ||
'#84bb5d', // pistachio | ||
'#9066a7', // purple | ||
'#aD6a58', // vermilion | ||
'#f5a4ce', // pale rose | ||
'#fff590', // pale gold | ||
'#212121', // Black | ||
'#818787', // dark grey | ||
'#d4d5d2', // light grey | ||
'#ffffff', // white | ||
]; | ||
/* Line colors are most appropriate to color as a stroke color */ | ||
const LINE_COLORS = [ | ||
'#cc2428', // red | ||
'#3769b1', // cobalt blue | ||
'#da7e30', // orange | ||
'#409852', // malachite green | ||
'#6b4c9a', // blue violet | ||
'#922426', // red | ||
'#e7298a', // brilliant rose | ||
'#ffe907', // vivid gold | ||
'#cc2428', // red | ||
'#3769b1', // cobalt blue | ||
'#da7e30', // orange | ||
'#409852', // malachite green | ||
'#6b4c9a', // blue violet | ||
'#922426', // red | ||
'#e7298a', // brilliant rose | ||
'#ffe907', // vivid gold | ||
'#000000', | ||
@@ -96,3 +92,3 @@ '#525055', | ||
'#ffffff', | ||
] | ||
]; | ||
@@ -114,73 +110,72 @@ /** | ||
const NAMED_COLORS = { | ||
'apricot': '#FBB982', | ||
'aquamarine': '#00B5BE', | ||
'bittersweet': '#C04F17', | ||
'black': '#221E1F', // Indeed. | ||
'blue': '#2D2F92', | ||
'bluegreen': '#00B3B8', | ||
'blueviolet': '#473992', | ||
'brickred': '#B6321C', | ||
'brown': '#792500', | ||
'burntorange': '#F7921D', | ||
'cadetblue': '#74729A', | ||
'carnationpink': '#F282B4', | ||
'cerulean': '#00A2E3', | ||
'cornflowerblue': '#41B0E4', | ||
'cyan': '#00AEEF', | ||
'dandelion': '#FDBC42', | ||
'darkorchid': '#A4538A', | ||
'emerald': '#00A99D', | ||
'forestgreen': '#009B55', | ||
'fuchsia': '#8C368C', | ||
'goldenrod': '#FFDF42', | ||
'gray': '#949698', | ||
'green': '#00A64F', | ||
'greenyellow': '#DFE674', | ||
'junglegreen': '#00A99A', | ||
'lavender': '#F49EC4', | ||
'limegreen': '#8DC73E', | ||
'magenta': '#EC008C', | ||
'mahogany': '#A9341F', | ||
'maroon': '#AF3235', | ||
'melon': '#F89E7B', | ||
'midnightblue': '#006795', | ||
'mulberry': '#A93C93', | ||
'navyblue': '#006EB8', | ||
'olivegreen': '#3C8031', | ||
'orange': '#F58137', | ||
'orangered': '#ED135A', | ||
'orchid': '#AF72B0', | ||
'peach': '#F7965A', | ||
'periwinkle': '#7977B8', | ||
'pinegreen': '#008B72', | ||
'plum': '#92268F', | ||
'processblue': '#00B0F0', | ||
'purple': '#99479B', | ||
'rawsienna': '#974006', | ||
'red': '#ED1B23', | ||
'redorange': '#F26035', | ||
'redviolet': '#A1246B', | ||
'rhodamine': '#EF559F', | ||
'royalblue': '#0071BC', | ||
'royalpurple': '#613F99', | ||
'rubinered': '#ED017D', | ||
'salmon': '#F69289', | ||
'seagreen': '#3FBC9D', | ||
'sepia': '#671800', | ||
'skyblue': '#46C5DD', | ||
'springgreen': '#C6DC67', | ||
'tan': '#DA9D76', | ||
'tealblue': '#00AEB3', | ||
'thistle': '#D883B7', | ||
'turquoise': '#00B4CE', | ||
'violet': '#58429B', | ||
'violetred': '#EF58A0', | ||
'white': '#FFFFFF', | ||
'wildstrawberry': '#EE2967', | ||
'yellow': '#FFF200', | ||
'yellowgreen': '#98CC70', | ||
'yelloworange': '#FAA21A', | ||
apricot: '#FBB982', | ||
aquamarine: '#00B5BE', | ||
bittersweet: '#C04F17', | ||
black: '#221E1F', // Indeed. | ||
blue: '#2D2F92', | ||
bluegreen: '#00B3B8', | ||
blueviolet: '#473992', | ||
brickred: '#B6321C', | ||
brown: '#792500', | ||
burntorange: '#F7921D', | ||
cadetblue: '#74729A', | ||
carnationpink: '#F282B4', | ||
cerulean: '#00A2E3', | ||
cornflowerblue: '#41B0E4', | ||
cyan: '#00AEEF', | ||
dandelion: '#FDBC42', | ||
darkorchid: '#A4538A', | ||
emerald: '#00A99D', | ||
forestgreen: '#009B55', | ||
fuchsia: '#8C368C', | ||
goldenrod: '#FFDF42', | ||
gray: '#949698', | ||
green: '#00A64F', | ||
greenyellow: '#DFE674', | ||
junglegreen: '#00A99A', | ||
lavender: '#F49EC4', | ||
limegreen: '#8DC73E', | ||
magenta: '#EC008C', | ||
mahogany: '#A9341F', | ||
maroon: '#AF3235', | ||
melon: '#F89E7B', | ||
midnightblue: '#006795', | ||
mulberry: '#A93C93', | ||
navyblue: '#006EB8', | ||
olivegreen: '#3C8031', | ||
orange: '#F58137', | ||
orangered: '#ED135A', | ||
orchid: '#AF72B0', | ||
peach: '#F7965A', | ||
periwinkle: '#7977B8', | ||
pinegreen: '#008B72', | ||
plum: '#92268F', | ||
processblue: '#00B0F0', | ||
purple: '#99479B', | ||
rawsienna: '#974006', | ||
red: '#ED1B23', | ||
redorange: '#F26035', | ||
redviolet: '#A1246B', | ||
rhodamine: '#EF559F', | ||
royalblue: '#0071BC', | ||
royalpurple: '#613F99', | ||
rubinered: '#ED017D', | ||
salmon: '#F69289', | ||
seagreen: '#3FBC9D', | ||
sepia: '#671800', | ||
skyblue: '#46C5DD', | ||
springgreen: '#C6DC67', | ||
tan: '#DA9D76', | ||
tealblue: '#00AEB3', | ||
thistle: '#D883B7', | ||
turquoise: '#00B4CE', | ||
violet: '#58429B', | ||
violetred: '#EF58A0', | ||
white: '#FFFFFF', | ||
wildstrawberry: '#EE2967', | ||
yellow: '#FFF200', | ||
yellowgreen: '#98CC70', | ||
yelloworange: '#FAA21A', | ||
}; | ||
// Other color lists: SVG colors, x11 colors | ||
@@ -377,6 +372,6 @@ /* | ||
// If the string is prefixed with a '-', use the complementary color | ||
const complementary = colorSpec.length > 0 && colorSpec[0].charAt(0) === '-'; | ||
const complementary = | ||
colorSpec.length > 0 && colorSpec[0].charAt(0) === '-'; | ||
if (complementary) colorSpec[0] = colorSpec[0].slice(1); | ||
for (let i = 0; i < colorSpec.length; i++) { | ||
@@ -400,3 +395,3 @@ baseRed = red; | ||
} else { | ||
m = color.match(/^#([0-9a-f]{3})$/i) | ||
m = color.match(/^#([0-9a-f]{3})$/i); | ||
if (m && m[1]) { | ||
@@ -406,3 +401,3 @@ // It's a three-digit hex number | ||
const g1 = parseInt(m[1][1], 16); | ||
const b1 = parseInt(m[1][2], 16) | ||
const b1 = parseInt(m[1][2], 16); | ||
red = Math.max(0, Math.min(255, r1 * 16 + r1)); | ||
@@ -413,3 +408,5 @@ green = Math.max(0, Math.min(255, g1 * 16 + g1)); | ||
// It's a rgb functional | ||
m = color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i); | ||
m = color.match( | ||
/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i | ||
); | ||
if (m && m[1] && m[2] && m[3]) { | ||
@@ -425,3 +422,3 @@ red = Math.max(0, Math.min(255, parseInt(m[1]))); | ||
if (mix >= 0) { | ||
red = (1.0 - mix) * red + mix * baseRed; | ||
red = (1.0 - mix) * red + mix * baseRed; | ||
green = (1.0 - mix) * green + mix * baseGreen; | ||
@@ -448,6 +445,8 @@ blue = (1.0 - mix) * blue + mix * baseBlue; | ||
return '#' + | ||
return ( | ||
'#' + | ||
('00' + Math.round(red).toString(16)).slice(-2) + | ||
('00' + Math.round(green).toString(16)).slice(-2) + | ||
('00' + Math.round(blue).toString(16)).slice(-2); | ||
('00' + Math.round(blue).toString(16)).slice(-2) | ||
); | ||
} | ||
@@ -481,5 +480,2 @@ | ||
LINE_COLORS, | ||
} | ||
}; |
@@ -1,2 +0,1 @@ | ||
import Mathstyle from './mathstyle.js'; | ||
@@ -41,4 +40,6 @@ | ||
this.mathstyle = Mathstyle.toMathstyle(from.mathstyle || 'displaystyle'); | ||
this.size = from.size || 'size5'; // medium size | ||
this.mathstyle = Mathstyle.toMathstyle( | ||
from.mathstyle || 'displaystyle' | ||
); | ||
this.size = from.size || 'size5'; // medium size | ||
@@ -78,3 +79,2 @@ this.parentMathstyle = from.parentMathstyle || this.mathstyle; | ||
/** | ||
@@ -95,9 +95,9 @@ * Change the mathstyle of this context | ||
cramp() { | ||
return this.clone({'mathstyle': this.mathstyle.cramp()}); | ||
return this.clone({ mathstyle: this.mathstyle.cramp() }); | ||
} | ||
sup() { | ||
return this.clone({'mathstyle': this.mathstyle.sup()}); | ||
return this.clone({ mathstyle: this.mathstyle.sup() }); | ||
} | ||
sub() { | ||
return this.clone({'mathstyle': this.mathstyle.sup()}); | ||
return this.clone({ mathstyle: this.mathstyle.sup() }); | ||
} | ||
@@ -107,3 +107,3 @@ } | ||
export default { | ||
Context | ||
} | ||
Context, | ||
}; |
@@ -35,4 +35,2 @@ /** | ||
/** | ||
@@ -48,10 +46,19 @@ * Makes a small delimiter. This is a delimiter that comes in the Main-Regular | ||
const span = Span.makeStyleWrap(type, text, context.mathstyle, style, classes); | ||
const span = Span.makeStyleWrap( | ||
type, | ||
text, | ||
context.mathstyle, | ||
style, | ||
classes | ||
); | ||
if (center) { | ||
span.setTop((1 - context.mathstyle.sizeMultiplier / style.sizeMultiplier) * | ||
context.mathstyle.metrics.axisHeight); | ||
span.setTop( | ||
(1 - context.mathstyle.sizeMultiplier / style.sizeMultiplier) * | ||
context.mathstyle.metrics.axisHeight | ||
); | ||
} | ||
span.setStyle('color', context.color); | ||
if (typeof context.opacity === 'number') span.setStyle('opacity', context.opacity); | ||
if (typeof context.opacity === 'number') | ||
span.setStyle('opacity', context.opacity); | ||
@@ -68,15 +75,24 @@ return span; | ||
function makeLargeDelim(type, delim, size, center, context, classes) { | ||
const inner = makeSymbol('Size' + size + '-Regular', | ||
Definitions.getValue('math', delim)); | ||
const inner = makeSymbol( | ||
'Size' + size + '-Regular', | ||
Definitions.getValue('math', delim) | ||
); | ||
const result = Span.makeStyleWrap( type, | ||
makeSpan(inner, 'delimsizing size' + size), | ||
context.mathstyle, Mathstyle.TEXT, classes); | ||
const result = Span.makeStyleWrap( | ||
type, | ||
makeSpan(inner, 'delimsizing size' + size), | ||
context.mathstyle, | ||
Mathstyle.TEXT, | ||
classes | ||
); | ||
if (center) { | ||
result.setTop((1 - context.mathstyle.sizeMultiplier) * | ||
context.mathstyle.metrics.axisHeight); | ||
result.setTop( | ||
(1 - context.mathstyle.sizeMultiplier) * | ||
context.mathstyle.metrics.axisHeight | ||
); | ||
} | ||
result.setStyle('color', context.color); | ||
if (typeof context.opacity === 'number') result.setStyle('opacity', context.opacity); | ||
if (typeof context.opacity === 'number') | ||
result.setStyle('opacity', context.opacity); | ||
@@ -103,4 +119,6 @@ return result; | ||
// be simplified | ||
const inner = makeSpan(makeSymbol(font, | ||
Definitions.getValue('math', symbol)), 'delimsizinginner' + sizeClass); | ||
const inner = makeSpan( | ||
makeSymbol(font, Definitions.getValue('math', symbol)), | ||
'delimsizinginner' + sizeClass | ||
); | ||
@@ -116,4 +134,3 @@ return inner; | ||
*/ | ||
function makeStackedDelim(type, delim, heightTotal, center, context, | ||
classes) { | ||
function makeStackedDelim(type, delim, heightTotal, center, context, classes) { | ||
// There are four parts, the top, an optional middle, a repeated part, and a | ||
@@ -133,6 +150,17 @@ // bottom. | ||
// repeats of the arrows | ||
if (delim === '\\vert' || delim === '\\lvert' || delim === '\\rvert' || delim === '\\mvert' || delim === '\\mid') { | ||
if ( | ||
delim === '\\vert' || | ||
delim === '\\lvert' || | ||
delim === '\\rvert' || | ||
delim === '\\mvert' || | ||
delim === '\\mid' | ||
) { | ||
repeat = top = bottom = '\u2223'; | ||
} else if (delim === '\\Vert' || delim === '\\lVert' || | ||
delim === '\\rVert' || delim === '\\mVert' || delim === '\\|') { | ||
} else if ( | ||
delim === '\\Vert' || | ||
delim === '\\lVert' || | ||
delim === '\\rVert' || | ||
delim === '\\mVert' || | ||
delim === '\\|' | ||
) { | ||
repeat = top = bottom = '\u2225'; | ||
@@ -244,9 +272,15 @@ } else if (delim === '\\uparrow') { | ||
const topMetrics = FontMetrics.getCharacterMetrics( | ||
Definitions.getValue('math', top), font); | ||
Definitions.getValue('math', top), | ||
font | ||
); | ||
const topHeightTotal = topMetrics.height + topMetrics.depth; | ||
const repeatMetrics = FontMetrics.getCharacterMetrics( | ||
Definitions.getValue('math', repeat), font); | ||
Definitions.getValue('math', repeat), | ||
font | ||
); | ||
const repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth; | ||
const bottomMetrics = FontMetrics.getCharacterMetrics( | ||
Definitions.getValue('math', bottom), font); | ||
Definitions.getValue('math', bottom), | ||
font | ||
); | ||
const bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth; | ||
@@ -257,3 +291,5 @@ let middleHeightTotal = 0; | ||
const middleMetrics = FontMetrics.getCharacterMetrics( | ||
Definitions.getValue('math', middle), font); | ||
Definitions.getValue('math', middle), | ||
font | ||
); | ||
middleHeightTotal = middleMetrics.height + middleMetrics.depth; | ||
@@ -269,3 +305,4 @@ middleFactor = 2; // repeat symmetrically above and below middle | ||
const repeatCount = Math.ceil( | ||
(heightTotal - minHeight) / (middleFactor * repeatHeightTotal)); | ||
(heightTotal - minHeight) / (middleFactor * repeatHeightTotal) | ||
); | ||
@@ -318,6 +355,12 @@ // Compute the total height of the delimiter including all the symbols | ||
inner.setStyle('color', context.color); | ||
if (typeof context.opacity === 'number') inner.setStyle('opacity', context.opacity); | ||
if (typeof context.opacity === 'number') | ||
inner.setStyle('opacity', context.opacity); | ||
return Span.makeStyleWrap(type, makeSpan(inner, 'delimsizing mult'), | ||
context.mathstyle, Mathstyle.TEXT, classes); | ||
return Span.makeStyleWrap( | ||
type, | ||
makeSpan(inner, 'delimsizing mult'), | ||
context.mathstyle, | ||
Mathstyle.TEXT, | ||
classes | ||
); | ||
} | ||
@@ -328,5 +371,16 @@ | ||
const stackLargeDelimiters = [ | ||
'(', ')', '[', '\\lbrack', ']', '\\rbrack', | ||
'\\{', '\\lbrace', '\\}', '\\rbrace', | ||
'\\lfloor', '\\rfloor', '\\lceil', '\\rceil', | ||
'(', | ||
')', | ||
'[', | ||
'\\lbrack', | ||
']', | ||
'\\rbrack', | ||
'\\{', | ||
'\\lbrace', | ||
'\\}', | ||
'\\rbrace', | ||
'\\lfloor', | ||
'\\rfloor', | ||
'\\lceil', | ||
'\\rceil', | ||
'\\surd', | ||
@@ -337,8 +391,22 @@ ]; | ||
const stackAlwaysDelimiters = [ | ||
'\\uparrow', '\\downarrow', '\\updownarrow', | ||
'\\Uparrow', '\\Downarrow', '\\Updownarrow', | ||
'|', '\\|', '\\vert', '\\Vert', | ||
'\\lvert', '\\rvert', '\\lVert', '\\rVert', | ||
'\\mvert', '\\mid', | ||
'\\lgroup', '\\rgroup', '\\lmoustache', '\\rmoustache', | ||
'\\uparrow', | ||
'\\downarrow', | ||
'\\updownarrow', | ||
'\\Uparrow', | ||
'\\Downarrow', | ||
'\\Updownarrow', | ||
'|', | ||
'\\|', | ||
'\\vert', | ||
'\\Vert', | ||
'\\lvert', | ||
'\\rvert', | ||
'\\lVert', | ||
'\\rVert', | ||
'\\mvert', | ||
'\\mid', | ||
'\\lgroup', | ||
'\\rgroup', | ||
'\\lmoustache', | ||
'\\rmoustache', | ||
]; | ||
@@ -348,3 +416,10 @@ | ||
const stackNeverDelimiters = [ | ||
'<', '>', '\\langle', '\\rangle', '/', '\\backslash', '\\lt', '\\gt', | ||
'<', | ||
'>', | ||
'\\langle', | ||
'\\rangle', | ||
'/', | ||
'\\backslash', | ||
'\\lt', | ||
'\\gt', | ||
]; | ||
@@ -378,10 +453,18 @@ | ||
// Sized delimiters are never centered. | ||
if (stackLargeDelimiters.includes(delim) || | ||
stackNeverDelimiters.includes(delim)) { | ||
if ( | ||
stackLargeDelimiters.includes(delim) || | ||
stackNeverDelimiters.includes(delim) | ||
) { | ||
return makeLargeDelim(type, delim, size, false, context, classes); | ||
} else if (stackAlwaysDelimiters.includes(delim)) { | ||
return makeStackedDelim( | ||
type, delim, sizeToMaxHeight[size], false, context, classes); | ||
type, | ||
delim, | ||
sizeToMaxHeight[size], | ||
false, | ||
context, | ||
classes | ||
); | ||
} | ||
console.assert(false, 'Unknown delimiter \'' + delim + '\''); | ||
console.assert(false, "Unknown delimiter '" + delim + "'"); | ||
return null; | ||
@@ -404,9 +487,9 @@ } | ||
const stackNeverDelimiterSequence = [ | ||
{type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.SCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.TEXT}, | ||
{type: 'large', size: 1}, | ||
{type: 'large', size: 2}, | ||
{type: 'large', size: 3}, | ||
{type: 'large', size: 4}, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.TEXT }, | ||
{ type: 'large', size: 1 }, | ||
{ type: 'large', size: 2 }, | ||
{ type: 'large', size: 3 }, | ||
{ type: 'large', size: 4 }, | ||
]; | ||
@@ -416,6 +499,6 @@ | ||
const stackAlwaysDelimiterSequence = [ | ||
{type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.SCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.TEXT}, | ||
{type: 'stack'}, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.TEXT }, | ||
{ type: 'stack' }, | ||
]; | ||
@@ -426,10 +509,10 @@ | ||
const stackLargeDelimiterSequence = [ | ||
{type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.SCRIPT}, | ||
{type: 'small', mathstyle: Mathstyle.TEXT}, | ||
{type: 'large', size: 1}, | ||
{type: 'large', size: 2}, | ||
{type: 'large', size: 3}, | ||
{type: 'large', size: 4}, | ||
{type: 'stack'}, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPTSCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.SCRIPT }, | ||
{ type: 'small', mathstyle: Mathstyle.TEXT }, | ||
{ type: 'large', size: 1 }, | ||
{ type: 'large', size: 2 }, | ||
{ type: 'large', size: 3 }, | ||
{ type: 'large', size: 4 }, | ||
{ type: 'stack' }, | ||
]; | ||
@@ -470,8 +553,9 @@ | ||
const metrics = FontMetrics.getCharacterMetrics( | ||
delim, | ||
delimTypeToFont(sequence[i])); | ||
delim, | ||
delimTypeToFont(sequence[i]) | ||
); | ||
if (metrics.defaultMetrics) { | ||
// If we don't have metrics info for this character, | ||
// assume we'll construct as a small delimiter | ||
return {type: 'small', mathstyle: Mathstyle.SCRIPT}; | ||
return { type: 'small', mathstyle: Mathstyle.SCRIPT }; | ||
} | ||
@@ -497,3 +581,2 @@ let heightDepth = metrics.height + metrics.depth; | ||
/** | ||
@@ -534,4 +617,8 @@ * Make a delimiter of a given height+depth, with optional centering. Here, we | ||
// Look through the sequence | ||
const delimType = traverseSequence(Definitions.getValue('math', delim), | ||
height, sequence, context); | ||
const delimType = traverseSequence( | ||
Definitions.getValue('math', delim), | ||
height, | ||
sequence, | ||
context | ||
); | ||
@@ -541,7 +628,19 @@ // Depending on the sequence element we decided on, call the appropriate | ||
if (delimType.type === 'small') { | ||
return makeSmallDelim(type, delim, delimType.mathstyle, center, context, | ||
classes); | ||
return makeSmallDelim( | ||
type, | ||
delim, | ||
delimType.mathstyle, | ||
center, | ||
context, | ||
classes | ||
); | ||
} else if (delimType.type === 'large') { | ||
return makeLargeDelim(type, delim, delimType.size, center, context, | ||
classes); | ||
return makeLargeDelim( | ||
type, | ||
delim, | ||
delimType.size, | ||
center, | ||
context, | ||
classes | ||
); | ||
} | ||
@@ -570,4 +669,4 @@ console.assert(delimType.type === 'stack'); | ||
// Taken from TeX source, tex.web, function make_left_right | ||
const delimiterFactor = 901; // plain.tex:327 | ||
const delimiterShortfall = 5.0 / FontMetrics.METRICS.ptPerEm; // plain.tex:345 | ||
const delimiterFactor = 901; // plain.tex:327 | ||
const delimiterShortfall = 5.0 / FontMetrics.METRICS.ptPerEm; // plain.tex:345 | ||
@@ -578,4 +677,4 @@ let delta2 = depth + axisHeight; | ||
let delta = (delta1 * delimiterFactor) / 500; | ||
delta2 = 2 * delta1 - delimiterShortfall; | ||
let delta = (delta1 * delimiterFactor) / 500; | ||
delta2 = 2 * delta1 - delimiterShortfall; | ||
delta = Math.max(delta, delta2); | ||
@@ -610,13 +709,13 @@ | ||
function makeNullFence(type, context, classes) { | ||
return Span.makeSpanOfType(type, '', | ||
'sizing' + // @todo not useful, redundant with 'nulldelimiter' | ||
return Span.makeSpanOfType( | ||
type, | ||
'', | ||
'sizing' + // @todo not useful, redundant with 'nulldelimiter' | ||
// 'reset-' + context.size, 'size5', // @todo: that seems like a lot of resizing... do we need both? | ||
context.mathstyle.adjustTo(Mathstyle.TEXT) + | ||
' nulldelimiter ' // The null delimiter has a width, specified by class 'nulldelimiter' | ||
+ (classes || '') | ||
' nulldelimiter ' + // The null delimiter has a width, specified by class 'nulldelimiter' | ||
(classes || '') | ||
); | ||
} | ||
// Export the public interface for this module | ||
@@ -626,6 +725,3 @@ export default { | ||
makeCustomSizedDelim, | ||
makeLeftRightDelim | ||
} | ||
makeLeftRightDelim, | ||
}; |
@@ -25,6 +25,4 @@ /* eslint no-unused-vars:0 */ | ||
// Notably missing are half width Katakana and Romaji glyphs. | ||
const cjkRegex = | ||
/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/; | ||
const cjkRegex = /[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/; | ||
/* | ||
@@ -58,24 +56,24 @@ * | ||
export 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 | ||
shrink: [0.000, 0.000, 0.000], // sigma4 | ||
xHeight: [0.431, 0.431, 0.431], // sigma5 | ||
quad: [1.000, 1.171, 1.472], // sigma6 | ||
extraSpace: [0.000, 0.000, 0.000], // sigma7 | ||
num1: [0.677, 0.732, 0.925], // sigma8 | ||
num2: [0.394, 0.384, 0.387], // sigma9 | ||
num3: [0.444, 0.471, 0.504], // sigma10 | ||
denom1: [0.686, 0.752, 1.025], // sigma11 | ||
denom2: [0.345, 0.344, 0.532], // sigma12 | ||
sup1: [0.413, 0.503, 0.504], // sigma13 | ||
sup2: [0.363, 0.431, 0.404], // sigma14 | ||
sup3: [0.289, 0.286, 0.294], // sigma15 | ||
sub1: [0.150, 0.143, 0.200], // sigma16 | ||
sub2: [0.247, 0.286, 0.400], // sigma17 | ||
supDrop: [0.386, 0.353, 0.494], // sigma18 | ||
subDrop: [0.050, 0.071, 0.100], // sigma19 | ||
delim1: [2.390, 1.700, 1.980], // sigma20 | ||
delim2: [1.010, 1.157, 1.420], // sigma21 | ||
axisHeight: [0.250, 0.250, 0.250], // sigma22 | ||
slant: [0.25, 0.25, 0.25], // sigma1 | ||
space: [0.0, 0.0, 0.0], // sigma2 | ||
stretch: [0.0, 0.0, 0.0], // sigma3 | ||
shrink: [0.0, 0.0, 0.0], // sigma4 | ||
xHeight: [0.431, 0.431, 0.431], // sigma5 | ||
quad: [1.0, 1.171, 1.472], // sigma6 | ||
extraSpace: [0.0, 0.0, 0.0], // sigma7 | ||
num1: [0.677, 0.732, 0.925], // sigma8 | ||
num2: [0.394, 0.384, 0.387], // sigma9 | ||
num3: [0.444, 0.471, 0.504], // sigma10 | ||
denom1: [0.686, 0.752, 1.025], // sigma11 | ||
denom2: [0.345, 0.344, 0.532], // sigma12 | ||
sup1: [0.413, 0.503, 0.504], // sigma13 | ||
sup2: [0.363, 0.431, 0.404], // sigma14 | ||
sup3: [0.289, 0.286, 0.294], // sigma15 | ||
sub1: [0.15, 0.143, 0.2], // sigma16 | ||
sub2: [0.247, 0.286, 0.4], // sigma17 | ||
supDrop: [0.386, 0.353, 0.494], // sigma18 | ||
subDrop: [0.05, 0.071, 0.1], // sigma19 | ||
delim1: [2.39, 1.7, 1.98], // sigma20 | ||
delim2: [1.01, 1.157, 1.42], // sigma21 | ||
axisHeight: [0.25, 0.25, 0.25], // sigma22 | ||
}; | ||
@@ -123,3 +121,3 @@ | ||
ptPerEm: ptPerEm, | ||
pxPerEm: ptPerEm * 4.0 / 3.0, // A CSS pt is fixed at 1.333px | ||
pxPerEm: (ptPerEm * 4.0) / 3.0, // A CSS pt is fixed at 1.333px | ||
doubleRuleSep: 2.0 / ptPerEm, | ||
@@ -129,7 +127,6 @@ arraycolsep: 5.0 / ptPerEm, | ||
arrayrulewidth: 0.4 / ptPerEm, | ||
fboxsep: 3 / ptPerEm, // From letter.dtx:1626 | ||
fboxrule: 0.4 / ptPerEm, // From letter.dtx:1627 | ||
fboxsep: 3 / ptPerEm, // From letter.dtx:1626 | ||
fboxrule: 0.4 / ptPerEm, // From letter.dtx:1627 | ||
}; | ||
// These are very rough approximations. We default to Times New Roman which | ||
@@ -143,81 +140,79 @@ // should have Latin-1 and Cyrillic characters, but may not depending on the | ||
const extraCharacterMap = { | ||
'\u00a0': '\u0020', // NON-BREAKING SPACE is like space | ||
'\u200b': '\u0020', // ZERO WIDTH SPACE is like space | ||
'\u00a0': '\u0020', // NON-BREAKING SPACE is like space | ||
'\u200b': '\u0020', // ZERO WIDTH SPACE is like space | ||
// Latin-1 | ||
'Å': 'A', | ||
'Ç': 'C', | ||
'Ð': 'D', | ||
'Þ': 'o', | ||
'å': 'a', | ||
'ç': 'c', | ||
'ð': 'd', | ||
'þ': 'o', | ||
Å: 'A', | ||
Ç: 'C', | ||
Ð: 'D', | ||
Þ: 'o', | ||
å: 'a', | ||
ç: 'c', | ||
ð: 'd', | ||
þ: 'o', | ||
// Cyrillic | ||
'А': 'A', | ||
'Б': 'B', | ||
'В': 'B', | ||
'Г': 'F', | ||
'Д': 'A', | ||
'Е': 'E', | ||
'Ж': 'K', | ||
'З': '3', | ||
'И': 'N', | ||
'Й': 'N', | ||
'К': 'K', | ||
'Л': 'N', | ||
'М': 'M', | ||
'Н': 'H', | ||
'О': 'O', | ||
'П': 'N', | ||
'Р': 'P', | ||
'С': 'C', | ||
'Т': 'T', | ||
'У': 'y', | ||
'Ф': 'O', | ||
'Х': 'X', | ||
'Ц': 'U', | ||
'Ч': 'h', | ||
'Ш': 'W', | ||
'Щ': 'W', | ||
'Ъ': 'B', | ||
'Ы': 'X', | ||
'Ь': 'B', | ||
'Э': '3', | ||
'Ю': 'X', | ||
'Я': 'R', | ||
'а': 'a', | ||
'б': 'b', | ||
'в': 'a', | ||
'г': 'r', | ||
'д': 'y', | ||
'е': 'e', | ||
'ж': 'm', | ||
'з': 'e', | ||
'и': 'n', | ||
'й': 'n', | ||
'к': 'n', | ||
'л': 'n', | ||
'м': 'm', | ||
'н': 'n', | ||
'о': 'o', | ||
'п': 'n', | ||
'р': 'p', | ||
'с': 'c', | ||
'т': 'o', | ||
'у': 'y', | ||
'ф': 'b', | ||
'х': 'x', | ||
'ц': 'n', | ||
'ч': 'n', | ||
'ш': 'w', | ||
'щ': 'w', | ||
'ъ': 'a', | ||
'ы': 'm', | ||
'ь': 'a', | ||
'э': 'e', | ||
'ю': 'm', | ||
'я': 'r', | ||
А: 'A', | ||
Б: 'B', | ||
В: 'B', | ||
Г: 'F', | ||
Д: 'A', | ||
Е: 'E', | ||
Ж: 'K', | ||
З: '3', | ||
И: 'N', | ||
Й: 'N', | ||
К: 'K', | ||
Л: 'N', | ||
М: 'M', | ||
Н: 'H', | ||
О: 'O', | ||
П: 'N', | ||
Р: 'P', | ||
С: 'C', | ||
Т: 'T', | ||
У: 'y', | ||
Ф: 'O', | ||
Х: 'X', | ||
Ц: 'U', | ||
Ч: 'h', | ||
Ш: 'W', | ||
Щ: 'W', | ||
Ъ: 'B', | ||
Ы: 'X', | ||
Ь: 'B', | ||
Э: '3', | ||
Ю: 'X', | ||
Я: 'R', | ||
а: 'a', | ||
б: 'b', | ||
в: 'a', | ||
г: 'r', | ||
д: 'y', | ||
е: 'e', | ||
ж: 'm', | ||
з: 'e', | ||
и: 'n', | ||
й: 'n', | ||
к: 'n', | ||
л: 'n', | ||
м: 'm', | ||
н: 'n', | ||
о: 'o', | ||
п: 'n', | ||
р: 'p', | ||
с: 'c', | ||
т: 'o', | ||
у: 'y', | ||
ф: 'b', | ||
х: 'x', | ||
ц: 'n', | ||
ч: 'n', | ||
ш: 'w', | ||
щ: 'w', | ||
ъ: 'a', | ||
ы: 'm', | ||
ь: 'a', | ||
э: 'e', | ||
ю: 'm', | ||
я: 'r', | ||
}; | ||
@@ -237,13 +232,14 @@ | ||
const getCharacterMetrics = function(character, fontCode) { | ||
const fontName = { | ||
'cal': 'Caligraphic-Regular', | ||
'ams': 'AMS-Regular', | ||
'frak': 'Fraktur-Regular', | ||
'bb': 'AMS-Regular', | ||
'scr': 'Script-Regular', | ||
'cmr': 'Main-Regular', | ||
'cmtt': 'Typewriter-Regular', | ||
'cmss': 'SansSerif-Regular' | ||
}[fontCode] || fontCode; | ||
const fontName = | ||
{ | ||
cal: 'Caligraphic-Regular', | ||
ams: 'AMS-Regular', | ||
frak: 'Fraktur-Regular', | ||
bb: 'AMS-Regular', | ||
scr: 'Script-Regular', | ||
cmr: 'Main-Regular', | ||
cmtt: 'Typewriter-Regular', | ||
cmss: 'SansSerif-Regular', | ||
}[fontCode] || fontCode; | ||
// console.assert(character.length === 1); | ||
@@ -270,7 +266,7 @@ // console.assert(metricMap[fontName], 'Unknown font "' + fontName + '"'); | ||
defaultMetrics: true, | ||
depth: .20, | ||
height: .70, | ||
depth: 0.2, | ||
height: 0.7, | ||
italic: 0, | ||
skew: 0 | ||
} | ||
skew: 0, | ||
}; | ||
} | ||
@@ -283,10 +279,9 @@ | ||
italic: metrics[2], | ||
skew: metrics[3] | ||
} | ||
skew: metrics[3], | ||
}; | ||
} | ||
return null; | ||
} | ||
}; | ||
/** | ||
@@ -312,17 +307,17 @@ * | ||
// If the units are missing, TeX assumes 'pt' | ||
const f = { | ||
'pt': 1.0, | ||
'mm': 7227 / 2540, | ||
'cm': 7227 / 254, | ||
'ex': 35271 / 8192, | ||
'px': 3.0 / 4.0, | ||
'em': METRICS.ptPerEm, | ||
'bp': 803 / 800, | ||
'dd': 1238 / 1157, | ||
'pc': 12.0, | ||
'in': 72.27, | ||
'mu': 10 / 18, | ||
const f = | ||
{ | ||
pt: 1.0, | ||
mm: 7227 / 2540, | ||
cm: 7227 / 254, | ||
ex: 35271 / 8192, | ||
px: 3.0 / 4.0, | ||
em: METRICS.ptPerEm, | ||
bp: 803 / 800, | ||
dd: 1238 / 1157, | ||
pc: 12.0, | ||
in: 72.27, | ||
mu: 10 / 18, | ||
}[unit] || 1.0; | ||
}[unit] || 1.0 | ||
if (isFinite(precision)) { | ||
@@ -340,9 +335,8 @@ const factor = Math.pow(10, precision); | ||
export default { | ||
toEm : convertDimenToEm, | ||
toEm: convertDimenToEm, | ||
toPx: convertDimenToPx, | ||
METRICS, | ||
SIGMAS, | ||
getCharacterMetrics | ||
} | ||
getCharacterMetrics, | ||
}; |
@@ -12,8 +12,6 @@ /** | ||
* {@link ftp://tug.ctan.org/pub/tex-archive/systems/knuth/dist/lib/plain.tex|plain.tex} | ||
*/ | ||
*/ | ||
import GraphemeSplitter from './grapheme-splitter.js'; | ||
/** | ||
@@ -118,3 +116,3 @@ * | ||
return /[ \f\n\r\t\v\xA0\u2028\u2029]/.test(this.s[this.pos]); | ||
/* | ||
/* | ||
Note that browsers are inconsistent in their definitions of the | ||
@@ -179,3 +177,3 @@ `\s` metacharacter, so we use an explicit pattern instead. | ||
} | ||
result = new Token('command', command); | ||
result = new Token('command', command); | ||
} | ||
@@ -248,6 +246,2 @@ } | ||
/** | ||
@@ -265,3 +259,3 @@ * Create Tokens from a stream of LaTeX | ||
const lines = s.toString().split(/\r?\n/); | ||
let stream = ''; | ||
let stream = ''; | ||
let sep = ''; | ||
@@ -286,8 +280,4 @@ for (const line of lines) { | ||
export default { | ||
tokenize | ||
} | ||
tokenize, | ||
}; |
@@ -19,3 +19,3 @@ /** | ||
import {SIGMAS} from './fontMetrics.js'; | ||
import { SIGMAS } from './fontMetrics.js'; | ||
@@ -125,11 +125,2 @@ const metrics = [{}, {}, {}]; /* textstyle, scriptstyle, scriptscriptstyle */ | ||
// IDs of the different styles | ||
@@ -154,3 +145,3 @@ const D = 0; | ||
new Mathstyle(SS, 3, 0.5, false), | ||
new Mathstyle(SSc, 3, 0.5, true) | ||
new Mathstyle(SSc, 3, 0.5, true), | ||
]; | ||
@@ -171,7 +162,7 @@ | ||
const STYLE_NAMES = { | ||
'displaystyle': styles[D], | ||
'textstyle': styles[T], | ||
'scriptstyle': styles[S], | ||
'scriptscriptstyle': styles[SS] | ||
} | ||
displaystyle: styles[D], | ||
textstyle: styles[T], | ||
scriptstyle: styles[S], | ||
scriptscriptstyle: styles[SS], | ||
}; | ||
@@ -182,4 +173,2 @@ console.assert(STYLE_NAMES[s], 'unknown style: "', s, '"'); | ||
// String names for the different sizes | ||
@@ -190,6 +179,5 @@ const sizeNames = [ | ||
'scriptstyle', | ||
'scriptscriptstyle' | ||
'scriptscriptstyle', | ||
]; | ||
const ADJUST_NAMES = [ | ||
@@ -200,3 +188,3 @@ [ | ||
'reset-textstyle scriptstyle', | ||
'reset-textstyle scriptscriptstyle' | ||
'reset-textstyle scriptscriptstyle', | ||
], | ||
@@ -206,5 +194,5 @@ | ||
'reset-textstyle displaystyle textstyle', | ||
'', // 'reset-textstyle textstyle', | ||
'', // 'reset-textstyle textstyle', | ||
'reset-textstyle scriptstyle', | ||
'reset-textstyle scriptscriptstyle' | ||
'reset-textstyle scriptscriptstyle', | ||
], | ||
@@ -216,3 +204,3 @@ | ||
'', // 'reset-scriptstyle scriptstyle', | ||
'reset-scriptstyle scriptscriptstyle' | ||
'reset-scriptstyle scriptscriptstyle', | ||
], | ||
@@ -224,7 +212,6 @@ | ||
'reset-scriptscriptstyle scriptstyle', | ||
'' // 'reset-scriptscriptstyle scriptscriptstyle' | ||
'', // 'reset-scriptscriptstyle scriptscriptstyle' | ||
], | ||
]; | ||
// Lookup tables for switching from one style to another | ||
@@ -244,6 +231,3 @@ const sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; | ||
SCRIPTSCRIPT: styles[SS], | ||
toMathstyle | ||
} | ||
toMathstyle, | ||
}; |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -89,3 +88,5 @@ * @module core/parser | ||
this.endCount = 0; | ||
return this.index < this.tokens.length ? this.tokens[this.index++] : null; | ||
return this.index < this.tokens.length | ||
? this.tokens[this.index++] | ||
: null; | ||
} | ||
@@ -103,4 +104,6 @@ peek(offset) { | ||
lastMathAtom() { | ||
const lastType = this.mathList.length === 0 ? 'none' : | ||
this.mathList[this.mathList.length - 1].type; | ||
const lastType = | ||
this.mathList.length === 0 | ||
? 'none' | ||
: this.mathList[this.mathList.length - 1].type; | ||
if (lastType !== 'mop' && lastType !== 'msubsup') { | ||
@@ -122,4 +125,5 @@ // ZERO WIDTH SPACE | ||
const index = this.index; | ||
return index < this.tokens.length ? | ||
this.tokens[index].type === type : false; | ||
return index < this.tokens.length | ||
? this.tokens[index].type === type | ||
: false; | ||
} | ||
@@ -136,5 +140,6 @@ /** | ||
const index = this.index; | ||
return index < this.tokens.length ? | ||
this.tokens[index].type === 'literal' && | ||
(!value || this.tokens[index].value === value) : false; | ||
return index < this.tokens.length | ||
? this.tokens[index].type === 'literal' && | ||
(!value || this.tokens[index].value === value) | ||
: false; | ||
} | ||
@@ -149,17 +154,29 @@ /** | ||
hasLiteralPattern(pattern) { | ||
return this.hasToken('literal') && | ||
pattern.test(this.tokens[this.index].value); | ||
return ( | ||
this.hasToken('literal') && | ||
pattern.test(this.tokens[this.index].value) | ||
); | ||
} | ||
hasCommand(command) { | ||
console.assert(command === '\\' || command.charAt(0) !== '\\', 'hasCommand() does not require a \\'); | ||
console.assert( | ||
command === '\\' || command.charAt(0) !== '\\', | ||
'hasCommand() does not require a \\' | ||
); | ||
const index = this.index; | ||
return index < this.tokens.length ? | ||
this.tokens[index].type === 'command' && | ||
this.tokens[index].value === command : false; | ||
return index < this.tokens.length | ||
? this.tokens[index].type === 'command' && | ||
this.tokens[index].value === command | ||
: false; | ||
} | ||
hasInfixCommand() { | ||
const index = this.index; | ||
if (index < this.tokens.length && | ||
this.tokens[index].type === 'command') { | ||
const info = Definitions.getInfo('\\' + this.tokens[index].value, this.parseMode, this.macros); | ||
if ( | ||
index < this.tokens.length && | ||
this.tokens[index].type === 'command' | ||
) { | ||
const info = Definitions.getInfo( | ||
'\\' + this.tokens[index].value, | ||
this.parseMode, | ||
this.macros | ||
); | ||
return info && info.infix; | ||
@@ -171,12 +188,14 @@ } | ||
const index = this.index; | ||
return this.tabularMode && index < this.tokens.length ? | ||
this.tokens[index].type === 'literal' && | ||
this.tokens[index].value === '&' : false; | ||
return this.tabularMode && index < this.tokens.length | ||
? this.tokens[index].type === 'literal' && | ||
this.tokens[index].value === '&' | ||
: false; | ||
} | ||
hasRowSeparator() { | ||
const index = this.index; | ||
return this.tabularMode && index < this.tokens.length ? | ||
this.tokens[index].type === 'command' && | ||
(this.tokens[index].value === '\\' || | ||
this.tokens[index].value === 'cr') : false; | ||
return this.tabularMode && index < this.tokens.length | ||
? this.tokens[index].type === 'command' && | ||
(this.tokens[index].value === '\\' || | ||
this.tokens[index].value === 'cr') | ||
: false; | ||
} | ||
@@ -198,6 +217,16 @@ parseColumnSeparator() { | ||
// use it. | ||
return parseTokens(Lexer.tokenize(this.args['?']), this.parseMode, null, this.macros); | ||
return parseTokens( | ||
Lexer.tokenize(this.args['?']), | ||
this.parseMode, | ||
null, | ||
this.macros | ||
); | ||
} | ||
// U+2753 = BLACK QUESTION MARK ORNAMENT | ||
const result = new MathAtom(this.parseMode, 'placeholder', '?', this.style); | ||
const result = new MathAtom( | ||
this.parseMode, | ||
'placeholder', | ||
'?', | ||
this.style | ||
); | ||
result.captureSelection = true; | ||
@@ -294,3 +323,5 @@ return [result]; | ||
} | ||
done = this.end() || token.type !== 'literal' || | ||
done = | ||
this.end() || | ||
token.type !== 'literal' || | ||
value.length >= keyword.length; | ||
@@ -330,3 +361,3 @@ } | ||
// \operatorname{lim~inf}. It's interpreted as a nbs | ||
result += '\u00a0'; // NO-BREAK SPACE | ||
result += '\u00a0'; // NO-BREAK SPACE | ||
} else { | ||
@@ -478,3 +509,7 @@ // TeX will give a 'Missing \endcsname inserted' error | ||
const savedParsemode = this.swapParseMode('math'); | ||
result.push({ gap: this.scanImplicitGroup(token => token.type === '}') }); | ||
result.push({ | ||
gap: this.scanImplicitGroup( | ||
token => token.type === '}' | ||
), | ||
}); | ||
this.swapParseMode(savedParsemode); | ||
@@ -502,3 +537,5 @@ } | ||
result.mathstyle = final === ')' ? 'textstyle' : 'displaystyle'; | ||
result.body = this.scanImplicitGroup(token => token.type === 'command' && token.value === final); | ||
result.body = this.scanImplicitGroup( | ||
token => token.type === 'command' && token.value === final | ||
); | ||
this.parseCommand(final); | ||
@@ -590,3 +627,5 @@ this.swapParseMode(savedParsemode); | ||
} else { | ||
this.mathList = this.mathList.concat(this.scanImplicitGroup()); | ||
this.mathList = this.mathList.concat( | ||
this.scanImplicitGroup() | ||
); | ||
} | ||
@@ -599,3 +638,6 @@ } | ||
// If we're in tabular mode, we should end up with an empty mathlist | ||
console.assert(!this.tabularMode || newMathList.length === 0, 'Leftover atoms in tabular mode'); | ||
console.assert( | ||
!this.tabularMode || newMathList.length === 0, | ||
'Leftover atoms in tabular mode' | ||
); | ||
this.parseMode = savedMode; | ||
@@ -605,7 +647,11 @@ this.tabularMode = savedTabularMode; | ||
if (env.tabular && array.length === 0) return null; | ||
const result = new MathAtom(this.parseMode, 'array', newMathList, | ||
env.parser ? env.parser(envName, args, array) : {}); | ||
const result = new MathAtom( | ||
this.parseMode, | ||
'array', | ||
newMathList, | ||
env.parser ? env.parser(envName, args, array) : {} | ||
); | ||
result.array = array; | ||
result.rowGaps = rowGaps; | ||
result.env = {...env}; | ||
result.env = { ...env }; | ||
result.env.name = envName; | ||
@@ -632,3 +678,4 @@ return result; | ||
if (!done) { | ||
done = token => token.type === '}' || | ||
done = token => | ||
token.type === '}' || | ||
(token.type === 'literal' && token.value === '&') || | ||
@@ -645,3 +692,10 @@ (token.type === 'command' && /^(end|cr|\\)$/.test(token.value)); | ||
while (!this.end() && !done(this.peek())) { | ||
if (this.hasImplicitCommand(['displaystyle', 'textstyle', 'scriptstyle', 'scriptscriptstyle'])) { | ||
if ( | ||
this.hasImplicitCommand([ | ||
'displaystyle', | ||
'textstyle', | ||
'scriptstyle', | ||
'scriptscriptstyle', | ||
]) | ||
) { | ||
// Implicit math style commands such as \displaystyle, \textstyle... | ||
@@ -671,9 +725,18 @@ // Note these commands switch to math mode and a specific size | ||
// for the parseMode | ||
const info = Definitions.getInfo('\\' + infix.value, 'math', this.macros); | ||
const info = Definitions.getInfo( | ||
'\\' + infix.value, | ||
'math', | ||
this.macros | ||
); | ||
if (info) { | ||
result = [new MathAtom(this.parseMode, | ||
info.type, | ||
info.value || infix.value, // Functions don't have | ||
info.parse ? info.parse('\\' + infix.value, [prefix, suffix]) : | ||
null)]; | ||
result = [ | ||
new MathAtom( | ||
this.parseMode, | ||
info.type, | ||
info.value || infix.value, // Functions don't have | ||
info.parse | ||
? info.parse('\\' + infix.value, [prefix, suffix]) | ||
: null | ||
), | ||
]; | ||
} else { | ||
@@ -756,3 +819,7 @@ result = [new MathAtom(this.parseMode, 'mop', infix.value)]; | ||
// (when the closing delimiter is displayed greyed out) | ||
if (/^(\?|\||<|>|\\vert|\\Vert|\\\||\\surd|\\uparrow|\\downarrow|\\Uparrow|\\Downarrow|\\updownarrow|\\Updownarrow|\\mid|\\mvert|\\mVert)$/.test(delim)) { | ||
if ( | ||
/^(\?|\||<|>|\\vert|\\Vert|\\\||\\surd|\\uparrow|\\downarrow|\\Uparrow|\\Downarrow|\\updownarrow|\\Updownarrow|\\mid|\\mvert|\\mVert)$/.test( | ||
delim | ||
) | ||
) { | ||
return delim; | ||
@@ -776,5 +843,3 @@ } | ||
// We have an unbalanced left/right (there's a \right, but no \left) | ||
const result = new MathAtom(this.parseMode, 'leftright'); | ||
result.rightDelim = this.scanDelim() || '.'; | ||
return result; | ||
return null; | ||
} | ||
@@ -789,3 +854,5 @@ | ||
} | ||
const leftDelim = this.scanDelim() || '.'; | ||
const leftDelim = this.scanDelim(); | ||
if (!leftDelim) return null; | ||
const savedMathList = this.swapMathList([]); | ||
@@ -801,2 +868,3 @@ while (!this.end() && !this.parseCommand(close)) { | ||
const rightDelim = this.scanDelim(); | ||
const result = new MathAtom(this.parseMode, 'leftright'); | ||
@@ -825,3 +893,7 @@ result.leftDelim = leftDelim; | ||
let result = false; | ||
while (this.hasLiteral('^') || this.hasLiteral('_') || this.hasLiteral("'")) { | ||
while ( | ||
this.hasLiteral('^') || | ||
this.hasLiteral('_') || | ||
this.hasLiteral("'") | ||
) { | ||
let supsub; | ||
@@ -846,3 +918,5 @@ if (this.hasLiteral('^')) { | ||
atom.superscript = atom.superscript || []; | ||
atom.superscript.push(new MathAtom(atom.parseMode, 'mord', '\u2032')); | ||
atom.superscript.push( | ||
new MathAtom(atom.parseMode, 'mord', '\u2032') | ||
); | ||
result = true; | ||
@@ -889,3 +963,4 @@ } | ||
scanOptionalArg(parseMode) { | ||
parseMode = (!parseMode || parseMode === 'auto') ? this.parseMode : parseMode; | ||
parseMode = | ||
!parseMode || parseMode === 'auto' ? this.parseMode : parseMode; | ||
this.skipWhitespace(); | ||
@@ -917,3 +992,6 @@ if (!this.parseLiteral('[')) return null; | ||
// ['x', 'rgb(a, b, c)'] | ||
const list = this.scanString().toLowerCase().trim().split(/,(?![^(]*\)(?:(?:[^(]*\)){2})*[^"]*$)/); | ||
const list = this.scanString() | ||
.toLowerCase() | ||
.trim() | ||
.split(/,(?![^(]*\)(?:(?:[^(]*\)){2})*[^"]*$)/); | ||
for (const elem of list) { | ||
@@ -939,4 +1017,11 @@ const color = Color.stringToColor(elem); | ||
} else { | ||
console.assert(parseMode === 'math', 'Unexpected parse mode: "' + parseMode + '"'); | ||
this.mathList = this.mathList.concat(this.scanImplicitGroup(token => token.type === 'literal' && token.value === ']')); | ||
console.assert( | ||
parseMode === 'math', | ||
'Unexpected parse mode: "' + parseMode + '"' | ||
); | ||
this.mathList = this.mathList.concat( | ||
this.scanImplicitGroup( | ||
token => token.type === 'literal' && token.value === ']' | ||
) | ||
); | ||
} | ||
@@ -960,3 +1045,4 @@ } | ||
scanArg(parseMode) { | ||
parseMode = (!parseMode || parseMode === 'auto') ? this.parseMode : parseMode; | ||
parseMode = | ||
!parseMode || parseMode === 'auto' ? this.parseMode : parseMode; | ||
this.parseFiller(); | ||
@@ -990,4 +1076,6 @@ let result; | ||
if (this.args) { | ||
if (this.args[paramToken.value] === undefined && | ||
this.args['?'] !== undefined) { | ||
if ( | ||
this.args[paramToken.value] === undefined && | ||
this.args['?'] !== undefined | ||
) { | ||
return this.placeholder(); | ||
@@ -1024,3 +1112,6 @@ } | ||
} else { | ||
console.assert(/^(math|text)$/.test(parseMode), 'Unexpected parse mode: "' + parseMode + '"'); | ||
console.assert( | ||
/^(math|text)$/.test(parseMode), | ||
'Unexpected parse mode: "' + parseMode + '"' | ||
); | ||
do { | ||
@@ -1054,5 +1145,9 @@ this.mathList = this.mathList.concat(this.scanImplicitGroup()); | ||
if (token.value === 'placeholder') { | ||
result = new MathAtom(this.parseMode, 'placeholder', this.scanArg('string'), this.style); | ||
result = new MathAtom( | ||
this.parseMode, | ||
'placeholder', | ||
this.scanArg('string'), | ||
this.style | ||
); | ||
result.captureSelection = true; | ||
} else if (token.value === 'char') { | ||
@@ -1062,11 +1157,20 @@ // \char has a special syntax and requires a non-braced integer | ||
let codepoint = Math.floor(this.scanNumber(true)); | ||
if (!isFinite(codepoint) || codepoint < 0 || codepoint > 0x10FFFF) { | ||
if ( | ||
!isFinite(codepoint) || | ||
codepoint < 0 || | ||
codepoint > 0x10ffff | ||
) { | ||
codepoint = 0x2753; // BLACK QUESTION MARK | ||
} | ||
result = new MathAtom(this.parseMode, | ||
result = new MathAtom( | ||
this.parseMode, | ||
this.parseMode === 'math' ? 'mord' : '', | ||
String.fromCodePoint(codepoint)); | ||
result.latex = '{\\char"' + | ||
('000000' + codepoint.toString(16)).toUpperCase().substr(-6) + '}'; | ||
String.fromCodePoint(codepoint) | ||
); | ||
result.latex = | ||
'{\\char"' + | ||
('000000' + codepoint.toString(16)) | ||
.toUpperCase() | ||
.substr(-6) + | ||
'}'; | ||
} else if (token.value === 'hskip' || token.value === 'kern') { | ||
@@ -1077,11 +1181,19 @@ // \hskip and \kern have a special syntax and requires a non-braced | ||
if (isFinite(width)) { | ||
result = new MathAtom(this.parseMode, 'spacing', null, this.style); | ||
result = new MathAtom( | ||
this.parseMode, | ||
'spacing', | ||
null, | ||
this.style | ||
); | ||
result.width = width; | ||
} | ||
result .latex = '\\' + token.value; | ||
result.latex = '\\' + token.value; | ||
} else { | ||
result = this.scanMacro(token.value); | ||
if (!result) { | ||
const info = Definitions.getInfo('\\' + token.value, this.parseMode, this.macros); | ||
const info = Definitions.getInfo( | ||
'\\' + token.value, | ||
this.parseMode, | ||
this.macros | ||
); | ||
const args = []; | ||
@@ -1116,4 +1228,8 @@ let argString = ''; | ||
const arg = this.scanArg(param.type); | ||
if (arg && arg.length === 1 && | ||
arg[0].type === 'placeholder' && param.placeholder) { | ||
if ( | ||
arg && | ||
arg.length === 1 && | ||
arg[0].type === 'placeholder' && | ||
param.placeholder | ||
) { | ||
arg[0].value = param.placeholder; | ||
@@ -1124,3 +1240,7 @@ } | ||
} else if (param.placeholder) { | ||
const placeholder = new MathAtom(this.parseMode, 'placeholder', param.placeholder); | ||
const placeholder = new MathAtom( | ||
this.parseMode, | ||
'placeholder', | ||
param.placeholder | ||
); | ||
placeholder.captureSelection = true; | ||
@@ -1132,4 +1252,7 @@ | ||
} | ||
if (param.type !== 'math' && typeof arg === 'string') { | ||
argString += arg | ||
if ( | ||
param.type !== 'math' && | ||
typeof arg === 'string' | ||
) { | ||
argString += arg; | ||
} | ||
@@ -1143,3 +1266,3 @@ } | ||
// (second infix command in an implicit group) and should be ignored. | ||
// Create the MathAtom. | ||
@@ -1149,3 +1272,6 @@ // If a parse function is present, invoke it with the arguments, | ||
if (info.parse) { | ||
const attributes = info.parse('\\' + token.value, args); | ||
const attributes = info.parse( | ||
'\\' + token.value, | ||
args | ||
); | ||
if (!attributes.type) { | ||
@@ -1165,3 +1291,6 @@ // No type provided -> the parse function will modify | ||
const saveStyle = this.style; | ||
this.style = {...this.style, ...attributes}; | ||
this.style = { | ||
...this.style, | ||
...attributes, | ||
}; | ||
result = this.scanArg(explicitGroup); | ||
@@ -1171,19 +1300,28 @@ this.style = saveStyle; | ||
// Merge the new style info with the current style | ||
this.style = {...this.style, ...attributes}; | ||
this.style = { | ||
...this.style, | ||
...attributes, | ||
}; | ||
} | ||
this.parseMode = savedMode; | ||
} else { | ||
result = new MathAtom(this.parseMode, | ||
result = new MathAtom( | ||
this.parseMode, | ||
info.type, | ||
explicitGroup ? this.scanArg(explicitGroup) : null, | ||
{...this.style, ...attributes}); | ||
explicitGroup | ||
? this.scanArg(explicitGroup) | ||
: null, | ||
{ ...this.style, ...attributes } | ||
); | ||
} | ||
} else { | ||
const style = {...this.style}; | ||
if (info.baseFontFamily) style.baseFontFamily = info.baseFontFamily; | ||
result = new MathAtom(this.parseMode, | ||
const style = { ...this.style }; | ||
if (info.baseFontFamily) | ||
style.baseFontFamily = info.baseFontFamily; | ||
result = new MathAtom( | ||
this.parseMode, | ||
info.type || 'mop', | ||
info.value || token.value, | ||
style); | ||
style | ||
); | ||
@@ -1194,6 +1332,9 @@ if (info.skipBoundary) { | ||
} | ||
if (result && !/^(llap|rlap|class|cssId)$/.test(token.value)) { | ||
if ( | ||
result && | ||
!/^(llap|rlap|class|cssId)$/.test(token.value) | ||
) { | ||
result.latex = '\\' + token.value; | ||
if (argString /*|| mandatoryParamsCount > 0*/) { | ||
result.latex += '{' + argString + '}' | ||
result.latex += '{' + argString + '}'; | ||
} | ||
@@ -1213,6 +1354,8 @@ if (result.isFunction && this.smartFence) { | ||
// An unknown command | ||
result = new MathAtom(this.parseMode, | ||
'error', '\\' + token.value); | ||
result = new MathAtom( | ||
this.parseMode, | ||
'error', | ||
'\\' + token.value | ||
); | ||
result.latex = '\\' + token.value; | ||
} | ||
@@ -1222,10 +1365,17 @@ } | ||
} else if (token.type === 'literal') { | ||
const info = Definitions.getInfo(token.value, this.parseMode, this.macros); | ||
const info = Definitions.getInfo( | ||
token.value, | ||
this.parseMode, | ||
this.macros | ||
); | ||
if (info) { | ||
const style = {...this.style}; | ||
if (info.baseFontFamily) style.baseFontFamily = info.baseFontFamily; | ||
result = new MathAtom(this.parseMode, | ||
const style = { ...this.style }; | ||
if (info.baseFontFamily) | ||
style.baseFontFamily = info.baseFontFamily; | ||
result = new MathAtom( | ||
this.parseMode, | ||
info.type, | ||
info.value || token.value, | ||
style); | ||
style | ||
); | ||
if (info.isFunction) { | ||
@@ -1235,8 +1385,13 @@ result.isFunction = true; | ||
} else { | ||
result = new MathAtom(this.parseMode, | ||
result = new MathAtom( | ||
this.parseMode, | ||
this.parseMode === 'math' ? 'mord' : '', | ||
token.value, this.style); | ||
token.value, | ||
this.style | ||
); | ||
} | ||
result.latex = Definitions.matchCodepoint(this.parseMode, | ||
token.value.codePointAt(0)); | ||
result.latex = Definitions.matchCodepoint( | ||
this.parseMode, | ||
token.value.codePointAt(0) | ||
); | ||
if (info && info.isFunction && this.smartFence) { | ||
@@ -1269,4 +1424,9 @@ // The atom was a function that may be followed by | ||
} else { | ||
console.warn('Unexpected token type "' + token.type + | ||
'", value ="' + token.value + '"'); | ||
console.warn( | ||
'Unexpected token type "' + | ||
token.type + | ||
'", value ="' + | ||
token.value + | ||
'"' | ||
); | ||
} | ||
@@ -1298,3 +1458,3 @@ return result; | ||
def = this.macros[macro].def; | ||
argCount = (this.macros[macro].args || 0); | ||
argCount = this.macros[macro].args || 0; | ||
} | ||
@@ -1311,3 +1471,7 @@ for (let i = 1; i <= argCount; i++) { | ||
// unit | ||
const atom = new MathAtom(this.parseMode, 'group', parseTokens(Lexer.tokenize(def), this.parseMode, args, this.macros)); | ||
const atom = new MathAtom( | ||
this.parseMode, | ||
'group', | ||
parseTokens(Lexer.tokenize(def), this.parseMode, args, this.macros) | ||
); | ||
atom.captureSelection = true; | ||
@@ -1335,3 +1499,4 @@ atom.latex = '\\' + macro; | ||
parseAtom() { | ||
let result = this.scanEnvironment() || | ||
let result = | ||
this.scanEnvironment() || | ||
this.scanModeShift() || | ||
@@ -1355,7 +1520,2 @@ this.scanModeSet() || | ||
/** | ||
@@ -1378,6 +1538,6 @@ * Given an array of tokens returned by the lexer, return a corresponding | ||
const parser = new Parser(tokens, args, macros); | ||
parser.parseMode = parseMode || 'math'; // other possible values: 'text', 'color', etc... | ||
parser.parseMode = parseMode || 'math'; // other possible values: 'text', 'color', etc... | ||
if (smartFence) parser.smartFence = true; | ||
while(!parser.end()) { | ||
while (!parser.end()) { | ||
mathlist = mathlist.concat(parser.scanImplicitGroup()); | ||
@@ -1391,6 +1551,3 @@ } | ||
Parser: Parser, | ||
parseTokens: parseTokens | ||
} | ||
parseTokens: parseTokens, | ||
}; |
@@ -34,3 +34,2 @@ /** | ||
//---------------------------------------------------------------------------- | ||
@@ -108,3 +107,2 @@ // SPAN | ||
selected(isSelected) { | ||
@@ -183,8 +181,10 @@ if (isSelected && !/ML__selected/.test(this.classes)) { | ||
if (style.fontShape) { | ||
this.classes += ' ' + ({ | ||
'it': 'ML__it', | ||
'sl': 'ML__shape_sl', // slanted | ||
'sc': 'ML__shape_sc', // small caps | ||
'ol': 'ML__shape_ol' // outline | ||
}[style.fontShape] || ''); | ||
this.classes += | ||
' ' + | ||
({ | ||
it: 'ML__it', | ||
sl: 'ML__shape_sl', // slanted | ||
sc: 'ML__shape_sc', // small caps | ||
ol: 'ML__shape_ol', // outline | ||
}[style.fontShape] || ''); | ||
} | ||
@@ -194,24 +194,28 @@ if (style.fontSeries) { | ||
if (m) { | ||
this.classes += ' ' + ({ | ||
'ul': 'ML__series_ul', | ||
'el': 'ML__series_el', | ||
'l': 'ML__series_l', | ||
'sl': 'ML__series_sl', | ||
'm': '', // medium (default) | ||
'sb': 'ML__series_sb', | ||
'b': 'ML__bold', | ||
'eb': 'ML__series_eb', | ||
'ub': 'ML__series_ub', | ||
}[m[1] || ''] || ''); | ||
this.classes += ' ' + ({ | ||
'uc': 'ML__series_uc', | ||
'ec': 'ML__series_ec', | ||
'c': 'ML__series_c', | ||
'sc': 'ML__series_sc', | ||
'n': '', // normal (default) | ||
'sx': 'ML__series_sx', | ||
'x': 'ML__series_x', | ||
'ex': 'ML__series_ex', | ||
'ux': 'ML__series_ux', | ||
}[m[2] || ''] || ''); | ||
this.classes += | ||
' ' + | ||
({ | ||
ul: 'ML__series_ul', | ||
el: 'ML__series_el', | ||
l: 'ML__series_l', | ||
sl: 'ML__series_sl', | ||
m: '', // medium (default) | ||
sb: 'ML__series_sb', | ||
b: 'ML__bold', | ||
eb: 'ML__series_eb', | ||
ub: 'ML__series_ub', | ||
}[m[1] || ''] || ''); | ||
this.classes += | ||
' ' + | ||
({ | ||
uc: 'ML__series_uc', | ||
ec: 'ML__series_ec', | ||
c: 'ML__series_c', | ||
sc: 'ML__series_sc', | ||
n: '', // normal (default) | ||
sx: 'ML__series_sx', | ||
x: 'ML__series_x', | ||
ex: 'ML__series_ex', | ||
ux: 'ML__series_ux', | ||
}[m[2] || ''] || ''); | ||
} | ||
@@ -233,18 +237,22 @@ } | ||
this.depth = 0.0; | ||
this.maxFontSize = { | ||
size1: 0.5, | ||
size2: 0.7, | ||
size3: 0.8, | ||
size4: 0.9, | ||
size5: 1.0, | ||
size6: 1.2, | ||
size7: 1.44, | ||
size8: 1.73, | ||
size9: 2.07, | ||
size10: 2.49, | ||
}[style.fontSize] || 1.0; | ||
this.maxFontSize = | ||
{ | ||
size1: 0.5, | ||
size2: 0.7, | ||
size3: 0.8, | ||
size4: 0.9, | ||
size5: 1.0, | ||
size6: 1.2, | ||
size7: 1.44, | ||
size8: 1.73, | ||
size9: 2.07, | ||
size10: 2.49, | ||
}[style.fontSize] || 1.0; | ||
this.skew = 0.0; | ||
this.italic = 0.0; | ||
for (let i = 0; i < this.body.length; i++) { | ||
const metrics = FontMetrics.getCharacterMetrics(this.body.charAt(i), fontName); | ||
const metrics = FontMetrics.getCharacterMetrics( | ||
this.body.charAt(i), | ||
fontName | ||
); | ||
// If we were able to get metrics info for this character, store it. | ||
@@ -259,6 +267,4 @@ if (metrics) { | ||
} | ||
} | ||
/** | ||
@@ -291,7 +297,7 @@ * Set the value of a CSS property associated with this span. | ||
/** | ||
* | ||
* @param {number} left | ||
* @private | ||
*/ | ||
/** | ||
* | ||
* @param {number} left | ||
* @private | ||
*/ | ||
setLeft(left) { | ||
@@ -303,7 +309,7 @@ if (left && left !== 0) { | ||
} | ||
/** | ||
* | ||
* @param {number} right | ||
* @private | ||
*/ | ||
/** | ||
* | ||
* @param {number} right | ||
* @private | ||
*/ | ||
setRight(right) { | ||
@@ -324,4 +330,8 @@ if (right && right !== 0) { | ||
if (margin && margin !== 0) { | ||
if (!this.style && | ||
!/qquad|quad|enspace|thickspace|mediumspace|thinspace|negativethinspace/.test(this.classes)) { | ||
if ( | ||
!this.style && | ||
!/qquad|quad|enspace|thickspace|mediumspace|thinspace|negativethinspace/.test( | ||
this.classes | ||
) | ||
) { | ||
// Attempt to use a class instead of an explicit margin | ||
@@ -335,3 +345,3 @@ const cls = { | ||
'0.166667': 'thinspace', | ||
'-0.166667': 'negativethinspace' | ||
'-0.166667': 'negativethinspace', | ||
}[margin.toString()]; | ||
@@ -345,3 +355,4 @@ if (cls) { | ||
const currentMargin = parseFloat(this.style['margin-right'] || '0'); | ||
this.style['margin-right'] = toString(currentMargin + margin) + 'em'; | ||
this.style['margin-right'] = | ||
toString(currentMargin + margin) + 'em'; | ||
} | ||
@@ -375,5 +386,10 @@ } | ||
if (child.isTight) { | ||
spacing = (INTER_ATOM_TIGHT_SPACING[previousType + '+' + type] || 0); | ||
spacing = | ||
INTER_ATOM_TIGHT_SPACING[ | ||
previousType + '+' + type | ||
] || 0; | ||
} else { | ||
spacing = (INTER_ATOM_SPACING[previousType + '+' + type] || 0); | ||
spacing = | ||
INTER_ATOM_SPACING[previousType + '+' + type] || | ||
0; | ||
} | ||
@@ -388,6 +404,7 @@ spacing = Math.floor(hscale * spacing); | ||
// Collapse 'empty' spans | ||
if ((body === '\u200b' || !body) && | ||
(!this.classes || this.classes === 'ML__selected')) { | ||
if ( | ||
(body === '\u200b' || !body) && | ||
(!this.classes || this.classes === 'ML__selected') | ||
) { | ||
result = ''; | ||
} else { | ||
@@ -399,3 +416,3 @@ // Note: We can't omit the tag, even if it has no class and no style, | ||
if (this.cssId) { | ||
result += ' id="' + this.cssId + '" ' | ||
result += ' id="' + this.cssId + '" '; | ||
} | ||
@@ -411,4 +428,14 @@ | ||
for (const attribute in this.attributes) { | ||
if (Object.prototype.hasOwnProperty.call(this.attributes, attribute)) { | ||
result += ' ' + attribute + '="' + this.attributes[attribute] + '"'; | ||
if ( | ||
Object.prototype.hasOwnProperty.call( | ||
this.attributes, | ||
attribute | ||
) | ||
) { | ||
result += | ||
' ' + | ||
attribute + | ||
'="' + | ||
this.attributes[attribute] + | ||
'"'; | ||
} | ||
@@ -423,7 +450,9 @@ } | ||
if (/command|placeholder|error/.test(this.type)) { | ||
classes.push({ | ||
'command': 'ML__command', | ||
'placeholder': 'ML__placeholder', | ||
'error': 'ML__error' | ||
}[this.type]); | ||
classes.push( | ||
{ | ||
command: 'ML__command', | ||
placeholder: 'ML__placeholder', | ||
error: 'ML__error', | ||
}[this.type] | ||
); | ||
} | ||
@@ -435,9 +464,10 @@ if (this.caret && this.type === 'command') { | ||
// Remove duplicate and empty classes | ||
let classList = ''; | ||
if (classes.length > 1) { | ||
classList = classes.filter(function (x, e, a) { | ||
return x.length > 0 && a.indexOf(x) === e; | ||
}).join(' '); | ||
classList = classes | ||
.filter(function(x, e, a) { | ||
return x.length > 0 && a.indexOf(x) === e; | ||
}) | ||
.join(' '); | ||
} else { | ||
@@ -456,3 +486,5 @@ classList = classes[0]; | ||
this.style['margin-left'] = | ||
toString((parseFloat(this.style['margin-left']) + hskip / 18)) + 'em'; | ||
toString( | ||
parseFloat(this.style['margin-left']) + hskip / 18 | ||
) + 'em'; | ||
} else { | ||
@@ -475,7 +507,10 @@ // No margin yet. Can we encode it as a Unicode space? | ||
for (const style in this.style) { | ||
if (Object.prototype.hasOwnProperty.call(this.style, style)) { | ||
if ( | ||
Object.prototype.hasOwnProperty.call(this.style, style) | ||
) { | ||
// Render the style property, except the background | ||
// of selected spans | ||
if (style !== 'background-color' || !isSelected) { | ||
styleString += style + ':' + this.style[style] + ';'; | ||
styleString += | ||
style + ':' + this.style[style] + ';'; | ||
} | ||
@@ -506,7 +541,14 @@ } | ||
result += 'height:' + (this.height + this.depth) + 'em;'; | ||
result += 'transform:translateY(-' + Math.round(FontMetrics.toPx(this.depth, 'em') + FontMetrics.toPx(this.style.padding)) + 'px);'; | ||
result += | ||
'transform:translateY(-' + | ||
Math.round( | ||
FontMetrics.toPx(this.depth, 'em') + | ||
FontMetrics.toPx(this.style.padding) | ||
) + | ||
'px);'; | ||
if (this.style && this.style.padding) { | ||
result += 'top:' + this.style.padding + ';'; | ||
result += 'left:' + this.style.padding + ';'; | ||
result += 'width:calc(100% - 2 * ' + this.style.padding + ' );'; | ||
result += | ||
'width:calc(100% - 2 * ' + this.style.padding + ' );'; | ||
} else { | ||
@@ -532,3 +574,2 @@ result += 'top:0;'; | ||
if (this.caret && this.type !== 'command') { | ||
@@ -545,3 +586,2 @@ if (this.caret === 'text') { | ||
/** | ||
@@ -564,4 +604,8 @@ * Can this span be coalesced with 'span'? | ||
// Don't coalesce consecutive errors or placeholders | ||
if (this.type === 'error' || this.type === 'placeholder' || | ||
this.type === 'command') return false; | ||
if ( | ||
this.type === 'error' || | ||
this.type === 'placeholder' || | ||
this.type === 'command' | ||
) | ||
return false; | ||
// If this span or the candidate span have children, we can't | ||
@@ -578,5 +622,9 @@ // coalesce them, but we'll try to coalesce their children | ||
// any 'empty' classes (whitespace) | ||
const classes = this.classes.trim().replace(/\s+/g, ' ') | ||
const classes = this.classes | ||
.trim() | ||
.replace(/\s+/g, ' ') | ||
.split(' '); | ||
const spanClasses = span.classes.trim().replace(/\s+/g, ' ') | ||
const spanClasses = span.classes | ||
.trim() | ||
.replace(/\s+/g, ' ') | ||
.split(' '); | ||
@@ -598,4 +646,6 @@ // If they have a different number of classes, can't coalesce | ||
for (const style in this.style) { | ||
if (Object.prototype.hasOwnProperty.call(this.style, style) && | ||
Object.prototype.hasOwnProperty.call(span.style, style)) { | ||
if ( | ||
Object.prototype.hasOwnProperty.call(this.style, style) && | ||
Object.prototype.hasOwnProperty.call(span.style, style) | ||
) { | ||
if (this.style[style] !== span.style[style]) return false; | ||
@@ -618,16 +668,2 @@ } | ||
/** | ||
@@ -644,58 +680,57 @@ * Return HTML markup representing this span, its style, classes and | ||
const INTER_ATOM_SPACING = { | ||
'mord+mop': 3, | ||
'mord+mbin': 4, | ||
'mord+mrel': 5, | ||
'mord+minner': 3, | ||
'mord+mop': 3, | ||
'mord+mbin': 4, | ||
'mord+mrel': 5, | ||
'mord+minner': 3, | ||
'mop+mord': 3, | ||
'mop+mop': 3, | ||
'mop+mbin': 5, | ||
'mop+minner': 3, | ||
'mop+mord': 3, | ||
'mop+mop': 3, | ||
'mop+mbin': 5, | ||
'mop+minner': 3, | ||
'mbin+mord': 4, | ||
'mbin+mop': 4, | ||
'mbin+mopen': 4, | ||
'mbin+minner': 4, | ||
'mbin+mord': 4, | ||
'mbin+mop': 4, | ||
'mbin+mopen': 4, | ||
'mbin+minner': 4, | ||
'mrel+mord': 5, | ||
'mrel+mop': 5, | ||
'mrel+mopen': 5, | ||
'mrel+minner': 5, | ||
'mrel+mord': 5, | ||
'mrel+mop': 5, | ||
'mrel+mopen': 5, | ||
'mrel+minner': 5, | ||
'mclose+mop': 3, | ||
'mclose+mbin': 4, | ||
'mclose+mrel': 5, | ||
'mclose+minner': 3, | ||
'mclose+mop': 3, | ||
'mclose+mbin': 4, | ||
'mclose+mrel': 5, | ||
'mclose+minner': 3, | ||
'mpunct+mord': 3, | ||
'mpunct+mop': 3, | ||
'mpunct+mbin': 4, | ||
'mpunct+mrel': 5, | ||
'mpunct+mopen': 3, | ||
'mpunct+mpunct': 3, | ||
'mpunct+minner': 3 | ||
} | ||
'mpunct+mord': 3, | ||
'mpunct+mop': 3, | ||
'mpunct+mbin': 4, | ||
'mpunct+mrel': 5, | ||
'mpunct+mopen': 3, | ||
'mpunct+mpunct': 3, | ||
'mpunct+minner': 3, | ||
}; | ||
// See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html | ||
// 6.1.4 Non-Marking Characters | ||
const SPACING_CHARACTER = [ | ||
'\u200b', // 0/18 ZERO-WIDTH SPACE | ||
'\u200a', // 1/18 HAIR SPACE | ||
'\u200a\u200a', // 2/18 | ||
'\u2009', // 3/18 THIN SPACE | ||
'\u205f', // 4/18 MEDIUM MATHEMATICAL SPACE | ||
'\u205f\u200a', // 5/18 MEDIUM MATHEMATICAL SPACE + HAIR SPACE | ||
'\u2004', // 6/18 THREE-PER-EM SPACE 1/3em | ||
'\u200b', // 0/18 ZERO-WIDTH SPACE | ||
'\u200a', // 1/18 HAIR SPACE | ||
'\u200a\u200a', // 2/18 | ||
'\u2009', // 3/18 THIN SPACE | ||
'\u205f', // 4/18 MEDIUM MATHEMATICAL SPACE | ||
'\u205f\u200a', // 5/18 MEDIUM MATHEMATICAL SPACE + HAIR SPACE | ||
'\u2004', // 6/18 THREE-PER-EM SPACE 1/3em | ||
'', | ||
'', | ||
'\u2002' // 9/18 EN SPACE 1/2em = 9/18 | ||
'\u2002', // 9/18 EN SPACE 1/2em = 9/18 | ||
]; | ||
const NEGATIVE_SPACING_CHARACTER = [ | ||
'', | ||
'\u200a\u2063', // -1/18 | ||
'\u200a\u2063', // -1/18 | ||
'', | ||
'\u2009\u2063', // -3/18 | ||
'\u205f\u2063', // -4/18 | ||
'\u2005\u2063' // -5/18 | ||
'\u2009\u2063', // -3/18 | ||
'\u205f\u2063', // -4/18 | ||
'\u2005\u2063', // -5/18 | ||
]; | ||
@@ -709,8 +744,8 @@ | ||
const INTER_ATOM_TIGHT_SPACING = { | ||
'mord+mop': 3, | ||
'mop+mord': 3, | ||
'mop+mop': 3, | ||
'mclose+mop': 3, | ||
'minner+mop': 3 | ||
} | ||
'mord+mop': 3, | ||
'mop+mord': 3, | ||
'mop+mop': 3, | ||
'mclose+mop': 3, | ||
'minner+mop': 3, | ||
}; | ||
@@ -724,5 +759,2 @@ function lastSpanType(span) { | ||
/** | ||
@@ -752,3 +784,2 @@ * Attempts to coalesce (merge) spans, for example consecutive text spans. | ||
//---------------------------------------------------------------------------- | ||
@@ -774,3 +805,2 @@ // UTILITY FUNCTIONS | ||
function skew(spans) { | ||
@@ -796,3 +826,2 @@ if (!spans) return 0; | ||
/** | ||
@@ -818,3 +847,2 @@ * Make an element made of a sequence of children with classes | ||
/** | ||
@@ -842,3 +870,2 @@ * | ||
/** | ||
@@ -855,19 +882,25 @@ * Makes an element placed in each of the vlist elements to ensure that each | ||
function makeFontSizer(context, fontSize) { | ||
const fontSizeAdjustment = fontSize ? fontSize / context.mathstyle.sizeMultiplier : 0; | ||
const fontSizeInner = new Span('\u200b'); // ZERO WIDTH SPACE | ||
const fontSizeAdjustment = fontSize | ||
? fontSize / context.mathstyle.sizeMultiplier | ||
: 0; | ||
const fontSizeInner = new Span('\u200b'); // ZERO WIDTH SPACE | ||
if (fontSizeAdjustment !== 1) { | ||
fontSizeInner.setStyle('font-size', | ||
fontSizeInner.setStyle( | ||
'font-size', | ||
fontSizeAdjustment, | ||
(fontSizeAdjustment > 0) ? 'em' : ''); | ||
fontSizeAdjustment > 0 ? 'em' : '' | ||
); | ||
fontSizeInner.attributes = { | ||
"aria-hidden": true | ||
} | ||
'aria-hidden': true, | ||
}; | ||
} | ||
if (context.size !== 'size5') { | ||
return new Span(fontSizeInner, | ||
'fontsize-ensurer reset-' + context.size + ' size5'); | ||
return new Span( | ||
fontSizeInner, | ||
'fontsize-ensurer reset-' + context.size + ' size5' | ||
); | ||
} | ||
return (fontSizeAdjustment !== 0) ? fontSizeInner : null; | ||
return fontSizeAdjustment !== 0 ? fontSizeInner : null; | ||
} | ||
@@ -921,3 +954,2 @@ | ||
function makeStyleWrap(type, children, fromStyle, toStyle, classes) { | ||
@@ -967,3 +999,3 @@ classes = classes || ''; | ||
// An array, with a single span, use the single span as the output | ||
return spans[0] | ||
return spans[0]; | ||
} | ||
@@ -1052,8 +1084,10 @@ } | ||
for (let i = 2; i < originalElements.length; i += 2) { | ||
const diff = -originalElements[i + 1] - currPos - | ||
originalElements[i].depth; | ||
const diff = | ||
-originalElements[i + 1] - currPos - originalElements[i].depth; | ||
currPos = currPos + diff; | ||
const kern = diff - | ||
(originalElements[i - 2].height + originalElements[i - 2].depth); | ||
const kern = | ||
diff - | ||
(originalElements[i - 2].height + | ||
originalElements[i - 2].depth); | ||
@@ -1129,4 +1163,2 @@ elements.push(kern); | ||
//---------------------------------------------------------------------------- | ||
@@ -1138,30 +1170,27 @@ // FONTS | ||
const FONT_NAME = { | ||
'ams': 'AMS-Regular', | ||
'bb': 'AMS-Regular', | ||
'cal': 'Caligraphic-Regular', | ||
'frak': 'Fraktur-Regular', | ||
'scr': 'Script-Regular', | ||
'cmr': 'Main-Regular', | ||
'cmss': 'SansSerif-Regular', | ||
'cmtt': 'Typewriter-Regular', | ||
'math': 'Math-Regular', | ||
'mainit': 'Main-Italic', | ||
ams: 'AMS-Regular', | ||
bb: 'AMS-Regular', | ||
cal: 'Caligraphic-Regular', | ||
frak: 'Fraktur-Regular', | ||
scr: 'Script-Regular', | ||
cmr: 'Main-Regular', | ||
cmss: 'SansSerif-Regular', | ||
cmtt: 'Typewriter-Regular', | ||
math: 'Math-Regular', | ||
mainit: 'Main-Italic', | ||
}; | ||
const FONT_CLASS = { | ||
'ams': 'ML__ams', | ||
'bb': 'ML__bb', | ||
'cal': 'ML__cal', | ||
'frak': 'ML__frak', | ||
'scr': 'ML__script', | ||
'cmr': 'ML__mathrm', | ||
'cmss': 'ML__sans', | ||
'cmtt': 'ML__tt', | ||
'math': 'ML__mathit', | ||
'mainit': 'ML__mainit', | ||
} | ||
ams: 'ML__ams', | ||
bb: 'ML__bb', | ||
cal: 'ML__cal', | ||
frak: 'ML__frak', | ||
scr: 'ML__script', | ||
cmr: 'ML__mathrm', | ||
cmss: 'ML__sans', | ||
cmtt: 'ML__tt', | ||
math: 'ML__mathit', | ||
mainit: 'ML__mainit', | ||
}; | ||
/** | ||
@@ -1179,5 +1208,7 @@ * Given a font family ('frak', 'math'...) return a corresponding | ||
// If this is not a single char, just do a simple fontFamily -> fontName mapping | ||
if (typeof symbol !== 'string' || | ||
if ( | ||
typeof symbol !== 'string' || | ||
symbol.length > 1 || | ||
symbol === '\u200b') { | ||
symbol === '\u200b' | ||
) { | ||
return FONT_NAME[fontFamily]; | ||
@@ -1193,7 +1224,5 @@ } | ||
if (!/^[A-Z ]$/.test(symbol)) return null; | ||
} else if (fontFamily === 'cal') { | ||
// Only supports uppercase latin and digits | ||
if (!/^[0-9A-Z ]$/.test(symbol)) return null; | ||
} else if (fontFamily === 'frak') { | ||
@@ -1204,3 +1233,7 @@ if (!/^[0-9A-Za-z ]$|^[!"#$%&'()*+,\-./:;=?[]^’‘]$/.test(symbol)) { | ||
} else if (fontFamily === 'cmtt' || fontFamily === 'cmss') { | ||
if (!/^[0-9A-Za-z ]$|^[!"&'()*+,\-./:;=?@[]^_~\u0131\u0237\u0393\u0394\u0398\u039b\u039e\u03A0\u03A3\u03A5\u03A8\u03a9’‘]$/.test(symbol)) { | ||
if ( | ||
!/^[0-9A-Za-z ]$|^[!"&'()*+,\-./:;=?@[]^_~\u0131\u0237\u0393\u0394\u0398\u039b\u039e\u03A0\u03A3\u03A5\u03A8\u03a9’‘]$/.test( | ||
symbol | ||
) | ||
) { | ||
return null; | ||
@@ -1238,5 +1271,3 @@ } | ||
skew, | ||
italic | ||
} | ||
italic, | ||
}; |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -13,85 +12,85 @@ * This modules handles low-level keyboard events and normalize them across | ||
const INTL_KEY = { | ||
'#': '#', | ||
'|': '|', | ||
'[': 'BracketLeft', | ||
']': 'BracketRight', | ||
'-': 'Minus', | ||
'+': 'Plus', | ||
'=': 'Equal', | ||
'/': 'Slash', | ||
'\\': 'Backslash', | ||
} | ||
'#': '#', | ||
'|': '|', | ||
'[': 'BracketLeft', | ||
']': 'BracketRight', | ||
'-': 'Minus', | ||
'+': 'Plus', | ||
'=': 'Equal', | ||
'/': 'Slash', | ||
'\\': 'Backslash', | ||
}; | ||
const KEY_NAMES = { | ||
'Space': 'Spacebar', | ||
' ': 'Spacebar', | ||
'Escape': 'Esc', | ||
'ArrowLeft': 'Left', | ||
'ArrowUp': 'Up', | ||
'ArrowRight': 'Right', | ||
'ArrowDown': 'Down', | ||
'Delete': 'Del' | ||
Space: 'Spacebar', | ||
' ': 'Spacebar', | ||
Escape: 'Esc', | ||
ArrowLeft: 'Left', | ||
ArrowUp: 'Up', | ||
ArrowRight: 'Right', | ||
ArrowDown: 'Down', | ||
Delete: 'Del', | ||
}; | ||
const VIRTUAL_KEY_NAMES = { | ||
'q' : 'KeyQ', | ||
'w' : 'KeyW', | ||
'e' : 'KeyE', | ||
'r' : 'KeyR', | ||
't' : 'KeyT', | ||
'y' : 'KeyY', | ||
'u' : 'KeyU', | ||
'i' : 'KeyI', | ||
'o' : 'KeyO', | ||
'p' : 'KeyP', | ||
'a' : 'KeyA', | ||
's' : 'KeyS', | ||
'd' : 'KeyD', | ||
'f' : 'KeyF', | ||
'g' : 'KeyG', | ||
'h' : 'KeyH', | ||
'j' : 'KeyJ', | ||
'k' : 'KeyK', | ||
'l' : 'KeyL', | ||
'z' : 'KeyZ', | ||
'x' : 'KeyX', | ||
'c' : 'KeyC', | ||
'v' : 'KeyV', | ||
'b' : 'KeyB', | ||
'n' : 'KeyN', | ||
'm' : 'KeyM', | ||
const VIRTUAL_KEY_NAMES = { | ||
q: 'KeyQ', | ||
w: 'KeyW', | ||
e: 'KeyE', | ||
r: 'KeyR', | ||
t: 'KeyT', | ||
y: 'KeyY', | ||
u: 'KeyU', | ||
i: 'KeyI', | ||
o: 'KeyO', | ||
p: 'KeyP', | ||
a: 'KeyA', | ||
s: 'KeyS', | ||
d: 'KeyD', | ||
f: 'KeyF', | ||
g: 'KeyG', | ||
h: 'KeyH', | ||
j: 'KeyJ', | ||
k: 'KeyK', | ||
l: 'KeyL', | ||
z: 'KeyZ', | ||
x: 'KeyX', | ||
c: 'KeyC', | ||
v: 'KeyV', | ||
b: 'KeyB', | ||
n: 'KeyN', | ||
m: 'KeyM', | ||
'1' : 'Digit1', | ||
'2' : 'Digit2', | ||
'3' : 'Digit3', | ||
'4' : 'Digit4', | ||
'5' : 'Digit5', | ||
'6' : 'Digit6', | ||
'7' : 'Digit7', | ||
'8' : 'Digit8', | ||
'9' : 'Digit9', | ||
'0' : 'Digit0', | ||
'1': 'Digit1', | ||
'2': 'Digit2', | ||
'3': 'Digit3', | ||
'4': 'Digit4', | ||
'5': 'Digit5', | ||
'6': 'Digit6', | ||
'7': 'Digit7', | ||
'8': 'Digit8', | ||
'9': 'Digit9', | ||
'0': 'Digit0', | ||
'!' : 'Shift-Digit1', | ||
'@' : 'Shift-Digit2', | ||
'#' : 'Shift-Digit3', | ||
'$' : 'Shift-Digit4', | ||
'%' : 'Shift-Digit5', | ||
'^' : 'Shift-Digit6', | ||
'&' : 'Shift-Digit7', | ||
'*' : 'Shift-Digit8', | ||
'(' : 'Shift-Digit9', | ||
')' : 'Shift-Digit0', | ||
'!': 'Shift-Digit1', | ||
'@': 'Shift-Digit2', | ||
'#': 'Shift-Digit3', | ||
$: 'Shift-Digit4', | ||
'%': 'Shift-Digit5', | ||
'^': 'Shift-Digit6', | ||
'&': 'Shift-Digit7', | ||
'*': 'Shift-Digit8', | ||
'(': 'Shift-Digit9', | ||
')': 'Shift-Digit0', | ||
'-' : 'Minus', | ||
'_' : 'Shift-Minus', | ||
'-': 'Minus', | ||
_: 'Shift-Minus', | ||
'/' : 'Slash', | ||
'\\' : 'Backslash', // Some virtual keyboards (iOS) return '\' as the event.key | ||
// with no evt.code | ||
'|' : 'Shift-Backslash', | ||
'?' : 'Shift-Slash', | ||
'/': 'Slash', | ||
'\\': 'Backslash', // Some virtual keyboards (iOS) return '\' as the event.key | ||
// with no evt.code | ||
'|': 'Shift-Backslash', | ||
'?': 'Shift-Slash', | ||
' ' : 'Spacebar' | ||
}; | ||
' ': 'Spacebar', | ||
}; | ||
@@ -137,3 +136,3 @@ /** | ||
if (!keyname) { | ||
keyname = VIRTUAL_KEY_NAMES[evt.key.toLowerCase()] || evt.key; | ||
keyname = VIRTUAL_KEY_NAMES[evt.key.toLowerCase()]; | ||
} | ||
@@ -159,5 +158,4 @@ } | ||
return modifiers.join('-'); | ||
} | ||
} | ||
/** | ||
@@ -225,6 +223,9 @@ * Setup to capture the keyboard events from a `TextArea` and redispatch them to | ||
function onKeydown(e) { | ||
const allowDeadKey = typeof handlers.allowDeadKey === 'function' && | ||
const allowDeadKey = | ||
typeof handlers.allowDeadKey === 'function' && | ||
handlers.allowDeadKey(); | ||
if (!allowDeadKey && | ||
((e.key === 'Dead' || e.key === 'Unidentified') || e.keyCode === 229)) { | ||
if ( | ||
!allowDeadKey && | ||
(e.key === 'Dead' || e.key === 'Unidentified' || e.keyCode === 229) | ||
) { | ||
deadKey = true; | ||
@@ -245,5 +246,7 @@ compositionInProgress = false; | ||
} | ||
if (!compositionInProgress && | ||
if ( | ||
!compositionInProgress && | ||
e.code !== 'CapsLock' && | ||
!/(Control|Meta|Alt|Shift)(Right|Left)/.test(e.code)) { | ||
!/(Control|Meta|Alt|Shift)(Right|Left)/.test(e.code) | ||
) { | ||
keydownEvent = e; | ||
@@ -261,3 +264,6 @@ keypressEvent = null; | ||
if (keydownEvent && keypressEvent) { | ||
handlers.keystroke(keyboardEventToString(keydownEvent), keydownEvent); | ||
handlers.keystroke( | ||
keyboardEventToString(keydownEvent), | ||
keydownEvent | ||
); | ||
} | ||
@@ -271,3 +277,3 @@ | ||
function onKeyup() { | ||
// If we've received a keydown, but no keypress, check what's in the | ||
// If we've received a keydown, but no keypress, check what's in the | ||
// textarea field. | ||
@@ -317,6 +323,17 @@ if (!compositionInProgress && keydownEvent && !keypressEvent) { | ||
target.addEventListener('focus', onFocus, true); | ||
target.addEventListener('compositionstart', | ||
() => { compositionInProgress = true }, true); | ||
target.addEventListener('compositionend', | ||
() => { compositionInProgress = false; defer(handleTypedText); }, true); | ||
target.addEventListener( | ||
'compositionstart', | ||
() => { | ||
compositionInProgress = true; | ||
}, | ||
true | ||
); | ||
target.addEventListener( | ||
'compositionend', | ||
() => { | ||
compositionInProgress = false; | ||
defer(handleTypedText); | ||
}, | ||
true | ||
); | ||
@@ -342,3 +359,2 @@ // The `input` handler gets called when the field is changed, for example | ||
}); | ||
} | ||
@@ -350,3 +366,2 @@ | ||
function eventToChar(evt) { | ||
@@ -363,3 +378,7 @@ if (!evt) return ''; | ||
result = result || evt.key || evt.code; | ||
if (/^(Return|Enter|Tab|Escape|Delete|PageUp|PageDown|Home|End|Help|ArrowLeft|ArrowRight|ArrowUp|ArrowDown)$/.test(result)) { | ||
if ( | ||
/^(Return|Enter|Tab|Escape|Delete|PageUp|PageDown|Home|End|Help|ArrowLeft|ArrowRight|ArrowUp|ArrowDown)$/.test( | ||
result | ||
) | ||
) { | ||
result = ''; | ||
@@ -376,3 +395,3 @@ } | ||
altKey: false, | ||
shiftKey: false | ||
shiftKey: false, | ||
}; | ||
@@ -388,6 +407,3 @@ | ||
eventToChar, | ||
charToEvent | ||
charToEvent, | ||
}; | ||
@@ -6,5 +6,2 @@ /** | ||
/** | ||
@@ -29,3 +26,2 @@ * | ||
/** | ||
@@ -40,3 +36,3 @@ * | ||
// Reset the path | ||
const result = {path: [], extent: 0}; | ||
const result = { path: [], extent: 0 }; | ||
@@ -56,3 +52,3 @@ // Parse the selection extent, if present | ||
relation: m2[1], | ||
offset: parseInt(m2[2]) | ||
offset: parseInt(m2[2]), | ||
}); | ||
@@ -78,5 +74,7 @@ } | ||
let i = 0; | ||
while ( i <= maxIndex && | ||
p[i].relation === q[i].relation && | ||
p[i].offset === q[i].offset) { | ||
while ( | ||
i <= maxIndex && | ||
p[i].relation === q[i].relation && | ||
p[i].offset === q[i].offset | ||
) { | ||
result.push(p[i]); | ||
@@ -99,11 +97,11 @@ i += 1; | ||
function pathDistance(p, q) { | ||
let result = 0; | ||
let i = -1; | ||
let done = false; | ||
while (!done) { | ||
let result = 0; | ||
let i = -1; | ||
let done = false; | ||
while (!done) { | ||
i += 1; | ||
done = i >= p.length || i >= q.length; | ||
done = done || | ||
!(p[i].relation === q[i].relation && | ||
p[i].offset === q[i].offset); | ||
done = | ||
done || | ||
!(p[i].relation === q[i].relation && p[i].offset === q[i].offset); | ||
} | ||
@@ -113,4 +111,7 @@ if (i === p.length && i === q.length) { | ||
result = 0; | ||
} else if (i + 1 === p.length && i + 1 === q.length && | ||
p[i].relation === q[i].relation ) { | ||
} else if ( | ||
i + 1 === p.length && | ||
i + 1 === q.length && | ||
p[i].relation === q[i].relation | ||
) { | ||
// They're siblings | ||
@@ -122,7 +123,5 @@ result = 1; | ||
return result; | ||
return result; | ||
} | ||
function clone(path) { | ||
@@ -137,7 +136,3 @@ return pathFromString(pathToString(path)).path; | ||
pathCommonAncestor, | ||
clone | ||
} | ||
clone, | ||
}; |
@@ -1,3 +0,1 @@ | ||
import MathAtom from '../core/mathAtom.js'; | ||
@@ -10,108 +8,107 @@ import Lexer from '../core/lexer.js'; | ||
const SAMPLES = { | ||
'\\mathrm': '\\mathrm{x=+3.14, x\\in A}', | ||
'\\mathbf': '\\mathbf{x=+3.14, x\\in A}', | ||
'\\bf': '\\bf{x=+3.14, x\\in A}', | ||
'\\bm': '\\bm{x=+3.14, x\\in A}', | ||
'\\bold': '\\bold{x=+3.14, x\\in A}', | ||
'\\mathit': '\\mathbb{x=+3.14}', | ||
'\\mathbb': '\\mathbb{ABCD}', | ||
'\\Bbb': '\\mathbb{ABCD}', | ||
'\\frak': '\\frak{ABCD}', | ||
'\\mathfrak': '\\mathfrak{ABCD}', | ||
'\\mathscr': '\\mathscr{ABCD}', | ||
'\\mathsf': '\\mathsf{ABab01}', | ||
'\\mathtt': '\\mathtt{x=+3.14, x\\in A}', | ||
'\\mathcal': '\\mathcal{ABCD}', | ||
'\\boldsymbol': '\\boldsymbol{ABab01+=}', | ||
'\\mathrm': '\\mathrm{x=+3.14, x\\in A}', | ||
'\\mathbf': '\\mathbf{x=+3.14, x\\in A}', | ||
'\\bf': '\\bf{x=+3.14, x\\in A}', | ||
'\\bm': '\\bm{x=+3.14, x\\in A}', | ||
'\\bold': '\\bold{x=+3.14, x\\in A}', | ||
'\\mathit': '\\mathbb{x=+3.14}', | ||
'\\mathbb': '\\mathbb{ABCD}', | ||
'\\Bbb': '\\mathbb{ABCD}', | ||
'\\frak': '\\frak{ABCD}', | ||
'\\mathfrak': '\\mathfrak{ABCD}', | ||
'\\mathscr': '\\mathscr{ABCD}', | ||
'\\mathsf': '\\mathsf{ABab01}', | ||
'\\mathtt': '\\mathtt{x=+3.14, x\\in A}', | ||
'\\mathcal': '\\mathcal{ABCD}', | ||
'\\boldsymbol': '\\boldsymbol{ABab01+=}', | ||
'\\text': '\\text{ABC abc}', | ||
'\\textrm': '\\textrm{ABC abc}', | ||
'\\textnormal': '\\textnormal{ABC abc}', | ||
'\\textit': '\\textit{ABC abc}', | ||
'\\textbf': '\\textbf{ABC abc}', | ||
'\\texttt': '\\texttt{ABC abc}', | ||
'\\textsf': '\\textsf{ABC abc}', | ||
'\\textcolor': `{\\textcolor{m0}A}{\\textcolor{m1}B}{\\textcolor{m2}C }{\\textcolor{m3}a}{\\textcolor{m4}b}{\\textcolor{m5}c}{\\textcolor{m6}8}`, | ||
'\\color': `{\\color{m0}A}{\\color{m1}B}{\\color{m2}C}{\\color{m3}a}{\\color{m4}b}{\\color{m5}c}{\\color{m6}8}`, | ||
'\\text': '\\text{ABC abc}', | ||
'\\textrm': '\\textrm{ABC abc}', | ||
'\\textnormal': '\\textnormal{ABC abc}', | ||
'\\textit': '\\textit{ABC abc}', | ||
'\\textbf': '\\textbf{ABC abc}', | ||
'\\texttt': '\\texttt{ABC abc}', | ||
'\\textsf': '\\textsf{ABC abc}', | ||
'\\textcolor': `{\\textcolor{m0}A}{\\textcolor{m1}B}{\\textcolor{m2}C }{\\textcolor{m3}a}{\\textcolor{m4}b}{\\textcolor{m5}c}{\\textcolor{m6}8}`, | ||
'\\color': `{\\color{m0}A}{\\color{m1}B}{\\color{m2}C}{\\color{m3}a}{\\color{m4}b}{\\color{m5}c}{\\color{m6}8}`, | ||
'\\underline': '\\underline{\\unicode{"2B1A}}', | ||
'\\overline': '\\overline{\\unicode{"2B1A}}', | ||
'\\underline': '\\underline{\\unicode{"2B1A}}', | ||
'\\overline': '\\overline{\\unicode{"2B1A}}', | ||
'\\vec': '\\vec{\\unicode{"25CC}}', | ||
'\\check': '\\check{\\unicode{"25CC}}', | ||
'\\acute': '\\acute{\\unicode{"25CC}}', | ||
'\\breve': '\\breve{\\unicode{"25CC}}', | ||
'\\tilde': '\\tilde{\\unicode{"25CC}}', | ||
'\\hat': '\\hat{\\unicode{"25CC}}', | ||
'\\ddot': '\\ddot{\\unicode{"25CC}}', | ||
'\\dot': '\\dot{\\unicode{"25CC}}', | ||
'\\bar': '\\bar{\\unicode{"25CC}}', | ||
'\\vec': '\\vec{\\unicode{"25CC}}', | ||
'\\check': '\\check{\\unicode{"25CC}}', | ||
'\\acute': '\\acute{\\unicode{"25CC}}', | ||
'\\breve': '\\breve{\\unicode{"25CC}}', | ||
'\\tilde': '\\tilde{\\unicode{"25CC}}', | ||
'\\hat': '\\hat{\\unicode{"25CC}}', | ||
'\\ddot': '\\ddot{\\unicode{"25CC}}', | ||
'\\dot': '\\dot{\\unicode{"25CC}}', | ||
'\\bar': '\\bar{\\unicode{"25CC}}', | ||
'\\!': '\\unicode{"203A}\\!\\unicode{"2039}', | ||
'\\,': '\\unicode{"203A}\\,\\unicode{"2039}', | ||
'\\:': '\\unicode{"203A}\\:\\unicode{"2039}', | ||
'\\;': '\\unicode{"203A}\\;\\unicode{"2039}', | ||
'\\quad': '\\unicode{"203A}\\quad\\unicode{"2039}', | ||
'\\qquad': '\\unicode{"203A}\\qquad\\unicode{"2039}', | ||
'\\enskip': '\\unicode{"203A}\\enskip\\unicode{"2039}', | ||
'\\space': '\\unicode{"203A}\\space\\unicode{"2039}', | ||
'\\!': '\\unicode{"203A}\\!\\unicode{"2039}', | ||
'\\,': '\\unicode{"203A}\\,\\unicode{"2039}', | ||
'\\:': '\\unicode{"203A}\\:\\unicode{"2039}', | ||
'\\;': '\\unicode{"203A}\\;\\unicode{"2039}', | ||
'\\quad': '\\unicode{"203A}\\quad\\unicode{"2039}', | ||
'\\qquad': '\\unicode{"203A}\\qquad\\unicode{"2039}', | ||
'\\enskip': '\\unicode{"203A}\\enskip\\unicode{"2039}', | ||
'\\space': '\\unicode{"203A}\\space\\unicode{"2039}', | ||
'\\frac': '\\frac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\dfrac': '\\dfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\cfrac': '\\cfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\tfrac': '\\tfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\dbinom': '\\dbinom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\tbinom': '\\tbinom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\binom': '\\binom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\pdiff': '\\pdiff{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\frac': '\\frac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\dfrac': '\\dfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\cfrac': '\\cfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\tfrac': '\\tfrac{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\dbinom': '\\dbinom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\tbinom': '\\tbinom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\binom': '\\binom{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\pdiff': '\\pdiff{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\in': 'n\\in\\N', | ||
'\\notin': 'n\\notin\\N', | ||
'\\not': 'B \\not A', | ||
'\\ni': 'N\\in n', | ||
'\\owns': 'N\\owns n', | ||
'\\subset': 'A\\subset B', | ||
'\\supset': 'B\\supset A', | ||
'\\subseteq': 'A\\subseteq B', | ||
'\\supseteq': 'B\\supseteq A', | ||
'\\nsubseteq': 'A\\nsubseteq B', | ||
'\\nsupseteq': 'B\\nsupseteq A', | ||
'\\subsetneq': 'A\\subsetneq B', | ||
'\\supsetneq': 'B\\supsetneq A', | ||
'\\varsubsetneq': 'A\\varsubsetneq B', | ||
'\\varsupsetneq': 'B\\varsupsetneq A', | ||
'\\nsubseteqq': 'A\\varsupsetneq B', | ||
'\\subsetneqq': 'A\\subsetneqq B', | ||
'\\varsubsetneqq': 'A\\varsubsetneqq B', | ||
'\\nsubset': 'A\\nsubset B', | ||
'\\nsupset': 'B\\nsupset A', | ||
'\\complement': 'A^\\complement', | ||
'\\in': 'n\\in\\N', | ||
'\\notin': 'n\\notin\\N', | ||
'\\not': 'B \\not A', | ||
'\\ni': 'N\\in n', | ||
'\\owns': 'N\\owns n', | ||
'\\subset': 'A\\subset B', | ||
'\\supset': 'B\\supset A', | ||
'\\subseteq': 'A\\subseteq B', | ||
'\\supseteq': 'B\\supseteq A', | ||
'\\nsubseteq': 'A\\nsubseteq B', | ||
'\\nsupseteq': 'B\\nsupseteq A', | ||
'\\subsetneq': 'A\\subsetneq B', | ||
'\\supsetneq': 'B\\supsetneq A', | ||
'\\varsubsetneq': 'A\\varsubsetneq B', | ||
'\\varsupsetneq': 'B\\varsupsetneq A', | ||
'\\nsubseteqq': 'A\\varsupsetneq B', | ||
'\\subsetneqq': 'A\\subsetneqq B', | ||
'\\varsubsetneqq': 'A\\varsubsetneqq B', | ||
'\\nsubset': 'A\\nsubset B', | ||
'\\nsupset': 'B\\nsupset A', | ||
'\\complement': 'A^\\complement', | ||
'\\bigcup': '\\bigcup_{\\unicode{"2B1A}}', | ||
'\\bigcap': '\\bigcap_{\\unicode{"2B1A}}', | ||
'\\sqrt': '\\sqrt{\\unicode{"2B1A}}', | ||
'\\prod': '\\prod_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\sum': '\\sum_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\int': '\\int_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\stackrel': '\\stackrel{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\stackbin': '\\stackbin{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\underset': '\\underset{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\overset': '\\overset{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\prime': '\\unicode{"2B1A}^{\\prime}', | ||
'\\boxed': '\\boxed{\\unicode{"2B1A}}', | ||
'\\colorbox': '\\colorbox{#fbc0bd}{\\unicode{"2B1A}}', | ||
'\\bbox': '\\bbox[#ffd400, solid 2px #ffd400]{\\unicode{"2B1A}}', | ||
'\\enclose': | ||
'\\enclose{updiagonalstrike,roundedbox}[1px solid red, mathbackground="#fbc0bd"]{23+45}', | ||
'\\fcolorbox': '\\fcolorbox{#cd0030}{#ffd400}{\\unicode{"2B1A}}', | ||
'\\ ': '\\char"2423', // OPEN BOX | ||
'\\bigcup': '\\bigcup_{\\unicode{"2B1A}}', | ||
'\\bigcap': '\\bigcap_{\\unicode{"2B1A}}', | ||
'\\sqrt': '\\sqrt{\\unicode{"2B1A}}', | ||
'\\prod': '\\prod_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\sum': '\\sum_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\int': '\\int_{\\unicode{"2B1A}}^{\\unicode{"2B1A}}', | ||
'\\stackrel': '\\stackrel{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\stackbin': '\\stackbin{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\underset': '\\underset{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\overset': '\\overset{\\unicode{"2B1A}}{\\unicode{"2B1A}}', | ||
'\\prime': '\\unicode{"2B1A}^{\\prime}', | ||
'\\top': '{\\color{red}P}\\top', | ||
'\\bot': '{\\color{#0F0}P}\\bot', | ||
'\\mid': 'P(p\\mid q)', | ||
'\\boxed': '\\boxed{\\unicode{"2B1A}}', | ||
'\\colorbox': '\\colorbox{#fbc0bd}{\\unicode{"2B1A}}', | ||
'\\bbox': '\\bbox[#ffd400, solid 2px #ffd400]{\\unicode{"2B1A}}', | ||
'\\enclose': '\\enclose{updiagonalstrike,roundedbox}[1px solid red, mathbackground="#fbc0bd"]{23+45}', | ||
'\\fcolorbox': '\\fcolorbox{#cd0030}{#ffd400}{\\unicode{"2B1A}}', | ||
'\\ ': '\\char"2423', // OPEN BOX | ||
'\\top': '{\\color{red}P}\\top', | ||
'\\bot': '{\\color{#0F0}P}\\bot', | ||
'\\mid': 'P(p\\mid q)', | ||
'\\rlap': '\\rlap{x}o', | ||
'\\llap': 'o\\llap{/}', | ||
'\\rlap': '\\rlap{x}o', | ||
'\\llap': 'o\\llap{/}', | ||
}; | ||
@@ -125,167 +122,187 @@ | ||
const NOTES = { | ||
'\\text': 'roman text', | ||
'\\textrm': 'roman text', | ||
'\\text': 'roman text', | ||
'\\textrm': 'roman text', | ||
'\\textnormal': 'roman text', | ||
'\\textit': 'italic text', | ||
'\\textbf': 'bold text', | ||
'\\texttt': 'monospaced text', | ||
'\\textsf': 'sans-serif text', | ||
'\\mathrm': ['roman', '(upright)'], | ||
'\\mathbf': 'bold', | ||
'\\bf': 'bold', | ||
'\\bold': 'bold', | ||
'\\mathit': 'italic', | ||
'\\mathbb': 'blackboard', | ||
'\\Bbb': 'blackboard', | ||
'\\mathscr': 'script', | ||
'\\mathtt': ['typewriter', '(monospaced)'], | ||
'\\mathsf': 'sans-serif', | ||
'\\mathcal': 'caligraphic', | ||
'\\frak': ['fraktur', '(gothic)'], | ||
'\\mathfrak': ['fraktur', '(gothic)'], | ||
'\\textit': 'italic text', | ||
'\\textbf': 'bold text', | ||
'\\texttt': 'monospaced text', | ||
'\\textsf': 'sans-serif text', | ||
'\\mathrm': ['roman', '(upright)'], | ||
'\\mathbf': 'bold', | ||
'\\bf': 'bold', | ||
'\\bold': 'bold', | ||
'\\mathit': 'italic', | ||
'\\mathbb': 'blackboard', | ||
'\\Bbb': 'blackboard', | ||
'\\mathscr': 'script', | ||
'\\mathtt': ['typewriter', '(monospaced)'], | ||
'\\mathsf': 'sans-serif', | ||
'\\mathcal': 'caligraphic', | ||
'\\frak': ['fraktur', '(gothic)'], | ||
'\\mathfrak': ['fraktur', '(gothic)'], | ||
'\\textcolor': 'text color', | ||
'\\color': 'color', | ||
'\\textcolor': 'text color', | ||
'\\color': 'color', | ||
'\\forall': 'for all', | ||
'\\exists': 'there exists', | ||
'\\nexists': 'there does not exist', | ||
'\\frac': 'fraction', | ||
'\\dfrac': 'display fraction', | ||
'\\cfrac': 'continuous fraction', | ||
'\\tfrac': 'text fraction', | ||
'\\binom': 'binomial coefficient', | ||
'\\dbinom': 'display binomial coefficient', | ||
'\\tbinom': 'text binomial coefficient', | ||
'\\pdiff': 'partial differential', | ||
'\\forall': 'for all', | ||
'\\exists': 'there exists', | ||
'\\nexists': 'there does not exist', | ||
'\\frac': 'fraction', | ||
'\\dfrac': 'display fraction', | ||
'\\cfrac': 'continuous fraction', | ||
'\\tfrac': 'text fraction', | ||
'\\binom': 'binomial coefficient', | ||
'\\dbinom': 'display binomial coefficient', | ||
'\\tbinom': 'text binomial coefficient', | ||
'\\pdiff': 'partial differential', | ||
'\\vec': 'vector', | ||
'\\check': 'caron', | ||
'\\acute': 'acute', | ||
'\\breve': 'breve', | ||
'\\tilde': 'tilde', | ||
'\\dot': 'dot', | ||
'\\hat': ['hat', 'circumflex'], | ||
'\\ddot': 'double dot', | ||
'\\bar': 'bar', | ||
'\\vec': 'vector', | ||
'\\check': 'caron', | ||
'\\acute': 'acute', | ||
'\\breve': 'breve', | ||
'\\tilde': 'tilde', | ||
'\\dot': 'dot', | ||
'\\hat': ['hat', 'circumflex'], | ||
'\\ddot': 'double dot', | ||
'\\bar': 'bar', | ||
'\\prime': 'prime', | ||
'\\doubleprime':'double prime', | ||
'\\prime': 'prime', | ||
'\\doubleprime': 'double prime', | ||
'\\varnothing': 'empty set', | ||
'\\emptyset': 'empty set', | ||
'\\subseteq': 'subset of or <br>equal to', | ||
'\\supseteq': 'superset of or <br>equal to', | ||
'\\supset': 'superset of', | ||
'\\subset': 'subset of', | ||
'\\partial': 'partial derivative', | ||
'\\bigcup': 'union', | ||
'\\bigcap': 'intersection', | ||
'\\approx': 'approximately equal to', | ||
'\\notin': 'not an element of', | ||
'\\in': ['element of', 'included in'], | ||
'\\infty': 'infinity', | ||
'\\land': 'logical and', | ||
'\\sqrt': 'square root', | ||
'\\prod': 'product', | ||
'\\sum': 'summation', | ||
'\\amalg': ['amalgamation', 'coproduct', 'free product', 'disjoint union'], | ||
'\\cup': 'union with', | ||
'\\cap': 'intersection with', | ||
'\\int': 'integral', | ||
'\\iint': 'surface integral', | ||
'\\oint': 'curve integral', | ||
'\\iiint': 'volume integral', | ||
'\\iff': 'if and only if', | ||
'\\ln': 'natural logarithm', | ||
'\\emptyset': 'empty set', | ||
'\\subseteq': 'subset of or <br>equal to', | ||
'\\supseteq': 'superset of or <br>equal to', | ||
'\\supset': 'superset of', | ||
'\\subset': 'subset of', | ||
'\\partial': 'partial derivative', | ||
'\\bigcup': 'union', | ||
'\\bigcap': 'intersection', | ||
'\\approx': 'approximately equal to', | ||
'\\notin': 'not an element of', | ||
'\\in': ['element of', 'included in'], | ||
'\\infty': 'infinity', | ||
'\\land': 'logical and', | ||
'\\sqrt': 'square root', | ||
'\\prod': 'product', | ||
'\\sum': 'summation', | ||
'\\amalg': ['amalgamation', 'coproduct', 'free product', 'disjoint union'], | ||
'\\cup': 'union with', | ||
'\\cap': 'intersection with', | ||
'\\int': 'integral', | ||
'\\iint': 'surface integral', | ||
'\\oint': 'curve integral', | ||
'\\iiint': 'volume integral', | ||
'\\iff': 'if and only if', | ||
'\\ln': 'natural logarithm', | ||
'\\boldsymbol': 'bold', | ||
'\\setminus': 'set subtraction', | ||
'\\stackrel': 'relation with symbol above', | ||
'\\stackbin': 'operator with symbol above', | ||
'\\underset': 'symbol with annotation below', | ||
'\\overset': 'symbol with annotation above', | ||
'\\hslash': ['h-bar', 'Planck constant'], | ||
'\\gtrsim': 'greater than or <br>similar to', | ||
'\\propto': 'proportional to', | ||
'\\equiv': 'equivalent to', | ||
'\\setminus': 'set subtraction', | ||
'\\stackrel': 'relation with symbol above', | ||
'\\stackbin': 'operator with symbol above', | ||
'\\underset': 'symbol with annotation below', | ||
'\\overset': 'symbol with annotation above', | ||
'\\hslash': ['h-bar', 'Planck constant'], | ||
'\\gtrsim': 'greater than or <br>similar to', | ||
'\\propto': 'proportional to', | ||
'\\equiv': 'equivalent to', | ||
'\\!': ['negative thin space', '(-3 mu)'], | ||
'\\ ': ['space', '(6 mu)'], | ||
'\\,': ['thin space', '(3 mu)'], | ||
'\\:': ['medium space', '(4 mu)'], | ||
'\\;': ['thick space', '(5 mu)'], | ||
'\\quad': ['1 em space', '(18 mu)'], | ||
'\\qquad': ['2 em space', '(36 mu)'], | ||
'\\enskip': ['½ em space', '(9 mu)'], | ||
'\\!': ['negative thin space', '(-3 mu)'], | ||
'\\ ': ['space', '(6 mu)'], | ||
'\\,': ['thin space', '(3 mu)'], | ||
'\\:': ['medium space', '(4 mu)'], | ||
'\\;': ['thick space', '(5 mu)'], | ||
'\\quad': ['1 em space', '(18 mu)'], | ||
'\\qquad': ['2 em space', '(36 mu)'], | ||
'\\enskip': ['½ em space', '(9 mu)'], | ||
'\\mp': 'minus or plus', | ||
'\\pm': 'plus or minus', | ||
'\\Im': 'Imaginary part of', | ||
'\\Re': 'Real part of', | ||
'\\mp': 'minus or plus', | ||
'\\pm': 'plus or minus', | ||
'\\Im': 'Imaginary part of', | ||
'\\Re': 'Real part of', | ||
'\\gothicCapitalR': 'Real part of', | ||
'\\gothicCapitalI': 'Imaginary part part of', | ||
'\\differentialD': 'differential d', | ||
'\\aleph': ['aleph', 'infinite cardinal', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Cardinal_number">Wikipedia <big>›</big></a>' | ||
'\\differentialD': 'differential d', | ||
'\\aleph': [ | ||
'aleph', | ||
'infinite cardinal', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Cardinal_number">Wikipedia <big>›</big></a>', | ||
], | ||
'\\beth': ['beth', 'beth number', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Beth_number">Wikipedia <big>›</big></a>' | ||
'\\beth': [ | ||
'beth', | ||
'beth number', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Beth_number">Wikipedia <big>›</big></a>', | ||
], | ||
'\\gimel': ['gimel', 'gimel function', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Gimel_function">Wikipedia <big>›</big></a>' | ||
'\\gimel': [ | ||
'gimel', | ||
'gimel function', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Gimel_function">Wikipedia <big>›</big></a>', | ||
], | ||
'\\O': 'empty set', | ||
'\\N': 'set of <br>natural numbers', | ||
'\\Z': 'set of <br>integers', | ||
'\\Q': 'set of <br>rational numbers', | ||
'\\C': 'set of <br>complex numbers', | ||
'\\R': 'set of <br>real numbers', | ||
'\\P': 'set of <br>prime numbers', | ||
'\\O': 'empty set', | ||
'\\N': 'set of <br>natural numbers', | ||
'\\Z': 'set of <br>integers', | ||
'\\Q': 'set of <br>rational numbers', | ||
'\\C': 'set of <br>complex numbers', | ||
'\\R': 'set of <br>real numbers', | ||
'\\P': 'set of <br>prime numbers', | ||
'\\lesseqqgtr': 'less than, equal to or<br> greater than', | ||
'\\gnapprox': 'greater than and <br>not approximately', | ||
'\\lnapprox': 'lesser than and <br>not approximately', | ||
'\\lesseqqgtr': 'less than, equal to or<br> greater than', | ||
'\\gnapprox': 'greater than and <br>not approximately', | ||
'\\lnapprox': 'lesser than and <br>not approximately', | ||
'\\j': 'dotless j', | ||
'\\i': 'dotless i', | ||
'\\cdot': 'centered dot', | ||
'\\lmoustache': 'left moustache', | ||
'\\rmoustache': 'right moustache', | ||
'\\nabla': ['nabla', 'del', 'differential vector operator'], | ||
'\\j': 'dotless j', | ||
'\\i': 'dotless i', | ||
'\\cdot': 'centered dot', | ||
'\\lmoustache': 'left moustache', | ||
'\\rmoustache': 'right moustache', | ||
'\\nabla': ['nabla', 'del', 'differential vector operator'], | ||
'\\square': ['square', 'd’Alembert operator', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/D%27Alembert_operator">Wikipedia <big>›</big></a>' | ||
'\\square': [ | ||
'square', | ||
'd’Alembert operator', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/D%27Alembert_operator">Wikipedia <big>›</big></a>', | ||
], | ||
'\\blacksquare': ['black square', 'end of proof', 'tombstone', 'Halmos symbol'], | ||
'\\Box': 'end of proof', | ||
'\\colon': ['such that', 'ratio'], | ||
'\\coloneq': ['is defined by', 'is assigned'], | ||
'\\Colon': ['is defined by', 'as'], | ||
'\\_': ['underbar', 'underscore'], | ||
'\\ll': 'much less than', | ||
'\\gg': 'much greater than', | ||
'\\doteq': 'approximately equal to', | ||
'\\Doteq': 'approximately equal to', | ||
'\\doteqdot': 'approximately equal to', | ||
'\\cong': ['isomorphism of', '(for algebras, modules...)'], | ||
'\\det': ['determinant of', '(of a matrix)'], | ||
'\\dotplus': 'Cartesian product algebra', | ||
'\\otimes': ['tensor product', '(of algebras)', | ||
'Kronecker product', '(of matrices)'], | ||
'\\oplus': ['direct sum', '(of modules)'], | ||
'\\lb': 'base-2 logarithm', | ||
'\\lg': 'base-10 logarithm', | ||
'\\wp': ['Weierstrass P', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Weierstrass%27s_elliptic_functions">Wikipedia <big>›</big></a>' | ||
], | ||
'\\wr': ['wreath product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Wreath_product">Wikipedia <big>›</big></a>' | ||
], | ||
'\\top': ['tautology', 'Proposition P is universally true'], | ||
'\\bot': ['contradiction', 'Proposition P is contradictory'], | ||
'\\mid': ['probability', 'of event A given B'], | ||
'\\mho': ['Siemens', 'electrical conductance in SI unit', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Siemens_(unit)">Wikipedia <big>›</big></a>' | ||
], | ||
'\\blacksquare': [ | ||
'black square', | ||
'end of proof', | ||
'tombstone', | ||
'Halmos symbol', | ||
], | ||
'\\Box': 'end of proof', | ||
'\\colon': ['such that', 'ratio'], | ||
'\\coloneq': ['is defined by', 'is assigned'], | ||
'\\Colon': ['is defined by', 'as'], | ||
'\\_': ['underbar', 'underscore'], | ||
'\\ll': 'much less than', | ||
'\\gg': 'much greater than', | ||
'\\doteq': 'approximately equal to', | ||
'\\Doteq': 'approximately equal to', | ||
'\\doteqdot': 'approximately equal to', | ||
'\\cong': ['isomorphism of', '(for algebras, modules...)'], | ||
'\\det': ['determinant of', '(of a matrix)'], | ||
'\\dotplus': 'Cartesian product algebra', | ||
'\\otimes': [ | ||
'tensor product', | ||
'(of algebras)', | ||
'Kronecker product', | ||
'(of matrices)', | ||
], | ||
'\\oplus': ['direct sum', '(of modules)'], | ||
'\\lb': 'base-2 logarithm', | ||
'\\lg': 'base-10 logarithm', | ||
'\\wp': [ | ||
'Weierstrass P', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Weierstrass%27s_elliptic_functions">Wikipedia <big>›</big></a>', | ||
], | ||
'\\wr': [ | ||
'wreath product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Wreath_product">Wikipedia <big>›</big></a>', | ||
], | ||
'\\top': ['tautology', 'Proposition P is universally true'], | ||
'\\bot': ['contradiction', 'Proposition P is contradictory'], | ||
'\\mid': ['probability', 'of event A given B'], | ||
'\\mho': [ | ||
'Siemens', | ||
'electrical conductance in SI unit', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Siemens_(unit)">Wikipedia <big>›</big></a>', | ||
], | ||
@@ -295,58 +312,57 @@ '\\Longrightarrow': 'implies', | ||
'\\prec': 'precedes', | ||
'\\preceq': 'precedes or is equal to', | ||
'\\succ': 'succeedes', | ||
'\\succeq': 'succeedes or is equal to', | ||
'\\perp': ['is perpendicular to', 'is independent of'], | ||
'\\prec': 'precedes', | ||
'\\preceq': 'precedes or is equal to', | ||
'\\succ': 'succeedes', | ||
'\\succeq': 'succeedes or is equal to', | ||
'\\perp': ['is perpendicular to', 'is independent of'], | ||
'\\models': ['entails', | ||
'double-turnstyle, models', | ||
'is a semantic consequence of', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Double_turnstile">Wikipedia <big>›</big></a>' | ||
], | ||
'\\vdash': ['satisfies', | ||
'turnstyle, assertion sign', | ||
'syntactic inference', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Turnstile_(symbol)">Wikipedia <big>›</big></a>' | ||
'\\models': [ | ||
'entails', | ||
'double-turnstyle, models', | ||
'is a semantic consequence of', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Double_turnstile">Wikipedia <big>›</big></a>', | ||
], | ||
'\\vdash': [ | ||
'satisfies', | ||
'turnstyle, assertion sign', | ||
'syntactic inference', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Turnstile_(symbol)">Wikipedia <big>›</big></a>', | ||
], | ||
'\\implies': ['implies', 'logical consequence'], | ||
'\\impliedby': ['implied by', 'logical consequence'], | ||
'\\implies': ['implies', 'logical consequence'], | ||
'\\impliedby': ['implied by', 'logical consequence'], | ||
'\\surd': ['surd', 'root of', 'checkmark'], | ||
'\\ltimes': ['semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>' | ||
], | ||
'\\rtimes': ['semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>' | ||
], | ||
'\\leftthreetimes': ['semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>' | ||
], | ||
'\\rightthreetimes': ['semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>' | ||
], | ||
'\\divideontimes': ['divide on times'], | ||
'\\curlywedge': 'nor', | ||
'\\curlyvee': 'nand', | ||
'\\surd': ['surd', 'root of', 'checkmark'], | ||
'\\ltimes': [ | ||
'semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>', | ||
], | ||
'\\rtimes': [ | ||
'semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>', | ||
], | ||
'\\leftthreetimes': [ | ||
'semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>', | ||
], | ||
'\\rightthreetimes': [ | ||
'semi direct product', | ||
'<a target="_blank" href="https://en.wikipedia.org/wiki/Semidirect_product">Wikipedia <big>›</big></a>', | ||
], | ||
'\\divideontimes': ['divide on times'], | ||
'\\curlywedge': 'nor', | ||
'\\curlyvee': 'nand', | ||
'\\simeq': 'is group isomorphic with', | ||
'\\vartriangleleft': [ | ||
'is a normal subgroup of', | ||
'is an ideal ring of' | ||
], | ||
'\\simeq': 'is group isomorphic with', | ||
'\\vartriangleleft': ['is a normal subgroup of', 'is an ideal ring of'], | ||
'\\circ': ['circle', 'ring', 'function composition'], | ||
'\\circ': ['circle', 'ring', 'function composition'], | ||
'\\rlap': ['overlap right', | ||
'\\rlap{x}o'], | ||
'\\llap': ['overlap left', | ||
'o\\llap{/}'], | ||
'\\colorbox': ['color box', | ||
'\\colorbox{#fbc0bd}{...}' | ||
], | ||
'\\ast': ['asterisk', 'reflexive closure (as a superscript)'], | ||
'\\bullet': 'bullet', | ||
'\\rlap': ['overlap right', '\\rlap{x}o'], | ||
'\\llap': ['overlap left', 'o\\llap{/}'], | ||
'\\colorbox': ['color box', '\\colorbox{#fbc0bd}{...}'], | ||
'\\ast': ['asterisk', 'reflexive closure (as a superscript)'], | ||
'\\bullet': 'bullet', | ||
'\\lim': 'limit', | ||
'\\lim': 'limit', | ||
}; | ||
@@ -363,12 +379,16 @@ | ||
function latexToMarkup(latex, mf) { | ||
const parse = ParserModule.parseTokens(Lexer.tokenize(latex), 'math', null, mf.config.macros); | ||
const parse = ParserModule.parseTokens( | ||
Lexer.tokenize(latex), | ||
'math', | ||
null, | ||
mf.config.macros | ||
); | ||
const spans = MathAtom.decompose( | ||
{ | ||
mathstyle: 'displaystyle', | ||
macros: mf.config.macros | ||
macros: mf.config.macros, | ||
}, | ||
parse); | ||
parse | ||
); | ||
@@ -382,3 +402,6 @@ const base = Span.makeSpan(spans, 'ML__base'); | ||
bottomStrut.setStyle('vertical-align', -base.depth, 'em'); | ||
const wrapper = Span.makeSpan([topStrut, bottomStrut, base], 'ML__mathlive'); | ||
const wrapper = Span.makeSpan( | ||
[topStrut, bottomStrut, base], | ||
'ML__mathlive' | ||
); | ||
@@ -399,17 +422,21 @@ return wrapper.toMarkup(); | ||
let template = displayArrows ? | ||
'<div class="ML__popover__prev-shortcut" role="button" aria-label="Previous suggestion"><span><span>▲</span></span></div>' : ''; | ||
let template = displayArrows | ||
? '<div class="ML__popover__prev-shortcut" role="button" aria-label="Previous suggestion"><span><span>▲</span></span></div>' | ||
: ''; | ||
template += '<span class="ML__popover__content" role="button">'; | ||
template += '<div class="ML__popover__command">' + | ||
command_markup + '</div>'; | ||
template += | ||
'<div class="ML__popover__command">' + command_markup + '</div>'; | ||
if (command_note) { | ||
template += '<div class="ML__popover__note">' + | ||
command_note + '</div>'; | ||
template += '<div class="ML__popover__note">' + command_note + '</div>'; | ||
} | ||
if (command_shortcuts) { | ||
template += '<div class="ML__popover__shortcut">' + | ||
command_shortcuts + '</div>'; | ||
template += | ||
'<div class="ML__popover__shortcut">' + | ||
command_shortcuts + | ||
'</div>'; | ||
} | ||
template += '</span>'; | ||
template += displayArrows ? '<div class="ML__popover__next-shortcut" role="button" aria-label="Next suggestion"><span><span>▼</span></span></div>' : ''; | ||
template += displayArrows | ||
? '<div class="ML__popover__next-shortcut" role="button" aria-label="Next suggestion"><span><span>▼</span></span></div>' | ||
: ''; | ||
showPopover(mf, template); | ||
@@ -419,6 +446,8 @@ | ||
if (el && el.length > 0) { | ||
mf._attachButtonHandlers(el[0], ['complete', {acceptSuggestion:true}]); | ||
mf._attachButtonHandlers(el[0], [ | ||
'complete', | ||
{ acceptSuggestion: true }, | ||
]); | ||
} | ||
el = mf.popover.getElementsByClassName('ML__popover__prev-shortcut'); | ||
@@ -433,3 +462,2 @@ if (el && el.length > 0) { | ||
} | ||
} | ||
@@ -450,3 +478,6 @@ | ||
} else { | ||
if (!mf.mathlist.anchor() || mf.mathlist.anchor().type !== 'command') { | ||
if ( | ||
!mf.mathlist.anchor() || | ||
mf.mathlist.anchor().type !== 'command' | ||
) { | ||
hidePopover(mf); | ||
@@ -473,6 +504,8 @@ } else { | ||
// get screen width & height (browser compatibility) | ||
const screen_height = window.innerHeight || | ||
const screen_height = | ||
window.innerHeight || | ||
document.documentElement.clientHeight || | ||
document.body.clientHeight; | ||
const screen_width = window.innerWidth || | ||
const screen_width = | ||
window.innerWidth || | ||
document.documentElement.clientWidth || | ||
@@ -482,29 +515,33 @@ document.body.clientWidth; | ||
// get scrollbar size. This would be 0 in mobile device (also no needed). | ||
const scrollbar_width = window.innerWidth - | ||
document.documentElement.clientWidth; | ||
const scrollbar_height = window.innerHeight - | ||
document.documentElement.clientHeight; | ||
const virtualkeyboard_height = mf.virtualKeyboardVisible ? | ||
mf.virtualKeyboard.offsetHeight : 0; | ||
const scrollbar_width = | ||
window.innerWidth - document.documentElement.clientWidth; | ||
const scrollbar_height = | ||
window.innerHeight - document.documentElement.clientHeight; | ||
const virtualkeyboard_height = mf.virtualKeyboardVisible | ||
? mf.virtualKeyboard.offsetHeight | ||
: 0; | ||
// prevent screen overflow horizontal. | ||
if (position.x + (mf.popover.offsetWidth / 2) > screen_width - scrollbar_width) { | ||
if ( | ||
position.x + mf.popover.offsetWidth / 2 > | ||
screen_width - scrollbar_width | ||
) { | ||
mf.popover.style.left = | ||
(screen_width - mf.popover.offsetWidth - scrollbar_width) + 'px'; | ||
} else if (position.x - (mf.popover.offsetWidth / 2) < 0) { | ||
screen_width - mf.popover.offsetWidth - scrollbar_width + 'px'; | ||
} else if (position.x - mf.popover.offsetWidth / 2 < 0) { | ||
mf.popover.style.left = 0; | ||
} else { | ||
mf.popover.style.left = | ||
(position.x - mf.popover.offsetWidth / 2) + 'px'; | ||
mf.popover.style.left = position.x - mf.popover.offsetWidth / 2 + 'px'; | ||
} | ||
// and position the popover right below or above the caret | ||
if (position.y + mf.popover.offsetHeight + 5 > | ||
screen_height - scrollbar_height - virtualkeyboard_height) { | ||
if ( | ||
position.y + mf.popover.offsetHeight + 5 > | ||
screen_height - scrollbar_height - virtualkeyboard_height | ||
) { | ||
mf.popover.classList.add('reverse-direction'); | ||
mf.popover.style.top = | ||
(position.y - position.height - | ||
mf.popover.offsetHeight - 5) + 'px'; | ||
position.y - position.height - mf.popover.offsetHeight - 5 + 'px'; | ||
} else { | ||
mf.popover.classList.remove('reverse-direction'); | ||
mf.popover.style.top = (position.y + 5) + 'px'; | ||
mf.popover.style.top = position.y + 5 + 'px'; | ||
} | ||
@@ -517,4 +554,2 @@ } | ||
export default { | ||
@@ -527,6 +562,3 @@ getNote, | ||
hidePopover, | ||
updatePopoverPosition | ||
} | ||
updatePopoverPosition, | ||
}; |
@@ -50,131 +50,133 @@ /** | ||
const KEYBOARD_SHORTCUTS = { | ||
'Left': 'moveToPreviousChar', | ||
'Right': 'moveToNextChar', | ||
'Up': 'moveUp', | ||
'Down': 'moveDown', | ||
Left: 'moveToPreviousChar', | ||
Right: 'moveToNextChar', | ||
Up: 'moveUp', | ||
Down: 'moveDown', | ||
'Shift-Left': 'extendToPreviousChar', | ||
'Shift-Right': 'extendToNextChar', | ||
'Shift-Up': 'extendUp', | ||
'Shift-Down': 'extendDown', | ||
'Shift-Left': 'extendToPreviousChar', | ||
'Shift-Right': 'extendToNextChar', | ||
'Shift-Up': 'extendUp', | ||
'Shift-Down': 'extendDown', | ||
'Backspace': 'deletePreviousChar', | ||
'Alt-Del': 'deletePreviousChar', | ||
Backspace: 'deletePreviousChar', | ||
'Alt-Del': 'deletePreviousChar', | ||
'Del': 'deleteNextChar', | ||
'Alt-Backspace': 'deleteNextChar', | ||
Del: 'deleteNextChar', | ||
'Alt-Backspace': 'deleteNextChar', | ||
'Alt-Left': 'moveToPreviousWord', | ||
'Alt-Right': 'moveToNextWord', | ||
'Alt-Left': 'moveToPreviousWord', | ||
'Alt-Right': 'moveToNextWord', | ||
'Alt-Shift-Left': 'extendToPreviousWord', | ||
'Alt-Shift-Right': 'extendToNextWord', | ||
'Alt-Shift-Left': 'extendToPreviousWord', | ||
'Alt-Shift-Right': 'extendToNextWord', | ||
'Ctrl-Left': 'moveToGroupStart', | ||
'Ctrl-Right': 'moveToGroupEnd', | ||
'Ctrl-Left': 'moveToGroupStart', | ||
'Ctrl-Right': 'moveToGroupEnd', | ||
'Ctrl-Shift-Left': 'extendToGroupStart', | ||
'Ctrl-Shift-Right': 'extendToGroupEnd', | ||
'Ctrl-Shift-Left': 'extendToGroupStart', | ||
'Ctrl-Shift-Right': 'extendToGroupEnd', | ||
'math:Spacebar': 'moveAfterParent', | ||
'math:Shift-Spacebar': 'moveBeforeParent', | ||
'math:Spacebar': 'moveAfterParent', | ||
'math:Shift-Spacebar': 'moveBeforeParent', | ||
'Home': 'moveToMathFieldStart', | ||
'mac:Meta-Left': 'moveToMathFieldStart', | ||
'Shift-Home': 'extendToMathFieldStart', | ||
'mac:Meta-Shift-Left': 'extendToMathFieldStart', | ||
Home: 'moveToMathFieldStart', | ||
'mac:Meta-Left': 'moveToMathFieldStart', | ||
'Shift-Home': 'extendToMathFieldStart', | ||
'mac:Meta-Shift-Left': 'extendToMathFieldStart', | ||
'End': 'moveToMathFieldEnd', | ||
'mac:Meta-Right': 'moveToMathFieldEnd', | ||
'Shift-End': 'extendToMathFieldEnd', | ||
'mac:Meta-Shift-Right': 'extendToMathFieldEnd', | ||
End: 'moveToMathFieldEnd', | ||
'mac:Meta-Right': 'moveToMathFieldEnd', | ||
'Shift-End': 'extendToMathFieldEnd', | ||
'mac:Meta-Shift-Right': 'extendToMathFieldEnd', | ||
'PageUp': 'moveToGroupStart', | ||
'PageDown': 'moveToGroupEnd', | ||
PageUp: 'moveToGroupStart', | ||
PageDown: 'moveToGroupEnd', | ||
'math:Tab': 'moveToNextPlaceholder', | ||
'math:F8': 'moveToNextPlaceholder', // Visual Studio | ||
'math:Shift-Tab': 'moveToPreviousPlaceholder', | ||
'math:Shift-F8': 'moveToPreviousPlaceholder', // Visual Studio | ||
'math:Tab': 'moveToNextPlaceholder', | ||
'math:F8': 'moveToNextPlaceholder', // Visual Studio | ||
'math:Shift-Tab': 'moveToPreviousPlaceholder', | ||
'math:Shift-F8': 'moveToPreviousPlaceholder', // Visual Studio | ||
'text:Tab': 'moveToNextPlaceholder', | ||
'text:F8': 'moveToNextPlaceholder', // Visual Studio | ||
'text:Shift-Tab': 'moveToPreviousPlaceholder', | ||
'text:Shift-F8': 'moveToPreviousPlaceholder', // Visual Studio | ||
'text:Tab': 'moveToNextPlaceholder', | ||
'text:F8': 'moveToNextPlaceholder', // Visual Studio | ||
'text:Shift-Tab': 'moveToPreviousPlaceholder', | ||
'text:Shift-F8': 'moveToPreviousPlaceholder', // Visual Studio | ||
'math:Esc': ['switch-mode', 'command'], | ||
'math:Backslash': ['switch-mode', 'command'], | ||
'math:IntlBackslash': ['switch-mode', 'command'], | ||
'math:Esc': ['switch-mode', 'command'], | ||
'math:Backslash': ['switch-mode', 'command'], | ||
'math:IntlBackslash': ['switch-mode', 'command'], | ||
'math:Alt-Equal': ['apply-style', {mode: 'text'}], | ||
'text:Alt-Equal': ['apply-style', {mode: 'math'}], | ||
'math:Alt-Equal': ['apply-style', { mode: 'text' }], | ||
'text:Alt-Equal': ['apply-style', { mode: 'math' }], | ||
'command:Esc': ['complete', {discard: true}], // discard the command, insert nothing | ||
'command:Tab': ['complete', {acceptSuggestion: true}], // complete the suggestion | ||
'command:Return': 'complete', | ||
'command:Enter': 'complete', | ||
'command:Shift-Esc': ['complete', {discard: true}], // Some keyboards can't generate | ||
// this combination, for example in 60% keyboards it is mapped to ~ | ||
'command:Down': 'nextSuggestion', | ||
'ios:command:Tab': 'nextSuggestion', | ||
'command:Up': 'previousSuggestion', | ||
'command:Esc': ['complete', { discard: true }], // discard the command, insert nothing | ||
'command:Tab': ['complete', { acceptSuggestion: true }], // complete the suggestion | ||
'command:Return': 'complete', | ||
'command:Enter': 'complete', | ||
'command:Shift-Esc': ['complete', { discard: true }], // Some keyboards can't generate | ||
// this combination, for example in 60% keyboards it is mapped to ~ | ||
'command:Down': 'nextSuggestion', | ||
'ios:command:Tab': 'nextSuggestion', | ||
'command:Up': 'previousSuggestion', | ||
'!mac:Ctrl-KeyA': 'selectAll', | ||
'mac:Meta-KeyA': 'selectAll', | ||
'!mac:Ctrl-KeyA': 'selectAll', | ||
'mac:Meta-KeyA': 'selectAll', | ||
// Rare keys on some extended keyboards | ||
'Cut': 'cut', | ||
'Copy': 'copy', | ||
'Paste': 'paste', | ||
'Clear': 'delete', | ||
Cut: 'cut', | ||
Copy: 'copy', | ||
Paste: 'paste', | ||
Clear: 'delete', | ||
'!mac:Ctrl-KeyZ': 'undo', | ||
'mac:Meta-KeyZ': 'undo', | ||
'Undo': 'undo', | ||
'!mac:Ctrl-KeyY': 'redo', // ARIA recommendation | ||
'mac:Meta-Shift-KeyY': 'redo', | ||
'!mac:Ctrl-Shift-KeyZ': 'redo', | ||
'mac:Meta-Shift-KeyZ': 'redo', | ||
'Redo': 'redo', | ||
'!mac:Ctrl-KeyZ': 'undo', | ||
'mac:Meta-KeyZ': 'undo', | ||
Undo: 'undo', | ||
'!mac:Ctrl-KeyY': 'redo', // ARIA recommendation | ||
'mac:Meta-Shift-KeyY': 'redo', | ||
'!mac:Ctrl-Shift-KeyZ': 'redo', | ||
'mac:Meta-Shift-KeyZ': 'redo', | ||
Redo: 'redo', | ||
'EraseEof': 'deleteToGroupEnd', | ||
EraseEof: 'deleteToGroupEnd', | ||
// EMACS/MACOS BINDINGS | ||
'mac:Ctrl-KeyB': 'moveToPreviousChar', | ||
'mac:Ctrl-KeyF': 'moveToNextChar', | ||
'mac:Ctrl-KeyP': 'moveUp', | ||
'mac:Ctrl-KeyN': 'moveDown', | ||
'mac:Ctrl-KeyA': 'moveToMathFieldStart', | ||
'mac:Ctrl-KeyE': 'moveToMathFieldEnd', | ||
'mac:Ctrl-KeyB': 'moveToPreviousChar', | ||
'mac:Ctrl-KeyF': 'moveToNextChar', | ||
'mac:Ctrl-KeyP': 'moveUp', | ||
'mac:Ctrl-KeyN': 'moveDown', | ||
'mac:Ctrl-KeyA': 'moveToMathFieldStart', | ||
'mac:Ctrl-KeyE': 'moveToMathFieldEnd', | ||
'mac:Ctrl-Shift-KeyB': 'extendToPreviousChar', | ||
'mac:Ctrl-Shift-KeyF': 'extendToNextChar', | ||
'mac:Ctrl-Shift-KeyP': 'extendUp', | ||
'mac:Ctrl-Shift-KeyN': 'extendDown', | ||
'mac:Ctrl-Shift-KeyA': 'extendToMathFieldStart', | ||
'mac:Ctrl-Shift-KeyE': 'extendToMathFieldEnd', | ||
'mac:Ctrl-Alt-KeyB': 'moveToPreviousWord', | ||
'mac:Ctrl-Alt-KeyF': 'moveToNextWord', | ||
'mac:Ctrl-Shift-Alt-KeyB': 'extendToPreviousWord', | ||
'mac:Ctrl-Shift-Alt-KeyF': 'extendToNextWord', | ||
'mac:Ctrl-Shift-KeyB': 'extendToPreviousChar', | ||
'mac:Ctrl-Shift-KeyF': 'extendToNextChar', | ||
'mac:Ctrl-Shift-KeyP': 'extendUp', | ||
'mac:Ctrl-Shift-KeyN': 'extendDown', | ||
'mac:Ctrl-Shift-KeyA': 'extendToMathFieldStart', | ||
'mac:Ctrl-Shift-KeyE': 'extendToMathFieldEnd', | ||
'mac:Ctrl-Alt-KeyB': 'moveToPreviousWord', | ||
'mac:Ctrl-Alt-KeyF': 'moveToNextWord', | ||
'mac:Ctrl-Shift-Alt-KeyB': 'extendToPreviousWord', | ||
'mac:Ctrl-Shift-Alt-KeyF': 'extendToNextWord', | ||
'mac:Ctrl-KeyH': 'deletePreviousChar', | ||
'mac:Ctrl-KeyD': 'deleteNextChar', | ||
'mac:Ctrl-KeyL': 'scrollIntoView', | ||
'mac:Ctrl-KeyT': 'transpose', | ||
'mac:Ctrl-KeyH': 'deletePreviousChar', | ||
'mac:Ctrl-KeyD': 'deleteNextChar', | ||
'mac:Ctrl-KeyL': 'scrollIntoView', | ||
'mac:Ctrl-KeyT': 'transpose', | ||
'math:Shift-Quote': ['switch-mode', 'text', '', '“'], | ||
'text:Shift-Quote': ['switch-mode', 'math', '”', ''], | ||
'math:Shift-Quote': ['switch-mode', 'text', '', '“'], | ||
'text:Shift-Quote': ['switch-mode', 'math', '”', ''], | ||
// WOLFRAM MATHEMATICA BINDINGS | ||
'math:Ctrl-Digit2': ['insert', '\\sqrt{#0}'], | ||
'math:Ctrl-Digit5': 'moveToOpposite', | ||
'math:Ctrl-Digit6': 'moveToSuperscript', | ||
'math:Ctrl-Minus': 'moveToSubscript', | ||
'math:Alt-BracketLeft': ['insert', '\\left\\lbrack #0 \\right\\rbrack'], | ||
'math:Alt-Shift-BracketLeft': ['insert', '\\left\\lbrace #0 \\right\\rbrace'], | ||
'math:Return': 'addRowAfter', | ||
'math:Enter': 'addRowAfter', | ||
'math:Ctrl-Comma': 'addColumnAfter', | ||
'math:Ctrl-Digit2': ['insert', '\\sqrt{#0}'], | ||
'math:Ctrl-Digit5': 'moveToOpposite', | ||
'math:Ctrl-Digit6': 'moveToSuperscript', | ||
'math:Ctrl-Minus': 'moveToSubscript', | ||
'math:Alt-BracketLeft': ['insert', '\\left\\lbrack #0 \\right\\rbrack'], | ||
'math:Alt-Shift-BracketLeft': [ | ||
'insert', | ||
'\\left\\lbrace #0 \\right\\rbrace', | ||
], | ||
'math:Return': 'addRowAfter', | ||
'math:Enter': 'addRowAfter', | ||
'math:Ctrl-Comma': 'addColumnAfter', | ||
// Excel shortcuts: | ||
@@ -186,35 +188,35 @@ // Shift-space: select entire row, ctrl+space: select an entire column | ||
// MATHLIVE BINDINGS | ||
'math:Alt-KeyQ': ['insert', '\\theta'], | ||
'math:Alt-KeyP': ['insert', '\\pi'], | ||
'math:Alt-KeyV': ['insert', '\\sqrt{#0}'], | ||
'math:Alt-KeyW': ['insert', '\\sum_{i=#?}^{#?}'], | ||
'math:Alt-KeyB': ['insert', '\\int_{#?}^{#?}'], | ||
'math:Alt-KeyU': ['insert', '\\cup'], | ||
'math:Alt-KeyN': ['insert', '\\cap'], | ||
'math:Alt-KeyO': ['insert', '\\emptyset'], | ||
'math:Alt-KeyD': ['insert', '\\differentialD'], | ||
'math:Alt-Shift-KeyO': ['insert', '\\varnothing'], | ||
'math:Alt-Shift-KeyD': ['insert', '\\partial'], | ||
'math:Alt-Shift-KeyP': ['insert', '\\prod_{i=#?}^{#?}'], | ||
'math:Alt-Shift-KeyU': ['insert', '\\bigcup'], | ||
'math:Alt-Shift-KeyN': ['insert', '\\bigcap'], | ||
'math:Alt-Shift-KeyA': ['insert', '\\forall'], | ||
'math:Alt-Shift-KeyE': ['insert', '\\exists'], | ||
'math:Alt-Digit5': ['insert', '\\infty'], // "%" key | ||
'math:Alt-Digit6': ['insert', '\\wedge'], // "^" key | ||
'math:Alt-Shift-Digit6': ['insert', '\\vee'], // "^" key | ||
'math:Alt-Digit9': ['insert', '('], // "(" key, override smartFence | ||
'math:Alt-Digit0': ['insert', ')'], // ")" key, override smartFence | ||
'math:Alt-Shift-Backslash': ['insert', '|'], // "|" key, override smartFence | ||
'math:Alt-Backslash': ['insert', '\\backslash'], // "|" key, override command mode | ||
'math:Slash': ['insert', '\\frac{#@}{#?}'], | ||
'math:Alt-Slash': ['insert', '\\frac{#?}{#@}'], | ||
'math:NumpadDivide': ['insert', '\\frac{#@}{#?}'], | ||
'math:Alt-NumpadDivide': ['insert', '\\frac{#?}{#@}'], | ||
'math:Shift-Backquote': ['insert', '\\~'], | ||
'math:Alt-Shift-Slash': ['insert', '\\/'], | ||
'math:Alt-KeyQ': ['insert', '\\theta'], | ||
'math:Alt-KeyP': ['insert', '\\pi'], | ||
'math:Alt-KeyV': ['insert', '\\sqrt{#0}'], | ||
'math:Alt-KeyW': ['insert', '\\sum_{i=#?}^{#?}'], | ||
'math:Alt-KeyB': ['insert', '\\int_{#?}^{#?}'], | ||
'math:Alt-KeyU': ['insert', '\\cup'], | ||
'math:Alt-KeyN': ['insert', '\\cap'], | ||
'math:Alt-KeyO': ['insert', '\\emptyset'], | ||
'math:Alt-KeyD': ['insert', '\\differentialD'], | ||
'math:Alt-Shift-KeyO': ['insert', '\\varnothing'], | ||
'math:Alt-Shift-KeyD': ['insert', '\\partial'], | ||
'math:Alt-Shift-KeyP': ['insert', '\\prod_{i=#?}^{#?}'], | ||
'math:Alt-Shift-KeyU': ['insert', '\\bigcup'], | ||
'math:Alt-Shift-KeyN': ['insert', '\\bigcap'], | ||
'math:Alt-Shift-KeyA': ['insert', '\\forall'], | ||
'math:Alt-Shift-KeyE': ['insert', '\\exists'], | ||
'math:Alt-Digit5': ['insert', '\\infty'], // "%" key | ||
'math:Alt-Digit6': ['insert', '\\wedge'], // "^" key | ||
'math:Alt-Shift-Digit6': ['insert', '\\vee'], // "^" key | ||
'math:Alt-Digit9': ['insert', '('], // "(" key, override smartFence | ||
'math:Alt-Digit0': ['insert', ')'], // ")" key, override smartFence | ||
'math:Alt-Shift-Backslash': ['insert', '|'], // "|" key, override smartFence | ||
'math:Alt-Backslash': ['insert', '\\backslash'], // "|" key, override command mode | ||
'math:Slash': ['insert', '\\frac{#@}{#?}'], | ||
'math:Alt-Slash': ['insert', '\\frac{#?}{#@}'], | ||
'math:NumpadDivide': ['insert', '\\frac{#@}{#?}'], | ||
'math:Alt-NumpadDivide': ['insert', '\\frac{#?}{#@}'], | ||
'math:Shift-Backquote': ['insert', '\\~'], | ||
'math:Alt-Shift-Slash': ['insert', '\\/'], | ||
// Accessibility | ||
'Alt-Shift-KeyK': 'toggleKeystrokeCaption', | ||
'Alt-Space': 'toggleVirtualKeyboard', | ||
'Alt-Shift-KeyK': 'toggleKeystrokeCaption', | ||
'Alt-Space': 'toggleVirtualKeyboard', | ||
@@ -225,3 +227,3 @@ // Note: On Mac OS (as of 10.12), there is a bug/behavior that causes | ||
// In ~/Library/KeyBindings/DefaultKeyBinding.dict add these entries: | ||
/* | ||
/* | ||
{ | ||
@@ -233,23 +235,31 @@ "^@\UF701" = "noop:"; | ||
*/ | ||
'mac:Ctrl-Meta-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Down': ['speak', 'all', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Down': ['speak', 'all', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Left': ['speak', 'left', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Left': ['speak', 'left', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Right': ['speak', 'right', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Right': ['speak', 'right', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Period': ['speak', 'selection', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Period': ['speak', 'selection', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Shift-Up': ['speak', 'parent', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Up': ['speak', 'parent', {withHighlighting: true}], | ||
'mac:Ctrl-Meta-Shift-Down': ['speak', 'all', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Down': ['speak', 'all', {withHighlighting: true}], | ||
'mac:Ctrl-Meta-Shift-Left': ['speak', 'left', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Left': ['speak', 'left', {withHighlighting: true}], | ||
'mac:Ctrl-Meta-Shift-Right': ['speak', 'right', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Right': ['speak', 'right', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Period': ['speak', 'selection', {withHighlighting: true}], | ||
'mac:Ctrl-Meta-Shift-Period': ['speak', 'selection', {withHighlighting: true}], | ||
'mac:Ctrl-Meta-Up': ['speak', 'parent', { withHighlighting: false }], | ||
'!mac:Ctrl-Alt-Up': ['speak', 'parent', { withHighlighting: false }], | ||
'mac:Ctrl-Meta-Down': ['speak', 'all', { withHighlighting: false }], | ||
'!mac:Ctrl-Alt-Down': ['speak', 'all', { withHighlighting: false }], | ||
'mac:Ctrl-Meta-Left': ['speak', 'left', { withHighlighting: false }], | ||
'!mac:Ctrl-Alt-Left': ['speak', 'left', { withHighlighting: false }], | ||
'mac:Ctrl-Meta-Right': ['speak', 'right', { withHighlighting: false }], | ||
'!mac:Ctrl-Alt-Right': ['speak', 'right', { withHighlighting: false }], | ||
'!mac:Ctrl-Alt-Period': ['speak', 'selection', { withHighlighting: false }], | ||
'mac:Ctrl-Meta-Period': ['speak', 'selection', { withHighlighting: false }], | ||
'mac:Ctrl-Meta-Shift-Up': ['speak', 'parent', { withHighlighting: true }], | ||
'!mac:Ctrl-Alt-Shift-Up': ['speak', 'parent', { withHighlighting: true }], | ||
'mac:Ctrl-Meta-Shift-Down': ['speak', 'all', { withHighlighting: true }], | ||
'!mac:Ctrl-Alt-Shift-Down': ['speak', 'all', { withHighlighting: true }], | ||
'mac:Ctrl-Meta-Shift-Left': ['speak', 'left', { withHighlighting: true }], | ||
'!mac:Ctrl-Alt-Shift-Left': ['speak', 'left', { withHighlighting: true }], | ||
'mac:Ctrl-Meta-Shift-Right': ['speak', 'right', { withHighlighting: true }], | ||
'!mac:Ctrl-Alt-Shift-Right': ['speak', 'right', { withHighlighting: true }], | ||
'!mac:Ctrl-Alt-Shift-Period': [ | ||
'speak', | ||
'selection', | ||
{ withHighlighting: true }, | ||
], | ||
'mac:Ctrl-Meta-Shift-Period': [ | ||
'speak', | ||
'selection', | ||
{ withHighlighting: true }, | ||
], | ||
// '!mac:Ctrl-Alt-Shift-Home': ['speak', 'start', {withHighlighting: true}], | ||
@@ -259,3 +269,3 @@ // 'mac:Ctrl-Alt-Shift-Home': ['speak', 'start', {withHighlighting: true}], | ||
// 'mac:Ctrl-Alt-Shift-End': ['speak', 'end', {withHighlighting: true}], | ||
} | ||
}; | ||
@@ -273,26 +283,25 @@ /** | ||
const REVERSE_KEYBOARD_SHORTCUTS = { | ||
'\\theta': 'Alt-KeyQ', | ||
'\\sqrt': ['Alt-KeyV', 'Ctrl-Digit2'], | ||
'\\pi': 'Alt-KeyP', | ||
'\\prod': 'Alt-Shift-KeyP', | ||
'\\sum': 'Alt-KeyW', | ||
'\\int': 'Alt-KeyB', | ||
'\\cup': 'Alt-KeyU', | ||
'\\cap': 'Alt-KeyN', | ||
'\\bigcup': 'Alt-Shift-KeyU', | ||
'\\bigcap': 'Alt-Shift-KeyN', | ||
'\\forall': 'Alt-Shift-KeyA', | ||
'\\exists': 'Alt-Shift-KeyE', | ||
'\\infty': 'Alt-Digit5', | ||
'\\wedge': 'Alt-Digit5', | ||
'\\vee': 'Alt-Shift-Digit6', | ||
'\\differentialD': 'Alt-keyD', | ||
'\\partial': 'Alt-Shift-KeyD', | ||
'\\frac': 'Slash', | ||
'\\emptyset': 'Alt-KeyO', | ||
'\\varnothing': 'Alt-Shift-KeyO', | ||
'\\~': '~' | ||
'\\theta': 'Alt-KeyQ', | ||
'\\sqrt': ['Alt-KeyV', 'Ctrl-Digit2'], | ||
'\\pi': 'Alt-KeyP', | ||
'\\prod': 'Alt-Shift-KeyP', | ||
'\\sum': 'Alt-KeyW', | ||
'\\int': 'Alt-KeyB', | ||
'\\cup': 'Alt-KeyU', | ||
'\\cap': 'Alt-KeyN', | ||
'\\bigcup': 'Alt-Shift-KeyU', | ||
'\\bigcap': 'Alt-Shift-KeyN', | ||
'\\forall': 'Alt-Shift-KeyA', | ||
'\\exists': 'Alt-Shift-KeyE', | ||
'\\infty': 'Alt-Digit5', | ||
'\\wedge': 'Alt-Digit5', | ||
'\\vee': 'Alt-Shift-Digit6', | ||
'\\differentialD': 'Alt-keyD', | ||
'\\partial': 'Alt-Shift-KeyD', | ||
'\\frac': 'Slash', | ||
'\\emptyset': 'Alt-KeyO', | ||
'\\varnothing': 'Alt-Shift-KeyO', | ||
'\\~': '~', | ||
}; | ||
} | ||
/** | ||
@@ -307,308 +316,343 @@ * These shortcut strings are replaced with the corresponding LaTeX expression | ||
// Primes | ||
"''": { mode: 'math', value: '^{\\doubleprime}'}, | ||
"''": { mode: 'math', value: '^{\\doubleprime}' }, | ||
// Greek letters | ||
'alpha': '\\alpha', | ||
'delta': '\\delta', | ||
'Delta': '\\Delta', | ||
'pi': { mode: 'math', value: '\\pi'}, | ||
'pi ': { mode: 'text', value: '\\pi '}, | ||
'Pi': { mode: 'math', value: '\\Pi'}, | ||
'theta': '\\theta', | ||
'Theta': '\\Theta', | ||
alpha: '\\alpha', | ||
delta: '\\delta', | ||
Delta: '\\Delta', | ||
pi: { mode: 'math', value: '\\pi' }, | ||
'pi ': { mode: 'text', value: '\\pi ' }, | ||
Pi: { mode: 'math', value: '\\Pi' }, | ||
theta: '\\theta', | ||
Theta: '\\Theta', | ||
// Letter-like | ||
'ii': { after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\imaginaryI' }, | ||
'jj': { after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\imaginaryJ' }, | ||
'ee': { | ||
mode: 'math', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\exponentialE', | ||
}, | ||
ii: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\imaginaryI', | ||
}, | ||
jj: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\imaginaryJ', | ||
}, | ||
ee: { | ||
mode: 'math', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\exponentialE', | ||
}, | ||
'nabla': { mode: 'math', value: '\\nabla'}, | ||
'grad': { mode: 'math', value: '\\nabla'}, | ||
'del': { mode: 'math', value: '\\partial'}, | ||
nabla: { mode: 'math', value: '\\nabla' }, | ||
grad: { mode: 'math', value: '\\nabla' }, | ||
del: { mode: 'math', value: '\\partial' }, | ||
'\u221e': '\\infty', // @TODO: doesn't work | ||
'\u221e': '\\infty', // @TODO: doesn't work | ||
// '∞': '\\infty', | ||
// '∞': '\\infty', | ||
'oo': { | ||
mode: 'math', | ||
after: 'nothing+digit+frac+surd+binop+relop+punct+array+openfence+closefence+space', | ||
value: '\\infty', | ||
}, | ||
oo: { | ||
mode: 'math', | ||
after: | ||
'nothing+digit+frac+surd+binop+relop+punct+array+openfence+closefence+space', | ||
value: '\\infty', | ||
}, | ||
// Big operators | ||
'∑': { mode: 'math', value: '\\sum'}, | ||
'sum': { mode: 'math', value: '\\sum_{#?}^{#?}' }, | ||
'prod': { mode: 'math', value: '\\prod_{#?}^{#?}' }, | ||
'sqrt': { mode: 'math', value: '\\sqrt'}, | ||
'∑': { mode: 'math', value: '\\sum' }, | ||
sum: { mode: 'math', value: '\\sum_{#?}^{#?}' }, | ||
prod: { mode: 'math', value: '\\prod_{#?}^{#?}' }, | ||
sqrt: { mode: 'math', value: '\\sqrt' }, | ||
// '∫': '\\int', // There's a alt-B command for this | ||
'∆': { mode: 'math', value: '\\differentialD'}, // @TODO: is \\diffD most common? | ||
'∂': { mode: 'math', value: '\\differentialD'}, | ||
'∆': { mode: 'math', value: '\\differentialD' }, // @TODO: is \\diffD most common? | ||
'∂': { mode: 'math', value: '\\differentialD' }, | ||
// Functions | ||
'sin': { mode: 'math', value: '\\sin'}, | ||
'cos': { mode: 'math', value: '\\cos'}, | ||
'tan': { mode: 'math', value: '\\tan'}, | ||
'tanh': { mode: 'math', value: '\\tanh'}, | ||
'log': { mode: 'math', value: '\\log'}, | ||
'ln': { mode: 'math', value: '\\ln'}, | ||
'exp': { mode: 'math', value: '\\exp'}, | ||
'lim': { mode: 'math', value: '\\lim_{#?}'}, | ||
sin: { mode: 'math', value: '\\sin' }, | ||
cos: { mode: 'math', value: '\\cos' }, | ||
tan: { mode: 'math', value: '\\tan' }, | ||
tanh: { mode: 'math', value: '\\tanh' }, | ||
log: { mode: 'math', value: '\\log' }, | ||
ln: { mode: 'math', value: '\\ln' }, | ||
exp: { mode: 'math', value: '\\exp' }, | ||
lim: { mode: 'math', value: '\\lim_{#?}' }, | ||
// Differentials | ||
// According to ISO31/XI (ISO 80000-2), differentials should be upright | ||
'dx': '\\differentialD x', | ||
'dy': '\\differentialD y', | ||
'dt': '\\differentialD t', | ||
dx: '\\differentialD x', | ||
dy: '\\differentialD y', | ||
dt: '\\differentialD t', | ||
// Logic | ||
'AA': { mode: 'math', value: '\\forall'}, | ||
'EE': { mode: 'math', value: '\\exists'}, | ||
'!EE': { mode: 'math', value: '\\nexists'}, | ||
'&&': { mode: 'math', value: '\\land'}, | ||
AA: { mode: 'math', value: '\\forall' }, | ||
EE: { mode: 'math', value: '\\exists' }, | ||
'!EE': { mode: 'math', value: '\\nexists' }, | ||
'&&': { mode: 'math', value: '\\land' }, | ||
// The shortcut for the greek letter "xi" is interfering with "x in" | ||
'xin': { | ||
mode: 'math', | ||
after: 'nothing+text+relop+punct+openfence+space', | ||
value: 'x \\in', | ||
}, | ||
'in': { | ||
mode: 'math', | ||
after: 'nothing+letter+closefence', | ||
value: '\\in', | ||
}, | ||
'!in': { mode: 'math', value: '\\notin'}, | ||
xin: { | ||
mode: 'math', | ||
after: 'nothing+text+relop+punct+openfence+space', | ||
value: 'x \\in', | ||
}, | ||
in: { | ||
mode: 'math', | ||
after: 'nothing+letter+closefence', | ||
value: '\\in', | ||
}, | ||
'!in': { mode: 'math', value: '\\notin' }, | ||
// Sets | ||
'NN': '\\N', // Natural numbers | ||
'ZZ': '\\Z', // Integers | ||
'QQ': '\\Q', // Rational numbers | ||
'RR': '\\R', // Real numbers | ||
'CC': '\\C', // Complex numbers | ||
'PP': '\\P', // Prime numbers | ||
NN: '\\N', // Natural numbers | ||
ZZ: '\\Z', // Integers | ||
QQ: '\\Q', // Rational numbers | ||
RR: '\\R', // Real numbers | ||
CC: '\\C', // Complex numbers | ||
PP: '\\P', // Prime numbers | ||
// Operators | ||
'xx': '\\times', | ||
'+-': '\\pm', | ||
xx: '\\times', | ||
'+-': '\\pm', | ||
// Relational operators | ||
'!=': '\\ne', | ||
'>=': '\\ge', | ||
'<=': '\\le', | ||
'<<': '\\ll', | ||
'>>': '\\gg', | ||
'~~': '\\approx', | ||
'!=': '\\ne', | ||
'>=': '\\ge', | ||
'<=': '\\le', | ||
'<<': '\\ll', | ||
'>>': '\\gg', | ||
'~~': '\\approx', | ||
// More operators | ||
'≈': '\\approx', | ||
'?=': '\\questeq', | ||
'÷': '\\div', | ||
'¬': '\\neg', | ||
':=': '\\coloneq', | ||
'::': '\\Colon', | ||
'≈': '\\approx', | ||
'?=': '\\questeq', | ||
'÷': '\\div', | ||
'¬': '\\neg', | ||
':=': '\\coloneq', | ||
'::': '\\Colon', | ||
// Fences | ||
'(:': '\\langle', | ||
':)': '\\rangle', | ||
'(:': '\\langle', | ||
':)': '\\rangle', | ||
// More Greek letters | ||
'beta': '\\beta', | ||
'chi': '\\chi', | ||
'epsilon': '\\epsilon', | ||
'varepsilon': '\\varepsilon', | ||
'eta': { | ||
mode: 'math', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\eta' | ||
}, | ||
'eta ': { | ||
mode: 'text', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\eta ' | ||
}, | ||
'gamma': '\\gamma', | ||
'Gamma': '\\Gamma', | ||
'iota': '\\iota', | ||
'kappa': '\\kappa', | ||
'lambda': '\\lambda', | ||
'Lambda': '\\Lambda', | ||
'mu': { | ||
mode: 'math', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\mu' | ||
}, | ||
'mu ': { | ||
mode: 'text', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\mu ' | ||
}, | ||
'nu': { | ||
mode: 'math', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\nu' | ||
}, | ||
'nu ': { | ||
mode: 'text', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\nu ' | ||
}, | ||
'µ': '\\mu', // @TODO: or micro? | ||
'phi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\phi' | ||
}, | ||
'Phi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\Phi' | ||
}, | ||
'varphi': '\\varphi', | ||
'psi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\psi' | ||
}, | ||
'Psi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\Psi' | ||
beta: '\\beta', | ||
chi: '\\chi', | ||
epsilon: '\\epsilon', | ||
varepsilon: '\\varepsilon', | ||
eta: { | ||
mode: 'math', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\eta', | ||
}, | ||
'rho': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\rho' | ||
'eta ': { | ||
mode: 'text', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\eta ', | ||
}, | ||
'sigma': '\\sigma', | ||
'Sigma': '\\Sigma', | ||
'tau': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\tau' | ||
gamma: '\\gamma', | ||
Gamma: '\\Gamma', | ||
iota: '\\iota', | ||
kappa: '\\kappa', | ||
lambda: '\\lambda', | ||
Lambda: '\\Lambda', | ||
mu: { | ||
mode: 'math', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\mu', | ||
}, | ||
'vartheta': '\\vartheta', | ||
'upsilon': '\\upsilon', | ||
'xi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\xi'}, | ||
'Xi': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value:'\\Xi'}, | ||
'zeta': '\\zeta', | ||
'omega': '\\omega', | ||
'Omega': '\\Omega', | ||
'Ω': '\\omega', // @TODO: or ohm? | ||
'mu ': { | ||
mode: 'text', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\mu ', | ||
}, | ||
nu: { | ||
mode: 'math', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\nu', | ||
}, | ||
'nu ': { | ||
mode: 'text', | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\nu ', | ||
}, | ||
µ: '\\mu', // @TODO: or micro? | ||
phi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\phi', | ||
}, | ||
Phi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\Phi', | ||
}, | ||
varphi: '\\varphi', | ||
psi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\psi', | ||
}, | ||
Psi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\Psi', | ||
}, | ||
rho: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\rho', | ||
}, | ||
sigma: '\\sigma', | ||
Sigma: '\\Sigma', | ||
tau: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\tau', | ||
}, | ||
vartheta: '\\vartheta', | ||
upsilon: '\\upsilon', | ||
xi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\xi', | ||
}, | ||
Xi: { | ||
after: | ||
'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\Xi', | ||
}, | ||
zeta: '\\zeta', | ||
omega: '\\omega', | ||
Omega: '\\Omega', | ||
Ω: '\\omega', // @TODO: or ohm? | ||
// More Logic | ||
'forall': '\\forall', | ||
'exists': { | ||
mode: 'math', | ||
value:'\\exists' | ||
}, | ||
'!exists': { | ||
mode: 'math', | ||
value: '\\nexists' | ||
}, | ||
':.': { | ||
mode: 'math', | ||
value:'\\therefore' | ||
forall: '\\forall', | ||
exists: { | ||
mode: 'math', | ||
value: '\\exists', | ||
}, | ||
'!exists': { | ||
mode: 'math', | ||
value: '\\nexists', | ||
}, | ||
':.': { | ||
mode: 'math', | ||
value: '\\therefore', | ||
}, | ||
// MORE FUNCTIONS | ||
// 'arg': '\\arg', | ||
'liminf': '\\operatorname*{lim~inf}_{#?}', | ||
'limsup': '\\operatorname*{lim~sup}_{#?}', | ||
'argmin': '\\operatorname*{arg~min}_{#?}', | ||
'argmax': '\\operatorname*{arg~max}_{#?}', | ||
'det': '\\det', | ||
'mod': { | ||
mode: 'math', | ||
value:'\\mod'}, | ||
'max': { | ||
mode: 'math', | ||
value:'\\max'}, | ||
'min': { | ||
mode: 'math', | ||
value:'\\min'}, | ||
'erf': '\\operatorname{erf}', | ||
'erfc': '\\operatorname{erfc}', | ||
'bessel': { | ||
mode: 'math', | ||
value:'\\operatorname{bessel}'}, | ||
'mean': { | ||
mode: 'math', | ||
value: '\\operatorname{mean}' | ||
liminf: '\\operatorname*{lim~inf}_{#?}', | ||
limsup: '\\operatorname*{lim~sup}_{#?}', | ||
argmin: '\\operatorname*{arg~min}_{#?}', | ||
argmax: '\\operatorname*{arg~max}_{#?}', | ||
det: '\\det', | ||
mod: { | ||
mode: 'math', | ||
value: '\\mod', | ||
}, | ||
'median': { | ||
mode: 'math', | ||
value: '\\operatorname{median}'}, | ||
'fft': { | ||
mode: 'math', | ||
value:'\\operatorname{fft}'}, | ||
'lcm': { | ||
mode: 'math', | ||
value:'\\operatorname{lcm}'}, | ||
'gcd': { | ||
mode: 'math', | ||
value:'\\operatorname{gcd}'}, | ||
'randomReal': '\\operatorname{randomReal}', | ||
'randomInteger': '\\operatorname{randomInteger}', | ||
'Re': { | ||
mode: 'math', | ||
value:'\\operatorname{Re}'}, | ||
'Im': { | ||
mode: 'math', | ||
value:'\\operatorname{Im}'}, | ||
max: { | ||
mode: 'math', | ||
value: '\\max', | ||
}, | ||
min: { | ||
mode: 'math', | ||
value: '\\min', | ||
}, | ||
erf: '\\operatorname{erf}', | ||
erfc: '\\operatorname{erfc}', | ||
bessel: { | ||
mode: 'math', | ||
value: '\\operatorname{bessel}', | ||
}, | ||
mean: { | ||
mode: 'math', | ||
value: '\\operatorname{mean}', | ||
}, | ||
median: { | ||
mode: 'math', | ||
value: '\\operatorname{median}', | ||
}, | ||
fft: { | ||
mode: 'math', | ||
value: '\\operatorname{fft}', | ||
}, | ||
lcm: { | ||
mode: 'math', | ||
value: '\\operatorname{lcm}', | ||
}, | ||
gcd: { | ||
mode: 'math', | ||
value: '\\operatorname{gcd}', | ||
}, | ||
randomReal: '\\operatorname{randomReal}', | ||
randomInteger: '\\operatorname{randomInteger}', | ||
Re: { | ||
mode: 'math', | ||
value: '\\operatorname{Re}', | ||
}, | ||
Im: { | ||
mode: 'math', | ||
value: '\\operatorname{Im}', | ||
}, | ||
// UNITS | ||
'mm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{mm}', // millimeter | ||
}, | ||
'cm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{cm}', // centimeter | ||
}, | ||
'km': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{km}', // kilometer | ||
}, | ||
'kg': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{kg}', // kilogram | ||
}, | ||
mm: { | ||
mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{mm}', // millimeter | ||
}, | ||
cm: { | ||
mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{cm}', // centimeter | ||
}, | ||
km: { | ||
mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{km}', // kilometer | ||
}, | ||
kg: { | ||
mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{kg}', // kilogram | ||
}, | ||
// '||': '\\lor', | ||
'...': '\\ldots', // In general, use \ldots | ||
'+...': '+\\cdots', // ... but use \cdots after + ... | ||
'-...': '-\\cdots', // ... - and ... | ||
'->...': '\\to\\cdots', // -> | ||
'...': '\\ldots', // In general, use \ldots | ||
'+...': '+\\cdots', // ... but use \cdots after + ... | ||
'-...': '-\\cdots', // ... - and ... | ||
'->...': '\\to\\cdots', // -> | ||
'->': '\\to', | ||
'|->': '\\mapsto', | ||
'-->': '\\longrightarrow', | ||
// '<-': '\\leftarrow', | ||
'<--': '\\longleftarrow', | ||
'=>': '\\Rightarrow', | ||
'==>': '\\Longrightarrow', | ||
// '<=': '\\Leftarrow', // CONFLICTS WITH LESS THAN OR EQUAL | ||
'<=>': '\\Leftrightarrow', | ||
'<->': '\\leftrightarrow', | ||
'->': '\\to', | ||
'|->': '\\mapsto', | ||
'-->': '\\longrightarrow', | ||
// '<-': '\\leftarrow', | ||
'<--': '\\longleftarrow', | ||
'=>': '\\Rightarrow', | ||
'==>': '\\Longrightarrow', | ||
// '<=': '\\Leftarrow', // CONFLICTS WITH LESS THAN OR EQUAL | ||
'<=>': '\\Leftrightarrow', | ||
'<->': '\\leftrightarrow', | ||
'(.)': '\\odot', | ||
'(+)': '\\oplus', | ||
'(/)': '\\oslash', | ||
'(*)': '\\otimes', | ||
'(-)': '\\ominus', | ||
'(.)': '\\odot', | ||
'(+)': '\\oplus', | ||
'(/)': '\\oslash', | ||
'(*)': '\\otimes', | ||
'(-)': '\\ominus', | ||
// '(-)': '\\circleddash', | ||
'||': '\\Vert', | ||
'{': '\\{', | ||
'}': '\\}', | ||
'*': '\\cdot', | ||
'||': '\\Vert', | ||
'{': '\\{', | ||
'}': '\\}', | ||
'*': '\\cdot', | ||
/* | ||
/* | ||
// | ||
@@ -695,3 +739,2 @@ // ASCIIIMath | ||
/** | ||
@@ -709,3 +752,4 @@ * Return an array of potential shortcuts | ||
const s2 = s.substring(i); | ||
const skipDefaultShortcuts = config && config.overrideDefaultInlineShortcuts; | ||
const skipDefaultShortcuts = | ||
config && config.overrideDefaultInlineShortcuts; | ||
if (!skipDefaultShortcuts) { | ||
@@ -719,4 +763,4 @@ Object.keys(INLINE_SHORTCUTS).forEach(key => { | ||
const customInlineShortcuts = config && config.inlineShortcuts ? | ||
config.inlineShortcuts : null; | ||
const customInlineShortcuts = | ||
config && config.inlineShortcuts ? config.inlineShortcuts : null; | ||
if (customInlineShortcuts) { | ||
@@ -733,3 +777,2 @@ Object.keys(customInlineShortcuts).forEach(key => { | ||
/** | ||
@@ -743,11 +786,12 @@ * | ||
function validateShortcut(mode, siblings, shortcut) { | ||
if (!shortcut) return shortcut | ||
if (!shortcut) return shortcut; | ||
// If it's a simple shortcut (no conditional), it's valid | ||
if (typeof shortcut === 'string') return shortcut | ||
if (typeof shortcut === 'string') return shortcut; | ||
if (typeof shortcut.mode === 'string' && shortcut.mode !== mode) return null; | ||
if (typeof shortcut.mode === 'string' && shortcut.mode !== mode) | ||
return null; | ||
// If we have no context, we assume all the shortcuts are valid | ||
if (!siblings) return shortcut ? shortcut.value : undefined; | ||
let nothing = false; | ||
@@ -773,7 +817,11 @@ let letter = false; | ||
} | ||
nothing = !sibling || sibling.type === 'first'; // start of a group | ||
nothing = !sibling || sibling.type === 'first'; // start of a group | ||
if (sibling) { | ||
text = sibling.mode === 'text'; | ||
letter = !text && sibling.type === 'mord' && Definitions.LETTER.test(sibling.body); | ||
digit = !text && sibling.type === 'mord' && /[0-9]+$/.test(sibling.body); | ||
letter = | ||
!text && | ||
sibling.type === 'mord' && | ||
Definitions.LETTER.test(sibling.body); | ||
digit = | ||
!text && sibling.type === 'mord' && /[0-9]+$/.test(sibling.body); | ||
isFunction = !text && sibling.isFunction; | ||
@@ -793,16 +841,18 @@ frac = sibling.type === 'genfrac'; | ||
// If this is a conditional shortcut, consider the conditions now | ||
if ( (/nothing/.test(shortcut.after) && nothing) || | ||
(/letter/.test(shortcut.after) && letter) || | ||
(/digit/.test(shortcut.after) && digit) || | ||
(/function/.test(shortcut.after) && isFunction) || | ||
(/frac/.test(shortcut.after) && frac) || | ||
(/surd/.test(shortcut.after) && surd) || | ||
(/binop/.test(shortcut.after) && binop) || | ||
(/relop/.test(shortcut.after) && relop) || | ||
(/punct/.test(shortcut.after) && punct) || | ||
(/array/.test(shortcut.after) && array) || | ||
(/openfence/.test(shortcut.after) && openfence) || | ||
(/closefence/.test(shortcut.after) && closefence) || | ||
(/text/.test(shortcut.after) && text) || | ||
(/space/.test(shortcut.after) && space)){ | ||
if ( | ||
(/nothing/.test(shortcut.after) && nothing) || | ||
(/letter/.test(shortcut.after) && letter) || | ||
(/digit/.test(shortcut.after) && digit) || | ||
(/function/.test(shortcut.after) && isFunction) || | ||
(/frac/.test(shortcut.after) && frac) || | ||
(/surd/.test(shortcut.after) && surd) || | ||
(/binop/.test(shortcut.after) && binop) || | ||
(/relop/.test(shortcut.after) && relop) || | ||
(/punct/.test(shortcut.after) && punct) || | ||
(/array/.test(shortcut.after) && array) || | ||
(/openfence/.test(shortcut.after) && openfence) || | ||
(/closefence/.test(shortcut.after) && closefence) || | ||
(/text/.test(shortcut.after) && text) || | ||
(/space/.test(shortcut.after) && space) | ||
) { | ||
return shortcut.value; | ||
@@ -832,3 +882,4 @@ } | ||
const skipDefaultShortcuts = config && config.overrideDefaultInlineShortcuts; | ||
const skipDefaultShortcuts = | ||
config && config.overrideDefaultInlineShortcuts; | ||
if (!skipDefaultShortcuts) { | ||
@@ -838,9 +889,13 @@ result = validateShortcut(mode, context, INLINE_SHORTCUTS[s]); | ||
const customInlineShortcuts = config && config.inlineShortcuts ? | ||
config.inlineShortcuts : null; | ||
const customInlineShortcuts = | ||
config && config.inlineShortcuts ? config.inlineShortcuts : null; | ||
let customResult; | ||
if (customInlineShortcuts) { | ||
customResult = validateShortcut(mode, context, customInlineShortcuts[s]); | ||
customResult = validateShortcut( | ||
mode, | ||
context, | ||
customInlineShortcuts[s] | ||
); | ||
} | ||
return customResult || result; | ||
@@ -875,5 +930,7 @@ } | ||
result = 'android'; | ||
} else if (/(iphone)/i.test(navigator.userAgent) || | ||
/(ipod)/i.test(navigator.userAgent) || | ||
/(ipad)/i.test(navigator.userAgent)) { | ||
} else if ( | ||
/(iphone)/i.test(navigator.userAgent) || | ||
/(ipod)/i.test(navigator.userAgent) || | ||
/(ipad)/i.test(navigator.userAgent) | ||
) { | ||
result = 'ios'; | ||
@@ -950,16 +1007,18 @@ } else if (/\bCrOS\b/i.test(navigator.userAgent)) { | ||
const regex = new RegExp('^' + | ||
command.replace('\\','\\\\'). | ||
replace('|', '\\|'). | ||
replace('*', '\\*'). | ||
replace('$', '\\$'). | ||
replace('^', '\\^') | ||
+ '([^*a-zA-Z]|$)'); | ||
Object.keys(KEYBOARD_SHORTCUTS).forEach(shortcut => { | ||
if (regex.test(commandToString(KEYBOARD_SHORTCUTS[shortcut]))) { | ||
const m = shortcut.match(/:([^:]*)$/); | ||
if (m) result.push(m[1]); | ||
} | ||
const regex = new RegExp( | ||
'^' + | ||
command | ||
.replace('\\', '\\\\') | ||
.replace('|', '\\|') | ||
.replace('*', '\\*') | ||
.replace('$', '\\$') | ||
.replace('^', '\\^') + | ||
'([^*a-zA-Z]|$)' | ||
); | ||
Object.keys(KEYBOARD_SHORTCUTS).forEach(shortcut => { | ||
if (regex.test(commandToString(KEYBOARD_SHORTCUTS[shortcut]))) { | ||
const m = shortcut.match(/:([^:]*)$/); | ||
if (m) result.push(m[1]); | ||
} | ||
); | ||
}); | ||
@@ -984,3 +1043,4 @@ return stringify(result); | ||
if (plat === platform('mac') || | ||
if ( | ||
plat === platform('mac') || | ||
plat === platform('win') || | ||
@@ -990,8 +1050,22 @@ plat === platform('ios') || | ||
plat === platform('chromeos') || | ||
plat === platform('other')) { | ||
plat === platform('other') | ||
) { | ||
const m = shortcut.match(/:([^:]*)$/); | ||
keyboardShortcut = m ? m[1] : shortcut; | ||
} else if (!['mac', '!mac', 'win', '!win', 'ios', '!ios', 'android', | ||
'!android', 'chromeos', '!chromeos', 'other', '!other'].includes(plat)) { | ||
} else if ( | ||
![ | ||
'mac', | ||
'!mac', | ||
'win', | ||
'!win', | ||
'ios', | ||
'!ios', | ||
'android', | ||
'!android', | ||
'chromeos', | ||
'!chromeos', | ||
'other', | ||
'!other', | ||
].includes(plat) | ||
) { | ||
const m = shortcut.match(/:([^:]*)$/); | ||
@@ -1001,11 +1075,13 @@ keyboardShortcut = m ? m[1] : shortcut; | ||
if (keyboardShortcut) { | ||
const useSymbol = platform('mac') === 'mac' || | ||
platform('ios') === 'ios'; | ||
const modifiers = keyboardShortcut.length > 1 ? | ||
keyboardShortcut.split('-') : [keyboardShortcut]; | ||
const useSymbol = | ||
platform('mac') === 'mac' || platform('ios') === 'ios'; | ||
const modifiers = | ||
keyboardShortcut.length > 1 | ||
? keyboardShortcut.split('-') | ||
: [keyboardShortcut]; | ||
let shortcutString = ''; | ||
for (const modifier of modifiers) { | ||
if (!useSymbol && shortcutString.length > 0) { | ||
shortcutString += '<span class="ML__shortcut-join">+</span>'; | ||
shortcutString += | ||
'<span class="ML__shortcut-join">+</span>'; | ||
} | ||
@@ -1017,45 +1093,46 @@ if (modifier.substr(0, 3) === 'Key') { | ||
} else { | ||
shortcutString += { | ||
'Meta': useSymbol ? '\u2318' : 'command', | ||
'Shift': useSymbol ? '\u21e7' : 'shift', | ||
'Alt': useSymbol ? '\u2325' : 'alt', | ||
'Ctrl': useSymbol ? '\u2303' : 'control', | ||
'\n': useSymbol ? '\u23ce' : 'return', | ||
'Return': useSymbol ? '\u23ce' : 'return', | ||
'Enter': useSymbol ? '\u2324' : 'enter', | ||
'Tab': useSymbol ? '\u21e5' : 'tab', | ||
// 'Esc': useSymbol ? '\u238b' : 'esc', | ||
'Esc': 'esc', | ||
shortcutString += | ||
{ | ||
Meta: useSymbol ? '\u2318' : 'command', | ||
Shift: useSymbol ? '\u21e7' : 'shift', | ||
Alt: useSymbol ? '\u2325' : 'alt', | ||
Ctrl: useSymbol ? '\u2303' : 'control', | ||
'\n': useSymbol ? '\u23ce' : 'return', | ||
Return: useSymbol ? '\u23ce' : 'return', | ||
Enter: useSymbol ? '\u2324' : 'enter', | ||
Tab: useSymbol ? '\u21e5' : 'tab', | ||
// 'Esc': useSymbol ? '\u238b' : 'esc', | ||
Esc: 'esc', | ||
'Backspace': useSymbol ? '\u232b' : 'backspace', | ||
'Del': useSymbol ? '\u2326' : 'del', | ||
'PageUp': useSymbol ? '\u21de' : 'page up', | ||
'PageDown': useSymbol ? '\u21df' : 'page down', | ||
'Home': useSymbol ? '\u2912' : 'home', | ||
'End': useSymbol ? '\u2913' : 'end', | ||
'Spacebar': 'space', | ||
'Semicolon': ';', | ||
'Period': '.', | ||
'Comma': ',', | ||
'Minus': '-', | ||
'Equal': '=', | ||
'Quote': '\'', | ||
'BracketLeft': '[', | ||
'BracketRight': ']', | ||
'Backslash': '\\', | ||
'IntlBackslash': '\\', | ||
'Backquote': '`', | ||
'Slash': '/', | ||
'NumpadMultiply': '* 🔢', | ||
'NumpadDivide': '/ 🔢', // Numeric keypad | ||
'NumpadSubtract': '- 🔢', | ||
'NumpadAdd': '+ 🔢', | ||
'NumpadDecimal': '. 🔢', | ||
'NumpadComma': ', 🔢', | ||
'Help': 'help', | ||
'Left': '\u21E0', | ||
'Up': '\u21E1', | ||
'Right': '\u21E2', | ||
'Down': '\u21E3', | ||
}[modifier] || modifier; | ||
Backspace: useSymbol ? '\u232b' : 'backspace', | ||
Del: useSymbol ? '\u2326' : 'del', | ||
PageUp: useSymbol ? '\u21de' : 'page up', | ||
PageDown: useSymbol ? '\u21df' : 'page down', | ||
Home: useSymbol ? '\u2912' : 'home', | ||
End: useSymbol ? '\u2913' : 'end', | ||
Spacebar: 'space', | ||
Semicolon: ';', | ||
Period: '.', | ||
Comma: ',', | ||
Minus: '-', | ||
Equal: '=', | ||
Quote: "'", | ||
BracketLeft: '[', | ||
BracketRight: ']', | ||
Backslash: '\\', | ||
IntlBackslash: '\\', | ||
Backquote: '`', | ||
Slash: '/', | ||
NumpadMultiply: '* 🔢', | ||
NumpadDivide: '/ 🔢', // Numeric keypad | ||
NumpadSubtract: '- 🔢', | ||
NumpadAdd: '+ 🔢', | ||
NumpadDecimal: '. 🔢', | ||
NumpadComma: ', 🔢', | ||
Help: 'help', | ||
Left: '\u21E0', | ||
Up: '\u21E1', | ||
Right: '\u21E2', | ||
Down: '\u21E3', | ||
}[modifier] || modifier; | ||
} | ||
@@ -1073,3 +1150,2 @@ } | ||
result += shortcutString; | ||
} | ||
@@ -1087,6 +1163,3 @@ } | ||
selectorForKeystroke, | ||
forCommand | ||
} | ||
forCommand, | ||
}; |
@@ -54,3 +54,6 @@ /** | ||
if (this.canUndo()) { | ||
if (options && typeof options.onUndoStateWillChange === 'function') { | ||
if ( | ||
options && | ||
typeof options.onUndoStateWillChange === 'function' | ||
) { | ||
options.onUndoStateWillChange(this.mathlist.target, 'undo'); | ||
@@ -115,3 +118,3 @@ } | ||
latex: this.mathlist.root.toLatex(), | ||
selection: this.mathlist.toString() | ||
selection: this.mathlist.toString(), | ||
}); | ||
@@ -151,7 +154,7 @@ | ||
* @private | ||
*/ | ||
*/ | ||
save() { | ||
return { | ||
latex: this.mathlist.root.toLatex(), | ||
selection: this.mathlist.toString() | ||
selection: this.mathlist.toString(), | ||
}; | ||
@@ -166,9 +169,10 @@ } | ||
* @private | ||
*/ | ||
*/ | ||
restore(state, options) { | ||
const wasSuppressing = this.mathlist.suppressChangeNotifications; | ||
if (options.suppressChangeNotifications !== undefined) { | ||
this.mathlist.suppressChangeNotifications = options.suppressChangeNotifications; | ||
this.mathlist.suppressChangeNotifications = | ||
options.suppressChangeNotifications; | ||
} | ||
// Restore the content | ||
@@ -180,7 +184,9 @@ this.mathlist.insert(state ? state.latex : '', { | ||
format: 'latex', | ||
...options | ||
...options, | ||
}); | ||
// Restore the selection | ||
this.mathlist.setPath(state ? state.selection : [{relation: 'body', offset: 0}]); | ||
this.mathlist.setPath( | ||
state ? state.selection : [{ relation: 'body', offset: 0 }] | ||
); | ||
@@ -192,6 +198,3 @@ this.mathlist.suppressChangeNotifications = wasSuppressing; | ||
export default { | ||
UndoManager | ||
} | ||
UndoManager, | ||
}; |
@@ -1,6 +0,2 @@ | ||
export function l10n(s) { | ||
const language = l10n.locale.substring(0, 2); | ||
@@ -20,6 +16,4 @@ | ||
return result; | ||
} | ||
l10n.plural = function(value, s, options) { | ||
@@ -30,6 +24,6 @@ options = options || {}; | ||
const rules = options.type === 'ordinal' ? l10n.ordinal : l10n.cardinal; | ||
let rule = options.type === 'ordinal' ? | ||
l10n._ordinalPluralCategories.indexOf(rules.select(value)) : | ||
l10n._cardinalPluralCategories.indexOf(rules.select(value)); | ||
let rule = | ||
options.type === 'ordinal' | ||
? l10n._ordinalPluralCategories.indexOf(rules.select(value)) | ||
: l10n._cardinalPluralCategories.indexOf(rules.select(value)); | ||
@@ -43,12 +37,14 @@ let result; | ||
if (options.type === 'ordinal') { | ||
rule = l10n._ordinalPluralCategories.indexOf(l10n._ordinalEnglish.select(value)); | ||
rule = l10n._ordinalPluralCategories.indexOf( | ||
l10n._ordinalEnglish.select(value) | ||
); | ||
} else { | ||
rule = l10n._cardinalPluralCategories.indexOf(l10n._cardinalEnglish.select(value)); | ||
rule = l10n._cardinalPluralCategories.indexOf( | ||
l10n._cardinalEnglish.select(value) | ||
); | ||
} | ||
} | ||
return result.split(';')[rule] || result.split(';')[0] | ||
} | ||
return result.split(';')[rule] || result.split(';')[0]; | ||
}; | ||
/* | ||
@@ -65,5 +61,5 @@ * Two forms for this function: | ||
const savedLocale = l10n._locale; | ||
l10n.locale = locale; // Load the necessary json file | ||
l10n.locale = locale; // Load the necessary json file | ||
l10n.strings[locale] = {...l10n.strings[locale], ...strings }; | ||
l10n.strings[locale] = { ...l10n.strings[locale], ...strings }; | ||
l10n.locale = savedLocale; | ||
@@ -74,5 +70,4 @@ } else if (locale && !strings) { | ||
} | ||
} | ||
}; | ||
// Add getter and setter for the _locale property of l10n | ||
@@ -90,7 +85,9 @@ Object.defineProperty(l10n, 'locale', { | ||
// Use the setter, which will load the necessary .json files. | ||
l10n._locale = typeof navigator === 'undefined' ? 'en' : | ||
navigator.language.slice(0, 5); | ||
l10n._locale = | ||
typeof navigator === 'undefined' | ||
? 'en' | ||
: navigator.language.slice(0, 5); | ||
} | ||
return l10n._locale | ||
} | ||
return l10n._locale; | ||
}, | ||
}); | ||
@@ -101,5 +98,9 @@ | ||
if (!l10n._ordinal) { | ||
l10n._ordinalEnglish = new Intl.PluralRules('en', {type: 'ordinal'}); | ||
l10n._ordinalEnglish = new Intl.PluralRules('en', { | ||
type: 'ordinal', | ||
}); | ||
l10n._ordinalEnglishPluralCategories = l10n._ordinalEnglish.resolvedOptions().pluralCategories; | ||
l10n._ordinal = new Intl.PluralRules(l10n.locale, {type: 'ordinal'}); | ||
l10n._ordinal = new Intl.PluralRules(l10n.locale, { | ||
type: 'ordinal', | ||
}); | ||
l10n._ordinalPluralCategories = l10n._ordinal.resolvedOptions().pluralCategories; | ||
@@ -109,3 +110,3 @@ // "zero", "one", "two", "few", "many" and "other" | ||
return l10n._ordinal; | ||
} | ||
}, | ||
}); | ||
@@ -116,139 +117,143 @@ | ||
if (!l10n._cardinal) { | ||
l10n._cardinalEnglish = new Intl.PluralRules('en', {type: 'cardinal'}); | ||
l10n._cardinalEnglish = new Intl.PluralRules('en', { | ||
type: 'cardinal', | ||
}); | ||
l10n._cardinalEnglishPluralCategories = l10n._cardinalEnglish.resolvedOptions().pluralCategories; | ||
l10n._cardinal = new Intl.PluralRules(l10n.locale, {type: 'cardinal'}); | ||
l10n._cardinal = new Intl.PluralRules(l10n.locale, { | ||
type: 'cardinal', | ||
}); | ||
l10n._cardinaPluralCategories = l10n._ordinal.resolvedOptions().pluralCategories; | ||
} | ||
return l10n._cardinal; | ||
} | ||
}, | ||
}); | ||
l10n.strings = { | ||
"en": { | ||
"keyboard.tooltip.functions": "Functions", | ||
"keyboard.tooltip.greek": "Greek Letters", | ||
"keyboard.tooltip.command": "LaTeX Command Mode", | ||
"keyboard.tooltip.numeric": "Numeric", | ||
"keyboard.tooltip.roman": "Symbols and Roman Letters", | ||
"tooltip.copy to clipboard": "Copy to Clipboard", | ||
"tooltip.redo": "Redo", | ||
"tooltip.toggle virtual keyboard": "Toggle Virtual Keyboard", | ||
"tooltip.undo": "Undo" | ||
en: { | ||
'keyboard.tooltip.functions': 'Functions', | ||
'keyboard.tooltip.greek': 'Greek Letters', | ||
'keyboard.tooltip.command': 'LaTeX Command Mode', | ||
'keyboard.tooltip.numeric': 'Numeric', | ||
'keyboard.tooltip.roman': 'Symbols and Roman Letters', | ||
'tooltip.copy to clipboard': 'Copy to Clipboard', | ||
'tooltip.redo': 'Redo', | ||
'tooltip.toggle virtual keyboard': 'Toggle Virtual Keyboard', | ||
'tooltip.undo': 'Undo', | ||
}, | ||
"ar": { | ||
"keyboard.tooltip.functions": "مهام", | ||
"keyboard.tooltip.greek": "حروف يونانية", | ||
"keyboard.tooltip.command": "حالة تلقي الأوامر اللاتك", | ||
"keyboard.tooltip.numeric": "الرقمية", | ||
"keyboard.tooltip.roman": "رموز الاحرف الرومانية", | ||
"tooltip.copy to clipboard": "نسخ إلى الحافظة", | ||
"tooltip.redo": "الإعادة", | ||
"tooltip.toggle virtual keyboard": "تبديل لوحة المفاتيح الإفتراضية", | ||
"tooltip.undo": "إلغاء" | ||
ar: { | ||
'keyboard.tooltip.functions': 'مهام', | ||
'keyboard.tooltip.greek': 'حروف يونانية', | ||
'keyboard.tooltip.command': 'حالة تلقي الأوامر اللاتك', | ||
'keyboard.tooltip.numeric': 'الرقمية', | ||
'keyboard.tooltip.roman': 'رموز الاحرف الرومانية', | ||
'tooltip.copy to clipboard': 'نسخ إلى الحافظة', | ||
'tooltip.redo': 'الإعادة', | ||
'tooltip.toggle virtual keyboard': 'تبديل لوحة المفاتيح الإفتراضية', | ||
'tooltip.undo': 'إلغاء', | ||
}, | ||
"de": { | ||
"keyboard.tooltip.functions": "Funktionen", | ||
"keyboard.tooltip.greek": "Griechische Buchstaben", | ||
"keyboard.tooltip.command": "LaTeX-Befehlsmodus", | ||
"keyboard.tooltip.numeric": "Numerisch", | ||
"keyboard.tooltip.roman": "Symbole und römische Buchstaben", | ||
"tooltip.copy to clipboard": "In die Zwischenablage kopieren", | ||
"tooltip.redo": "Wiederholen", | ||
"tooltip.toggle virtual keyboard": "Virtuelle Tastatur umschalten", | ||
"tooltip.undo": "Widerrufen" | ||
de: { | ||
'keyboard.tooltip.functions': 'Funktionen', | ||
'keyboard.tooltip.greek': 'Griechische Buchstaben', | ||
'keyboard.tooltip.command': 'LaTeX-Befehlsmodus', | ||
'keyboard.tooltip.numeric': 'Numerisch', | ||
'keyboard.tooltip.roman': 'Symbole und römische Buchstaben', | ||
'tooltip.copy to clipboard': 'In die Zwischenablage kopieren', | ||
'tooltip.redo': 'Wiederholen', | ||
'tooltip.toggle virtual keyboard': 'Virtuelle Tastatur umschalten', | ||
'tooltip.undo': 'Widerrufen', | ||
}, | ||
"el": { | ||
"keyboard.tooltip.functions": "συναρτήσεις", | ||
"keyboard.tooltip.greek": "ελληνικά γράμματα", | ||
"keyboard.tooltip.command": "Λειτουργία εντολών LaTeX", | ||
"keyboard.tooltip.numeric": "Αριθμητικός", | ||
"keyboard.tooltip.roman": "Σύμβολα και ρωμαϊκά γράμματα", | ||
"tooltip.copy to clipboard": "Αντιγραφή στο πρόχειρο", | ||
"tooltip.redo": "Ξανακάνω", | ||
"tooltip.toggle virtual keyboard": "Εναλλαγή εικονικού πληκτρολογίου", | ||
"tooltip.undo": "Ξεκάνω" | ||
el: { | ||
'keyboard.tooltip.functions': 'συναρτήσεις', | ||
'keyboard.tooltip.greek': 'ελληνικά γράμματα', | ||
'keyboard.tooltip.command': 'Λειτουργία εντολών LaTeX', | ||
'keyboard.tooltip.numeric': 'Αριθμητικός', | ||
'keyboard.tooltip.roman': 'Σύμβολα και ρωμαϊκά γράμματα', | ||
'tooltip.copy to clipboard': 'Αντιγραφή στο πρόχειρο', | ||
'tooltip.redo': 'Ξανακάνω', | ||
'tooltip.toggle virtual keyboard': 'Εναλλαγή εικονικού πληκτρολογίου', | ||
'tooltip.undo': 'Ξεκάνω', | ||
}, | ||
"es": { | ||
"keyboard.tooltip.functions": "Funciones", | ||
"keyboard.tooltip.greek": "Letras griegas", | ||
"keyboard.tooltip.command": "Modo Comando LaTeX", | ||
"keyboard.tooltip.numeric": "Numérico", | ||
"keyboard.tooltip.roman": "Símbolos y letras romanas", | ||
"tooltip.copy to clipboard": "Copiar al portapapeles", | ||
"tooltip.redo": "Rehacer", | ||
"tooltip.toggle virtual keyboard": "Alternar teclado virtual", | ||
"tooltip.undo": "Deshacer" | ||
es: { | ||
'keyboard.tooltip.functions': 'Funciones', | ||
'keyboard.tooltip.greek': 'Letras griegas', | ||
'keyboard.tooltip.command': 'Modo Comando LaTeX', | ||
'keyboard.tooltip.numeric': 'Numérico', | ||
'keyboard.tooltip.roman': 'Símbolos y letras romanas', | ||
'tooltip.copy to clipboard': 'Copiar al portapapeles', | ||
'tooltip.redo': 'Rehacer', | ||
'tooltip.toggle virtual keyboard': 'Alternar teclado virtual', | ||
'tooltip.undo': 'Deshacer', | ||
}, | ||
"fa": { | ||
"keyboard.tooltip.functions": "توابع", | ||
"keyboard.tooltip.greek": "حروف یونانی", | ||
"keyboard.tooltip.command": "حالت دستور لاتک", | ||
"keyboard.tooltip.numeric": "عددی", | ||
"keyboard.tooltip.roman": "علائم و حروف لاتین", | ||
"tooltip.copy to clipboard": "کپی به کلیپبورد", | ||
"tooltip.redo": "بازگشت به بعد", | ||
"tooltip.toggle virtual keyboard": "نمایش/نهفتن کیبورد مجازی", | ||
"tooltip.undo": "بازگشت به قبل" | ||
fa: { | ||
'keyboard.tooltip.functions': 'توابع', | ||
'keyboard.tooltip.greek': 'حروف یونانی', | ||
'keyboard.tooltip.command': 'حالت دستور لاتک', | ||
'keyboard.tooltip.numeric': 'عددی', | ||
'keyboard.tooltip.roman': 'علائم و حروف لاتین', | ||
'tooltip.copy to clipboard': 'کپی به کلیپبورد', | ||
'tooltip.redo': 'بازگشت به بعد', | ||
'tooltip.toggle virtual keyboard': 'نمایش/نهفتن کیبورد مجازی', | ||
'tooltip.undo': 'بازگشت به قبل', | ||
}, | ||
"fr": { | ||
"keyboard.tooltip.functions": "Fonctions", | ||
"keyboard.tooltip.greek": "Lettres grecques", | ||
"keyboard.tooltip.command": "Mode de commandes LaTeX", | ||
"keyboard.tooltip.numeric": "Numérique", | ||
"keyboard.tooltip.roman": "Lettres et symboles romains", | ||
"tooltip.copy to clipboard": "Copier dans le presse-papiers", | ||
"tooltip.redo": "Rétablir", | ||
"tooltip.toggle virtual keyboard": "Afficher/Masquer le clavier virtuel", | ||
"tooltip.undo": "Annuler" | ||
fr: { | ||
'keyboard.tooltip.functions': 'Fonctions', | ||
'keyboard.tooltip.greek': 'Lettres grecques', | ||
'keyboard.tooltip.command': 'Mode de commandes LaTeX', | ||
'keyboard.tooltip.numeric': 'Numérique', | ||
'keyboard.tooltip.roman': 'Lettres et symboles romains', | ||
'tooltip.copy to clipboard': 'Copier dans le presse-papiers', | ||
'tooltip.redo': 'Rétablir', | ||
'tooltip.toggle virtual keyboard': | ||
'Afficher/Masquer le clavier virtuel', | ||
'tooltip.undo': 'Annuler', | ||
}, | ||
"it": { | ||
"keyboard.tooltip.functions": "Funzioni", | ||
"keyboard.tooltip.greek": "Lettere greche", | ||
"keyboard.tooltip.command": "Modalità di comando LaTeX", | ||
"keyboard.tooltip.numeric": "Numerico", | ||
"keyboard.tooltip.roman": "Simboli e lettere romane", | ||
"tooltip.copy to clipboard": "Copia negli appunti", | ||
"tooltip.redo": "Rifare", | ||
"tooltip.toggle virtual keyboard": "Attiva / disattiva la tastiera virtuale", | ||
"tooltip.undo": "Disfare" | ||
it: { | ||
'keyboard.tooltip.functions': 'Funzioni', | ||
'keyboard.tooltip.greek': 'Lettere greche', | ||
'keyboard.tooltip.command': 'Modalità di comando LaTeX', | ||
'keyboard.tooltip.numeric': 'Numerico', | ||
'keyboard.tooltip.roman': 'Simboli e lettere romane', | ||
'tooltip.copy to clipboard': 'Copia negli appunti', | ||
'tooltip.redo': 'Rifare', | ||
'tooltip.toggle virtual keyboard': | ||
'Attiva / disattiva la tastiera virtuale', | ||
'tooltip.undo': 'Disfare', | ||
}, | ||
"ja": { | ||
"keyboard.tooltip.functions": "関数", | ||
"keyboard.tooltip.greek": "ギリシャ文字", | ||
"keyboard.tooltip.command": "LaTeXコマンドモード", | ||
"keyboard.tooltip.numeric": "数値", | ||
"keyboard.tooltip.roman": "記号とローマ字", | ||
"tooltip.copy to clipboard": "クリップボードにコピー", | ||
"tooltip.redo": "やり直し", | ||
"tooltip.toggle virtual keyboard": "仮想キーボードの切り替え", | ||
"tooltip.undo": "元に戻す" | ||
ja: { | ||
'keyboard.tooltip.functions': '関数', | ||
'keyboard.tooltip.greek': 'ギリシャ文字', | ||
'keyboard.tooltip.command': 'LaTeXコマンドモード', | ||
'keyboard.tooltip.numeric': '数値', | ||
'keyboard.tooltip.roman': '記号とローマ字', | ||
'tooltip.copy to clipboard': 'クリップボードにコピー', | ||
'tooltip.redo': 'やり直し', | ||
'tooltip.toggle virtual keyboard': '仮想キーボードの切り替え', | ||
'tooltip.undo': '元に戻す', | ||
}, | ||
"pl": { | ||
"keyboard.tooltip.functions": "Funkcje", | ||
"keyboard.tooltip.greek": "Litery greckie", | ||
"keyboard.tooltip.command": "Tryb poleceń LaTeX", | ||
"keyboard.tooltip.numeric": "Numeryczne", | ||
"keyboard.tooltip.roman": "Symbole i litery rzymskie", | ||
"tooltip.copy to clipboard": "Kopiuj do Schowka", | ||
"tooltip.redo": "Przywróć", | ||
"tooltip.toggle virtual keyboard": "Przełącz wirtualną klawiaturę", | ||
"tooltip.undo": "Cofnij" | ||
pl: { | ||
'keyboard.tooltip.functions': 'Funkcje', | ||
'keyboard.tooltip.greek': 'Litery greckie', | ||
'keyboard.tooltip.command': 'Tryb poleceń LaTeX', | ||
'keyboard.tooltip.numeric': 'Numeryczne', | ||
'keyboard.tooltip.roman': 'Symbole i litery rzymskie', | ||
'tooltip.copy to clipboard': 'Kopiuj do Schowka', | ||
'tooltip.redo': 'Przywróć', | ||
'tooltip.toggle virtual keyboard': 'Przełącz wirtualną klawiaturę', | ||
'tooltip.undo': 'Cofnij', | ||
}, | ||
"ru": { | ||
"keyboard.tooltip.functions": "Функции", | ||
"keyboard.tooltip.greek": "Греческие буквы", | ||
"keyboard.tooltip.command": "Режим командной строки LaTeX", | ||
"keyboard.tooltip.numeric": "числовой", | ||
"keyboard.tooltip.roman": "Символы и римские буквы", | ||
"tooltip.copy to clipboard": "Скопировать в буфер обмена", | ||
"tooltip.redo": "переделывать", | ||
"tooltip.toggle virtual keyboard": "Переключить виртуальную клавиатуру", | ||
"tooltip.undo": "расстегивать" | ||
} | ||
ru: { | ||
'keyboard.tooltip.functions': 'Функции', | ||
'keyboard.tooltip.greek': 'Греческие буквы', | ||
'keyboard.tooltip.command': 'Режим командной строки LaTeX', | ||
'keyboard.tooltip.numeric': 'числовой', | ||
'keyboard.tooltip.roman': 'Символы и римские буквы', | ||
'tooltip.copy to clipboard': 'Скопировать в буфер обмена', | ||
'tooltip.redo': 'переделывать', | ||
'tooltip.toggle virtual keyboard': 'Переключить виртуальную клавиатуру', | ||
'tooltip.undo': 'расстегивать', | ||
}, | ||
}; | ||
export default { | ||
l10n | ||
} | ||
l10n, | ||
}; |
const SPECIAL_IDENTIFIERS = { | ||
'\u2212': '-', // MINUS SIGN | ||
'-': '-', | ||
'\\alpha': 'alpha', | ||
'\\beta': 'beta', | ||
'\\gamma': 'gamma', | ||
'\\delta': 'delta', | ||
'\\epsilon': 'epsilon', | ||
'\u2212': '-', // MINUS SIGN | ||
'-': '-', | ||
'\\alpha': 'alpha', | ||
'\\beta': 'beta', | ||
'\\gamma': 'gamma', | ||
'\\delta': 'delta', | ||
'\\epsilon': 'epsilon', | ||
'\\varepsilon': 'varepsilon', | ||
'\\zeta': 'zeta', | ||
'\\eta': 'eta', | ||
'\\theta': 'theta', | ||
'\\vartheta': 'vartheta', | ||
'\\iota': 'iota', | ||
'\\kappa': 'kappa', | ||
'\\lambda': 'lambda', | ||
'\\mu': 'mu', | ||
'\\nu': 'nu', | ||
'\\xi': 'xi', | ||
'\\pi': 'pi', | ||
'\\rho': 'rho', | ||
'\\sigma': 'sigma', | ||
'\\tau': 'tau', | ||
'\\upsilon': 'upsilon', | ||
'\\phi': 'phi', | ||
'\\varphi': 'varphi', | ||
'\\chi': 'chi', | ||
'\\psi': 'psi', | ||
'\\omega': 'omega', | ||
'\\Gamma': 'Gamma', | ||
'\\Delta': 'Delta', | ||
'\\Theta': 'Theta', | ||
'\\Lambda': 'Lambda', | ||
'\\Xi': 'Xi', | ||
'\\Pi': 'Pi', | ||
'\\Sigma': 'Sigma', | ||
'\\Phi': 'Phi', | ||
'\\Psi': 'Psi', | ||
'\\Omega': 'Omega', | ||
'\\zeta': 'zeta', | ||
'\\eta': 'eta', | ||
'\\theta': 'theta', | ||
'\\vartheta': 'vartheta', | ||
'\\iota': 'iota', | ||
'\\kappa': 'kappa', | ||
'\\lambda': 'lambda', | ||
'\\mu': 'mu', | ||
'\\nu': 'nu', | ||
'\\xi': 'xi', | ||
'\\pi': 'pi', | ||
'\\rho': 'rho', | ||
'\\sigma': 'sigma', | ||
'\\tau': 'tau', | ||
'\\upsilon': 'upsilon', | ||
'\\phi': 'phi', | ||
'\\varphi': 'varphi', | ||
'\\chi': 'chi', | ||
'\\psi': 'psi', | ||
'\\omega': 'omega', | ||
'\\Gamma': 'Gamma', | ||
'\\Delta': 'Delta', | ||
'\\Theta': 'Theta', | ||
'\\Lambda': 'Lambda', | ||
'\\Xi': 'Xi', | ||
'\\Pi': 'Pi', | ||
'\\Sigma': 'Sigma', | ||
'\\Phi': 'Phi', | ||
'\\Psi': 'Psi', | ||
'\\Omega': 'Omega', | ||
}; | ||
@@ -70,3 +70,3 @@ | ||
export function toASCIIMath(atom, options){ | ||
export function toASCIIMath(atom, options) { | ||
if (!atom) return ''; | ||
@@ -97,2 +97,6 @@ if (Array.isArray(atom)) { | ||
if (atom.mode === 'text') { | ||
return '"' + atom.body + '"'; // text -- add in (ASCII) quotes | ||
} | ||
let result = ''; | ||
@@ -102,3 +106,3 @@ const command = atom.latex ? atom.latex.trim() : null; | ||
switch(atom.type) { | ||
switch (atom.type) { | ||
case 'group': | ||
@@ -114,3 +118,6 @@ case 'root': | ||
if (atom.leftDelim || atom.rightDelim) { | ||
result += (atom.leftDelim === '.' || !atom.leftDelim) ? '{:' : atom.leftDelim; | ||
result += | ||
atom.leftDelim === '.' || !atom.leftDelim | ||
? '{:' | ||
: atom.leftDelim; | ||
} | ||
@@ -129,10 +136,17 @@ if (atom.hasBarLine) { | ||
if (atom.leftDelim || atom.rightDelim) { | ||
result += (atom.rightDelim === '.' || !atom.rightDelim) ? '{:' : atom.rightDelim; | ||
result += | ||
atom.rightDelim === '.' || !atom.rightDelim | ||
? '{:' | ||
: atom.rightDelim; | ||
} | ||
break; | ||
break; | ||
case 'surd': | ||
if (atom.index) { | ||
result += 'root(' + toASCIIMath(atom.index, options) + ')(' + | ||
toASCIIMath(atom.body, options) + ')'; | ||
result += | ||
'root(' + | ||
toASCIIMath(atom.index, options) + | ||
')(' + | ||
toASCIIMath(atom.body, options) + | ||
')'; | ||
} else { | ||
@@ -144,5 +158,11 @@ result += 'sqrt(' + toASCIIMath(atom.body, options) + ')'; | ||
case 'leftright': | ||
result += (atom.leftDelim === '.' || !atom.leftDelim) ? '{:' : atom.leftDelim; | ||
result += | ||
atom.leftDelim === '.' || !atom.leftDelim | ||
? '{:' | ||
: atom.leftDelim; | ||
result += toASCIIMath(atom.body, options); | ||
result += (atom.rightDelim === '.' || !atom.rightDelim) ? '{:' : atom.rightDelim; | ||
result += | ||
atom.rightDelim === '.' || !atom.rightDelim | ||
? '{:' | ||
: atom.rightDelim; | ||
break; | ||
@@ -155,3 +175,2 @@ | ||
case 'accent': | ||
@@ -165,3 +184,2 @@ break; | ||
case 'overunder': | ||
break; | ||
@@ -171,9 +189,13 @@ | ||
// @todo, deal with some special identifiers: \alpha, etc... | ||
result = SPECIAL_IDENTIFIERS[command] || command || | ||
result = | ||
SPECIAL_IDENTIFIERS[command] || | ||
command || | ||
(typeof atom.body === 'string' ? atom.body : ''); | ||
if (result[0] === '\\') result += ''; | ||
m = command ? command.match(/[{]?\\char"([0-9abcdefABCDEF]*)[}]?/) : null; | ||
m = command | ||
? command.match(/[{]?\\char"([0-9abcdefABCDEF]*)[}]?/) | ||
: null; | ||
if (m) { | ||
// It's a \char command | ||
result = String.fromCharCode(parseInt('0x' + m[1])) | ||
result = String.fromCharCode(parseInt('0x' + m[1])); | ||
} else if (result.length > 0 && result.charAt(0) === '\\') { | ||
@@ -219,3 +241,3 @@ // atom is an identifier with no special handling. Use the | ||
if (command === '\\operatorname') { | ||
result += atom.body; | ||
result += toASCIIMath(atom.body, options); | ||
} else { | ||
@@ -241,5 +263,4 @@ result += atom.body || command; | ||
case 'space': | ||
result = ' ' | ||
result = ' '; | ||
break; | ||
} | ||
@@ -251,3 +272,3 @@ // Subscripts before superscripts (according to the ASCIIMath spec) | ||
if (arg.length > 1 && !/^(-)?\d+(\.\d*)?$/.test(arg)) { | ||
result += '(' + arg + ')' | ||
result += '(' + arg + ')'; | ||
} else { | ||
@@ -262,3 +283,3 @@ result += arg; | ||
if (arg.length > 1 && !/^(-)?\d+(\.\d*)?$/.test(arg)) { | ||
result += '(' + arg + ')' | ||
result += '(' + arg + ')'; | ||
} else { | ||
@@ -273,3 +294,3 @@ result += arg; | ||
export default { | ||
toASCIIMath | ||
} | ||
toASCIIMath, | ||
}; |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -57,4 +56,7 @@ * | ||
console.assert(/displaystyle|textstyle|scriptstyle|scriptscriptstyle/.test(mathstyle), | ||
"Invalid style:", mathstyle); | ||
console.assert( | ||
/displaystyle|textstyle|scriptstyle|scriptscriptstyle/.test(mathstyle), | ||
'Invalid style:', | ||
mathstyle | ||
); | ||
@@ -76,4 +78,2 @@ // | ||
// | ||
@@ -83,5 +83,4 @@ // 3. Transform the math atoms into elementary spans | ||
// | ||
let spans = MathAtom.decompose({mathstyle: mathstyle}, mathlist); | ||
let spans = MathAtom.decompose({ mathstyle: mathstyle }, mathlist); | ||
// | ||
@@ -101,3 +100,3 @@ // 4. Simplify by coalescing adjacent nodes | ||
const topStrut = Span.makeSpan('', 'ML__strut') | ||
const topStrut = Span.makeSpan('', 'ML__strut'); | ||
topStrut.setStyle('height', base.height, 'em'); | ||
@@ -114,3 +113,2 @@ const struts = [topStrut]; | ||
// | ||
@@ -123,4 +121,2 @@ // 6. Generate markup | ||
/** | ||
@@ -185,4 +181,8 @@ * Convert a DOM element into an editable mathfield. | ||
const mathlist = ParserModule.parseTokens(Lexer.tokenize(latex), | ||
'math', null, options.macros); | ||
const mathlist = ParserModule.parseTokens( | ||
Lexer.tokenize(latex), | ||
'math', | ||
null, | ||
options.macros | ||
); | ||
@@ -215,4 +215,8 @@ return MathAtom.toMathML(mathlist, options); | ||
const mathlist = ParserModule.parseTokens(Lexer.tokenize(latex), | ||
'math', null, options.macros); | ||
const mathlist = ParserModule.parseTokens( | ||
Lexer.tokenize(latex), | ||
'math', | ||
null, | ||
options.macros | ||
); | ||
@@ -222,3 +226,2 @@ return MathAtom.toAST(mathlist, options); | ||
/** | ||
@@ -247,3 +250,3 @@ * Converts an Abstract Syntax Tree (MathJSON) to a LaTeX string. | ||
* used at the end of repeating digits. **Default** = `"}"` | ||
* | ||
* | ||
* @return {string} The LaTeX representation of the Abstract Syntax Tree, if valid. | ||
@@ -257,3 +260,2 @@ * @category Converting | ||
/** | ||
@@ -300,3 +302,3 @@ * Converts a LaTeX string to a textual representation ready to be spoken | ||
console.warn('The outputSpokenText module is not loaded.'); | ||
return ""; | ||
return ''; | ||
} | ||
@@ -307,4 +309,8 @@ options = options || {}; | ||
const mathlist = ParserModule.parseTokens(Lexer.tokenize(latex), | ||
'math', null, options.macros); | ||
const mathlist = ParserModule.parseTokens( | ||
Lexer.tokenize(latex), | ||
'math', | ||
null, | ||
options.macros | ||
); | ||
@@ -314,3 +320,2 @@ return MathAtom.toSpeakableText(mathlist, options); | ||
function removeHighlight(node) { | ||
@@ -369,5 +374,7 @@ node.classList.remove('highlight'); | ||
if (!window || !window.AWS) { | ||
console.warn('AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk'); | ||
console.warn( | ||
'AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk' | ||
); | ||
} else { | ||
const polly = new window.AWS.Polly({apiVersion: '2016-06-10'}); | ||
const polly = new window.AWS.Polly({ apiVersion: '2016-06-10' }); | ||
const params = { | ||
@@ -383,7 +390,13 @@ OutputFormat: 'mp3', | ||
if (err) { | ||
console.warn('polly.synthesizeSpeech() error:', err, err.stack); | ||
console.warn( | ||
'polly.synthesizeSpeech() error:', | ||
err, | ||
err.stack | ||
); | ||
} else { | ||
if (data && data.AudioStream) { | ||
const uInt8Array = new Uint8Array(data.AudioStream); | ||
const blob = new Blob([uInt8Array.buffer], {type: 'audio/mpeg'}); | ||
const blob = new Blob([uInt8Array.buffer], { | ||
type: 'audio/mpeg', | ||
}); | ||
const url = URL.createObjectURL(blob); | ||
@@ -402,3 +415,5 @@ | ||
} else if (config.speechEngine === 'google') { | ||
console.warn('The Google speech engine is not supported yet. Please come again.'); | ||
console.warn( | ||
'The Google speech engine is not supported yet. Please come again.' | ||
); | ||
// @todo: implement support for Google Text-to-Speech API, | ||
@@ -408,19 +423,19 @@ // using config.speechEngineToken, config.speechEngineVoice and | ||
// curl -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \ | ||
// -H "Content-Type: application/json; charset=utf-8" \ | ||
// --data "{ | ||
// 'input':{ | ||
// 'text':'Android is a mobile operating system developed by Google, | ||
// based on the Linux kernel and designed primarily for | ||
// touchscreen mobile devices such as smartphones and tablets.' | ||
// }, | ||
// 'voice':{ | ||
// 'languageCode':'en-gb', | ||
// 'name':'en-GB-Standard-A', | ||
// 'ssmlGender':'FEMALE' | ||
// }, | ||
// 'audioConfig':{ | ||
// 'audioEncoding':'MP3' | ||
// } | ||
// }" "https://texttospeech.googleapis.com/v1beta1/text:synthesize" > synthesize-text.txt | ||
// curl -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \ | ||
// -H "Content-Type: application/json; charset=utf-8" \ | ||
// --data "{ | ||
// 'input':{ | ||
// 'text':'Android is a mobile operating system developed by Google, | ||
// based on the Linux kernel and designed primarily for | ||
// touchscreen mobile devices such as smartphones and tablets.' | ||
// }, | ||
// 'voice':{ | ||
// 'languageCode':'en-gb', | ||
// 'name':'en-GB-Standard-A', | ||
// 'ssmlGender':'FEMALE' | ||
// }, | ||
// 'audioConfig':{ | ||
// 'audioEncoding':'MP3' | ||
// } | ||
// }" "https://texttospeech.googleapis.com/v1beta1/text:synthesize" > synthesize-text.txt | ||
} | ||
@@ -454,6 +469,8 @@ } | ||
if (!window.AWS) { | ||
console.warn('AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk'); | ||
console.warn( | ||
'AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk' | ||
); | ||
return; | ||
} | ||
const polly = new window.AWS.Polly({apiVersion: '2016-06-10'}); | ||
const polly = new window.AWS.Polly({ apiVersion: '2016-06-10' }); | ||
@@ -465,3 +482,3 @@ const params = { | ||
TextType: 'ssml', | ||
SpeechMarkTypes: ['ssml'] | ||
SpeechMarkTypes: ['ssml'], | ||
}; | ||
@@ -472,3 +489,4 @@ | ||
const status = config.onReadAloudStatus || window.mathlive.onReadAloudStatus; | ||
const status = | ||
config.onReadAloudStatus || window.mathlive.onReadAloudStatus; | ||
@@ -481,4 +499,8 @@ // Request the mark points | ||
if (data && data.AudioStream) { | ||
const response = new TextDecoder('utf-8').decode(new Uint8Array(data.AudioStream)); | ||
window.mathlive.readAloudMarks = response.split('\n').map(x => x ? JSON.parse(x) : {}); | ||
const response = new TextDecoder('utf-8').decode( | ||
new Uint8Array(data.AudioStream) | ||
); | ||
window.mathlive.readAloudMarks = response | ||
.split('\n') | ||
.map(x => (x ? JSON.parse(x) : {})); | ||
window.mathlive.readAloudTokens = []; | ||
@@ -497,7 +519,15 @@ for (const mark of window.mathlive.readAloudMarks) { | ||
if (err) { | ||
console.warn('polly.synthesizeSpeech(', text , ') error:', err, err.stack); | ||
console.warn( | ||
'polly.synthesizeSpeech(', | ||
text, | ||
') error:', | ||
err, | ||
err.stack | ||
); | ||
} else { | ||
if (data && data.AudioStream) { | ||
const uInt8Array = new Uint8Array(data.AudioStream); | ||
const blob = new Blob([uInt8Array.buffer], {type: 'audio/mpeg'}); | ||
const blob = new Blob([uInt8Array.buffer], { | ||
type: 'audio/mpeg', | ||
}); | ||
const url = URL.createObjectURL(blob); | ||
@@ -507,38 +537,72 @@ | ||
window.mathlive.readAloudAudio = new Audio(); | ||
window.mathlive.readAloudAudio.addEventListener('ended', () => { | ||
if (status) status(window.mathlive.readAloudMathField, 'ended'); | ||
if (window.mathlive.readAloudMathField) { | ||
window.mathlive.readAloudMathField._render(); | ||
window.mathlive.readAloudElement = null; | ||
window.mathlive.readAloudMathField = null; | ||
window.mathlive.readAloudTokens = []; | ||
window.mathlive.readAloudMarks = []; | ||
window.mathlive.readAloudCurrentMark = ''; | ||
} else { | ||
removeHighlight(window.mathlive.readAloudElement); | ||
window.mathlive.readAloudAudio.addEventListener( | ||
'ended', | ||
() => { | ||
if (status) | ||
status( | ||
window.mathlive | ||
.readAloudMathField, | ||
'ended' | ||
); | ||
if ( | ||
window.mathlive.readAloudMathField | ||
) { | ||
window.mathlive.readAloudMathField._render(); | ||
window.mathlive.readAloudElement = null; | ||
window.mathlive.readAloudMathField = null; | ||
window.mathlive.readAloudTokens = []; | ||
window.mathlive.readAloudMarks = []; | ||
window.mathlive.readAloudCurrentMark = | ||
''; | ||
} else { | ||
removeHighlight( | ||
window.mathlive.readAloudElement | ||
); | ||
} | ||
} | ||
}); | ||
window.mathlive.readAloudAudio.addEventListener('timeupdate', () => { | ||
let value = ''; | ||
// The target, the atom we're looking for, is the one matching the current audio | ||
// plus 100 ms. By anticipating it a little bit, it feels more natural, otherwise it | ||
// feels like the highlighting is trailing the audio. | ||
const target = window.mathlive.readAloudAudio.currentTime * 1000 + 100; | ||
); | ||
window.mathlive.readAloudAudio.addEventListener( | ||
'timeupdate', | ||
() => { | ||
let value = ''; | ||
// The target, the atom we're looking for, is the one matching the current audio | ||
// plus 100 ms. By anticipating it a little bit, it feels more natural, otherwise it | ||
// feels like the highlighting is trailing the audio. | ||
const target = | ||
window.mathlive.readAloudAudio | ||
.currentTime * | ||
1000 + | ||
100; | ||
// Find the smallest element which is bigger than the target time | ||
for (const mark of window.mathlive.readAloudMarks) { | ||
if (mark.time < target) { | ||
value = mark.value; | ||
// Find the smallest element which is bigger than the target time | ||
for (const mark of window.mathlive | ||
.readAloudMarks) { | ||
if (mark.time < target) { | ||
value = mark.value; | ||
} | ||
} | ||
} | ||
if (window.mathlive.readAloudCurrentMark !== value) { | ||
window.mathlive.readAloudCurrentToken = value; | ||
if (value && value === window.mathlive.readAloudFinalToken) { | ||
window.mathlive.readAloudAudio.pause(); | ||
} else { | ||
window.mathlive.readAloudCurrentMark = value; | ||
highlightAtomID(window.mathlive.readAloudElement, window.mathlive.readAloudCurrentMark); | ||
if ( | ||
window.mathlive | ||
.readAloudCurrentMark !== value | ||
) { | ||
window.mathlive.readAloudCurrentToken = value; | ||
if ( | ||
value && | ||
value === | ||
window.mathlive | ||
.readAloudFinalToken | ||
) { | ||
window.mathlive.readAloudAudio.pause(); | ||
} else { | ||
window.mathlive.readAloudCurrentMark = value; | ||
highlightAtomID( | ||
window.mathlive | ||
.readAloudElement, | ||
window.mathlive | ||
.readAloudCurrentMark | ||
); | ||
} | ||
} | ||
} | ||
}); | ||
); | ||
} else { | ||
@@ -550,3 +614,6 @@ window.mathlive.readAloudAudio.pause(); | ||
if (status) { | ||
status(window.mathlive.readAloudMathField, 'playing'); | ||
status( | ||
window.mathlive.readAloudMathField, | ||
'playing' | ||
); | ||
} | ||
@@ -604,3 +671,6 @@ window.mathlive.readAloudAudio.play(); | ||
if (window.mathlive.onReadAloudStatus) { | ||
window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'paused'); | ||
window.mathlive.onReadAloudStatus( | ||
window.mathlive.readAloudMathField, | ||
'paused' | ||
); | ||
} | ||
@@ -623,3 +693,6 @@ window.mathlive.readAloudAudio.pause(); | ||
if (window.mathlive.onReadAloudStatus) { | ||
window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'playing'); | ||
window.mathlive.onReadAloudStatus( | ||
window.mathlive.readAloudMathField, | ||
'playing' | ||
); | ||
} | ||
@@ -647,3 +720,4 @@ window.mathlive.readAloudAudio.play(); | ||
if (token) { | ||
window.mathlive.readAloudMarks = window.mathlive.readAloudMarks || []; | ||
window.mathlive.readAloudMarks = | ||
window.mathlive.readAloudMarks || []; | ||
for (const mark of window.mathlive.readAloudMarks) { | ||
@@ -664,3 +738,6 @@ if (mark.value === token) { | ||
if (window.mathlive.onReadAloudStatus) { | ||
window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'playing'); | ||
window.mathlive.onReadAloudStatus( | ||
window.mathlive.readAloudMathField, | ||
'playing' | ||
); | ||
} | ||
@@ -671,3 +748,2 @@ window.mathlive.readAloudAudio.play(); | ||
/** | ||
@@ -794,3 +870,4 @@ * Transform all the elements in the document body that contain LaTeX code | ||
options.renderToMathML = options.renderToMathML || toMathML; | ||
options.renderToSpeakableText = options.renderToSpeakableText || latexToSpeakableText; | ||
options.renderToSpeakableText = | ||
options.renderToSpeakableText || latexToSpeakableText; | ||
options.macros = options.macros || Definitions.MACROS; | ||
@@ -800,11 +877,11 @@ AutoRender.renderMathInElement(getElement(element), options); | ||
function validateNamespace(options) { | ||
if (options.namespace) { | ||
if (!/^[a-z]+[-]?$/.test(options.namespace)) { | ||
throw Error('options.namespace must be a string of lowercase characters only'); | ||
throw Error( | ||
'options.namespace must be a string of lowercase characters only' | ||
); | ||
} | ||
if (!/-$/.test(options.namespace)) { | ||
options.namespace += '-'; | ||
options.namespace += '-'; | ||
} | ||
@@ -834,9 +911,8 @@ } | ||
validateNamespace(options); | ||
element.innerHTML = element.getAttribute('data-' + | ||
(options.namespace || '') + 'original-content'); | ||
element.innerHTML = element.getAttribute( | ||
'data-' + (options.namespace || '') + 'original-content' | ||
); | ||
} | ||
} | ||
/** | ||
@@ -881,4 +957,5 @@ * After calling {@linkcode module:mathlive#renderMathInElement renderMathInElement} | ||
validateNamespace(options); | ||
return element.getAttribute('data-' + | ||
(options.namespace || '') + 'original-content'); | ||
return element.getAttribute( | ||
'data-' + (options.namespace || '') + 'original-content' | ||
); | ||
} | ||
@@ -901,8 +978,5 @@ | ||
resumeReadAloud, | ||
playReadAloud | ||
playReadAloud, | ||
}; | ||
export default MathLive; | ||
export default { | ||
name: 'mathlive-mathfield', | ||
template: '<div class="mathfield" :id="id"><slot></slot></div>', | ||
props: | ||
{ | ||
props: { | ||
id: { | ||
type: String, | ||
default: '' | ||
default: '', | ||
}, | ||
value: { | ||
type: String, | ||
default: '' | ||
default: '', | ||
}, | ||
config: { | ||
type: Object, | ||
default: () => ({}) | ||
default: () => ({}), | ||
}, | ||
onKeystroke: { | ||
type: Function, | ||
default: function(_keystroke, _ev) { return true; } | ||
default: function(_keystroke, _ev) { | ||
return true; | ||
}, | ||
}, | ||
onMoveOutOf: { | ||
type: Function, | ||
default: function(_direction) { return true; } | ||
default: function(_direction) { | ||
return true; | ||
}, | ||
}, | ||
onTabOutOf: { | ||
type: Function, | ||
default: function(_direction) { return true; } | ||
} | ||
default: function(_direction) { | ||
return true; | ||
}, | ||
}, | ||
}, | ||
@@ -63,3 +68,3 @@ /* | ||
this.$el.mathfield.$text(newValue, { | ||
suppressChangeNotifications: true | ||
suppressChangeNotifications: true, | ||
}); | ||
@@ -71,11 +76,11 @@ } | ||
handler: function(config) { | ||
this.$el.mathfield.$setConfig(config) | ||
} | ||
this.$el.mathfield.$setConfig(config); | ||
}, | ||
}, | ||
}, | ||
mounted: function () { | ||
mounted: function() { | ||
// A new instance is being created | ||
const vm = this; // Keep a reference to the ViewModel | ||
const vm = this; // Keep a reference to the ViewModel | ||
// Wait until the DOM has been constructed... | ||
this.$nextTick(function () { | ||
this.$nextTick(function() { | ||
// ... then make the MathField | ||
@@ -93,17 +98,42 @@ vm.$mathlive.makeMathField(vm.$el, { | ||
// Those asynchronous notification handlers are translated to events | ||
onFocus: _ => { vm.$emit('focus'); }, | ||
onBlur: _ => { vm.$emit('blur'); }, | ||
onContentWillChange: _ => { vm.$emit('content-will-change'); }, | ||
onSelectionWillChange: _ => { vm.$emit('selection-will-change'); }, | ||
onUndoStateWillChange: (_, command) => { vm.$emit('undo-state-will-change', command); }, | ||
onUndoStateDidChange: (_, command) => { vm.$emit('undo-state-did-change', command); }, | ||
onVirtualKeyboardToggle: (_, visible, keyboardElement) => { vm.$emit('virtual-keyboard-toggle', visible, keyboardElement); }, | ||
onReadAloudStatus: (_, status) => { vm.$emit('read-aloud-status', status); }, | ||
onFocus: _ => { | ||
vm.$emit('focus'); | ||
}, | ||
onBlur: _ => { | ||
vm.$emit('blur'); | ||
}, | ||
onContentWillChange: _ => { | ||
vm.$emit('content-will-change'); | ||
}, | ||
onSelectionWillChange: _ => { | ||
vm.$emit('selection-will-change'); | ||
}, | ||
onUndoStateWillChange: (_, command) => { | ||
vm.$emit('undo-state-will-change', command); | ||
}, | ||
onUndoStateDidChange: (_, command) => { | ||
vm.$emit('undo-state-did-change', command); | ||
}, | ||
onVirtualKeyboardToggle: (_, visible, keyboardElement) => { | ||
vm.$emit( | ||
'virtual-keyboard-toggle', | ||
visible, | ||
keyboardElement | ||
); | ||
}, | ||
onReadAloudStatus: (_, status) => { | ||
vm.$emit('read-aloud-status', status); | ||
}, | ||
// Those notification handlers expect an answer back, so translate | ||
// them to callbacks via props | ||
onKeystroke: function(_, keystroke, ev) { return vm.onKeystroke(keystroke, ev); }, | ||
onMoveOutOf: (_, direction) => { return vm.onMoveOutOf(direction); }, | ||
onTabOutOf: (_, direction) => { return vm.onTabOutOf(direction); }, | ||
onKeystroke: function(_, keystroke, ev) { | ||
return vm.onKeystroke(keystroke, ev); | ||
}, | ||
onMoveOutOf: (_, direction) => { | ||
return vm.onMoveOutOf(direction); | ||
}, | ||
onTabOutOf: (_, direction) => { | ||
return vm.onTabOutOf(direction); | ||
}, | ||
}); | ||
@@ -164,4 +194,4 @@ }); | ||
this.$el.mathfield.$clearSelection(); | ||
} | ||
} | ||
}; | ||
}, | ||
}, | ||
}; |
{ | ||
"name": "mathlive", | ||
"version": "0.33.2", | ||
"version": "0.34.0", | ||
"description": "Render and edit beautifully typeset math", | ||
@@ -42,6 +42,5 @@ "license": "MIT", | ||
"watch": "npm-run-all -p watch-*", | ||
"http-server": "http-server . -c-1 --cors='*' -o http://localhost:8080/examples/index.html", | ||
"http-server": "http-server . -c-1 --cors='*' -o examples/index.html", | ||
"start": "npm-run-all -p watch-js watch-css http-server", | ||
"lint": "eslint src/ -c .eslintrc.json", | ||
"lint:fix": "eslint src/ -c .eslintrc.json --fix", | ||
"lint": "prettier --ignore-path ./.prettierignore --write \"**/*.{ts,js,css,md,yml,json}\" \"!dist/**\" \"!docs/**\" \"!examples/**\"", | ||
"test": "tape -r @babel/register test/* | tap-spec", | ||
@@ -58,2 +57,3 @@ "watch-test": "chokidar \"src/*.js\" -c \"npm run test -s\" ", | ||
}, | ||
"prettier": "@cortex-js/prettier-config", | ||
"husky": { | ||
@@ -68,2 +68,6 @@ "hooks": { | ||
"git add" | ||
], | ||
"*.{js,css,json,md}": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
@@ -101,26 +105,30 @@ }, | ||
"devDependencies": { | ||
"@babel/cli": "^7.7.5", | ||
"@babel/core": "^7.7.5", | ||
"@babel/preset-env": "^7.7.6", | ||
"@babel/register": "^7.7.4", | ||
"autoprefixer": "^9.7.3", | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.8.4", | ||
"@babel/preset-env": "^7.8.4", | ||
"@babel/register": "^7.8.3", | ||
"@cortex-js/prettier-config": "^1.0.0", | ||
"autoprefixer": "^9.7.4", | ||
"chokidar-cli": "^2.1.0", | ||
"cssnano": "^4.1.10", | ||
"eslint": "^6.7.2", | ||
"eslint": "^6.8.0", | ||
"eslint-config-prettier": "^6.10.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"eslint-watch": "^6.0.1", | ||
"http-server": "^0.12.0", | ||
"husky": "^3.1.0", | ||
"http-server": "^0.12.1", | ||
"husky": "^4.2.1", | ||
"jsdoc": "^3.6.3", | ||
"less": "^3.10.3", | ||
"lint-staged": "^9.5.0", | ||
"lint-staged": "^10.0.7", | ||
"npm-run-all": "^4.1.5", | ||
"nyc": "^14.1.1", | ||
"postcss-cli": "^6.1.3", | ||
"rimraf": "^3.0.0", | ||
"rollup": "^1.27.12", | ||
"rollup-plugin-copy": "^3.1.0", | ||
"rollup-plugin-terser": "^5.1.3", | ||
"nyc": "^15.0.0", | ||
"postcss-cli": "^7.1.0", | ||
"prettier": "^1.19.1", | ||
"rimraf": "^3.0.1", | ||
"rollup": "^1.31.0", | ||
"rollup-plugin-copy": "^3.3.0", | ||
"rollup-plugin-terser": "^5.2.0", | ||
"sutro-jsdoc-theme": "^1.0", | ||
"tap-spec": "^5.0.0", | ||
"tape": "^4.11.0", | ||
"tape": "^4.13.0", | ||
"tsd-jsdoc": "^2.4.0" | ||
@@ -127,0 +135,0 @@ }, |
140
README.md
<img alt="math live" src="assets/logo.png?raw=true"> | ||
[![Maintenance](https://img.shields.io/maintenance/yes/2019.svg)]() | ||
[![Maintenance](https://img.shields.io/maintenance/yes/2020.svg)]() | ||
[![GitHub license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://raw.githubusercontent.com/arnog/mathlive/master/LICENSE.txt) | ||
@@ -11,16 +9,15 @@ | ||
<img alt="Screenshot" src="assets/screenshots/screenshot.jpg"> | ||
MathLive: Math Input Made Easy | ||
MathLive is a JavaScript library to render and edit math. | ||
- [x] JavaScript library easy to integrate in your project | ||
- [x] Beautiful, TeX-quality typesetting | ||
- [x] Easy to use interface for formula editing | ||
- [x] Designed for mobile devices with an extensive set of virtual keyboards | ||
- [x] Accessility support: screen reader compatible, and includes custom | ||
math-to-speech support | ||
- [x] Outputs **LaTeX**, **MathML** and **MathJSON** (Abstract Syntax Tree) | ||
- [x] And it is easy to customize to your needs! | ||
- [x] TeX-quality typesetting | ||
- [x] Easy to use interface for math editing | ||
- [x] Fast and small | ||
- [x] Works great on desktop and on mobile devices thanks to an extensive set of virtual keyboards | ||
- [x] Outputs **LaTeX**, **MathML** and **MathJSON** (Abstract Syntax Tree) | ||
- [x] And it is easy to customize to your needs! | ||
Try it at [mathlive.io](https://mathlive.io) | ||
@@ -50,32 +47,38 @@ | ||
## How To Use MathLive | ||
### Displaying Math | ||
Render math equations by | ||
[adding a few lines to your web page](tutorials/USAGE_GUIDE.md). | ||
Render math equations by | ||
[adding a few lines to your web page](tutorials/USAGE_GUIDE.md). | ||
```html | ||
<!doctype html><html lang="en-US"> | ||
<head> | ||
... | ||
<link href="https://unpkg.com/mathlive/dist/mathlive.core.css" rel="stylesheet" > | ||
<link href="https://unpkg.com/mathlive/dist/mathlive.css" rel="stylesheet" > | ||
</head> | ||
<body> | ||
<h1>Euler's Identity</h1> | ||
<p>$$e^{i\pi} + 1 = 0$$</p> | ||
<!DOCTYPE html> | ||
<html lang="en-US"> | ||
<head> | ||
... | ||
<link | ||
href="https://unpkg.com/mathlive/dist/mathlive.core.css" | ||
rel="stylesheet" | ||
/> | ||
<link | ||
href="https://unpkg.com/mathlive/dist/mathlive.css" | ||
rel="stylesheet" | ||
/> | ||
</head> | ||
<body> | ||
<h1>Euler's Identity</h1> | ||
<p>$$e^{i\pi} + 1 = 0$$</p> | ||
<script type='module'> | ||
import MathLive from 'https://unpkg.com/mathlive/dist/mathlive.mjs'; | ||
MathLive.renderMathInDocument(); | ||
</script> | ||
</body> | ||
<script type="module"> | ||
import MathLive from 'https://unpkg.com/mathlive/dist/mathlive.mjs'; | ||
MathLive.renderMathInDocument(); | ||
</script> | ||
</body> | ||
</html> | ||
``` | ||
### Editing Math | ||
### Editing Math | ||
You can also incorporate a “mathfield” to edit math just like you would edit | ||
You can also incorporate a “mathfield” to edit math just like you would edit | ||
text. The MathLive APIs allow you to interact with the mathfield, | ||
@@ -85,16 +88,23 @@ including extracting its content, inserting placeholders and more. | ||
```html | ||
<!doctype html><html lang="en-US"> | ||
<head> | ||
... | ||
<link rel="stylesheet" href="https://unpkg.com/mathlive/dist/mathlive.core.css"> | ||
<link rel="stylesheet" href="https://unpkg.com/mathlive/dist/mathlive.css"> | ||
</head> | ||
<body> | ||
<div id='mathfield'>f(x)=</div> | ||
<!DOCTYPE html> | ||
<html lang="en-US"> | ||
<head> | ||
... | ||
<link | ||
rel="stylesheet" | ||
href="https://unpkg.com/mathlive/dist/mathlive.core.css" | ||
/> | ||
<link | ||
rel="stylesheet" | ||
href="https://unpkg.com/mathlive/dist/mathlive.css" | ||
/> | ||
</head> | ||
<body> | ||
<div id="mathfield">f(x)=</div> | ||
<script type='module'> | ||
import MathLive from 'https://unpkg.com/mathlive/dist/mathlive.mjs'; | ||
MathLive.makeMathField('mathfield'); | ||
</script> | ||
</body> | ||
<script type="module"> | ||
import MathLive from 'https://unpkg.com/mathlive/dist/mathlive.mjs'; | ||
MathLive.makeMathField('mathfield'); | ||
</script> | ||
</body> | ||
</html> | ||
@@ -107,3 +117,2 @@ ``` | ||
### Installing MathLive | ||
@@ -113,8 +122,10 @@ | ||
However, if you: | ||
- want to contribute to MathLive | ||
- use your own CDN | ||
- make some other changes to MathLive | ||
you can also install it locally in your project. | ||
- want to contribute to MathLive | ||
- use your own CDN | ||
- make some other changes to MathLive | ||
you can also install it locally in your project. | ||
To do so: | ||
```bash | ||
@@ -124,2 +135,3 @@ $ npm install -s mathlive | ||
``` | ||
This will make a local build of MathLive, run a local HTTP server and open a page with the examples in your browser. | ||
@@ -129,18 +141,18 @@ | ||
* Using MathLive in your project? Want to support the project ongoing maintenance? | ||
Consider becoming a patron on [Patreon](https://patreon.com/arnog) or making a | ||
donation with [PayPal](https://www.paypal.me/arnogourdol) | ||
* Something wrong? Got ideas for new features? Write up an issue. Read about | ||
[Contributing](CONTRIBUTING.md) and follow our [Code of Conduct](CODE_OF_CONDUCT.md) | ||
* Want to use MathLive in your web page? The [Usage Guide](tutorials/USAGE_GUIDE.md) | ||
has all the details. | ||
* Want to contribute some code for an issue or a feature? Read the | ||
[Contributor Guide](tutorials/CONTRIBUTOR_GUIDE.md) and the | ||
[docs](http://docs.mathlive.io). Looking for inspiration? Pick one of | ||
the [good first issues](https://github.com/arnog/mathlive/labels/good%20first%20issue) | ||
- Using MathLive in your project? Want to support the project ongoing maintenance? | ||
Consider becoming a patron on [Patreon](https://patreon.com/arnog) or making a | ||
donation with [PayPal](https://www.paypal.me/arnogourdol) | ||
- Something wrong? Got ideas for new features? Write up an issue. Read about | ||
[Contributing](CONTRIBUTING.md) and follow our [Code of Conduct](CODE_OF_CONDUCT.md) | ||
- Want to use MathLive in your web page? The [Usage Guide](tutorials/USAGE_GUIDE.md) | ||
has all the details. | ||
- Want to contribute some code for an issue or a feature? Read the | ||
[Contributor Guide](tutorials/CONTRIBUTOR_GUIDE.md) and the | ||
[docs](http://docs.mathlive.io). Looking for inspiration? Pick one of | ||
the [good first issues](https://github.com/arnog/mathlive/labels/good%20first%20issue) | ||
## More Questions? | ||
* Join our Slack channel at https://mathlive.slack.com. | ||
* Drop a line to arno@arno.org or [/u/real_arnog](https://www.reddit.com/user/real_arnog) | ||
- Join our Slack channel at https://mathlive.slack.com. | ||
- Drop a line to arno@arno.org or [/u/real_arnog](https://www.reddit.com/user/real_arnog) | ||
@@ -147,0 +159,0 @@ ## License |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
4132943
69662
155
0
29