Comparing version 0.28.0 to 0.29.0
@@ -0,1 +1,47 @@ | ||
## 0.29 (May 9, 2019) | ||
### Major New Features | ||
- Scrollable mathfield. The mathfield now behaves like a text area: the content | ||
that does not fit withing the bounds of the mathfield will not overflow | ||
but will be scrollable. The scrolling can be done using the mouse wheel or | ||
trackpad gestures, or by dragging while selecting. The AP | ||
### Improvements | ||
- When smartFence is on, and a new smart fence is inserted (by typing | ||
`(` for example), the closing 'phantom' fence would be displayed immediately | ||
after the opening fence. The closing fence will now be inserted after | ||
the end of the expression. | ||
- The heuristics for determining implicit arguments, for example the implicit | ||
numerator when typing `/` have been improved. For example, typing `/` after | ||
`3 + 2sin x` will result in `3 + (2sin x)/(...)` instead of `3 + sin (x)/(...)`. | ||
- When `config.removeExtraneousParentheses` is true (default), if a frac is | ||
inserted inside parentheses, the parens will be removed. So, if a `/` is typed | ||
after `1` in `(1)` it will become `1/(...)`. | ||
- When smartMode is on, textual operators are eligible for conversion to text. | ||
Previously, if an inline shortcuts for `rad` was defined to `\operatorname{rad}` | ||
and 'radius' was typed, only `ius` would be turned to text. | ||
- Smartmode is now applied when there is a selection. That is, if some text is | ||
selected and the `/` is pressed the selection will become the numerator. Previously | ||
the selection was deleted and replaced with an empty fraction | ||
- Improved layout of surds, particularly when the surd is empty | ||
- Made `\mathbb{}` et al. apply to the argument only, and not affect the style | ||
of following characters. Previously, if a `\mathbb{R}` was inserted, the following | ||
typed character would also be in Blackboard style. | ||
- Improved build system on Windows. That is, it now works. | ||
- Merge speak and readAloud APIs into one (contribution from Neil. Thanks Neil!) | ||
- Switched to using `npm ci` for CI builds. Even for local builds, | ||
it is recommended to use `npm ci` to ensure the correct version of the dependencies | ||
are installed. | ||
- In smartMode, the currency symbols are handled better. "One apple is $3.14" | ||
will result in the "$" being in math mode. | ||
- Switching to/from command mode will not suppress smart mode. | ||
### Bug fixes | ||
- Fixed a crash when using smartFence with `sin(x^2/` | ||
- Fixed `alt+=` keyboard shortcut on Windows. | ||
- Fixed some layout issues with `box` and `enclose` | ||
- Smart Fences will now work when invoked from the virtual keyboard. | ||
- Fixed #177: custom localization strings are now handled correctly. | ||
- Fixed some issues toggling style when selection is empty. | ||
## 0.28 (Apr 22, 2019) | ||
@@ -2,0 +48,0 @@ This release contains some small bug fixes and improvements. |
@@ -16,3 +16,4 @@ /** | ||
while (atoms[i]) { | ||
if (atoms[i].type !== 'mop' && atoms[i][property] !== value) break | ||
if (atoms[i].type !== 'mop' && | ||
atoms[i][property] !== value) break | ||
i++; | ||
@@ -128,2 +129,5 @@ } | ||
suffix = '}'; | ||
} else if (atoms[0].fontSeries && atoms[0].fontSeries !== 'n') { | ||
prefix = '{\\fontSeries{' + atoms[0].fontSeries + '}'; | ||
suffix = '}'; | ||
} | ||
@@ -138,2 +142,5 @@ } else if (prop === 'fontShape') { | ||
suffix = '}'; | ||
} else if (atoms[0].fontShape && atoms[0].fontShape !== 'n') { | ||
prefix = '{\\fontShape{' + atoms[0].fontShape + '}'; | ||
suffix = '}'; | ||
} | ||
@@ -186,2 +193,9 @@ | ||
if (prop === 'backgroundColor' && atoms[0].backgroundColor && | ||
atoms[0].backgroundColor !== 'none' && | ||
(!parent || parent.backgroundColor !== atoms[0].backgroundColor)) { | ||
prefix = '\\colorbox{' + Color.colorToString(atoms[0].backgroundColor) + '}{'; | ||
suffix = '}'; | ||
} | ||
result += prefix; | ||
@@ -228,5 +242,5 @@ | ||
], value, expandMacro); | ||
if (result.startsWith('{') && result.endsWith('}')) { | ||
result = result.slice(1, result.length - 1); | ||
} | ||
// if (result.startsWith('{') && result.endsWith('}')) { | ||
// result = result.slice(1, result.length - 1); | ||
// } | ||
@@ -266,9 +280,14 @@ } else if (typeof value === 'number' || typeof value === 'boolean') { | ||
if (this.cssId) result += '\\cssId{' + this.cssId + '}{'; | ||
if (this.cssClass) result += '\\class{' + this.cssClass + '}{'; | ||
result += expandMacro ? latexify(this, this.body, true) : | ||
(this.latex || latexify(this, this.body, false)); | ||
if (this.cssClass === 'ML__emph') { | ||
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)); | ||
if (this.cssClass) result += '}'; | ||
} | ||
if (this.cssId) result += '}'; | ||
if (this.cssClass) result += '}'; | ||
@@ -343,6 +362,6 @@ result += this.latexClose || ((this.cssId || this.cssClass) ? '' : '}'); | ||
} else { | ||
result += this.leftDelim === '.' ? '' : (this.leftDelim || ''); | ||
result += '\\mleft' + (this.leftDelim || '.'); | ||
if (this.leftDelim && this.leftDelim.length > 1) result += ' '; | ||
result += latexify(this, this.body, expandMacro); | ||
result += (!this.rightDelim || this.rightDelim === '?' || this.rightDelim === '.') ? '' : this.rightDelim; | ||
result += '\\mright' + (this.rightDelim || '.'); | ||
if (this.rightDelim && this.rightDelim.length > 1) result += ' '; | ||
@@ -444,3 +463,3 @@ } | ||
if (isFinite(this.padding)) { | ||
bboxParams.push(Math.floor(1e5 * this.padding) / 1e5 + 'em') | ||
bboxParams.push(Math.floor(1e2 * this.padding) / 1e2 + 'em') | ||
} | ||
@@ -447,0 +466,0 @@ if (this.border) { |
@@ -326,5 +326,10 @@ /* eslint no-unused-vars:0 */ | ||
function convertDimenToPx(value, unit) { | ||
return convertDimenToEm(value, unit) * (4.0 / 3.0) * METRICS.ptPerEm; | ||
} | ||
export default { | ||
toEm : convertDimenToEm, | ||
toPx: convertDimenToPx, | ||
METRICS, | ||
@@ -331,0 +336,0 @@ SIGMAS, |
@@ -222,6 +222,2 @@ /** | ||
// } | ||
} else if (this.peek() === '^') { | ||
result = new Token(this.get()); | ||
} else if (this.peek() === '_') { | ||
result = new Token(this.get()); | ||
} else if (this.peek() === '~') { | ||
@@ -228,0 +224,0 @@ // Spacing |
@@ -684,2 +684,4 @@ | ||
this.parseToken('}'); | ||
result.latexOpen = '{'; | ||
result.latexClose = '}'; | ||
return result; | ||
@@ -798,10 +800,10 @@ } | ||
let result = false; | ||
while (this.hasToken('^') || this.hasToken('_') || this.hasLiteral("'")) { | ||
while (this.hasLiteral('^') || this.hasLiteral('_') || this.hasLiteral("'")) { | ||
let supsub; | ||
if (this.hasToken('^')) { | ||
if (this.hasLiteral('^')) { | ||
supsub = 'superscript'; | ||
} else if (this.hasToken('_')) { | ||
} else if (this.hasLiteral('_')) { | ||
supsub = 'subscript'; | ||
} | ||
if (this.parseToken('^') || this.parseToken('_')) { | ||
if (this.parseLiteral('^') || this.parseLiteral('_')) { | ||
const arg = this.scanArg(); | ||
@@ -808,0 +810,0 @@ if (arg) { |
@@ -21,3 +21,3 @@ /** | ||
if (typeof arg === 'number') { | ||
result += Math.floor(1e5 * arg) / 1e5; | ||
result += Math.floor(1e2 * arg) / 1e2; | ||
} else if (typeof arg === 'string') { | ||
@@ -218,3 +218,3 @@ result += arg; | ||
this.classes += ' ' + FONT_CLASS[fontFamily]; | ||
} else { | ||
} else if (fontFamily) { | ||
// Not a well-known family. Use a style. | ||
@@ -374,8 +374,11 @@ this.setStyle('font-family', fontFamily); | ||
} | ||
const tag = this.tag || 'span'; | ||
// Collapse 'empty' spans | ||
if ((body === '\u200b' || !body) && | ||
(!this.classes || this.classes === 'ML__selected')) { | ||
result = ''; | ||
if (tag.length === 0) { | ||
result = body || ''; | ||
} else { | ||
result = '<' + tag; | ||
// Note: We can't omit the tag, even if it has no class and no style, | ||
// as some layouts (vlist) depends on the presence of the tag to function | ||
result = '<span'; | ||
@@ -387,4 +390,5 @@ if (this.cssId) { | ||
if (this.svgOverlay) { | ||
if (!this.style) this.style = {}; | ||
this.style['position'] = 'relative'; | ||
this.setStyle('position', 'relative'); | ||
this.setStyle('height', this.height + this.depth, 'em'); | ||
this.setStyle('vertical-align', -this.depth, 'em'); | ||
} | ||
@@ -472,5 +476,25 @@ | ||
if (this.svgOverlay) { | ||
result += body; // @todo maybe safe encode here...? (< >) | ||
result += '<svg '; | ||
result += 'style="position:absolute;left:0;top:0;width:100%;height:100%;z-index:2;'; | ||
result += '<span style="'; | ||
result += 'display: inline-block;'; | ||
result += 'height:' + (this.height + this.depth) + 'em;'; | ||
result += 'vertical-align:' + this.depth + 'em;'; | ||
result += '">'; | ||
result += body; | ||
result += '</span>'; | ||
result += '<svg '; | ||
// result += 'style="position:absolute;left:0;top:0;width:100%;height:100%;z-index:2;'; | ||
result += 'style="position:absolute;'; | ||
result += 'overflow:overlay;'; | ||
result += 'height:' + (this.height + this.depth) + 'em;'; | ||
result += 'transform:translateY(' + Math.round(- FontMetrics.toPx(this.depth, 'em') + 2 * 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 + ' );'; | ||
} else { | ||
result += 'top:0;'; | ||
result += 'left:0;'; | ||
result += 'width:100%;'; | ||
} | ||
result += 'z-index:2;'; | ||
result += '"'; | ||
@@ -484,14 +508,8 @@ if (this.svgStyle) { | ||
} else { | ||
result += body; // @todo maybe safe encode here...? (< >) | ||
result += body; | ||
} | ||
// Note: We can't omit the tag, even if it has no class and no style, | ||
// as some layouts (vlist) depends on the presence of the tag to function | ||
result = result + '</' + tag + '>'; | ||
result = result + '</span>'; | ||
} | ||
// Collapse 'empty' spans | ||
if (result === '<span>\u200b</span>') { | ||
result = ''; | ||
} | ||
@@ -498,0 +516,0 @@ if (this.caret && this.type !== 'command') { |
@@ -25,4 +25,5 @@ | ||
const KEY_NAMES = { | ||
'Space': 'Spacebar', | ||
' ': 'Spacebar', | ||
'Escape': 'Esc', | ||
' ': 'Spacebar', | ||
'ArrowLeft': 'Left', | ||
@@ -122,2 +123,6 @@ 'ArrowUp': 'Up', | ||
if (!keyname && evt.code) { | ||
keyname = KEY_NAMES[evt.code] || evt.code; | ||
} | ||
if (!keyname) { | ||
@@ -128,3 +133,3 @@ if (INTL_KEY[evt.key]) { | ||
} else { | ||
keyname = KEY_NAMES[evt.key] || evt.code; | ||
keyname = KEY_NAMES[evt.key]; | ||
} | ||
@@ -131,0 +136,0 @@ |
@@ -231,13 +231,27 @@ /** | ||
*/ | ||
'mac:Ctrl-Meta-Up': 'speakParent', | ||
'!mac:Ctrl-Alt-Up': 'speakParent', | ||
'mac:Ctrl-Meta-Down': 'speakGroup', | ||
'!mac:Ctrl-Alt-Down': 'speakGroup', | ||
'mac:Ctrl-Meta-Left': 'speakLeftSibling', | ||
'!mac:Ctrl-Alt-Left': 'speakLeftSibling', | ||
'mac:Ctrl-Meta-Right': 'speakRightSibling', | ||
'!mac:Ctrl-Alt-Right': 'speakRightSibling', | ||
'mac:Ctrl-Meta-Shift-Down': 'speakAllWithSynchronizedHighlighting', | ||
'!mac:Ctrl-Alt-Shift-Down': 'speakAllWithSynchronizedHighlighting', | ||
'mac:Ctrl-Meta-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Down': ['speak', 'group', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Down': ['speak', 'group', {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', 'group', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Down': ['speak', 'group', {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}], | ||
// 'mac:Ctrl-Alt-Shift-Home': ['speak', 'start', {withHighlighting: true}], | ||
// '!mac:Ctrl-Alt-Shift-End': ['speak', 'end', {withHighlighting: true}], | ||
// 'mac:Ctrl-Alt-Shift-End': ['speak', 'end', {withHighlighting: true}], | ||
} | ||
@@ -289,3 +303,3 @@ | ||
// Primes | ||
"''": '^{\\doubleprime}', | ||
"''": { mode: 'math', value: '^{\\doubleprime}'}, | ||
@@ -296,3 +310,4 @@ // Greek letters | ||
'Delta': '\\Delta', | ||
'pi': '\\pi', | ||
'pi': { mode: 'math', value: '\\pi'}, | ||
'pi ': { mode: 'text', value: '\\pi '}, | ||
'π': '\\pi', | ||
@@ -304,13 +319,15 @@ 'Pi': '\\Pi', | ||
// Letter-like | ||
'ii': '\\imaginaryI', | ||
'jj': '\\imaginaryJ', | ||
'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', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\exponentialE', | ||
}, | ||
'nabla': '\\nabla', | ||
'grad': '\\nabla', | ||
'del': '\\partial', | ||
'nabla': { mode: 'math', value: '\\nabla'}, | ||
'grad': { mode: 'math', value: '\\nabla'}, | ||
'del': { mode: 'math', value: '\\partial'}, | ||
@@ -327,19 +344,19 @@ '\u221e': '\\infty', // @TODO: doesn't work | ||
// Big operators | ||
'∑': '\\sum', | ||
'sum': '\\sum_{#?}^{#?}', | ||
'prod': '\\prod_{#?}^{#?}', | ||
'sqrt': '\\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 | ||
'∆': '\\differentialD', // @TODO: is \\diffD most common? | ||
'∂': '\\differentialD', | ||
'∆': { mode: 'math', value: '\\differentialD'}, // @TODO: is \\diffD most common? | ||
'∂': { mode: 'math', value: '\\differentialD'}, | ||
// Functions | ||
'sin': '\\sin', | ||
'cos': '\\cos', | ||
'tan': '\\tan', | ||
'tanh': '\\tanh', | ||
'log': '\\log', | ||
'ln': '\\ln', | ||
'exp': '\\exp', | ||
'lim': '\\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_{#?}'}, | ||
@@ -353,6 +370,6 @@ // Differentials | ||
// Logic | ||
'AA': '\\forall', | ||
'EE': '\\exists', | ||
'!EE': '\\nexists', | ||
'&&': '\\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" | ||
@@ -369,3 +386,3 @@ 'xin': { | ||
}, | ||
'!in': '\\notin', | ||
'!in': { mode: 'math', value: '\\notin'}, | ||
@@ -409,3 +426,12 @@ // Sets | ||
'varepsilon': '\\varepsilon', | ||
'eta': '\\eta', | ||
'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', | ||
@@ -417,18 +443,58 @@ 'Gamma': '\\Gamma', | ||
'Lambda': '\\Lambda', | ||
'mu': '\\mu', | ||
'nu': '\\nu', | ||
'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': '\\phi', | ||
'Phi': '\\Phi', | ||
'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': '\\psi', | ||
'Psi': '\\Psi', | ||
'rho': '\\rho', | ||
'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': '\\tau', | ||
'tau': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\tau' | ||
}, | ||
'vartheta': '\\vartheta', | ||
'upsilon': '\\upsilon', | ||
'xi': '\\xi', | ||
'Xi': '\\Xi', | ||
'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', | ||
@@ -441,5 +507,14 @@ 'omega': '\\omega', | ||
'forall': '\\forall', | ||
'exists': '\\exists', | ||
'!exists': '\\nexists', | ||
':.': '\\therefore', | ||
'exists': { | ||
mode: 'math', | ||
value:'\\exists' | ||
}, | ||
'!exists': { | ||
mode: 'math', | ||
value: '\\nexists' | ||
}, | ||
':.': { | ||
mode: 'math', | ||
value:'\\therefore' | ||
}, | ||
@@ -453,29 +528,56 @@ // MORE FUNCTIONS | ||
'det': '\\det', | ||
'mod': '\\mod', | ||
'max': '\\max', | ||
'min': '\\min', | ||
'mod': { | ||
mode: 'math', | ||
value:'\\mod'}, | ||
'max': { | ||
mode: 'math', | ||
value:'\\max'}, | ||
'min': { | ||
mode: 'math', | ||
value:'\\min'}, | ||
'erf': '\\operatorname{erf}', | ||
'erfc': '\\operatorname{erfc}', | ||
'bessel': '\\operatorname{bessel}', | ||
'mean': '\\operatorname{mean}', | ||
'median': '\\operatorname{median}', | ||
'fft': '\\operatorname{fft}', | ||
'lcm': '\\operatorname{lcm}', | ||
'gcd': '\\operatorname{gcd}', | ||
'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': '\\operatorname{Re}', | ||
'Im': '\\operatorname{Im}', | ||
'Re': { | ||
mode: 'math', | ||
value:'\\operatorname{Re}'}, | ||
'Im': { | ||
mode: 'math', | ||
value:'\\operatorname{Im}'}, | ||
// UNITS | ||
'mm': { after: 'digit', | ||
'mm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{mm}', // millimeter | ||
}, | ||
'cm': { after: 'digit', | ||
'cm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{cm}', // centimeter | ||
}, | ||
'km': { after: 'digit', | ||
'km': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{km}', // kilometer | ||
}, | ||
'kg': { after: 'digit', | ||
'kg': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{kg}', // kilogram | ||
@@ -636,9 +738,13 @@ }, | ||
* | ||
* @param {string} mode | ||
* @param {object[]} siblings atoms preceding this potential shortcut | ||
* @param {string} shortcut | ||
*/ | ||
function validateShortcut(siblings, shortcut) { | ||
function validateShortcut(mode, siblings, 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.mode === 'string' && shortcut.mode !== mode) return null; | ||
// If we have no context, we assume all the shortcuts are valid | ||
@@ -663,3 +769,3 @@ if (!siblings) return shortcut ? shortcut.value : undefined; | ||
let index = siblings.length - 1; | ||
while (sibling && sibling.type === 'msubsup') { | ||
while (sibling && /msubsup|placeholder/.test(sibling.type)) { | ||
index -= 1; | ||
@@ -685,3 +791,3 @@ sibling = siblings[index]; | ||
if (typeof shortcut === 'object') { | ||
if (typeof shortcut.after !== 'undefined') { | ||
// If this is a conditional shortcut, consider the conditions now | ||
@@ -702,9 +808,8 @@ if ( (/nothing/.test(shortcut.after) && nothing) || | ||
(/space/.test(shortcut.after) && space)){ | ||
shortcut = shortcut.value; | ||
} else { | ||
shortcut = null; | ||
return shortcut.value; | ||
} | ||
return null; | ||
} | ||
return shortcut; | ||
return shortcut.value; | ||
} | ||
@@ -715,2 +820,3 @@ | ||
* | ||
* @param {string} mode | ||
* @param {string} context - atoms preceding the candidate, potentially used | ||
@@ -725,3 +831,3 @@ * to reduce which shortcuts are applicable. If 'null', no restrictions are | ||
*/ | ||
function forString(context, s, config) { | ||
function forString(mode, context, s, config) { | ||
let result = ''; | ||
@@ -731,3 +837,3 @@ | ||
if (!skipDefaultShortcuts) { | ||
result = validateShortcut(context, INLINE_SHORTCUTS[s]); | ||
result = validateShortcut(mode, context, INLINE_SHORTCUTS[s]); | ||
} | ||
@@ -739,3 +845,3 @@ | ||
if (customInlineShortcuts) { | ||
customResult = validateShortcut(context, customInlineShortcuts[s]); | ||
customResult = validateShortcut(mode, context, customInlineShortcuts[s]); | ||
} | ||
@@ -742,0 +848,0 @@ |
@@ -156,2 +156,7 @@ /** | ||
restore(state, options) { | ||
const wasSuppressing = this.mathlist.suppressChangeNotifications; | ||
if (options.suppressChangeNotifications !== undefined) { | ||
this.mathlist.suppressChangeNotifications = options.suppressChangeNotifications; | ||
} | ||
// Restore the content | ||
@@ -165,4 +170,7 @@ this.mathlist.insert(state ? state.latex : '', { | ||
}); | ||
// Restore the selection | ||
this.mathlist.setPath(state ? state.selection : [{relation: 'body', offset: 0}]); | ||
this.mathlist.suppressChangeNotifications = wasSuppressing; | ||
} | ||
@@ -169,0 +177,0 @@ } |
@@ -5,11 +5,4 @@ | ||
export function l10n(s) { | ||
// Use the browser defined language as the default language, | ||
// "english" if not running in a browser (node.js) | ||
if (!l10n._locale) { | ||
// Use the setter, which will load the necessary .json files. | ||
l10n.locale = typeof navigator === 'undefined' ? 'en' : | ||
navigator.language.slice(0, 5); | ||
} | ||
const language = l10n._locale.substring(0, 2); | ||
const language = l10n.locale.substring(0, 2); | ||
@@ -19,3 +12,3 @@ let result = ''; | ||
// Attempt to find a match for the current locale | ||
if (l10n.strings[l10n._locale]) result = l10n.strings[l10n._locale][s]; | ||
if (l10n.strings[l10n.locale]) result = l10n.strings[l10n.locale][s]; | ||
// If none is found, attempt to find a match for the language | ||
@@ -50,3 +43,3 @@ if (!result && l10n.strings[language]) result = l10n.strings[language][s]; | ||
strings = locale; | ||
for (const l of strings) { | ||
for (const l in strings) { | ||
if (strings.hasOwnProperty(l)) { | ||
@@ -66,2 +59,9 @@ l10n.merge(l, strings[l]); | ||
get() { | ||
// Use the browser defined language as the default language, | ||
// "english" if not running in a browser (node.js) | ||
if (!l10n._locale) { | ||
// Use the setter, which will load the necessary .json files. | ||
l10n._locale = typeof navigator === 'undefined' ? 'en' : | ||
navigator.language.slice(0, 5); | ||
} | ||
return l10n._locale | ||
@@ -84,2 +84,13 @@ } | ||
}, | ||
"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": { | ||
@@ -94,3 +105,3 @@ "keyboard.tooltip.functions": "Funktionen", | ||
"tooltip.toggle virtual keyboard": "Virtuelle Tastatur umschalten", | ||
"tooltip.undo": "Rückgängig machen" | ||
"tooltip.undo": "Widerrufen" | ||
}, | ||
@@ -108,2 +119,13 @@ "es": { | ||
}, | ||
"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": { | ||
@@ -115,4 +137,4 @@ "keyboard.tooltip.functions": "Fonctions", | ||
"keyboard.tooltip.roman": "Lettres et symboles romains", | ||
"tooltip.copy to clipboard": "Copier dans le Presse-papiers", | ||
"tooltip.redo": "Refaire", | ||
"tooltip.copy to clipboard": "Copier dans le presse-papiers", | ||
"tooltip.redo": "Rétablir", | ||
"tooltip.toggle virtual keyboard": "Afficher/Masquer le clavier virtuel", | ||
@@ -119,0 +141,0 @@ "tooltip.undo": "Annuler" |
{ | ||
"name": "mathlive", | ||
"version": "0.28.0", | ||
"version": "0.29.0", | ||
"description": "Render and edit beautifully typeset math", | ||
@@ -29,25 +29,30 @@ "license": "MIT", | ||
"scripts": { | ||
"preclean": "echo '\\033[0;32mClean...\\033[0m'", | ||
"preclean": "echo Clean directories...", | ||
"clean": "rimraf build dist docs", | ||
"build-js": "echo '\\033[0;32mESLint...\\033[0m' && eslint src/ -c .eslintrc.json", | ||
"build-js": "eslint src/ -c .eslintrc.json", | ||
"watch-js": "esw -w src/", | ||
"build-css": "echo '\\033[0;32mCompile .less...\\033[0m' & lessc css/mathlive.core.less dist/mathlive.core.css & lessc css/mathlive.less dist/mathlive.css", | ||
"watch-css": "chokidar 'css/*.less' --initial -c 'npm run build-css -s'", | ||
"build-corecss": "lessc css/mathlive.core.less dist/mathlive.core.css", | ||
"build-othercss": "lessc css/mathlive.less dist/mathlive.css", | ||
"build-postcss": "postcss dist/*.css -d dist", | ||
"build-css": "npm-run-all -s build-corecss build-othercss build-postcss", | ||
"watch-css": "chokidar \"css/*.less\" --initial -c \"npm run build-css -s\"", | ||
"build": "npm-run-all -p build-css build-js rollup", | ||
"watch": "npm-run-all -p watch-css watch-js watch-test watch-rollup", | ||
"start": "npm run watch & http-server ./ -c-1 --cors='*' -P https://mathlive.io & opn http://localhost:8080/examples/", | ||
"dev": "npm start & npm run watch -s", | ||
"lint": "eslint src/ -c", | ||
"pretest": "echo '\\033[0;32mTest...\\033[0m'", | ||
"watch": "npm-run-all -p watch-*", | ||
"http-server": "http-server ./ -c-1 --cors='*'", | ||
"open": "opn http://localhost:8080/examples/", | ||
"start": "npm-run-all -p watch* http-server open", | ||
"lint": "eslint src/ -c .eslintrc.json", | ||
"pretest": "echo Test...", | ||
"test": "tape -r @babel/register test/* | tap-spec", | ||
"watch-test": "chokidar src/*.js -c 'npm run test -s' ", | ||
"coverage": "nyc node ./test/test.js && nyc report", | ||
"watch-test": "chokidar \"src/*.js\" -c \"npm run test -s\" ", | ||
"coverage": "nyc npm run babel-node ./test/test.js && nyc report", | ||
"coverage:report": "nyc report", | ||
"prepare": "npm run dist", | ||
"predocs": "echo '\\033[0;32mBuild docs...\\033[0m'", | ||
"docs": "jsdoc -c ./jsdoc.conf.json && echo \"docs.mathlive.io\" > docs/CNAME", | ||
"watch-docs": "chokidar 'src/*.js' 'tutorials/*.md' 'examples/*.md' -c 'npm run docs -s'", | ||
"prerollup": "echo '\\033[0;32mRollup...\\033[0m'", | ||
"predocs": "echo Build docs...", | ||
"docs": "jsdoc -c ./jsdoc.conf.json && echo docs.mathlive.io > docs/CNAME", | ||
"watch-docs": "chokidar \"src/*.js\" \"tutorials/*.md\" \"examples/*.md\" -c \"npm run docs -s\"", | ||
"prerollup": "echo Rollup...", | ||
"rollup": "rollup --config", | ||
"watch-rollup": "rollup --config --watch", | ||
"dist": "npm run clean -s && cpx \"src/**\" dist/src && npm run build -s && postcss dist/*.css -d dist && npm run docs -s && npm test" | ||
"dist": "npm-run-all -s clean build docs test" | ||
}, | ||
@@ -84,23 +89,22 @@ "nyc": { | ||
"devDependencies": { | ||
"@babel/cli": "^7.4.3", | ||
"@babel/core": "^7.4.3", | ||
"@babel/polyfill": "^7.4.3", | ||
"@babel/preset-env": "^7.4.3", | ||
"@babel/register": "^7.4.0", | ||
"@babel/cli": "^7.4.4", | ||
"@babel/core": "^7.4.4", | ||
"@babel/polyfill": "^7.4.4", | ||
"@babel/preset-env": "^7.4.4", | ||
"@babel/register": "^7.4.4", | ||
"autoprefixer": "^9.5.1", | ||
"chokidar-cli": "^1.2.2", | ||
"cpx": "latest", | ||
"cssnano": "^4.1.10", | ||
"eslint": "^5.16.0", | ||
"eslint-watch": "^5.0.1", | ||
"eslint-watch": "^5.1.2", | ||
"http-server": "^0.11.1", | ||
"jsdoc": "^3.5.5", | ||
"jsdoc": "^3.6.1", | ||
"less": "^3.9.0", | ||
"npm-run-all": "^4.1.5", | ||
"nyc": "^13.3.0", | ||
"nyc": "^14.1.0", | ||
"opn-cli": "^4.1.0", | ||
"postcss-cli": "^6.1.2", | ||
"rimraf": "^2.6.3", | ||
"rollup": "^1.10.1", | ||
"rollup-plugin-copy": "^1.0.0", | ||
"rollup": "^1.11.3", | ||
"rollup-plugin-copy": "^1.1.0", | ||
"rollup-plugin-terser": "^4.0.4", | ||
@@ -107,0 +111,0 @@ "sutro-jsdoc-theme": "^1.0", |
@@ -19,10 +19,10 @@ <img alt="math live" src="assets/logo-1024.jpg?raw=true"> | ||
- [x] Fast and small | ||
- [x] Tex-quality typesetting | ||
- [x] Easy to use interface for math editing | ||
- [x] Works great on desktop and on mobile devices thanks to an extensive set of virtual keyboards. | ||
- [x] Comprehensive APIs, including generation of **LaTeX**, **MathML** and **Abstract Syntax Tree (MASTON)** | ||
- [x] And it is easy to customize to your needs! | ||
- [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 **JSON** (Abstract Syntax Tree, MASTON)** | ||
- [x] And it is easy to customize to your needs! | ||
Try it at [mathlive.io](https://mathlive.io)! | ||
Try it at [mathlive.io](https://mathlive.io) | ||
@@ -119,3 +119,3 @@ <table align="center" > | ||
$ npm install -s mathlive | ||
$ npm run start | ||
$ npm start | ||
``` | ||
@@ -122,0 +122,0 @@ This will make a local build of MathLive, run a local HTTP server and open a page with the examples in your browser. |
@@ -16,3 +16,4 @@ /** | ||
while (atoms[i]) { | ||
if (atoms[i].type !== 'mop' && atoms[i][property] !== value) break | ||
if (atoms[i].type !== 'mop' && | ||
atoms[i][property] !== value) break | ||
i++; | ||
@@ -128,2 +129,5 @@ } | ||
suffix = '}'; | ||
} else if (atoms[0].fontSeries && atoms[0].fontSeries !== 'n') { | ||
prefix = '{\\fontSeries{' + atoms[0].fontSeries + '}'; | ||
suffix = '}'; | ||
} | ||
@@ -138,2 +142,5 @@ } else if (prop === 'fontShape') { | ||
suffix = '}'; | ||
} else if (atoms[0].fontShape && atoms[0].fontShape !== 'n') { | ||
prefix = '{\\fontShape{' + atoms[0].fontShape + '}'; | ||
suffix = '}'; | ||
} | ||
@@ -186,2 +193,9 @@ | ||
if (prop === 'backgroundColor' && atoms[0].backgroundColor && | ||
atoms[0].backgroundColor !== 'none' && | ||
(!parent || parent.backgroundColor !== atoms[0].backgroundColor)) { | ||
prefix = '\\colorbox{' + Color.colorToString(atoms[0].backgroundColor) + '}{'; | ||
suffix = '}'; | ||
} | ||
result += prefix; | ||
@@ -228,5 +242,5 @@ | ||
], value, expandMacro); | ||
if (result.startsWith('{') && result.endsWith('}')) { | ||
result = result.slice(1, result.length - 1); | ||
} | ||
// if (result.startsWith('{') && result.endsWith('}')) { | ||
// result = result.slice(1, result.length - 1); | ||
// } | ||
@@ -266,9 +280,14 @@ } else if (typeof value === 'number' || typeof value === 'boolean') { | ||
if (this.cssId) result += '\\cssId{' + this.cssId + '}{'; | ||
if (this.cssClass) result += '\\class{' + this.cssClass + '}{'; | ||
result += expandMacro ? latexify(this, this.body, true) : | ||
(this.latex || latexify(this, this.body, false)); | ||
if (this.cssClass === 'ML__emph') { | ||
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)); | ||
if (this.cssClass) result += '}'; | ||
} | ||
if (this.cssId) result += '}'; | ||
if (this.cssClass) result += '}'; | ||
@@ -343,6 +362,6 @@ result += this.latexClose || ((this.cssId || this.cssClass) ? '' : '}'); | ||
} else { | ||
result += this.leftDelim === '.' ? '' : (this.leftDelim || ''); | ||
result += '\\mleft' + (this.leftDelim || '.'); | ||
if (this.leftDelim && this.leftDelim.length > 1) result += ' '; | ||
result += latexify(this, this.body, expandMacro); | ||
result += (!this.rightDelim || this.rightDelim === '?' || this.rightDelim === '.') ? '' : this.rightDelim; | ||
result += '\\mright' + (this.rightDelim || '.'); | ||
if (this.rightDelim && this.rightDelim.length > 1) result += ' '; | ||
@@ -444,3 +463,3 @@ } | ||
if (isFinite(this.padding)) { | ||
bboxParams.push(Math.floor(1e5 * this.padding) / 1e5 + 'em') | ||
bboxParams.push(Math.floor(1e2 * this.padding) / 1e2 + 'em') | ||
} | ||
@@ -447,0 +466,0 @@ if (this.border) { |
@@ -326,5 +326,10 @@ /* eslint no-unused-vars:0 */ | ||
function convertDimenToPx(value, unit) { | ||
return convertDimenToEm(value, unit) * (4.0 / 3.0) * METRICS.ptPerEm; | ||
} | ||
export default { | ||
toEm : convertDimenToEm, | ||
toPx: convertDimenToPx, | ||
METRICS, | ||
@@ -331,0 +336,0 @@ SIGMAS, |
@@ -222,6 +222,2 @@ /** | ||
// } | ||
} else if (this.peek() === '^') { | ||
result = new Token(this.get()); | ||
} else if (this.peek() === '_') { | ||
result = new Token(this.get()); | ||
} else if (this.peek() === '~') { | ||
@@ -228,0 +224,0 @@ // Spacing |
@@ -684,2 +684,4 @@ | ||
this.parseToken('}'); | ||
result.latexOpen = '{'; | ||
result.latexClose = '}'; | ||
return result; | ||
@@ -798,10 +800,10 @@ } | ||
let result = false; | ||
while (this.hasToken('^') || this.hasToken('_') || this.hasLiteral("'")) { | ||
while (this.hasLiteral('^') || this.hasLiteral('_') || this.hasLiteral("'")) { | ||
let supsub; | ||
if (this.hasToken('^')) { | ||
if (this.hasLiteral('^')) { | ||
supsub = 'superscript'; | ||
} else if (this.hasToken('_')) { | ||
} else if (this.hasLiteral('_')) { | ||
supsub = 'subscript'; | ||
} | ||
if (this.parseToken('^') || this.parseToken('_')) { | ||
if (this.parseLiteral('^') || this.parseLiteral('_')) { | ||
const arg = this.scanArg(); | ||
@@ -808,0 +810,0 @@ if (arg) { |
@@ -21,3 +21,3 @@ /** | ||
if (typeof arg === 'number') { | ||
result += Math.floor(1e5 * arg) / 1e5; | ||
result += Math.floor(1e2 * arg) / 1e2; | ||
} else if (typeof arg === 'string') { | ||
@@ -218,3 +218,3 @@ result += arg; | ||
this.classes += ' ' + FONT_CLASS[fontFamily]; | ||
} else { | ||
} else if (fontFamily) { | ||
// Not a well-known family. Use a style. | ||
@@ -374,8 +374,11 @@ this.setStyle('font-family', fontFamily); | ||
} | ||
const tag = this.tag || 'span'; | ||
// Collapse 'empty' spans | ||
if ((body === '\u200b' || !body) && | ||
(!this.classes || this.classes === 'ML__selected')) { | ||
result = ''; | ||
if (tag.length === 0) { | ||
result = body || ''; | ||
} else { | ||
result = '<' + tag; | ||
// Note: We can't omit the tag, even if it has no class and no style, | ||
// as some layouts (vlist) depends on the presence of the tag to function | ||
result = '<span'; | ||
@@ -387,4 +390,5 @@ if (this.cssId) { | ||
if (this.svgOverlay) { | ||
if (!this.style) this.style = {}; | ||
this.style['position'] = 'relative'; | ||
this.setStyle('position', 'relative'); | ||
this.setStyle('height', this.height + this.depth, 'em'); | ||
this.setStyle('vertical-align', -this.depth, 'em'); | ||
} | ||
@@ -472,5 +476,25 @@ | ||
if (this.svgOverlay) { | ||
result += body; // @todo maybe safe encode here...? (< >) | ||
result += '<svg '; | ||
result += 'style="position:absolute;left:0;top:0;width:100%;height:100%;z-index:2;'; | ||
result += '<span style="'; | ||
result += 'display: inline-block;'; | ||
result += 'height:' + (this.height + this.depth) + 'em;'; | ||
result += 'vertical-align:' + this.depth + 'em;'; | ||
result += '">'; | ||
result += body; | ||
result += '</span>'; | ||
result += '<svg '; | ||
// result += 'style="position:absolute;left:0;top:0;width:100%;height:100%;z-index:2;'; | ||
result += 'style="position:absolute;'; | ||
result += 'overflow:overlay;'; | ||
result += 'height:' + (this.height + this.depth) + 'em;'; | ||
result += 'transform:translateY(' + Math.round(- FontMetrics.toPx(this.depth, 'em') + 2 * 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 + ' );'; | ||
} else { | ||
result += 'top:0;'; | ||
result += 'left:0;'; | ||
result += 'width:100%;'; | ||
} | ||
result += 'z-index:2;'; | ||
result += '"'; | ||
@@ -484,14 +508,8 @@ if (this.svgStyle) { | ||
} else { | ||
result += body; // @todo maybe safe encode here...? (< >) | ||
result += body; | ||
} | ||
// Note: We can't omit the tag, even if it has no class and no style, | ||
// as some layouts (vlist) depends on the presence of the tag to function | ||
result = result + '</' + tag + '>'; | ||
result = result + '</span>'; | ||
} | ||
// Collapse 'empty' spans | ||
if (result === '<span>\u200b</span>') { | ||
result = ''; | ||
} | ||
@@ -498,0 +516,0 @@ if (this.caret && this.type !== 'command') { |
@@ -25,4 +25,5 @@ | ||
const KEY_NAMES = { | ||
'Space': 'Spacebar', | ||
' ': 'Spacebar', | ||
'Escape': 'Esc', | ||
' ': 'Spacebar', | ||
'ArrowLeft': 'Left', | ||
@@ -122,2 +123,6 @@ 'ArrowUp': 'Up', | ||
if (!keyname && evt.code) { | ||
keyname = KEY_NAMES[evt.code] || evt.code; | ||
} | ||
if (!keyname) { | ||
@@ -128,3 +133,3 @@ if (INTL_KEY[evt.key]) { | ||
} else { | ||
keyname = KEY_NAMES[evt.key] || evt.code; | ||
keyname = KEY_NAMES[evt.key]; | ||
} | ||
@@ -131,0 +136,0 @@ |
@@ -231,13 +231,27 @@ /** | ||
*/ | ||
'mac:Ctrl-Meta-Up': 'speakParent', | ||
'!mac:Ctrl-Alt-Up': 'speakParent', | ||
'mac:Ctrl-Meta-Down': 'speakGroup', | ||
'!mac:Ctrl-Alt-Down': 'speakGroup', | ||
'mac:Ctrl-Meta-Left': 'speakLeftSibling', | ||
'!mac:Ctrl-Alt-Left': 'speakLeftSibling', | ||
'mac:Ctrl-Meta-Right': 'speakRightSibling', | ||
'!mac:Ctrl-Alt-Right': 'speakRightSibling', | ||
'mac:Ctrl-Meta-Shift-Down': 'speakAllWithSynchronizedHighlighting', | ||
'!mac:Ctrl-Alt-Shift-Down': 'speakAllWithSynchronizedHighlighting', | ||
'mac:Ctrl-Meta-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Up': ['speak', 'parent', {withHighlighting: false}], | ||
'mac:Ctrl-Meta-Down': ['speak', 'group', {withHighlighting: false}], | ||
'!mac:Ctrl-Alt-Down': ['speak', 'group', {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', 'group', {withHighlighting: true}], | ||
'!mac:Ctrl-Alt-Shift-Down': ['speak', 'group', {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}], | ||
// 'mac:Ctrl-Alt-Shift-Home': ['speak', 'start', {withHighlighting: true}], | ||
// '!mac:Ctrl-Alt-Shift-End': ['speak', 'end', {withHighlighting: true}], | ||
// 'mac:Ctrl-Alt-Shift-End': ['speak', 'end', {withHighlighting: true}], | ||
} | ||
@@ -289,3 +303,3 @@ | ||
// Primes | ||
"''": '^{\\doubleprime}', | ||
"''": { mode: 'math', value: '^{\\doubleprime}'}, | ||
@@ -296,3 +310,4 @@ // Greek letters | ||
'Delta': '\\Delta', | ||
'pi': '\\pi', | ||
'pi': { mode: 'math', value: '\\pi'}, | ||
'pi ': { mode: 'text', value: '\\pi '}, | ||
'π': '\\pi', | ||
@@ -304,13 +319,15 @@ 'Pi': '\\Pi', | ||
// Letter-like | ||
'ii': '\\imaginaryI', | ||
'jj': '\\imaginaryJ', | ||
'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', | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\exponentialE', | ||
}, | ||
'nabla': '\\nabla', | ||
'grad': '\\nabla', | ||
'del': '\\partial', | ||
'nabla': { mode: 'math', value: '\\nabla'}, | ||
'grad': { mode: 'math', value: '\\nabla'}, | ||
'del': { mode: 'math', value: '\\partial'}, | ||
@@ -327,19 +344,19 @@ '\u221e': '\\infty', // @TODO: doesn't work | ||
// Big operators | ||
'∑': '\\sum', | ||
'sum': '\\sum_{#?}^{#?}', | ||
'prod': '\\prod_{#?}^{#?}', | ||
'sqrt': '\\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 | ||
'∆': '\\differentialD', // @TODO: is \\diffD most common? | ||
'∂': '\\differentialD', | ||
'∆': { mode: 'math', value: '\\differentialD'}, // @TODO: is \\diffD most common? | ||
'∂': { mode: 'math', value: '\\differentialD'}, | ||
// Functions | ||
'sin': '\\sin', | ||
'cos': '\\cos', | ||
'tan': '\\tan', | ||
'tanh': '\\tanh', | ||
'log': '\\log', | ||
'ln': '\\ln', | ||
'exp': '\\exp', | ||
'lim': '\\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_{#?}'}, | ||
@@ -353,6 +370,6 @@ // Differentials | ||
// Logic | ||
'AA': '\\forall', | ||
'EE': '\\exists', | ||
'!EE': '\\nexists', | ||
'&&': '\\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" | ||
@@ -369,3 +386,3 @@ 'xin': { | ||
}, | ||
'!in': '\\notin', | ||
'!in': { mode: 'math', value: '\\notin'}, | ||
@@ -409,3 +426,12 @@ // Sets | ||
'varepsilon': '\\varepsilon', | ||
'eta': '\\eta', | ||
'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', | ||
@@ -417,18 +443,58 @@ 'Gamma': '\\Gamma', | ||
'Lambda': '\\Lambda', | ||
'mu': '\\mu', | ||
'nu': '\\nu', | ||
'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': '\\phi', | ||
'Phi': '\\Phi', | ||
'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': '\\psi', | ||
'Psi': '\\Psi', | ||
'rho': '\\rho', | ||
'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': '\\tau', | ||
'tau': { | ||
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text', | ||
value: '\\tau' | ||
}, | ||
'vartheta': '\\vartheta', | ||
'upsilon': '\\upsilon', | ||
'xi': '\\xi', | ||
'Xi': '\\Xi', | ||
'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', | ||
@@ -441,5 +507,14 @@ 'omega': '\\omega', | ||
'forall': '\\forall', | ||
'exists': '\\exists', | ||
'!exists': '\\nexists', | ||
':.': '\\therefore', | ||
'exists': { | ||
mode: 'math', | ||
value:'\\exists' | ||
}, | ||
'!exists': { | ||
mode: 'math', | ||
value: '\\nexists' | ||
}, | ||
':.': { | ||
mode: 'math', | ||
value:'\\therefore' | ||
}, | ||
@@ -453,29 +528,56 @@ // MORE FUNCTIONS | ||
'det': '\\det', | ||
'mod': '\\mod', | ||
'max': '\\max', | ||
'min': '\\min', | ||
'mod': { | ||
mode: 'math', | ||
value:'\\mod'}, | ||
'max': { | ||
mode: 'math', | ||
value:'\\max'}, | ||
'min': { | ||
mode: 'math', | ||
value:'\\min'}, | ||
'erf': '\\operatorname{erf}', | ||
'erfc': '\\operatorname{erfc}', | ||
'bessel': '\\operatorname{bessel}', | ||
'mean': '\\operatorname{mean}', | ||
'median': '\\operatorname{median}', | ||
'fft': '\\operatorname{fft}', | ||
'lcm': '\\operatorname{lcm}', | ||
'gcd': '\\operatorname{gcd}', | ||
'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': '\\operatorname{Re}', | ||
'Im': '\\operatorname{Im}', | ||
'Re': { | ||
mode: 'math', | ||
value:'\\operatorname{Re}'}, | ||
'Im': { | ||
mode: 'math', | ||
value:'\\operatorname{Im}'}, | ||
// UNITS | ||
'mm': { after: 'digit', | ||
'mm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{mm}', // millimeter | ||
}, | ||
'cm': { after: 'digit', | ||
'cm': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{cm}', // centimeter | ||
}, | ||
'km': { after: 'digit', | ||
'km': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{km}', // kilometer | ||
}, | ||
'kg': { after: 'digit', | ||
'kg': { mode: 'math', | ||
after: 'nothing+digit', | ||
value: '\\operatorname{kg}', // kilogram | ||
@@ -636,9 +738,13 @@ }, | ||
* | ||
* @param {string} mode | ||
* @param {object[]} siblings atoms preceding this potential shortcut | ||
* @param {string} shortcut | ||
*/ | ||
function validateShortcut(siblings, shortcut) { | ||
function validateShortcut(mode, siblings, 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.mode === 'string' && shortcut.mode !== mode) return null; | ||
// If we have no context, we assume all the shortcuts are valid | ||
@@ -663,3 +769,3 @@ if (!siblings) return shortcut ? shortcut.value : undefined; | ||
let index = siblings.length - 1; | ||
while (sibling && sibling.type === 'msubsup') { | ||
while (sibling && /msubsup|placeholder/.test(sibling.type)) { | ||
index -= 1; | ||
@@ -685,3 +791,3 @@ sibling = siblings[index]; | ||
if (typeof shortcut === 'object') { | ||
if (typeof shortcut.after !== 'undefined') { | ||
// If this is a conditional shortcut, consider the conditions now | ||
@@ -702,9 +808,8 @@ if ( (/nothing/.test(shortcut.after) && nothing) || | ||
(/space/.test(shortcut.after) && space)){ | ||
shortcut = shortcut.value; | ||
} else { | ||
shortcut = null; | ||
return shortcut.value; | ||
} | ||
return null; | ||
} | ||
return shortcut; | ||
return shortcut.value; | ||
} | ||
@@ -715,2 +820,3 @@ | ||
* | ||
* @param {string} mode | ||
* @param {string} context - atoms preceding the candidate, potentially used | ||
@@ -725,3 +831,3 @@ * to reduce which shortcuts are applicable. If 'null', no restrictions are | ||
*/ | ||
function forString(context, s, config) { | ||
function forString(mode, context, s, config) { | ||
let result = ''; | ||
@@ -731,3 +837,3 @@ | ||
if (!skipDefaultShortcuts) { | ||
result = validateShortcut(context, INLINE_SHORTCUTS[s]); | ||
result = validateShortcut(mode, context, INLINE_SHORTCUTS[s]); | ||
} | ||
@@ -739,3 +845,3 @@ | ||
if (customInlineShortcuts) { | ||
customResult = validateShortcut(context, customInlineShortcuts[s]); | ||
customResult = validateShortcut(mode, context, customInlineShortcuts[s]); | ||
} | ||
@@ -742,0 +848,0 @@ |
@@ -156,2 +156,7 @@ /** | ||
restore(state, options) { | ||
const wasSuppressing = this.mathlist.suppressChangeNotifications; | ||
if (options.suppressChangeNotifications !== undefined) { | ||
this.mathlist.suppressChangeNotifications = options.suppressChangeNotifications; | ||
} | ||
// Restore the content | ||
@@ -165,4 +170,7 @@ this.mathlist.insert(state ? state.latex : '', { | ||
}); | ||
// Restore the selection | ||
this.mathlist.setPath(state ? state.selection : [{relation: 'body', offset: 0}]); | ||
this.mathlist.suppressChangeNotifications = wasSuppressing; | ||
} | ||
@@ -169,0 +177,0 @@ } |
@@ -5,11 +5,4 @@ | ||
export function l10n(s) { | ||
// Use the browser defined language as the default language, | ||
// "english" if not running in a browser (node.js) | ||
if (!l10n._locale) { | ||
// Use the setter, which will load the necessary .json files. | ||
l10n.locale = typeof navigator === 'undefined' ? 'en' : | ||
navigator.language.slice(0, 5); | ||
} | ||
const language = l10n._locale.substring(0, 2); | ||
const language = l10n.locale.substring(0, 2); | ||
@@ -19,3 +12,3 @@ let result = ''; | ||
// Attempt to find a match for the current locale | ||
if (l10n.strings[l10n._locale]) result = l10n.strings[l10n._locale][s]; | ||
if (l10n.strings[l10n.locale]) result = l10n.strings[l10n.locale][s]; | ||
// If none is found, attempt to find a match for the language | ||
@@ -50,3 +43,3 @@ if (!result && l10n.strings[language]) result = l10n.strings[language][s]; | ||
strings = locale; | ||
for (const l of strings) { | ||
for (const l in strings) { | ||
if (strings.hasOwnProperty(l)) { | ||
@@ -66,2 +59,9 @@ l10n.merge(l, strings[l]); | ||
get() { | ||
// Use the browser defined language as the default language, | ||
// "english" if not running in a browser (node.js) | ||
if (!l10n._locale) { | ||
// Use the setter, which will load the necessary .json files. | ||
l10n._locale = typeof navigator === 'undefined' ? 'en' : | ||
navigator.language.slice(0, 5); | ||
} | ||
return l10n._locale | ||
@@ -84,2 +84,13 @@ } | ||
}, | ||
"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": { | ||
@@ -94,3 +105,3 @@ "keyboard.tooltip.functions": "Funktionen", | ||
"tooltip.toggle virtual keyboard": "Virtuelle Tastatur umschalten", | ||
"tooltip.undo": "Rückgängig machen" | ||
"tooltip.undo": "Widerrufen" | ||
}, | ||
@@ -108,2 +119,13 @@ "es": { | ||
}, | ||
"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": { | ||
@@ -115,4 +137,4 @@ "keyboard.tooltip.functions": "Fonctions", | ||
"keyboard.tooltip.roman": "Lettres et symboles romains", | ||
"tooltip.copy to clipboard": "Copier dans le Presse-papiers", | ||
"tooltip.redo": "Refaire", | ||
"tooltip.copy to clipboard": "Copier dans le presse-papiers", | ||
"tooltip.redo": "Rétablir", | ||
"tooltip.toggle virtual keyboard": "Afficher/Masquer le clavier virtuel", | ||
@@ -119,0 +141,0 @@ "tooltip.undo": "Annuler" |
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 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
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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 2 instances 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
4078524
24
121
57861
4