diff --git a/README.md b/README.md index 94c3a7c95..25e158a50 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,42 @@ +⚠️ Fork to fix IE 11 + Edge issue ⚠️ +Based on https://github.com/arnog/mathlive/issues/195 + +Global changes : + +```diff +// package.json + +"scripts": { + ... ++ "babel": "rm -rf dist && npx babel src --out-dir dist" +}, +``` + +```diff +// src/core/definitions.js + ++// Edit : https://github.com/arnog/mathlive/issues/195#issuecomment-493741744 +-const LETTER = +- typeof navigator !== 'undefined' && /firefox|edge/i.test(navigator.userAgent) ? +- /[a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/ : +- new RegExp("\\p{Letter}", 'u'); + ++const LETTER = ++ // typeof navigator !== 'undefined' && /firefox/i.test(navigator.userAgent) ? ++ /[a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/; // : ++ // new RegExp("\\p{Letter}", 'u'); + +-const LETTER_AND_DIGITS = +- typeof navigator !== 'undefined' && /firefox|edge/i.test(navigator.userAgent) ? +- /[0-9a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/ : +- new RegExp("[0-9\\p{Letter}]", 'u'); + ++const LETTER_AND_DIGITS = ++ // typeof navigator !== 'undefined' && /firefox/i.test(navigator.userAgent) ? ++ /[0-9a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/; // : ++ // new RegExp("[0-9\\p{Letter}]", 'u'); +``` + math live @@ -28,20 +67,20 @@ Try it at [mathlive.io](https://mathlive.io) @@ -52,8 +91,8 @@ Try it at [mathlive.io](https://mathlive.io) ### To display math -You can use MathLive to simply render math equations by -[adding a few lines to your web page](tutorials/USAGE_GUIDE.md). +You can use MathLive to simply render math equations by +[adding a few lines to your web page](tutorials/USAGE_GUIDE.md). ```html @@ -65,9 +104,9 @@ You can use MathLive to simply render math equations by

Euler's Identity

-

$$e^{i\pi} + 1 = 0$$

+

$$e^{i\pi} + 1 = 0$$

- @@ -76,7 +115,7 @@ You can use MathLive to simply render math equations by ### To edit math -You can also incorporate a “math field” to edit math just like you would edit +You can also incorporate a “math field” to edit math just like you would edit text. The MathLive APIs allow you to interact with the math field, including extracting its content, inserting placeholders and more. @@ -90,7 +129,7 @@ including extracting its content, inserting placeholders and more.
f(x)=
- @@ -110,7 +149,7 @@ 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. +you can also install it locally in your project. To do so: ```bash @@ -123,16 +162,16 @@ This will make a local build of MathLive, run a local HTTP server and open a pag * 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) +* 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 +* 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. +* 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) ## License diff --git a/dist/addons/auto-render.js b/dist/addons/auto-render.js new file mode 100755 index 000000000..26d00086d --- /dev/null +++ b/dist/addons/auto-render.js @@ -0,0 +1,409 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +require("../core/mathAtom.js"); + +var _definitions = _interopRequireDefault(require("../core/definitions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* eslint no-console:0 */ +// eslint-disable-line no-unused-vars +function findEndOfMath(delimiter, text, startIndex) { + // Adapted from + // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx + var index = startIndex; + var braceLevel = 0; + var delimLength = delimiter.length; + + while (index < text.length) { + var character = text[index]; + + if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { + return index; + } else if (character === '\\') { + index++; + } else if (character === '{') { + braceLevel++; + } else if (character === '}') { + braceLevel--; + } + + index++; + } + + return -1; +} + +function splitAtDelimiters(startData, leftDelim, rightDelim, mathstyle) { + var finalData = []; + + for (var i = 0; i < startData.length; i++) { + if (startData[i].type === 'text') { + var text = startData[i].data; + var lookingForLeft = true; + var currIndex = 0; + var nextIndex = void 0; + nextIndex = text.indexOf(leftDelim); + + if (nextIndex !== -1) { + currIndex = nextIndex; + + if (currIndex > 0) { + finalData.push({ + type: 'text', + data: text.slice(0, currIndex) + }); + } + + lookingForLeft = false; + } + + var done = false; + + while (!done) { + if (lookingForLeft) { + nextIndex = text.indexOf(leftDelim, currIndex); + + if (nextIndex === -1) { + done = true; + break; + } + + if (currIndex !== nextIndex) { + finalData.push({ + type: 'text', + data: text.slice(currIndex, nextIndex) + }); + } + + currIndex = nextIndex; + } else { + nextIndex = findEndOfMath(rightDelim, text, currIndex + leftDelim.length); + + if (nextIndex === -1) { + done = true; + break; + } + + finalData.push({ + type: 'math', + data: text.slice(currIndex + leftDelim.length, nextIndex), + rawData: text.slice(currIndex, nextIndex + rightDelim.length), + mathstyle: mathstyle + }); + currIndex = nextIndex + rightDelim.length; + } + + lookingForLeft = !lookingForLeft; + } + + if (currIndex < text.length) { + finalData.push({ + type: 'text', + data: text.slice(currIndex) + }); + } + } else { + finalData.push(startData[i]); + } + } + + return finalData; +} + +function splitWithDelimiters(text, delimiters) { + var data = [{ + type: 'text', + data: text + }]; + + for (var i = 0; i < delimiters.inline.length; i++) { + var delimiter = delimiters.inline[i]; + data = splitAtDelimiters(data, delimiter[0], delimiter[1], 'textstyle'); + } + + for (var _i = 0; _i < delimiters.display.length; _i++) { + var _delimiter = delimiters.display[_i]; + data = splitAtDelimiters(data, _delimiter[0], _delimiter[1], 'displaystyle'); + } + + return data; +} + +function createMathMLNode(latex, options) { + // Create a node for AT (Assistive Technology, e.g. screen reader) to speak, etc. + // This node has a style that makes it be invisible to display but is seen by AT + var span = document.createElement('span'); + + try { + span.innerHTML = "" + options.renderToMathML(latex, options) + ""; + } catch (e) { + console.error('Could not convert\'' + latex + '\' to MathML with ', e); + span.textContent = latex; + } + + span.className = 'sr-only'; + return span; +} + +function createMarkupNode(text, options, mathstyle, createNodeOnFailure) { + // Create a node for displaying math. + // This is slightly ugly because in the case of failure to create the markup, + // sometimes a text node is desired and sometimes not. + // 'createTextNodeOnFailure' controls this and null is returned when no node is created. + // This node is made invisible to AT (screen readers) + var span = document.createElement('span'); + span.setAttribute('aria-hidden', 'true'); + + if (options.preserveOriginalContent) { + span.setAttribute('data-' + options.namespace + 'original-content', text); + + if (mathstyle) { + span.setAttribute('data-' + options.namespace + 'original-mathstyle', mathstyle); + } + } + + try { + span.innerHTML = options.renderToMarkup(text, mathstyle || 'displaystyle', 'html', options.macros); + } catch (e) { + console.error('Could not parse\'' + text + '\' with ', e); + + if (createNodeOnFailure) { + span = document.createTextNode(text); + } else { + return null; + } + } + + return span; +} + +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. + var markupNode = createMarkupNode(text, options, mathstyle, createNodeOnFailure); + + if (markupNode && /\b(mathml|speakable-text)\b/i.test(options.renderAccessibleContent)) { + var fragment = document.createDocumentFragment(); + + if (/\bmathml\b/i.test(options.renderAccessibleContent) && options.renderToMathML) { + fragment.appendChild(createMathMLNode(text, options)); + } + + if (/\bspeakable-text\b/i.test(options.renderAccessibleContent) && options.renderToSpeakableText) { + var span = document.createElement('span'); + span.innerHTML = options.renderToSpeakableText(text, options); + span.className = 'sr-only'; + fragment.appendChild(span); + } + + fragment.appendChild(markupNode); + return fragment; + } + + return markupNode; +} + +function scanText(text, options) { + // If the text starts with '\begin'... + // (this is a MathJAX behavior) + var fragment = null; + + if (options.TeX.processEnvironments && /^\s*\\begin/.test(text)) { + fragment = document.createDocumentFragment(); + fragment.appendChild(createAccessibleMarkupPair(text, undefined, options, true)); + } else { + var data = splitWithDelimiters(text, options.TeX.delimiters); + + if (data.length === 1 && data[0].type === 'text') { + // This text contains no math. No need to continue processing + return null; + } + + fragment = document.createDocumentFragment(); + + for (var i = 0; i < data.length; i++) { + if (data[i].type === 'text') { + fragment.appendChild(document.createTextNode(data[i].data)); + } else { + fragment.appendChild(createAccessibleMarkupPair(data[i].data, data[i].mathstyle, options, true)); + } + } + } + + return fragment; +} + +function scanElement(elem, options) { + var originalContent = elem.getAttribute('data-' + options.namespace + 'original-content'); + + if (originalContent) { + var mathstyle = elem.getAttribute('data-' + options.namespace + 'mathstyle'); + var span = createAccessibleMarkupPair(originalContent, mathstyle, options, false); + + if (span != null) { + elem.textContent = ''; + elem.appendChild(span); + } + + return; + } + + if (elem.childNodes.length === 1 && elem.childNodes[0].nodeType === 3) { + // This is a node with textual content only. Perhaps an opportunity + // to simplify and avoid creating extra nested elements... + var text = elem.childNodes[0].textContent; + + if (options.TeX.processEnvironments && /^\s*\\begin/.test(text)) { + elem.textContent = ''; + elem.appendChild(createAccessibleMarkupPair(text, undefined, options, true)); + return; + } + + var data = splitWithDelimiters(text, options.TeX.delimiters); + + if (data.length === 1 && data[0].type === 'math') { + // The entire content is a math expression: we can replace the content + // with the latex markup without creating additional wrappers. + elem.textContent = ''; + elem.appendChild(createAccessibleMarkupPair(data[0].data, data[0].mathstyle, options, true)); + return; + } else if (data.length === 1 && data[0].type === 'text') { + // This element only contained text with no math. No need to + // do anything. + return; + } + } + + for (var i = 0; i < elem.childNodes.length; i++) { + var childNode = elem.childNodes[i]; + + if (childNode.nodeType === 3) { + // A text node + // Look for math mode delimiters inside the text + var frag = scanText(childNode.textContent, options); + + if (frag) { + i += frag.childNodes.length - 1; + elem.replaceChild(frag, childNode); + } + } else if (childNode.nodeType === 1) { + // An element node + var tag = childNode.nodeName.toLowerCase(); + + if (tag === 'script' && options.processScriptTypePattern.test(childNode.type)) { + var style = 'displaystyle'; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = childNode.type.split(';')[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var l = _step.value; + var v = l.split('='); + + if (v[0].toLowerCase() === 'mode') { + if (v[1].toLoweCase() === 'display') { + style = 'displaystyle'; + } else { + style = 'textstyle'; + } + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + var _span = createAccessibleMarkupPair(childNode.textContent, style, options, true); + + childNode.parentNode.replaceChild(_span, childNode); + } else { + // Element node + var shouldRender = options.processClassPattern.test(childNode.className) || !(options.skipTags.includes(tag) || options.ignoreClassPattern.test(childNode.className)); + + if (shouldRender) { + scanElement(childNode, options); + } + } + } // Otherwise, it's something else, and ignore it. + + } +} + +var defaultOptions = { + // Optional namespace for the `data-` attributes. + namespace: '', + // Name of tags whose content will not be scanned for math delimiters + skipTags: ['noscript', 'style', 'textarea', 'pre', 'code', 'annotation', 'annotation-xml'], + // - - - - - - - - - - - - - - -
Fork me on GitHub
- - -
- - - - - - -
- -
- -

exports.Span

- - - - - - - -
- -
- -

- core/span. - - exports.Span -

- -

A span is the most elementary element that can be rendered. -It is composed of an optional body of text and an optional list -of children (other spans). Each span can be decorated with -CSS classes and style attributes.

- - -
- -
-
- - -
- - -

Constructor

- - -

new exports.Span(content: string | Span | Span[], classes: string): voidprivate

- - - - - - - - - - - - - - - - -
- - - -
- - content - - - - - : -string -| - -Span -| - -Span[] - - - - - - - - - - -

-

the items 'contained' by this node

-

- - -
- - - -
- - classes - - - - - : -string - - - - - - - - - - -

-

list of classes attributes associated with this node

-

- - -
- - -
- - - - - - → - - - - - : -void - - -    - - - - - - - - - - - -
Properties
- - - - - - -
- - type - - - - - : -string - - - - - - - - - -

For example, 'command', 'mrel', etc...

- -
-
- - - -
- - classes - - - - - : -string - - - - - - - - - -

A string of space separated CSS classes -associated with this element

- -
-
- - - -
- - cssID - - - - - : -string - - - - - - - - - -

A CSS ID assigned to this span (optional)

- -
-
- - - -
- - children - - - - - : -Span[] - - - - - - - - - -

An array, potentially empty, of spans which -this span encloses

- -
-
- - - -
- - body - - - - - : -string - - - - - - - - - -

Content of this span. Can be empty.

- -
-
- - - -
- - style - - - - - : -[string]:any - - - - - - - - - -

A set of key/value pairs specifying CSS properties -associated with this element.

- -
-
- - - -
- - height - - - - - : -number - - - - - - - - - -

The measurement from baseline to top, in em.

- -
-
- - - -
- - depth - - - - - : -number - - - - - - - - - -

The measurement from baseline to bottom, in em.

- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/module-editor_keyboard.html b/docs/module-editor_keyboard.html index cf1707f6a..c47a1d09f 100644 --- a/docs/module-editor_keyboard.html +++ b/docs/module-editor_keyboard.html @@ -608,7 +608,9 @@

keyboardEventToStringTo Do:
    -
  • See https://github.com/madrobby/keymaster/blob/master/keymaster.js - Doesn't work very well for command- - Returns "Alt-Alt" when only the Alt key is pressed
  • +
  • See https://github.com/madrobby/keymaster/blob/master/keymaster.js +- Doesn't work very well for command- +- Returns "Alt-Alt" when only the Alt key is pressed
diff --git a/docs/module-mathlive.html b/docs/module-mathlive.html index b5175281b..92f93ed4c 100644 --- a/docs/module-mathlive.html +++ b/docs/module-mathlive.html @@ -153,7 +153,11 @@

mathlive

-
// To invoke the functions in this module, import the MathLive module. 

import MathLive from 'dist/mathlive.mjs';

const markup = MathLive.latexToMarkup('e^{i\\pi}+1=0');
+
// To invoke the functions in this module, import the MathLive module. 
+
+import MathLive from 'dist/mathlive.mjs';
+
+const markup = MathLive.latexToMarkup('e^{i\\pi}+1=0');
@@ -1276,7 +1280,8 @@

latexToSpeakableTextconsole.log(MathLive.latexToSpeakableText('\\frac{1}{2}')); // ➡︎'half' +
console.log(MathLive.latexToSpeakableText('\\frac{1}{2}'));
+// ➡︎'half'
@@ -3265,7 +3270,10 @@

renderMathInDocumentimport MathLive from 'dist/mathlive.mjs'; document.addEventListener("load", () => { MathLive.renderMathInDocument(); }); +
import MathLive from 'dist/mathlive.mjs';
+document.addEventListener("load", () => { 
+    MathLive.renderMathInDocument();
+});
diff --git a/package.json b/package.json index 029863991..2c85d19e2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "mathlive", + "name": "@lls/mathlive", "version": "0.29.0", "description": "Render and edit beautifully typeset math", "license": "MIT", @@ -53,7 +53,8 @@ "prerollup": "echo Rollup...", "rollup": "rollup --config", "watch-rollup": "rollup --config --watch", - "dist": "npm-run-all -s clean build docs test" + "dist": "npm-run-all -s clean build docs test", + "babel": "rm -rf dist && npm run rollup && npx babel src --out-dir dist" }, "nyc": { "exclude": [ diff --git a/src/core/definitions.js b/src/core/definitions.js index 832a28fd6..872842f8a 100644 --- a/src/core/definitions.js +++ b/src/core/definitions.js @@ -455,7 +455,7 @@ function codepointToLatex(parseMode, cp) { } else if (v.style === 'bolditalic') { result = '\\mathbf{\\mathit{' + result + '}}'; } - return '\\mathord{' + result + '}'; + return '\\mathord{' + result + '}'; } @@ -494,7 +494,7 @@ function commandAllowed(mode, command) { function getValue(mode, symbol) { if (mode === 'math') { - return MATH_SYMBOLS[symbol] && MATH_SYMBOLS[symbol].value ? + return MATH_SYMBOLS[symbol] && MATH_SYMBOLS[symbol].value ? MATH_SYMBOLS[symbol].value : symbol; } return TEXT_SYMBOLS[symbol] ? TEXT_SYMBOLS[symbol] : symbol; @@ -597,7 +597,7 @@ function getInfo(symbol, parseMode, macros) { } // Special case `f`, `g` and `h` are recognized as functions. - if (info && info.type === 'mord' && + if (info && info.type === 'mord' && (info.value === 'f' || info.value === 'g' || info.value === 'h')) { info.isFunction = true; } @@ -814,7 +814,7 @@ function defineFunction(names, params, options, parseFunction) { // strictly to group items in generateDocumentation(). category: category, - // The base font family, if present, indicates that this font family + // The base font family, if present, indicates that this font family // should always be used to render atom. For example, functions such // as "sin", etc... are always drawn in a roman font, // regardless of the font styling a user may specify. @@ -871,7 +871,7 @@ category = 'Environments'; first row left aligned, last right aligned, others centered last line has an eqn. counter. multline* will omit the counter no output if inside an equation - + 'gather' at most two columns first column centered, second column right aligned @@ -1329,13 +1329,13 @@ function(name, args) { }; }); -defineFunction('\\color', '{:color}', {allowedInText: true}, (_name, args) => { +defineFunction('\\color', '{:color}', {allowedInText: true}, (_name, args) => { return { color: args[0] } }); // From the xcolor package. -// As per xcolor, this command does not set the mode to text +// As per xcolor, this command does not set the mode to text // (unlike what its name might suggest) defineFunction('\\textcolor', '{:color}{content:auto*}', {allowedInText: true}, (_name, args) => { return { color: args[0] }; @@ -1816,7 +1816,7 @@ defineFunction('\\textnormal', '{:text*}', {allowedInText: true}, (_name, _args) // Rough synomym for \text{} /* -An \mbox within math mode does not use the current math font; rather it uses +An \mbox within math mode does not use the current math font; rather it uses the typeface of the surrounding running text. */ defineFunction('\\mbox', '{:text*}', null, (_name, _args) => { @@ -2649,7 +2649,7 @@ defineSymbol( '\\circeq', AMS, REL, '\u2257', 31); defineSymbol( '\\lessdot', AMS, BIN, '\u22d6', 88); defineSymbol( '\\gtrdot', AMS, BIN, '\u22d7', 45); -// In TeX, '~' is a spacing command (non-breaking space). +// In TeX, '~' is a spacing command (non-breaking space). // However, '~' is used as an ASCII Math shortctut character, so define a \\~ // command which maps to the '~' character defineSymbol( '\\~', MAIN, REL, '~'); @@ -2834,7 +2834,7 @@ function getSimpleString(atoms) { } else { success = false; } - } + } return success ? result : ''; } @@ -3054,14 +3054,14 @@ defineSymbol( '"', MAIN, MATHORD, '\u201D'); // Double Prime category = 'Others'; defineFunction('\\^', '{:string}', - {allowedInText: true}, + {allowedInText: true}, function(name, args) { return { type: 'mord', limits: 'nolimits', symbol: true, isFunction: false, - body: args[0] ? + body: args[0] ? ({'a':'â','e':'ê','i':'î','o':'ô','u':'û', 'A':'Â','E':'Ê','I':'Î','O':'Ô','U':'Û'}[args[0]] || '^') : '^', @@ -3069,15 +3069,15 @@ defineFunction('\\^', '{:string}', }; }) -defineFunction("\\`", '{:string}', - {allowedInText: true}, +defineFunction("\\`", '{:string}', + {allowedInText: true}, function(name, args) { return { type: 'mord', limits: 'nolimits', symbol: true, isFunction: false, - body: args[0] ? + body: args[0] ? ({'a':'à','e':'è','i':'ì','o':'ò','u':'ù', 'A':'À','E':'È','I':'Ì','O':'Ò','U':'Ù'}[args[0]] || '`') : '`', @@ -3086,15 +3086,15 @@ defineFunction("\\`", '{:string}', }) -defineFunction("\\'", '{:string}', - {allowedInText: true}, +defineFunction("\\'", '{:string}', + {allowedInText: true}, function(name, args) { return { type: 'mord', limits: 'nolimits', symbol: true, isFunction: false, - body: args[0] ? + body: args[0] ? ({'a':'á','e':'é','i':'í','o':'ó','u':'ú', 'A':'Á','E':'É','I':'Í','O':'Ó','U':'Ú'}[args[0]] || '\u005e') : '\u005e', @@ -3102,30 +3102,30 @@ defineFunction("\\'", '{:string}', }; }) -defineFunction('\\~', '{:string}', - {allowedInText: true}, +defineFunction('\\~', '{:string}', + {allowedInText: true}, function(name, args) { return { type: 'mord', limits: 'nolimits', symbol: true, isFunction: false, - body: args[0] ? + body: args[0] ? ({'n':'ñ', 'N':'Ñ', 'a':'ã', 'o':'õ', 'A':'Ã', 'O':'Õ'}[args[0]] || '\u00B4') : '\u00B4', baseFontFamily: 'cmr' }; }) -defineFunction('\\c', '{:string}', - {allowedInText: true}, +defineFunction('\\c', '{:string}', + {allowedInText: true}, function(name, args) { return { type: 'mord', limits: 'nolimits', symbol: true, isFunction: false, - body: args[0] ? + body: args[0] ? ({'c':'ç', 'C':'Ç'}[args[0]] || '') : '', baseFontFamily: 'cmr' @@ -3188,18 +3188,19 @@ const COMMAND_MODE_CHARACTERS = /[a-zA-Z0-9!@*()-=+{}[\]\\';:?/.,~<>`|'$%#&^_" ] // Word boundaries for Cyrillic, Polish, French, German, Italian // and Spanish. We use \p{L} (Unicode property escapes: "Letter") -// but Firefox doesn't support it +// but Firefox doesn't support it // (https://bugzilla.mozilla.org/show_bug.cgi?id=1361876). Booo... // See also https://stackoverflow.com/questions/26133593/using-regex-to-match-international-unicode-alphanumeric-characters-in-javascript -const LETTER = - typeof navigator !== 'undefined' && /firefox|edge/i.test(navigator.userAgent) ? - /[a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/ : - new RegExp("\\p{Letter}", 'u'); +// Edit : https://github.com/arnog/mathlive/issues/195#issuecomment-493741744 +const LETTER = + // typeof navigator !== 'undefined' && /firefox/i.test(navigator.userAgent) ? + /[a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/; // : + // new RegExp("\\p{Letter}", 'u'); -const LETTER_AND_DIGITS = - typeof navigator !== 'undefined' && /firefox|edge/i.test(navigator.userAgent) ? - /[0-9a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/ : - new RegExp("[0-9\\p{Letter}]", 'u'); +const LETTER_AND_DIGITS = + // typeof navigator !== 'undefined' && /firefox/i.test(navigator.userAgent) ? + /[0-9a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘꣳŃńÓ󌜏źŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏΟÇÙÛÜÆŒäöüßÄÖÜẞàèéìíîòóùúÀÈÉÌÍÎÒÓÙÚáéíñóúüÁÉÍÑÓÚÜ]/; // : + // new RegExp("[0-9\\p{Letter}]", 'u'); export default { matchCodepoint, @@ -3265,4 +3266,4 @@ export default { See http://mirrors.ibiblio.org/CTAN/macros/latex/contrib/mathtools/mathtools.pdf -*/ \ No newline at end of file +*/

- The popover panel - A Virtual Keyboard
- The Loop Equation