diff --git a/.codeclimate.yml b/.codeclimate.yml
index 2e45f9e13..737d132ad 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -1,18 +1,16 @@
engines:
- eslint:
- enabled: true
- duplication:
- enabled: true
- config:
- languages:
- - javascript:
+ eslint:
+ enabled: true
+ duplication:
+ enabled: true
+ config:
+ languages:
+ - javascript:
exclude_paths:
-- "docs/"
-- "dist/"
-- "build/"
-- "test/"
+ - 'docs/'
+ - 'dist/'
+ - 'build/'
+ - 'test/'
ratings:
- paths:
- - "src/**/*"
-
-
+ paths:
+ - 'src/**/*'
diff --git a/.dependabot/config.yml b/.dependabot/config.yml
new file mode 100644
index 000000000..76d57987e
--- /dev/null
+++ b/.dependabot/config.yml
@@ -0,0 +1,17 @@
+version: 1
+
+update_configs:
+ # Keep package.json (& lockfiles) up to date
+ # batching pull requests weekly
+ - package_manager: 'javascript'
+ directory: '/'
+ update_schedule: 'weekly'
+ automerged_updates:
+ - match:
+ # Supported dependency types:
+ # - "development"
+ # - "production"
+ # - "all"
+ dependency_type: 'all'
+ update_type: 'semver:minor'
+ version_requirement_updates: 'increase_versions'
diff --git a/.eslintrc.json b/.eslintrc.json
index 70e7f1b98..f8693994e 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -16,11 +16,17 @@
}
},
- "extends": "eslint:recommended",
+ "extends": [
+ // Uses the recommended rules for Typescript
+ "plugin:@typescript-eslint/recommended",
+ // Disable rules that conflict with prettier
+ // See https://prettier.io/docs/en/integrating-with-linters.html
+ "plugin:prettier/recommended"
+ ],
// See http://eslint.org/docs/rules/
"rules": {
- // Note:
+ // Note:
// "off" or 0 - turn the rule off
// "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code)
// "error" or 2 - turn the rule on as an error (exit code is 1 when triggered)
@@ -35,38 +41,37 @@
"array-bracket-spacing": ["error", "never"],
"block-spacing": ["error", "always"],
- "brace-style": [1, "1tbs", { "allowSingleLine": true }],
+ "brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
"prefer-const": "warn",
"valid-typeof": "error",
"consistent-return": "error",
- "curly": ["warn","multi-line"],
- "eqeqeq": ["error","smart"],
+ "curly": ["warn", "multi-line"],
+ "eqeqeq": ["error", "smart"],
"guard-for-in": "warn",
// "max-len": "warn",
- "new-cap": 1,
+ "new-cap": "warn",
"no-bitwise": "off",
"no-console": "off",
- "no-else-return": 1,
- "no-eval": 2,
- "no-fallthrough": 1,
- "no-invalid-this": 1,
- "no-lone-blocks": 1,
- "no-return-assign": [1,"always"],
- "no-self-compare": 2,
- "no-sequences": 1,
- "no-unneeded-ternary": 1,
- "no-unused-expressions": 1,
- "no-useless-call": 1,
+ "no-else-return": "warn",
+ "no-eval": "error",
+ "no-fallthrough": "error",
+ "no-invalid-this": "warn",
+ "no-lone-blocks": "warn",
+ "no-return-assign": ["warn", "always"],
+ "no-self-compare": "error",
+ "no-sequences": "warn",
+ "no-unneeded-ternary": "warn",
+ "no-unused-expressions": "warn",
+ "no-useless-call": "warn",
"no-var": "error",
- "no-with": 2,
- // "vars-on-top": 1,
- "no-delete-var": 1,
- "no-mixed-spaces-and-tabs": [1,"smart-tabs"],
+ "no-with": "error",
+ // "vars-on-top": "warn",
+ "no-delete-var": "warn",
+ "no-mixed-spaces-and-tabs": ["warn", "smart-tabs"],
"require-jsdoc": "off",
- "space-infix-ops": ["error", {"int32Hint": false}]
+ "space-infix-ops": ["error", { "int32Hint": false }],
-
- // "no-trailing-spaces": [1,{"skipBlankLines":true}]
+ "no-trailing-spaces": [1, { "skipBlankLines": true }]
}
-}
\ No newline at end of file
+}
diff --git a/.gitattributes b/.gitattributes
index 212566614..045c5b478 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,107 @@
-* text=auto
\ No newline at end of file
+#
+# Normalize text files line ending to LF in the repository
+#
+* text=auto
+
+#
+# Text files
+#
+
+*.css text
+*.htm text diff=html
+*.html text diff=html
+*.js text
+*.json text
+*.map text -diff
+# Markdown
+*.md text
+*.sass text diff=css
+*.scss text diff=css
+# shell script, always LF
+*.sh text eol=lf
+*.svg text
+*.ts text
+*.yaml text
+*.yml text
+
+#
+# Text files without extension
+#
+
+AUTHORS* text
+CHANGELOG* text
+CHANGES text
+CONTRIBUTING* text
+COPYING text
+copyright text
+*COPYRIGHT* text
+INSTALL* text
+license text
+LICENSE* text
+NEWS text
+readme text
+*README* text
+TODO text
+
+#
+# Configuration files
+#
+
+*.bowerrc text
+*.cnf text
+*.conf text
+*.config text
+.babelrc text
+.browserslistrc text
+.editorconfig text
+.env text
+.gitattributes text
+.gitconfig text
+.htaccess text
+*.lock text -diff
+package-lock.json text -diff
+*.npmignore text
+*.yaml text
+*.yml text
+browserslist text
+Makefile text
+makefile text
+
+
+#
+# Configuration files without extension
+#
+
+.csslintrc text
+.editorconfig text
+.eslintrc text
+.gitignore text
+.gitmodules text
+.htmlhintrc text
+.prettierignore text
+.jscsrc text
+.jshintrc text
+.jshintignore text
+.stylelintrc text
+
+
+#
+# Graphics
+#
+
+*.gif binary
+*.ico binary
+*.jpg binary
+*.jpeg binary
+*.png binary
+
+#
+# Exclude files from exporting
+# (used by the "download ZIP archive" option, for example)
+#
+
+.gitattributes export-ignore
+.gitignore export-ignore
+.gitmodules export-ignore
+.prettierignore export-ignore
+.package-lock.json export-ignore
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index adcfa912c..952d61279 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,35 +1,40 @@
## Prerequisites
-* [ ] New issue
-[Did you check the [issue tracker](https://github.com/arnog/mathlive/issues) to see if this issue has already been reported? If it has, you can +1 it to indicate your interest and be notified when it gets resolved.]
+- [ ] New issue
+ [Did you check the [issue tracker](https://github.com/arnog/mathlive/issues) to see if this issue has already been reported? If it has, you can +1 it to indicate your interest and be notified when it gets resolved.]
[For more information, see the `CONTRIBUTING` guide.]
## Description
+
[Description of the bug or feature.]
[Include screenshots or code fragments if applicable]
### Actual behavior
+
[What actually happened]
-[If there are any error messages, include the exact text shown,
+[If there are any error messages, include the exact text shown,
or upload a screenshot. Some error messages may displayed in the Javascript console.]
-### Expected Behavior
+### Expected Behavior
+
[What you expected to happen]
[Is this a regression: did it use to work in a previous version?]
## Steps to Reproduce
+
[Provide steps that are specific and repeatable, if possible]
+
1. [First Step]
2. [Second Step]
3. [and so on...]
-
### Environment
-**Operating System**
+
+**Operating System**
[macOS, Windows, iOS. Include the version if possible]
**Browser** [Safari, Chrome, IE, Firefox, etc...]
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 4b4035e1f..a1d30c3a0 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,11 +1,17 @@
---
+
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
+---**Funding**
----
+> If you're using MathLive consider donating to project development via [Patreon](https://patreon.com/arnog) (recurring donation) or [PayPal](https://www.paypal.me/arnogourdol) (one time donation).
+
+> Issues submitted by funding partners are given higher priority.
+
+> We welcome both individual and corporate sponsors. In addition to Patreon and PayPal, we can also accept short-term development contracts for specific features or maintenance of the project.
**Funding**
> If you're using MathLive consider donating to project development via [Patreon](https://patreon.com/arnog) (recurring donation) or [PayPal](https://www.paypal.me/arnogourdol) (one time donation).
@@ -20,6 +26,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
[Steps to reproduce the behavior, for example:]
+
1. [Go to '...']
2. [Click on '....']
3. [Scroll down to '....']
@@ -36,9 +43,9 @@ A clear and concise description of what the bug is.
**Source Code**
[If applicable, provide a code sample demonstrating the issue. Use JSFiddle, CodePen or similar to provide a relevant snippet.]
-
**Environment**
-- Device: [pc, mac, iPhone, Android...]
-- OS: [e.g. iOS]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
+
+- Device: [pc, mac, iPhone, Android...]
+- OS: [e.g. iOS]
+- Browser [e.g. chrome, safari]
+- Version [e.g. 22]
diff --git a/.npmignore b/.npmignore
index caeaec9cc..a006af1df 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,6 +1,3 @@
# An empty .npmignore file is necessary for the .gitignore file to be ignored
# Without it, the /dist directory (which is in .gitignore) would not be
-# taken into account by npm.
-
-._*
-.DS_Store
\ No newline at end of file
+# taken into account by npm
diff --git a/.travis.yml b/.travis.yml
index b9875fd20..f41a53dc2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,22 +1,37 @@
language: node_js
-node_js:
-- lts/*
-before_install:
-- '[[ $(node -v) =~ ^v9.*$ ]] || npm install -g npm@latest' # skipped when using node 9
-- npm install -g greenkeeper-lockfile
-install:
-- npm install
-before_script: greenkeeper-lockfile-update
-after_script: greenkeeper-lockfile-upload
+node_js: [lts/*]
+before_install: [npm install -g npm@latest]
+install: [npm ci]
cache:
- directories:
- - node_modules
- - "$HOME/.npm"
+ directories:
+ - node_modules
+ - '$HOME/.npm'
branches:
- only:
- - master
- - release
- - /^greenkeeper/.*$/
+ only:
+ - master
+ - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ # tagged with version
+ # - release
+before_deploy:
+ - npm run dist
+ - npm run deploy-ci
+deploy:
+ provider: npm
+ on:
+ tags: true
+ email: '$NPM_EMAIL'
+ api_token: '$NPM_API_TOKEN'
+ access: public
+ # dry_run: true
+ edge: true
+script:
+ - npm run lint
+ - npm run test
notifications:
- slack:
- secure: dctz771vJCv6UdjBz65n8XkKx5q/LF5UIY+qSRAxLpqwFp9Y3i9trUNoSaDya4PH5sfAHbUHxsBvG8njIKDJY1pckcrCt2Ml2+9fRQ01cCMggNnSK5OlcuoL6lrnbMbaLz3XEUKJY8mfJnnHggUFNqT0IhCR4xgcxiyg90AtHhIGQcIpkFrpmwbW+ZXm7PMTP/svGkL3OMs4lDO6V8XzEGKXd+4rkcvINZwOtKDXbIf7Wm5MXQ2lf4o1DviAJeFqlIUPRRonAs2KPUAl86t+M22EWDExy6NOtmbdA68m+pDaBJ0mMN0OwxsoEJh5e7ml1/UAs82hCu+Kl3xW4emDrrF7k6C065NmWeRqLBVJxcfy+rdNsiBfJhPmBBGc0VTYLqnWR5PLxDBHgLyO7zAjG4n4G8WpCEY0j891Xaw3Cktz8tWWo336BxCmsd2zOUdoWr+aQsml25mlpLYuX2t4HR66jJdz8A7X+e5m4V3/BE+afMKhRYgeuwPVq03TBAtHZp5jLr0TCw9t3qyNrUEXGtqoAYdCThCP1zcpxTTYnxoYHgoEfiE8OVMkMf6R3JpCUQMk1+AbpyVIHeCxfaq7jCZjUG4exMGFNFhTSjl3ePoCLdwfP75uEIiQU/LOJGb2JrJWVjTEBs5P/atk71ijomygAU3D6BtYwoZm0Hqy+l8=
+ slack:
+ secure: dctz771vJCv6UdjBz65n8XkKx5q/LF5UIY+qSRAxLpqwFp9Y3i9trUNoSaDya4PH5sfAHbUHxsBvG8njIKDJY1pckcrCt2Ml2+9fRQ01cCMggNnSK5OlcuoL6lrnbMbaLz3XEUKJY8mfJnnHggUFNqT0IhCR4xgcxiyg90AtHhIGQcIpkFrpmwbW+ZXm7PMTP/svGkL3OMs4lDO6V8XzEGKXd+4rkcvINZwOtKDXbIf7Wm5MXQ2lf4o1DviAJeFqlIUPRRonAs2KPUAl86t+M22EWDExy6NOtmbdA68m+pDaBJ0mMN0OwxsoEJh5e7ml1/UAs82hCu+Kl3xW4emDrrF7k6C065NmWeRqLBVJxcfy+rdNsiBfJhPmBBGc0VTYLqnWR5PLxDBHgLyO7zAjG4n4G8WpCEY0j891Xaw3Cktz8tWWo336BxCmsd2zOUdoWr+aQsml25mlpLYuX2t4HR66jJdz8A7X+e5m4V3/BE+afMKhRYgeuwPVq03TBAtHZp5jLr0TCw9t3qyNrUEXGtqoAYdCThCP1zcpxTTYnxoYHgoEfiE8OVMkMf6R3JpCUQMk1+AbpyVIHeCxfaq7jCZjUG4exMGFNFhTSjl3ePoCLdwfP75uEIiQU/LOJGb2JrJWVjTEBs5P/atk71ijomygAU3D6BtYwoZm0Hqy+l8=
+ webhooks:
+ urls:
+ - '$GITTER_URL'
+ on_success: change # options: [always|never|change] default: always
+ on_failure: always # options: [always|never|change] default: always
+ on_start: never # options: [always|never|change] default: always
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 677795c9c..2d6e0e9f8 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -19,4 +19,4 @@
"webRoot": "${workspaceFolder}"
}
]
-}
\ No newline at end of file
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ea98f958e..bf106296d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,14 +1,10 @@
{
"eslint.provideLintTask": true,
"eslint.options": {
- "configFile":".eslintrc.json"
+ "configFile": ".eslintrc.json"
},
"cSpell.allowCompoundWords": true,
- "cSpell.words": [
- "assistive",
- "grapheme",
- "latexify",
- "mathrm"
- ],
- "search.usePCRE2": true
-}
\ No newline at end of file
+ "cSpell.words": ["assistive", "grapheme", "latexify", "mathrm"],
+ "search.usePCRE2": true,
+ "cSpell.enabled": false
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 000000000..284aa267e
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,12 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "npm",
+ "script": "http-server",
+ "problemMatcher": []
+ }
+ ]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3630323d8..9a6f4fcce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,128 +1,170 @@
+##
+
+### Bug Fixes
+
+- 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).
+
+## 0.33 (December 16, 2019)
+
+### Bug Fixes
+
+- Fix #313. Text mode content is not output in MathML, speech and MathJSON (contribution by @NSoiffer)
+- Fix #275: Selection improvements (use centerpoint to calculate nearest atom) and make delimiters selection eligible.
+
+## 0.32.3 (October 29, 2019)
+
+### Bug Fixes
+
+- Fix #286 `\mathbb{}`s are missing in the Latex output
+
+## 0.32.2 (September 24, 2019)
+
+### Bug Fixes
+
+- Fixed an issue where some keys in the virtual keyboard would be unresponsive
+
## 0.30.1 (July 30, 2019)
### Features / Improvements
-- Added Typescript type definition
+
+- Added Typescript type definition
## 0.30 (July 18, 2019)
### Non-backward compatible changes
-- #157: Public APIs that don't start with `$` have been removed. If your code
-used any of these APIs, add a `$` in front of their name. See #157 for the
-complete list.
+- #157: Public APIs that don't start with `$` have been removed. If your code
+ used any of these APIs, add a `$` in front of their name. See #157 for the
+ complete list.
### Features / Improvements
-- #231: `smartMode` now supports Greek (the language). Also, Greek localization.
-- Don't display i-beam cursor over non-interactive content
-- Use CSS class `.ML__smart-fence__close` to style closing smart fence
-- Added speech support for text mode and units (contributed by @NSoiffer)
+- #231: `smartMode` now supports Greek (the language). Also, Greek localization.
+- Don't display i-beam cursor over non-interactive content
+- Use CSS class `.ML__smart-fence__close` to style closing smart fence
+- Added speech support for text mode and units (contributed by @NSoiffer)
### Bug Fixes
-- Fixed an issue where clicking past the end of the equation would select the
-numerator or denominator if the last element was a fraction, instead of place
-the cursor after the fraction (regression)
-- Removed dependency on open-cli
-- #220 Fixed an issue where tabbing out of a mathfield would break command mode and some functions
-- #209, #214, #211 et. al. Improvements to SSML support and karaoke mode contributed by @NSoiffer
-- #217 Fixed an issue with parentheses in numerator of fractions
-- #212: Fix round-tripping of `\mathbb`
-- #194: When using the virtual keyboard, interpolate `#@`
-- Fixed an issue where "(" was incorrectly gobbled as argument to a fraction
-- Fixed an issue where smartFence off was ignored
-- #202: use numeric character references instead of named entities in MathML output
-
+- Fixed an issue where clicking past the end of the equation would select the
+ numerator or denominator if the last element was a fraction, instead of place
+ the cursor after the fraction (regression)
+- Removed dependency on open-cli
+- #220 Fixed an issue where tabbing out of a mathfield would break command mode and some functions
+- #209, #214, #211 et. al. Improvements to SSML support and karaoke mode contributed by @NSoiffer
+- #217 Fixed an issue with parentheses in numerator of fractions
+- #212: Fix round-tripping of `\mathbb`
+- #194: When using the virtual keyboard, interpolate `#@`
+- Fixed an issue where "(" was incorrectly gobbled as argument to a fraction
+- Fixed an issue where smartFence off was ignored
+- #202: use numeric character references instead of named entities in MathML output
## 0.29.1 (May 19, 2019)
### Bug fixes
-- #201: the popover button was not responsive
-- #195: (partial fix) improve support for Edge (still requires Babelization)
-- Fixed an issue while dragging to select across elements of different depths
-- Fixed issue with smartMode for expressions including "x^2", "xyz" and "\pi"
-- Fixed an issue with styling, where the Latex output could sometimes include the non-existent `\mathup` command. The correct command is `\upshape`
-- Fixed issues with enclose layout
-- Avoid triggering spurious notifications while inserting an inline shortcut
+- #201: the popover button was not responsive
+- #195: (partial fix) improve support for Edge (still requires Babelization)
+- Fixed an issue while dragging to select across elements of different depths
+- Fixed issue with smartMode for expressions including "x^2", "xyz" and "\pi"
+- Fixed an issue with styling, where the Latex output could sometimes include the non-existent `\mathup` command. The correct command is `\upshape`
+- Fixed issues with enclose layout
+- Avoid triggering spurious notifications while inserting an inline shortcut
## 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
+
+- 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"
+
+- 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.
+- 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.
+
+- 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)
+
This release contains some small bug fixes and improvements.
-- Reduced Node version required (for dev builds) to Node LTS
-- Fixed some issues with focus state of mathfields, particularly with multiple mathfields on a page
-- Fixed an issue with some keys (such as /) on international keyboards (such as QWERTZ)
-- Made `moveToOpposite` correctly select the opposite superscript/subscript
-- Use the correct font for `\operatorname`, even for single character operators
-- Send content change notifications when array cells are created
-- Fixed a layout issue with upsized (`\huge`) content in fractions
-- More accurate layout for `box` atoms (with `\bbox`, `\colorbox`, `\boxed` and `\fcolorbox`)
-- Fixed an issue where units after an exponent were not recognized
-- Fixed an issue displaying virtual keyboard on narrow Android phones
+- Reduced Node version required (for dev builds) to Node LTS
+- Fixed some issues with focus state of mathfields, particularly with multiple mathfields on a page
+- Fixed an issue with some keys (such as /) on international keyboards (such as QWERTZ)
+- Made `moveToOpposite` correctly select the opposite superscript/subscript
+- Use the correct font for `\operatorname`, even for single character operators
+- Send content change notifications when array cells are created
+- Fixed a layout issue with upsized (`\huge`) content in fractions
+- More accurate layout for `box` atoms (with `\bbox`, `\colorbox`, `\boxed` and `\fcolorbox`)
+- Fixed an issue where units after an exponent were not recognized
+- Fixed an issue displaying virtual keyboard on narrow Android phones
### New Features
-- Added support for applying size to the selection with `applyStyle({size:'size9'})` (default size is `size5`, smallest is `size1`, largest is `size10`).
-- Added support for `npm run start` which will start a local web server for ease of debugging (some features, such as using JavaScript native modules, require a local server)
+
+- Added support for applying size to the selection with `applyStyle({size:'size9'})` (default size is `size5`, smallest is `size1`, largest is `size10`).
+- Added support for `npm run start` which will start a local web server for ease of debugging (some features, such as using JavaScript native modules, require a local server)
## 0.27 (Apr 8, 2019)
+
### Breaking Changes
-- The syntax that MathJSON/MASTON can recognized has been significantly expanded. It also has been made more consistent, and in some cases it may be different than what was previously returned.
-- Future breaking change: the selector `enterCommandMode` will be deprecated and replaced by the more general `switchMode('command')`. The selector `switchMode('command')` is available in this release, and `enterCommandMode` is supported as well but it will be removed in a future release and you should migrate to `switchMode()` as soon as possible.
+
+- The syntax that MathJSON/MASTON can recognized has been significantly expanded. It also has been made more consistent, and in some cases it may be different than what was previously returned.
+- Future breaking change: the selector `enterCommandMode` will be deprecated and replaced by the more general `switchMode('command')`. The selector `switchMode('command')` is available in this release, and `enterCommandMode` is supported as well but it will be removed in a future release and you should migrate to `switchMode()` as soon as possible.
### Major New Features
+
#### Text Mode (#153)
+
It was previously possible to enter text in an equation using the `\text{}` command and its family using the command mode. However, this feature was only suitable for advanced users, and had many limitations (text could not include spaces, for example).
-MathLive now fully support a dedicated text mode.
+MathLive now fully support a dedicated text mode.
To switch between math and text mode, use the `alt/option+=` keyboard shortcut, or programmatically using `mf.$perform(['apply-style', {mode: 'math'}])`.
-If there is a selection it will be converted to the specified mode (math is converted to ASCII Math). If there's no selection, the next user input will be considered to be in the specified mode.
+If there is a selection it will be converted to the specified mode (math is converted to ASCII Math). If there's no selection, the next user input will be considered to be in the specified mode.
The current mode can also be changed using `mf.$perform(['switch-mode', {mode: 'math'}])` without affecting the selection.
@@ -131,32 +173,36 @@ To indicate the current mode, a (slightly) different cursor is used (it's thinne
A notification is invoked when the mode changes: `config.onModeChange(mf, mode)` with mode either `"text"`, `"math"` or `"command"`.
#### Smart Mode
-If `config.smartMode = true`, during text input the field will switch automatically between 'math' and 'text' mode depending on what is typed and the context of the formula. If necessary, what was previously typed will be 'fixed' to account for the new info.
+
+If `config.smartMode = true`, during text input the field will switch automatically between 'math' and 'text' mode depending on what is typed and the context of the formula. If necessary, what was previously typed will be 'fixed' to account for the new info.
For example, when typing "if x >0":
-- "i" -> math mode, imaginary unit
-- "if" -> text mode, english word "if"
-- "if x" -> all in text mode, maybe the next word is xylophone?
-- "if x >" -> "if" stays in text mode, but now "x >" is in math mode
-- "if x > 0" -> "if" in text mode, "x > 0" in math mode
+
+- "i" -> math mode, imaginary unit
+- "if" -> text mode, english word "if"
+- "if x" -> all in text mode, maybe the next word is xylophone?
+- "if x >" -> "if" stays in text mode, but now "x >" is in math mode
+- "if x > 0" -> "if" in text mode, "x > 0" in math mode
Smart Mode is off by default.
Manually switching mode (by typing `alt/option+=`) will temporarily turn off smart mode.
**Examples**
-- slope = rise/run
-- If x > 0, then f(x) = sin(x)
-- x^2 + sin (x) when x > 0
-- When x<0, x^{2n+1}<0
-- Graph x^2 -x+3 =0 for 0<=x<=5
-- Divide by x-3 and then add x^2-1 to both sides
-- Given g(x) = 4x – 3, when does g(x)=0?
-- Let D be the set {(x,y)|0<=x<=1 and 0<=y<=x}
-- \int_{the unit square} f(x,y) dx dy
-- For all n in NN
+
+- slope = rise/run
+- If x > 0, then f(x) = sin(x)
+- x^2 + sin (x) when x > 0
+- When x<0, x^{2n+1}<0
+- Graph x^2 -x+3 =0 for 0<=x<=5
+- Divide by x-3 and then add x^2-1 to both sides
+- Given g(x) = 4x – 3, when does g(x)=0?
+- Let D be the set {(x,y)|0<=x<=1 and 0<=y<=x}
+- \int\_{the unit square} f(x,y) dx dy
+- For all n in NN
#### Styling
+
It is now possible to apply styling: font family, bold, italic, color and background color. This information is rendered correctly across math and text mode, and preserved in the LaTeX output.
The key to control styling is the `$applyStyle(style)` method:
@@ -167,49 +213,22 @@ If the selection already has this style, it will be removed from it. If the sele
If there is no selection, the style will apply to the next character typed.
-- **style** an object with the following properties. All the
-properties are optional, but they can be combined.
-- **style.mode** - Either `'math'`, `'text'` or `'command'`
-- **style.color** - The text/fill color, as a CSS RGB value or a string for some 'well-known' colors, e.g. 'red', '#f00', etc...
-- **style.backgroundColor** - The background color.
-- **style.fontFamily** - The font family used to render text.
-This value can the name of a locally available font, or a CSS font stack, e.g.
-"Avenir", "Georgia, Times, serif", etc...
-This can also be one of the following TeX-specific values:
- - `'cmr'`: Computer Modern Roman, serif
- - `'cmss'`: Computer Modern Sans-serif, latin characters only
- - `'cmtt'`: Typewriter, slab, latin characters only
- - `'cal'`: Calligraphic style, uppercase latin letters and digits only
- - `'frak'`: Fraktur, gothic, uppercase, lowercase and digits
- - `'bb'`: Blackboard bold, uppercase only
- - `'scr'`: Script style, uppercase only
-- **style.fontSeries** - The font 'series', i.e. weight and
-stretch ("series" is TeX terminology). The following values can be combined, for example: "ebc": extra-bold, condensed. These attributes may not have visible effect if the font family does not support this style:
- - `'ul'` ultra-light weight
- - `'el'`: extra-light
- - `'l'`: light
- - `'sl'`: semi-light
- - `'m'`: medium (default)
- - `'sb'`: semi-bold
- - `'b'`: bold
- - `'eb'`: extra-bold
- - `'ub'`: ultra-bold
- - `'uc'`: ultra-condensed
- - `'ec'`: extra-condensed
- - `'c'`: condensed
- - `'sc'`: semi-condensed
- - `'n'`: normal (default)
- - `'sx'`: semi-expanded
- - `'x'`: expanded
- - `'ex'`: extra-expanded
- - `'ux'`: ultra-expanded
-- **style.fontShape** - The font 'shape' (again, TeX terminology), i.e. italic or condensed.
- - `'it'`: italic
- - `'sl'`: slanted or oblique (often the same as italic)
- - `'sc'`: small caps
- - `'ol'`: outline
-
-
+- **style** an object with the following properties. All the
+ properties are optional, but they can be combined.
+- **style.mode** - Either `'math'`, `'text'` or `'command'`
+- **style.color** - The text/fill color, as a CSS RGB value or a string for some 'well-known' colors, e.g. 'red', '#f00', etc...
+- **style.backgroundColor** - The background color.
+- **style.fontFamily** - The font family used to render text.
+ This value can the name of a locally available font, or a CSS font stack, e.g.
+ "Avenir", "Georgia, Times, serif", etc...
+ This can also be one of the following TeX-specific values: - `'cmr'`: Computer Modern Roman, serif - `'cmss'`: Computer Modern Sans-serif, latin characters only - `'cmtt'`: Typewriter, slab, latin characters only - `'cal'`: Calligraphic style, uppercase latin letters and digits only - `'frak'`: Fraktur, gothic, uppercase, lowercase and digits - `'bb'`: Blackboard bold, uppercase only - `'scr'`: Script style, uppercase only
+- **style.fontSeries** - The font 'series', i.e. weight and
+ stretch ("series" is TeX terminology). The following values can be combined, for example: "ebc": extra-bold, condensed. These attributes may not have visible effect if the font family does not support this style: - `'ul'` ultra-light weight - `'el'`: extra-light - `'l'`: light - `'sl'`: semi-light - `'m'`: medium (default) - `'sb'`: semi-bold - `'b'`: bold - `'eb'`: extra-bold - `'ub'`: ultra-bold - `'uc'`: ultra-condensed - `'ec'`: extra-condensed - `'c'`: condensed - `'sc'`: semi-condensed - `'n'`: normal (default) - `'sx'`: semi-expanded - `'x'`: expanded - `'ex'`: extra-expanded - `'ux'`: ultra-expanded
+- **style.fontShape** - The font 'shape' (again, TeX terminology), i.e. italic or condensed.
+ - `'it'`: italic
+ - `'sl'`: slanted or oblique (often the same as italic)
+ - `'sc'`: small caps
+ - `'ol'`: outline
#### Contextual Inline Shortcuts
@@ -218,21 +237,21 @@ Previously, some shortcuts would get triggered too frequently, for example when
Now, a shortcut can be defined with some pre-conditions. It is still possible to define a shortcut unconditionally, and thus if you are using custom inline shortcuts, they do not need to be updated:
```javascript
- config.inlineShortcuts = {
- 'in': '\\in'
- }
+config.inlineShortcuts = {
+ in: '\\in',
+};
```
However, a shortcut can now be specified with an object:
```javascript
- config.inlineShortcuts = {
- 'in': {
- mode: 'math',
- after: 'space+letter+digit+symbol+fence',
- value: '\\in',
- },
- }
+config.inlineShortcuts = {
+ in: {
+ mode: 'math',
+ after: 'space+letter+digit+symbol+fence',
+ value: '\\in',
+ },
+};
```
The `value` key is required an indicate the shortcut substitution.
@@ -240,444 +259,487 @@ The `value` key is required an indicate the shortcut substitution.
The `mode` key, if present, indicate in which mode this shortcut should apply, either `'math'` or `'text'`. If the key is not present the shortcut apply in both modes.
The `'after'` key, if present, indicate in what context the shortcut should apply. One or more values can be specified, separated by a '+' sign. If any of the values match, the shortcut will be applicable. Possible values are:
-- `'space'` A spacing command, such as `\quad`
-- `'nothing'` The begining of a group
-- `'surd'` A square root or n-th root
-- `'frac'` A fraction
-- `'function'` A function such as `\sin` or `f`
-- `'letter'` A letter, such as `x` or `n`
-- `'digit'` `0` through `9`
-- `'binop'` A binary operator, such as `+`
-- `'relop'` A relational operator, such as `=`
-- `'punct'` A punctuation mark, such as `,`
-- `'array'` An array, such as a matrix or cases statement
-- `'openfence'` An opening fence, such as `(`
-- `'closefence'` A closing fence such as `}`
-- `'text'` Some plain text
+- `'space'` A spacing command, such as `\quad`
+- `'nothing'` The begining of a group
+- `'surd'` A square root or n-th root
+- `'frac'` A fraction
+- `'function'` A function such as `\sin` or `f`
+- `'letter'` A letter, such as `x` or `n`
+- `'digit'` `0` through `9`
+- `'binop'` A binary operator, such as `+`
+- `'relop'` A relational operator, such as `=`
+- `'punct'` A punctuation mark, such as `,`
+- `'array'` An array, such as a matrix or cases statement
+- `'openfence'` An opening fence, such as `(`
+- `'closefence'` A closing fence such as `}`
+- `'text'` Some plain text
+#### Other Features
+- Arrays, matrices and cases can now be edited. To create a a matrix, after a `(` or a `[`, type some content then `[RETURN]`: a second row will be added to the matrix. Similarly, typing `[RETURN]` after a `{` will create a cases statements.
+ - To insert a new row, type `[RETURN]`
+ - To insert a new column, type `alt/option+,` (comma), the Excel shortcut for this operation.
+- Support for `\emph` (emphasis) command, which can be used to (semantically) highlight an element. This command works both in text and math mode (it only works in text mode in TeX). For example:
-#### Other Features
-- Arrays, matrices and cases can now be edited. To create a a matrix, after a `(` or a `[`, type some content then `[RETURN]`: a second row will be added to the matrix. Similarly, typing `[RETURN]` after a `{` will create a cases statements.
- - To insert a new row, type `[RETURN]`
- - To insert a new column, type `alt/option+,` (comma), the Excel shortcut for this operation.
-- Support for `\emph` (emphasis) command, which can be used to (semantically) highlight an element. This command works both in text and math mode (it only works in text mode in TeX). For example:
```tex
\text{In the formula}\emph{x}+1=0\text{x is the \emph{unknown}}
```
-- Support for `\cssId` and `\class` commands. These are non-standard TeX commands which are supported by MathJax.
- - `\cssId{id}{content}` Attaches an id attribute with value `id` to the output associated with content when it is included in the HTML page. This allows your CSS to style the element, or your javascript to locate it on the page.
- - `\class{name}{content}` Attaches the CSS class `name` to the output associated with content when it is included in the HTML page. This allows your CSS to style the element.
-- `config.removeExtraneousParentheses` (true by default) extra parentheses, for example around a numerator or denominator are removed automatically.
-Particularly useful when pasting content.
-- Improvements to clipboard handling, pasting and copying. Now supports pasting of ASCIIMath and UnicodeMath (from MS Word) and LaTeX.
-- Support for output of ASCIIMath using `mf.$text('ASCIIMath')` and
-`mf.$selectedText('ASCIIMath')`
-- `config.smartSuperscript` If `true` (default), when a digit is entered in an empty superscript, the cursor leaps automatically out of the superscript. This makes entry of common polynomials easier and faster.
-- `config.scriptDepth` Controls how many levels of subscript/superscript can be entered. By restricting, this can help avoid unwanted entry of superscript and subscript. By default, there are no restrictions.
-- #156: localization support, including French, Italian, Spanish, Polish and Russian.
-- New visual appearance for selected elements.
+- Support for `\cssId` and `\class` commands. These are non-standard TeX commands which are supported by MathJax.
+ - `\cssId{id}{content}` Attaches an id attribute with value `id` to the output associated with content when it is included in the HTML page. This allows your CSS to style the element, or your javascript to locate it on the page.
+ - `\class{name}{content}` Attaches the CSS class `name` to the output associated with content when it is included in the HTML page. This allows your CSS to style the element.
+- `config.removeExtraneousParentheses` (true by default) extra parentheses, for example around a numerator or denominator are removed automatically.
+ Particularly useful when pasting content.
+- Improvements to clipboard handling, pasting and copying. Now supports pasting of ASCIIMath and UnicodeMath (from MS Word) and LaTeX.
+- Support for output of ASCIIMath using `mf.$text('ASCIIMath')` and
+ `mf.$selectedText('ASCIIMath')`
+- `config.smartSuperscript` If `true` (default), when a digit is entered in an empty superscript, the cursor leaps automatically out of the superscript. This makes entry of common polynomials easier and faster.
+- `config.scriptDepth` Controls how many levels of subscript/superscript can be entered. By restricting, this can help avoid unwanted entry of superscript and subscript. By default, there are no restrictions.
+- #156: localization support, including French, Italian, Spanish, Polish and Russian.
+- New visual appearance for selected elements.
### Other Improvements
-- When in command mode (after pressing the '\' or 'ESC' key), pressing these keys will have the indicated effect:
- - `[ESC]`: discards entry and return to math mode
- - `[TAB]`: accept suggestion and enter it
- - `[RETURN]`: enter characters typed so far, ignoring any suggestion.
-- #132: Support for smart fence with `{}`, and `\langle`.
-- Pressing the spacebar next to a closing smartfence will close it. Useful
-for semi-open fences.
-- Improved rendering performance by 8%
-- Updated SRE support
-- Improvements to undo/redo support. Fix #137, #139 and #140.
-- Significant improvements to the Abstract Syntax Tree generation
-(MASTON/MathJSON), including #147
-- Keyboard shortcuts that override inline shortcuts and Smart Fence: `option/alt+|`, `option/alt+\`. Also available are `option/alt+(` and `option/alt+)`
+
+- When in command mode (after pressing the '\' or 'ESC' key), pressing these keys will have the indicated effect:
+ - `[ESC]`: discards entry and return to math mode
+ - `[TAB]`: accept suggestion and enter it
+ - `[RETURN]`: enter characters typed so far, ignoring any suggestion.
+- #132: Support for smart fence with `{}`, and `\langle`.
+- Pressing the spacebar next to a closing smartFence will close it. Useful
+ for semi-open fences.
+- Improved rendering performance by 8%
+- Updated SRE support
+- Improvements to undo/redo support. Fix #137, #139 and #140.
+- Significant improvements to the Abstract Syntax Tree generation
+ (MASTON/MathJSON), including #147
+- Keyboard shortcuts that override inline shortcuts and Smart Fence: `option/alt+|`, `option/alt+\`. Also available are `option/alt+(` and `option/alt+)`
### Bug Fixes
-- #155: A cases statement (or a matrix) can now be deleted. The rows and columns inside a cases statement (or a matrix) can also be deleted.
-- #133: Clicking on a placeholder selects it.
-- Fixed issue with positioning of Popover panel.
-- Correctly render `\ulcorner`, `\urcorner`, `\llcorner` and `\rrcorner`
-- #141: Improved interaction of placeholders and smart fences
-- #136: Close open smart fence with moveAfterParent only when at the closing
-of a smart fence
-- #142: MathML output: supports sup/sub applied to a function
-- Improved handling of shortcuts.
-- #149: Fix handling of `\prime` and `\doubleprime`
-- #111: Fix issue where a subscript followed a superscript and were not
-properly combined.
-- #118. Improved navigating out of inferior limits
-- Improve visual blinking when selecting with the mouse to the left
+
+- #155: A cases statement (or a matrix) can now be deleted. The rows and columns inside a cases statement (or a matrix) can also be deleted.
+- #133: Clicking on a placeholder selects it.
+- Fixed issue with positioning of Popover panel.
+- Correctly render `\ulcorner`, `\urcorner`, `\llcorner` and `\rrcorner`
+- #141: Improved interaction of placeholders and smart fences
+- #136: Close open smart fence with moveAfterParent only when at the closing
+ of a smart fence
+- #142: MathML output: supports sup/sub applied to a function
+- Improved handling of shortcuts.
+- #149: Fix handling of `\prime` and `\doubleprime`
+- #111: Fix issue where a subscript followed a superscript and were not
+ properly combined.
+- #118. Improved navigating out of inferior limits
+- Improve visual blinking when selecting with the mouse to the left
## 0.26 (Feb 4, 2019)
### Breaking Changes
-- Public method now start with `$`. This convention is also used, for example,
-by the Vue.js project. For now, aliases exist that begin with '_' (the previous
-convention), however you are encourage to migrate as soon as possible. The
-function that are affected are: `_el()`, `_insert()`, `_keystroke()`, `_latex()`,
- `_perform()`, `_revertToOriginalContent()`, `_selectedText()`,
- `_selectionAtEnd()`, `_selectionAtStart()`, `_selectionDepth()`,
- `_selectionIsCollapsed()`, `_setConfig()`, `_text()`, `_typedText()` (this was initially implemented in 0.25)
+
+- Public method now start with `$`. This convention is also used, for example,
+ by the Vue.js project. For now, aliases exist that begin with '\_' (the previous
+ convention), however you are encourage to migrate as soon as possible. The
+ function that are affected are: `_el()`, `_insert()`, `_keystroke()`, `_latex()`,
+ `_perform()`, `_revertToOriginalContent()`, `_selectedText()`,
+ `_selectionAtEnd()`, `_selectionAtStart()`, `_selectionDepth()`,
+ `_selectionIsCollapsed()`, `_setConfig()`, `_text()`, `_typedText()` (this was initially implemented in 0.25)
### Major New Features
-- Support for dark mode. Triggered automatically by the browser or
-by setting `theme="dark"` on the `
` tag.
-- New implementation for inline shortcuts. Now support complex inline
-shortcuts including `_`, `(` and other keys.
-- Virtual Keyboards can now be described using a JSON data structure. Contribution from @rpdiss. Thanks!
-- New `MathLive.toSpeakableText()` function
-- New `config.onAnnounce` handler
+- Support for dark mode. Triggered automatically by the browser or
+ by setting `theme="dark"` on the `` tag.
+- New implementation for inline shortcuts. Now support complex inline
+ shortcuts including `_`, `(` and other keys.
+- Virtual Keyboards can now be described using a JSON data structure. Contribution from @rpdiss. Thanks!
+- New `MathLive.toSpeakableText()` function
+- New `config.onAnnounce` handler
### Other Improvements
-- The `$perform()` function now accepts selector both in camelCase
-or kebab-case.
-- Improved display of some keys in the keyboard caption panel
-- New logo!
-- Improved documentation, including adding pages for keyboard shortcuts,
-examples, macros, selectors and config options.
-- Better support for IE11 via transpiling (thanks @synergycodes!)
+
+- The `$perform()` function now accepts selector both in camelCase
+ or kebab-case.
+- Improved display of some keys in the keyboard caption panel
+- New logo!
+- Improved documentation, including adding pages for keyboard shortcuts,
+ examples, macros, selectors and config options.
+- Better support for IE11 via transpiling (thanks @synergycodes!)
### Bug fixes
-- #103 - Fixed issues where the math path could become invalid. Also made the
-code more resilient to invalid paths.
-- #128 - Properly cleanup event handlers on destruction
+
+- #103 - Fixed issues where the math path could become invalid. Also made the
+ code more resilient to invalid paths.
+- #128 - Properly cleanup event handlers on destruction
### Codebase Health and Performance
-- Some minor optimizations and performance improvements, including
-lazy loading of sounds and some other resources.
-- Moved some modules to classes.
+
+- Some minor optimizations and performance improvements, including
+ lazy loading of sounds and some other resources.
+- Moved some modules to classes.
## 0.25 (December 29, 2018)
### Major New Features
-- A Vue.js wrapper and example is available in `examples/vue`
+
+- A Vue.js wrapper and example is available in `examples/vue`
### Bug fixes
-- #104 - Numeric keypard "/" was ignored.
-- #91 - Handling of '~' as an operator and a shortcut.
+
+- #104 - Numeric keypard "/" was ignored.
+- #91 - Handling of '~' as an operator and a shortcut.
## 0.24 (December 16, 2018)
### Breaking Changes
-- Several handlers had some inconsistent signatures, or in some cases passed
-invalid values as their arguments. This has been fixed, but it
-required changing the signature of some handlers. For consistency, the first
-argument of the handlers now refers to the mathfield to which it applies.
+
+- Several handlers had some inconsistent signatures, or in some cases passed
+ invalid values as their arguments. This has been fixed, but it
+ required changing the signature of some handlers. For consistency, the first
+ argument of the handlers now refers to the mathfield to which it applies.
```javascript
- MathLive.makeMathField('input', {
- onContentDidChange: mf => {
- document.getElementById('output').innerHTML = mf.latex();
- }
- });
+MathLive.makeMathField('input', {
+ onContentDidChange: mf => {
+ document.getElementById('output').innerHTML = mf.latex();
+ },
+});
```
-Keep in mind that arrow functions lexically bind their context, so `this`
+Keep in mind that arrow functions lexically bind their context, so `this`
actually refers to the originating context (not to the mathfield).
The affected handlers are:
-- `onFocus`
-- `onBlur`
-- `onKeystroke`
-- `onMoveOutOf`
-- `onTabOutOf`
-- `onContentWillChange`
-- `onContentDidChange`
-- `onSelectionWillChange`
-- `onSelectionDidChange`
-- `onUndoStateWillChange`
-- `onUndoStateDidChange`
-- `onVirtualKeyboardToggle`
-- `onReadAloudStatus`
-
-It is recommended that you check if you use any of those handlers and
+
+- `onFocus`
+- `onBlur`
+- `onKeystroke`
+- `onMoveOutOf`
+- `onTabOutOf`
+- `onContentWillChange`
+- `onContentDidChange`
+- `onSelectionWillChange`
+- `onSelectionDidChange`
+- `onUndoStateWillChange`
+- `onUndoStateDidChange`
+- `onVirtualKeyboardToggle`
+- `onReadAloudStatus`
+
+It is recommended that you check if you use any of those handlers and
validate their signatures.
### Major New Features
-- Support for native JavaScript modules, contributed by
-Jason Boxman (https://github.com/jboxman). Thanks, Jason!
+
+- Support for native JavaScript modules, contributed by
+ Jason Boxman (https://github.com/jboxman). Thanks, Jason!
The previous method, using a `
+
```
+
but it is recommended to use native JavaScript modules:
+
```html
-
+
```
+
(note the `.mjs` extension indicating this is a JavaScript module).
A few caveats about using modules:
-- JavaScript modules are automatically in strict mode
-- To use JavaScript modules you need to be in your own module. With a `
-
+
+
+
+ ...
+
+
+
+
+
Euler's Identity
+
$$e^{i\pi} + 1 = 0$$
+
+
+
```
-
### Editing Math
-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,
+
+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,
including extracting its content, inserting placeholders and more.
```html
-
-
- ...
-
-
-
-
-
f(x)=
-
-
-
+
+
+
+ ...
+
+
+
+
+
f(x)=
+
+
+
```
### More Examples
-More examples are available at https://mathlive.io/deploy/examples/
-
+More examples are available at https://mathlive.io/examples/
### Installing MathLive
The examples above use a CDN, which is the fastest and easiest way to get started.
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
$ npm install -s mathlive
$ npm start
```
+
This will make a local build of MathLive, run a local HTTP server and open a page with the examples in your browser.
## How You Can Help
-* 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)
## License
diff --git a/WELCOME.md b/WELCOME.md
index 0bad72068..8c73fd8dc 100644
--- a/WELCOME.md
+++ b/WELCOME.md
@@ -4,11 +4,11 @@
+Welcome to MathLive, a JavaScript library to render and edit math.
-Welcome to MathLive, a JavaScript library to render and edit math.
-
-It is fast, small and provides TeX-quality typesetting
+It is fast, small and provides TeX-quality typesetting
with an easy to use interface for math editing. Try it at [mathlive.io](https://mathlive.io)!
+
void;
+declare type MathFieldCallback = (mathfield: MathField) => void;
/**
@typedef MathFieldConfig
@@ -22,6 +22,7 @@ declare type MathFieldCallback = (mf: MathField) => void;
@property {boolean} overrideDefaultInlineShortcuts?
@property {object} inlineShortcuts?
@property {number} inlineShortcutTimeout?
+ @property {object} macros?
@property {boolean} smartFence?
@property {boolean} smartSuperscript?
@property {number} scriptDepth?
@@ -76,6 +77,9 @@ declare type MathFieldConfig = {
[key: string]: string;
};
inlineShortcutTimeout?: number;
+ macros?: {
+ [key: string]: string;
+ };
smartFence?: boolean;
smartSuperscript?: boolean;
scriptDepth?: number;
@@ -135,163 +139,354 @@ declare type MathFieldConfig = {
*/
declare class MathField {
/**
- * Revert this math field to its original content. After this method has been
- * called, no other methods can be called on the MathField object. To turn the
- * element back into a MathField, call `MathLive.makeMathField()` on the
- * element again to get a new math field object.
+ * Reverts this mathfield to its original content.
+ *
+ * After this method has been
+ * called, no other methods can be called on the object.
+ *
+ * To turn the
+ * element back into a mathfield, call `MathLive.makeMathField()` on the
+ * element again to get a new mathfield object.
*
* @method MathField#$revertToOriginalContent
*/
$revertToOriginalContent(): void;
/**
+ * Performs a command defined by a selector.
+ *
+ *
+ #### Moving the insertion point
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"moveToNextChar"` | |
+ | `"moveToPreviousChar"` | |
+ | `"moveUp"` | |
+ | `"moveDown"` | |
+ | `"moveToNextPlaceholder"` | |
+ | `"moveToPreviousPlaceholder"` | |
+ | `"moveToNextWord"` | |
+ | `"moveToPreviousWord"` | |
+ | `"moveToGroupStart"` | |
+ | `"moveToGroupEnd"` | |
+ | `"moveToMathFieldStart"` | |
+ | `"moveToMathFieldEnd"` | |
+ | `"moveToSuperscript"` | |
+ | `"moveToSubscript"` | |
+ | `"moveToOpposite"` | |
+ | `"moveBeforeParent"` | |
+ | `"moveAfterParent"` | |
+
+
+ #### Selection
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"selectGroup"` | Select all the atoms in the current group, that is all the siblings. When the selection is in a numerator, the group is the numerator. When the selection is a superscript or subscript, the group is the supsub.|
+ | `"selectAll"` | Select all the atoms in the mathfield|
+
+
+ #### Extending the selection
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"extendToNextChar"` | |
+ | `"extendToPreviousChar"` | |
+ | `"extendToNextWord"` | |
+ | `"extendToPreviousWord"` | |
+ | `"extendUp"` | |
+ | `"extendDown"` | |
+ | `"extendToNextBoundary"` | |
+ | `"extendToPreviousBoundary"` | |
+ | `"extendToGroupStart"` | |
+ | `"extendToGroupEnd"` | |
+ | `"extendToMathFieldStart"` | |
+ | `"extendToMathFieldEnd"` | |
+
+
+ #### Editing / deleting
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"deleteAll"` | Delete everything in the field |
+ | `"delete"` | Delete the current selection |
+ | `"deleteNextChar"` | |
+ | `"deletePreviousChar"` | |
+ | `"deleteNextWord"` | |
+ | `"deletePreviousWord"` | |
+ | `"deleteToGroupStart"` | |
+ | `"deleteToGroupEnd"` | |
+ | `"deleteToMathFieldEnd"` | |
+ | `"transpose"` | |
+
+
+ #### Editing a matrix
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"addRowAfter"` | |
+ | `"addRowBefore"` | |
+ | `"addColumnAfter"` | |
+ | `"addColumnBefore"` | |
+
+
+ #### Other editing commands
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"scrollIntoView"` | |
+ | `"scrollToStart"` | |
+ | `"switchMode"` | |
+ | `"complete"` | |
+ | `"nextSuggestion"` | |
+ | `"previousSuggestion"` | |
+ | `"toggleKeystrokeCaption"` | |
+ | `"applyStyle"` | |
+
+
+ #### Clipboard
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"undo"` | |
+ | `"redo"` | |
+ | `"copyToClipboard"` | |
+ | `"cutToClipboard"` | |
+ | `"pasteFromClipboard"` | |
+
+
+ #### Virtual Keyboard
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"toggleVirtualKeyboard"` | |
+ | `"showVirtualKeyboard"` | |
+ | `"hideVirtualKeyboard"` | |
+ | `"toggleVirtualKeyboardAlt"` | |
+ | `"toggleVirtualKeyboardShift"` | |
+ | `"showAlternateKeys"` | |
+ | `"hideAlternateKeys"` | |
+ | `"performAlternateKeys"` | |
+ | `"switchKeyboardLayer"` | |
+ | `"shiftKeyboardLayer"` | |
+ | `"unshiftKeyboardLayer"` | |
+ | `"insertAndUnshiftKeyboardLayer"` | |
+ | `"performWithFeedback"` | |
+
+
+ #### Speech
+
+ | Name | Description |
+ | --------------------- | ------------------------- |
+ | `"speak"` | speaks the amount specified by the first parameter. |
+ *
* @param {string|string[]} command - A selector, or an array whose first element
* is a selector, and whose subsequent elements are arguments to the selector.
+ *
* Note that selectors do not include a final "_". They can be passed either
- * in camelCase or kebab-case. So:
+ * in camelCase or kebab-case.
+ *
* ```javascript
* mf.$perform('selectAll');
* mf.$perform('select-all');
* ```
- * both calls are valid and invoke the same selector.
+ * In the above example, both calls invoke the same selector.
+ *
*
* @method MathField#$perform
*/
$perform(command: string | string[]): void;
/**
- * Return a textual representation of the mathfield.
- * @param {string} [format='latex']. One of
- * * `'latex'`
- * * `'latex-expanded'` : all macros are recursively expanded to their definition
- * * `'spoken'`
- * * `'spoken-text'`
- * * `'spoken-ssml'`
- * * `spoken-ssml-withHighlighting`
- * * `'mathML'`
- * * `'json'`
+ * Returns a textual representation of the mathfield.
+ *
+ * @param {string} [format] - The format of the result.
+ *
+ | Format | Description |
+ | :------------------ | :---------------------- |
+ | `"latex"` |LaTeX rendering of the content, with LaTeX macros not expanded|
+ | `"latex-expanded"` |All macros are recursively expanded to their definition|
+ | `"json"` | A MathJSON abstract syntax tree, as an object literal formated as a JSON string (see {@tutorial MATHJSON})|
+ | `"spoken"` |Spoken text rendering, using the default format defined in config, which could be either text or SSML markup.|
+ | `"spoken-text"` |A plain spoken text rendering of the content.|
+ | `"spoken-ssml"` |A SSML (Speech Synthesis Markup Language) version of the content, which can be used with some text-to-speech engines such as AWS|
+ | `"spoken-ssml-withHighlighting"`|Like `"spoken-ssml"` but with additional annotations necessary for synchronized higlighting (read aloud)|
+ | `"mathML"` | A string of MathML markup|
+ *
+ * **Default** = `"latex"`
* @return {string}
+ * @category Accessing the Content
* @method MathField#$text
*/
$text(format?: string): string;
/**
- * Return a textual representation of the selection in the mathfield.
- * @param {string} [format='latex']. One of
- * * `'latex'`
- * * `'latex-expanded'` : all macros are recursively expanded to their definition
- * * `'spoken'`
- * * `'spoken-text'`
- * * `'spoken-ssml'`
- * * `spoken-ssml-withHighlighting`
- * * `'mathML'`
- * * `'json'`
+ * Returns a textual representation of the selection in the mathfield.
+ *
+ * @param {string} [format] - The format of the result.
+ *
+ | Format | Description |
+ | :------------------ | :---------------------- |
+ | `"latex"` |LaTeX rendering of the content, with LaTeX macros not expanded|
+ | `"latex-expanded"` |All macros are recursively expanded to their definition|
+ | `"json"` | A MathJSON abstract syntax tree, as an object literal formated as a JSON string (see {@tutorial MATHJSON})|
+ | `"spoken"` |Spoken text rendering, using the default format defined in config, which could be either text or SSML markup.|
+ | `"spoken-text"` |A plain spoken text rendering of the content.|
+ | `"spoken-ssml"` |A SSML (Speech Synthesis Markup Language) version of the content, which can be used with some text-to-speech engines such as AWS|
+ | `"spoken-ssml-withHighlighting"`|Like `"spoken-ssml"` but with additional annotations necessary for synchronized higlighting (read aloud)|
+ | `"mathML"` | A string of MathML markup|
+ *
+ * **Default** = `"latex"`
* @return {string}
+ * @category Accessing the Content
* @method MathField#$selectedText
*/
$selectedText(format?: string): string;
/**
- * Return true if the length of the selection is 0, that is, if it is a single
+ * Checks if the selection is collapsed.
+ *
+ * @return {boolean} True if the length of the selection is 0, that is, if it is a single
* insertion point.
- * @return {boolean}
+ * @category Selection
* @method MathField#$selectionIsCollapsed
*/
$selectionIsCollapsed(): boolean;
/**
- * Return the depth of the selection group. If the selection is at the root level,
- * returns 0. If the selection is a portion of the numerator of a fraction
+ * Returns the depth of the selection group.
+ *
+ * If the selection is at the root level, returns 0.
+ *
+ * If the selection is a portion of the numerator of a fraction
* which is at the root level, return 1. Note that in that case, the numerator
* would be the "selection group".
+ *
* @return {number}
+ * @category Selection
* @method MathField#$selectionDepth
*/
$selectionDepth(): number;
/**
- * Return true if the selection starts at the beginning of the selection group.
+ * Checks if the selection starts at the beginning of the selection group.
+ *
* @return {boolean}
+ * @category Selection
* @method MathField#$selectionAtStart
*/
$selectionAtStart(): boolean;
/**
- * Return true if the selection extends to the end of the selection group.
+ * Checks if the selection extends to the end of the selection group.
+ *
* @return {boolean}
+ * @category Selection
* @method MathField#$selectionAtEnd
*/
$selectionAtEnd(): boolean;
/**
+ * Sets or gets the content of the mathfield.
+ *
* If `text` is not empty, sets the content of the mathfield to the
* text interpreted as a LaTeX expression.
- * If `text` is empty (or omitted), return the content of the mahtfield as a
+ *
+ * If `text` is empty (or omitted), return the content of the mathfield as a
* LaTeX expression.
- * @param {string} text
+ * @param {string} [text]
*
- * @param {Object.} options
- * @param {boolean} options.suppressChangeNotifications - If true, the
+ * @param {Object.} [options]
+ * @param {boolean} [options.suppressChangeNotifications] - If true, the
* handlers for the contentWillChange and contentDidChange notifications will
- * not be invoked. Default `false`.
+ * not be invoked. **Default** = `false`.
*
* @return {string}
+ * @category Accessing the Content
* @method MathField#$latex
*/
- $latex(text: string, options: {
- suppressChangeNotifications: boolean;
+ $latex(text?: string, options?: {
+ suppressChangeNotifications?: boolean;
}): string;
/**
* Return the DOM element associated with this mathfield.
*
- * Note that `this.$el().mathfield = this`
+ * Note that `this.$el().mathfield === this`
+ *
* @return {HTMLElement}
* @method MathField#$el
*/
$el(): HTMLElement;
/**
- * This method can be invoked as a selector with {@linkcode MathField#$perform $perform("insert")}
- * or called explicitly.
+ * Inserts a block of text at the current insertion point.
*
- * It will insert the specified block of text at the current insertion point,
- * according to the insertion mode specified.
+ * This method can be called explicitly or invoked as a selector with {@linkcode MathField#$perform $perform("insert")}
+ * .
*
* After the insertion, the selection will be set according to the `selectionMode`.
+ *
* @param {string} s - The text to be inserted
*
- * @param {Object.} [options={}]
+ * @param {Object.} [options]
+ *
+ * @param {"replaceSelection"|"replaceAll"|"insertBefore"|"insertAfter"} options.insertionMode -
+ *
+ | | |
+ | :---------- | :---------- |
+ |`"replaceSelection"`| (default)|
+ |`"replaceAll"`| |
+ |`"insertBefore"`| |
+ |`"insertAfter"`| |
*
* @param {'placeholder' | 'after' | 'before' | 'item'} options.selectionMode - Describes where the selection
* will be after the insertion:
- * * `'placeholder'`: the selection will be the first available placeholder
- * in the item that has been inserted (default)
- * * `'after'`: the selection will be an insertion point after the item that
- * has been inserted,
- * * `'before'`: the selection will be an insertion point before
- * the item that has been inserted
- * * `'item'`: the item that was inserted will be selected
+ *
+ | | |
+ | :---------- | :---------- |
+ |`"placeholder"`| The selection will be the first available placeholder in the text that has been inserted (default)|
+ |`"after"`| The selection will be an insertion point after the inserted text|
+ |`"before"`| The selection will be an insertion point before the inserted text|
+ |`"item"`| The inserted text will be selected|
*
* @param {'auto' | 'latex'} options.format - The format of the string `s`:
- * * `'auto'`: the string is interpreted as a latex fragment or command)
- * (default)
- * * `'latex'`: the string is interpreted strictly as a latex fragment
+ *
+ | | |
+ |:------------|:------------|
+ |`"auto"`| The string is Latex fragment or command) (default)|
+ |`"latex"`| The string is a Latex fragment|
*
* @param {boolean} options.focus - If true, the mathfield will be focused after
* the insertion
*
* @param {boolean} options.feedback - If true, provide audio and haptic feedback
*
- * @param {'text' | 'math' | ''} options.mode - 'text' or 'math'. If empty, the current mode
+ * @param {"text" | "math" | ""} options.mode - If empty, the current mode
* is used (default)
*
+ * @param {object} options.style
+ *
* @param {boolean} options.resetStyle - If true, the style after the insertion
- * is the same as the style before (if false, the style after the
- * insertion is the style of the last inserted atom).
+ * is the same as the style before. If false, the style after the
+ * insertion is the style of the last inserted atom.
+ *
+ * @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
* @method MathField#$insert
*/
$insert(s: string, options?: {
+ insertionMode: "replaceSelection" | "replaceAll" | "insertBefore" | "insertAfter";
selectionMode: 'placeholder' | 'after' | 'before' | 'item';
format: 'auto' | 'latex';
focus: boolean;
feedback: boolean;
- mode: 'text' | 'math' | '';
+ mode: "text" | "math" | "";
+ style: any;
resetStyle: boolean;
+ smartFence: boolean;
+ suppressChangeNotifications: boolean;
}): void;
/**
- * Apply a style (color, bold, italic, etc...).
+ * Updates the style (color, bold, italic, etc...) of the selection or sets
+ * the style to be applied to future input.
*
* If there is a selection, the style is applied to the selection
*
@@ -301,61 +496,76 @@ declare class MathField {
*
* If there is no selection, the style will apply to the next character typed.
*
- * @param {object} style an object with the following properties. All the
- * properties are optional, but they can be combined.
+ * @param {object} style The style properties to be applied. All the
+ * properties are optional and they can be combined.
*
- * @param {string} [style.mode=''] - Either `'math'`, `'text'` or '`command`'
- * @param {string} [style.color=''] - The text/fill color, as a CSS RGB value or
- * a string for some 'well-known' colors, e.g. 'red', '#f00', etc...
+ * @param {string} [style.mode] - Either `"math"`, `"text"` or `"command"`
*
- * @param {string} [style.backgroundColor=''] - The background color.
+ * @param {string} [style.color] - The text/fill color, as a CSS RGB value or
+ * a string for some "well-known" colors, e.g. `"red"`, `"#f00"`, etc...
+ *
+ * @param {string} [style.backgroundColor] - The background color.
+ *
+ * @param {string} [style.fontFamily] - The font family used to render text.
*
- * @param {string} [style.fontFamily=''] - The font family used to render text.
* This value can the name of a locally available font, or a CSS font stack, e.g.
- * "Avenir", "Georgia, serif", etc...
+ * `"Avenir"`, `"Georgia, serif"`, etc...
+ *
* This can also be one of the following TeX-specific values:
- * - 'cmr': Computer Modern Roman, serif
- * - 'cmss': Computer Modern Sans-serif, latin characters only
- * - 'cmtt': Typewriter, slab, latin characters only
- * - 'cal': Calligraphic style, uppercase latin letters and digits only
- * - 'frak': Fraktur, gothic, uppercase, lowercase and digits
- * - 'bb': Blackboard bold, uppercase only
- * - 'scr': Script style, uppercase only
- *
- * @param {string} [style.series=''] - The font 'series', i.e. weight and
- * stretch. The following values can be combined, for example: "ebc": extra-bold,
- * condensed. Aside from 'b', these attributes may not have visible effect if the
+ *
+ | | |
+ | :---------- | :---------- |
+ |`"cmr"`| Computer Modern Roman, serif|
+ |`"cmss"`| Computer Modern Sans-serif, latin characters only|
+ |`"cmtt"`| Typewriter, slab, latin characters only|
+ |`"cal"`| Calligraphic style, uppercase latin letters and digits only|
+ |`"frak"`| Fraktur, gothic, uppercase, lowercase and digits|
+ |`"bb"`| Blackboard bold, uppercase only|
+ |`"scr"`| Script style, uppercase only|
+ *
+ * @param {string} [style.series] - The font 'series', i.e. weight and
+ * stretch.
+ *
+ * The following values can be combined, for example: `"ebc"`: extra-bold,
+ * condensed. Aside from `"b"`, these attributes may not have visible effect if the
* font family does not support this attribute:
- * - 'ul' ultra-light weight
- * - 'el': extra-light
- * - 'l': light
- * - 'sl': semi-light
- * - 'm': medium (default)
- * - 'sb': semi-bold
- * - 'b': bold
- * - 'eb': extra-bold
- * - 'ub': ultra-bold
- * - 'uc': ultra-condensed
- * - 'ec': extra-condensed
- * - 'c': condensed
- * - 'sc': semi-condensed
- * - 'n': normal (default)
- * - 'sx': semi-expanded
- * - 'x': expanded
- * - 'ex': extra-expanded
- * - 'ux': ultra-expanded
- *
- * @param {string} [style.shape=''] - The font 'shape', i.e. italic.
- * - 'auto': italic or upright, depending on mode and letter (single letters are
- * italic in math mode)
- * - 'up': upright
- * - 'it': italic
- * - 'sl': slanted or oblique (often the same as italic)
- * - 'sc': small caps
- * - 'ol': outline
- *
- * @param {string} [style.size=''] - The font size: 'size1'...'size10'
- * 'size5' is the default size
+ *
+ | | |
+ | :---------- | :---------- |
+ |`"ul"`| ultra-light weight|
+ |`"el"`| extra-light|
+ |`"l"`| light|
+ |`"sl"`| semi-light|
+ |`"m"`| medium (default)|
+ |`"sb"`| semi-bold|
+ |`"b"`| bold|
+ |`"eb"`| extra-bold|
+ |`"ub"`| ultra-bold|
+ |`"uc"`| ultra-condensed|
+ |`"ec"`| extra-condensed|
+ |`"c"`| condensed|
+ |`"sc"`| semi-condensed|
+ |`"n"`| normal (default)|
+ |`"sx"`| semi-expanded|
+ |`"x"`| expanded|
+ |`"ex"`| extra-expanded|
+ |`"ux"`| ultra-expanded|
+ *
+ * @param {string} [style.shape] - The font "shape", i.e. italic or upright.
+ *
+ | | |
+ | :---------- | :---------- |
+ |`"auto"`| italic or upright, depending on mode and letter (single letters are italic in math mode)|
+ |`"up"`| upright|
+ |`"it"`| italic|
+ |`"sl"`| slanted or oblique (often the same as italic)|
+ |`"sc"`| small caps|
+ |`"ol"`| outline|
+ *
+ * @param {string} [style.size] - The font size: `"size1"`...`"size10"`.
+ * '"size5"' is the default size
+ *
+ * @category Changing the Content
* @method MathField#$applyStyle
*
*/
@@ -371,17 +581,25 @@ declare class MathField {
/**
* @param {string} keys - A string representation of a key combination.
*
- * For example `'Alt-KeyU'`.
+ * For example `"Alt-KeyU"`.
*
* See [W3C UIEvents](https://www.w3.org/TR/uievents/#code-virtual-keyboards)
- * @param {Event} evt
+ * for more information on the format of the descriptor.
+ *
+ * @param {Event?} [evt] - An event corresponding to the keystroke. Pass this
+ * event if the keystroke originated from a user interaction that produced it.
+ * If the keystroke is synthetic (for example, triggered in response to a
+ * click or other event not involving a keyboard), omit it.
* @return {boolean}
+ * @category Changing the Content
* @method MathField#$keystroke
*/
- $keystroke(keys: string, evt: Event): boolean;
+ $keystroke(keys: string, evt?: Event): boolean;
/**
- * Simulate a user typing the keys indicated by text.
+ * Simulates a user typing the keys indicated by text.
+ *
* @param {string} text - A sequence of one or more characters.
+ * @category Changing the Content
* @method MathField#$typedText
*/
$typedText(text: string): void;
@@ -389,78 +607,108 @@ declare class MathField {
*
* Update the configuration options for this mathfield.
*
- * @param {MathFieldConfig} [config={}] See {@tutorial CONFIG} for details.
+ * @param {MathFieldConfig} config - See {@tutorial CONFIG Configuration Options} for details.
*
* @method MathField#$setConfig
*/
- $setConfig(config?: MathFieldConfig): void;
+ $setConfig(config: MathFieldConfig): void;
/**
*
* Speak some part of the expression, either with or without synchronized highlighting.
*
- * @param {string} amount (all, selection, left, right, group, parent)
+ * @param {string} amount - `"all"`, `"selection"`, `"left"`, `"right"`, `"group"`, `"parent"`
* @param {object} speakOptions
- * @param {boolean} speakOptions.withHighlighting - If true, synchronized highlighting of speech will happen (if possible). Default is false.
+ * @param {boolean} speakOptions.withHighlighting - If true, synchronized
+ * highlighting of speech will happen (if possible). Default is false.
*
* @method MathField#speak_
*/
speak_(amount: string, speakOptions: {
withHighlighting: boolean;
}): void;
+ /**
+ * The DOM element this mathfield is attached to.
+ */
+ element: HTMLElement;
+ /**
+ * A set of key/value pairs that can
+ be used to customize the behavior of the mathfield
+ */
+ config: {
+ [key: string]: any;
+ };
+ /**
+ * A unique ID identifying this mathfield
+ */
+ id: string;
+ /**
+ * True if the keystroke caption
+ panel is visible
+ */
+ keystrokeCaptionVisible: boolean;
+ /**
+ * True if the virtual keyboard is
+ visible
+ */
+ virtualKeyboardVisible: boolean;
+ /**
+ * The last few keystrokes, to look out
+ for inline shortcuts
+ */
+ keystrokeBuffer: string;
+ /**
+ * The saved state for each of the
+ past keystrokes
+ */
+ keystrokeBufferStates: object[];
}
-/**
- * Return an array of potential shortcuts
- * @param {string} s
- * @param {object} config
- * @return {string[]}
- */
-declare function startsWithString(s: string, config: any): string[];
-
/**
*
- * @param {string} mode
- * @param {object[]} siblings atoms preceding this potential shortcut
- * @param {string} shortcut
- */
-declare function validateShortcut(mode: string, siblings: object[], shortcut: string): void;
-
-/**
+ * Use MathLive to render and edit mathematical formulas in your browser.
*
- * This modules exports the MathLive entry points.
+ * This module exports {@link #functions%3Amathlive some functions} and the {@link #class%3AMathField `MathField`} class.
+ *
+ * See {@tutorial USAGE_GUIDE the Usage Guide} for more details on how to get
+ * started.
*
- * @module mathlive
* @example
- * // To invoke the functions in this module, import the MathLive module.
+ * // To invoke the functions in this module, import the `mathlive` module.
+ *
+ * import mathlive from 'dist/mathlive.mjs';
*
- * import MathLive from 'dist/mathlive.mjs';
+ * console.log(mathlive.latexToMarkup('e^{i\\pi}+1=0'));
*
- * const markup = MathLive.latexToMarkup('e^{i\\pi}+1=0');
+ * @module mathlive
+ * @packageDocumentation MathLive API Reference
*
*/
declare module "mathlive" {
/**
- * Convert a LaTeX string to a string of HTML markup.
+ * Converts a LaTeX string to a string of HTML markup.
*
* @param {string} text A string of valid LaTeX. It does not have to start
* with a mode token such as `$$` or `\(`.
*
- * @param {string} mathstyle If `'displaystyle'` the "display" mode of TeX
+ * @param {"displaystyle" | "textstyle"} mathstyle If `'displaystyle'` the "display" mode of TeX
* is used to typeset the formula, which is most appropriate for formulas that are
- * displayed in a standalone block. If `'textstyle'` is used, the "text" mode
+ * displayed in a standalone block.
+ *
+ * If `'textstyle'` is used, the "text" mode
* of TeX is used, which is most appropriate when displaying math "inline"
* with other text (on the same line).
*
- * @param {string} [format='html'] For debugging purposes, this function
+ * @param {"mathlist" | "span" | "html"} [format='html'] For debugging purposes, this function
* can also return a text representation of internal data structures
- * used to construct the markup. Valid values include `'mathlist'` and `'span'`
+ * used to construct the markup.
*
* @return {string}
+ * @category Converting
* @function module:mathlive#latexToMarkup
*/
- function latexToMarkup(text: string, mathstyle: string, format?: string): string;
+ function latexToMarkup(text: string, mathstyle: "displaystyle" | "textstyle", format?: "mathlist" | "span" | "html"): string;
/**
- * Convert a DOM element into an editable math field.
+ * Convert a DOM element into an editable mathfield.
*
* After the DOM element has been created, the value `element.mathfield` will
* return a reference to the mathfield object. This value is also returned
@@ -488,45 +736,93 @@ declare module "mathlive" {
*/
function makeMathField(element: HTMLElement | string, config?: MathFieldConfig): MathField;
/**
- * Convert a LaTeX string to a string of MathML markup.
+ * Converts a LaTeX string to a string of MathML markup.
*
* @param {string} latex A string of valid LaTeX. It does not have to start
* with a mode token such as a `$$` or `\(`.
* @param {object} options
- * @param {boolean} [options.generateID=false] - If true, add an `extid` attribute
- * to the MathML nodes with a value matching the `atomID`.
+ * @param {boolean} [options.generateID=false] - If true, add an `"extid"` attribute
+ * to the MathML nodes with a value matching the `atomID`. This can be used
+ * to map items on the screen with their MathML representation or vice-versa.
* @return {string}
+ * @category Converting
* @function module:mathlive#latexToMathML
*/
function latexToMathML(latex: string, options: {
generateID?: boolean;
}): string;
/**
- * Convert a LaTeX string to an Abstract Syntax Tree
+ * Converts a LaTeX string to an Abstract Syntax Tree (MathJSON)
*
- * **See:** {@tutorial MASTON}
+ * **See:** {@tutorial MATHJSON}
*
* @param {string} latex A string of valid LaTeX. It does not have to start
* with a mode token such as a `$$` or `\(`.
+ * @param {Object.} options
+ * @param {object} [options.macros] A dictionary of LaTeX macros
*
- * @return {object} The Abstract Syntax Tree as a JavaScript object.
+ * @return {object} The Abstract Syntax Tree as an object literal using the MathJSON format.
+ * @category Converting
* @function module:mathlive#latexToAST
*/
- function latexToAST(latex: string): any;
+ function latexToAST(latex: string, options: {
+ macros?: any;
+ }): any;
+ /**
+ * Converts an Abstract Syntax Tree (MathJSON) to a LaTeX string.
+ *
+ * **See:** {@tutorial MATHJSON}
+ *
+ * @param {object} ast - The Abstract Syntax Tree as an object literal (MathJSON).
+ * @param {Object.} options
+ * @param {number} [options.precision=14] The number of digits used in the
+ * representation of numbers. **Default** = 14.
+ * @param {string} [options.decimalMarker='.'] The character used as the decimal
+ * marker. **Default** = `"."`.
+ * @param {string} [options.groupSeparator='\\, '] The character used to separate group of numbers, typically thousands. **Default** = `"\\, "`
+ * @param {string} [options.product='\\cdot '] The character used to indicate product. Other option would be `"\\times "`. **Default** = `"\\cdot "`
+ * @param {string} [options.exponentProduct='\\cdot '] The character used before an
+ * exponent indicator. **Default** = `"\\cdot "`
+ * @param {string} [options.exponentMarker=''] The character used to indicate an
+ * exponent. **Default** = `""`
+ * @param {"auto" | "engineering" | "on"} [options.scientificNotation='auto'] The format used for numbers
+ * using the scientific notation. **Default** = `"auto"`
+ * @param {string} [options.beginRepeatingDigits='\\overline{'] The string
+ * used at the begining of repeating digits. **Default** = `"\\overline{"`
+ * @param {string} [options.endRepeatingDigits='}'] The string
+ * used at the end of repeating digits. **Default** = `"}"`
+ *
+ * @return {string} The LaTeX representation of the Abstract Syntax Tree, if valid.
+ * @category Converting
+ * @function module:mathlive#astToLatex
+ */
+ function astToLatex(ast: any, options: {
+ precision?: number;
+ decimalMarker?: string;
+ groupSeparator?: string;
+ product?: string;
+ exponentProduct?: string;
+ exponentMarker?: string;
+ scientificNotation?: "auto" | "engineering" | "on";
+ beginRepeatingDigits?: string;
+ endRepeatingDigits?: string;
+ }): string;
/**
- * Convert a LaTeX string to a textual representation ready to be spoken
+ * Converts a LaTeX string to a textual representation ready to be spoken
*
* @param {string} latex A string of valid LaTeX. It does not have to start
* with a mode token such as a `$$` or `\(`.
*
- * @param {Object.} options -
+ * @param {Object.} options
+ *
+ * @param {"mathlive" | "sre"} [options.textToSpeechRules='mathlive'] The set of text to
+ * speech rules to use.
*
- * @param {string} [options.textToSpeechRules='mathlive'] Specify which
- * set of text to speech rules to use.
+ * A value of `"mathlive"` (the default) indicates that
+ * the simple rules built into MathLive should be used.
*
- * A value of `mathlive` indicates that
- * the simple rules built into MathLive should be used. A value of `sre`
- * indicates that the Speech Rule Engine from Volker Sorge should be used.
+ * A value of `"sre"` indicates that the Speech Rule Engine from Volker Sorge
+ * should be used.
* Note that SRE is not included or loaded by MathLive and for this option to
* work SRE should be loaded separately.
*
@@ -534,7 +830,7 @@ declare module "mathlive" {
* for the output of conversion to spoken text.
*
* Possible values are `ssml` for
- * the SSML markup or `mac` for the MacOS markup (e.g. `[[ltr]]`)
+ * the SSML markup or `mac` for the MacOS markup (e.g. `"[[ltr]]"`)
*
* @param {Object.} [options.textToSpeechRulesOptions={}] A set of
* key/value pairs that can be used to configure the speech rule engine.
@@ -546,49 +842,55 @@ declare module "mathlive" {
* @example
* console.log(MathLive.latexToSpeakableText('\\frac{1}{2}'));
* // ➡︎'half'
+ * @category Converting
* @function module:mathlive#latexToSpeakableText
*/
function latexToSpeakableText(latex: string, options: {
- textToSpeechRules?: string;
+ textToSpeechRules?: "mathlive" | "sre";
textToSpeechMarkup?: string;
textToSpeechRulesOptions?: {
[key: string]: any;
};
}): string;
/**
- * Highlight the span corresponding to the specified atomID
- * This is used for TTS with synchronized highlighting (read aloud)
+ * Highlights the span corresponding to the specified atomID.
+ *
+ * This is used for text-to-speech with synchronized highlighting (read aloud)
*
+ * @category Read Aloud
* @param {string} atomID
*
*/
function highlightAtomID(atomID: string): void;
/**
- * Return the status of a Read Aloud operation (reading with synchronized
+ * Returns the status of a Read Aloud operation (reading with synchronized
* highlighting).
*
- * Possible values include:
- * - `ready`
- * - `playing`
- * - `paused`
- * - `unavailable`
+ * Possible values are:
+ * - `"ready"`
+ * - `"playing"`
+ * - `"paused"`
+ * - `"unavailable"`
*
* **See** {@linkcode module:editor-mathfield#speak speak}
- * @return {string}
+ * @category Read Aloud
+ * @return {"ready" | "playing" | "paused" | "unavailable"}
* @function module:mathlive#readAloudStatus
*/
- function readAloudStatus(): string;
+ function readAloudStatus(): "ready" | "playing" | "paused" | "unavailable";
/**
- * If a Read Aloud operation is in progress, stop it.
+ * Pauses a read aloud operation if one is in progress.
*
* **See** {@linkcode module:editor/mathfield#speak speak}
+ * @category Read Aloud
* @function module:mathlive#pauseReadAloud
*/
function pauseReadAloud(): void;
/**
- * If a Read Aloud operation is paused, resume it
+ * Resumes a read aloud operation if one was paused.
*
* **See** {@linkcode module:editor-mathfield#speak speak}
+ * @category Read Aloud
* @function module:mathlive#resumeReadAloud
*/
function resumeReadAloud(): void;
@@ -597,11 +899,12 @@ declare module "mathlive" {
*
* **See** {@linkcode module:editor-mathfield#speak speak}
*
- * @param {string} token
- * @param {number} [count]
+ * @param {string} [token]
+ * @param {number} [count] The number of tokens to read.
+ * @category Read Aloud
* @function module:mathlive#playReadAloud
*/
- function playReadAloud(token: string, count?: number): void;
+ function playReadAloud(token?: string, count?: number): void;
/**
* Transform all the elements in the document body that contain LaTeX code
* into typeset math.
@@ -728,7 +1031,7 @@ declare module "mathlive" {
/**
* After calling {@linkcode module:mathlive#renderMathInElement renderMathInElement}
* or {@linkcode module:mathlive#makeMathField makeMathField} the original content
- * can be retrived by calling this function.
+ * can be retrieved by calling this function.
*
* Given the following markup:
* ```html
@@ -748,7 +1051,7 @@ declare module "mathlive" {
* @param {object} [options={}]
* @param {string} [options.namespace=""] The namespace used for the `data-`
* attributes.
- * If you used a namespace with `renderMathInElement`, you must
+ * If you used a namespace with `renderMathInElement()`, you must
* use the same namespace here.
* @return {string} the original content of the element.
* @function module:mathlive#getOriginalContent
diff --git a/dist/mathlive.js b/dist/mathlive.js
index ee192f9d0..536c70204 100644
--- a/dist/mathlive.js
+++ b/dist/mathlive.js
@@ -1,917 +1 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = void 0;
-
-var _lexer = _interopRequireDefault(require("./core/lexer.js"));
-
-var _mathAtom = _interopRequireDefault(require("./core/mathAtom.js"));
-
-var _parser = _interopRequireDefault(require("./core/parser.js"));
-
-var _span = _interopRequireDefault(require("./core/span.js"));
-
-var _definitions = _interopRequireDefault(require("./core/definitions.js"));
-
-var _editorMathfield = _interopRequireDefault(require("./editor/editor-mathfield.js"));
-
-var _autoRender = _interopRequireDefault(require("./addons/auto-render.js"));
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/**
- *
- * This modules exports the MathLive entry points.
- *
- * @module mathlive
- * @example
- * // 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');
- *
- */
-
-/**
- * Convert a LaTeX string to a string of HTML markup.
- *
- * @param {string} text A string of valid LaTeX. It does not have to start
- * with a mode token such as `$$` or `\(`.
- *
- * @param {string} mathstyle If `'displaystyle'` the "display" mode of TeX
- * is used to typeset the formula, which is most appropriate for formulas that are
- * displayed in a standalone block. If `'textstyle'` is used, the "text" mode
- * of TeX is used, which is most appropriate when displaying math "inline"
- * with other text (on the same line).
- *
- * @param {string} [format='html'] For debugging purposes, this function
- * can also return a text representation of internal data structures
- * used to construct the markup. Valid values include `'mathlist'` and `'span'`
- *
- * @return {string}
- * @function module:mathlive#latexToMarkup
- */
-function toMarkup(text, mathstyle, format, macros) {
- mathstyle = mathstyle || 'displaystyle';
- console.assert(/displaystyle|textstyle|scriptstyle|scriptscriptstyle/.test(mathstyle), "Invalid style:", mathstyle); //
- // 1. Tokenize the text
- //
-
- var tokens = _lexer.default.tokenize(text); //
- // 2. Parse each token in the formula
- // Turn the list of tokens in the formula into
- // a tree of high-level MathAtom, e.g. 'genfrac'.
- //
-
-
- var mathlist = _parser.default.parseTokens(tokens, 'math', null, macros);
-
- if (format === 'mathlist') return mathlist; //
- // 3. Transform the math atoms into elementary spans
- // for example from genfrac to vlist.
- //
-
- var spans = _mathAtom.default.decompose({
- mathstyle: mathstyle
- }, mathlist); //
- // 4. Simplify by coalescing adjacent nodes
- // for example, from 12
- // to 12
- //
-
-
- spans = _span.default.coalesce(spans);
- if (format === 'span') return spans; //
- // 5. Wrap the expression with struts
- //
-
- var base = _span.default.makeSpan(spans, 'ML__base');
-
- var topStrut = _span.default.makeSpan('', 'ML__strut');
-
- topStrut.setStyle('height', base.height, 'em');
- var struts = [topStrut];
-
- if (base.depth !== 0) {
- var bottomStrut = _span.default.makeSpan('', 'ML__strut--bottom');
-
- bottomStrut.setStyle('height', base.height + base.depth, 'em');
- bottomStrut.setStyle('vertical-align', -base.depth, 'em');
- struts.push(bottomStrut);
- }
-
- struts.push(base);
-
- var wrapper = _span.default.makeSpan(struts, 'ML__mathlive'); //
- // 6. Generate markup
- //
-
-
- return wrapper.toMarkup();
-}
-/**
- * Convert a DOM element into an editable math field.
- *
- * After the DOM element has been created, the value `element.mathfield` will
- * return a reference to the mathfield object. This value is also returned
- * by `makeMathField`
- *
- * @param {HTMLElement|string} element A DOM element, for example as obtained
- * by `document.getElementById()`, or the ID of a DOM element as a string.
- *
- * @param {MathFieldConfig} [config={}] See {@tutorial CONFIG} for details.
- *
- *
- * @return {MathField}
- *
- * Given the HTML markup:
- * ```html
- * $f(x)=sin(x)$
- * ```
- * The following code will turn the span into an editable mathfield.
- * ```
- * import MathLive from 'dist/mathlive.mjs';
- * MathLive.makeMathField('equation');
- * ```
- *
- * @function module:mathlive#makeMathField
- */
-
-
-function makeMathField(element, config) {
- if (!_editorMathfield.default) {
- throw Error('The MathField module is not loaded.');
- }
-
- config = config || {};
- config.handleSpeak = config.handleSpeak || speak;
- config.handleReadAloud = config.handleReadAloud || readAloud;
- return new _editorMathfield.default.MathField(getElement(element), config);
-}
-/**
- * Convert a LaTeX string to a string of MathML markup.
- *
- * @param {string} latex A string of valid LaTeX. It does not have to start
- * with a mode token such as a `$$` or `\(`.
- * @param {object} options
- * @param {boolean} [options.generateID=false] - If true, add an `extid` attribute
- * to the MathML nodes with a value matching the `atomID`.
- * @return {string}
- * @function module:mathlive#latexToMathML
- */
-
-
-function toMathML(latex, options) {
- if (!_mathAtom.default.toMathML) {
- console.warn('The MathML module is not loaded.');
- return '';
- }
-
- options = options || {};
- options.macros = options.macros || {};
- Object.assign(options.macros, _definitions.default.MACROS);
-
- var mathlist = _parser.default.parseTokens(_lexer.default.tokenize(latex), 'math', null, options.macros);
-
- return _mathAtom.default.toMathML(mathlist, options);
-}
-/**
- * Convert a LaTeX string to an Abstract Syntax Tree
- *
- * **See:** {@tutorial MASTON}
- *
- * @param {string} latex A string of valid LaTeX. It does not have to start
- * with a mode token such as a `$$` or `\(`.
- *
- * @return {object} The Abstract Syntax Tree as a JavaScript object.
- * @function module:mathlive#latexToAST
- */
-
-
-function latexToAST(latex, options) {
- if (!_mathAtom.default.toAST) {
- console.warn('The AST module is not loaded.');
- return {};
- }
-
- options = options || {};
- options.macros = options.macros || {};
- Object.assign(options.macros, _definitions.default.MACROS);
-
- var mathlist = _parser.default.parseTokens(_lexer.default.tokenize(latex), 'math', null, options.macros);
-
- return _mathAtom.default.toAST(mathlist, options);
-}
-/**
- * Convert a LaTeX string to a textual representation ready to be spoken
- *
- * @param {string} latex A string of valid LaTeX. It does not have to start
- * with a mode token such as a `$$` or `\(`.
- *
- * @param {Object.} options -
- *
- * @param {string} [options.textToSpeechRules='mathlive'] Specify which
- * set of text to speech rules to use.
- *
- * A value of `mathlive` indicates that
- * the simple rules built into MathLive should be used. A value of `sre`
- * indicates that the Speech Rule Engine from Volker Sorge should be used.
- * Note that SRE is not included or loaded by MathLive and for this option to
- * work SRE should be loaded separately.
- *
- * @param {string} [options.textToSpeechMarkup=''] The markup syntax to use
- * for the output of conversion to spoken text.
- *
- * Possible values are `ssml` for
- * the SSML markup or `mac` for the MacOS markup (e.g. `[[ltr]]`)
- *
- * @param {Object.} [options.textToSpeechRulesOptions={}] A set of
- * key/value pairs that can be used to configure the speech rule engine.
- *
- * Which options are available depends on the speech rule engine in use. There
- * are no options available with MathLive's built-in engine. The options for
- * the SRE engine are documented [here]{@link:https://github.com/zorkow/speech-rule-engine}
- * @return {string} The spoken representation of the input LaTeX.
- * @example
- * console.log(MathLive.latexToSpeakableText('\\frac{1}{2}'));
- * // ➡︎'half'
- * @function module:mathlive#latexToSpeakableText
- */
-
-
-function latexToSpeakableText(latex, options) {
- if (!_mathAtom.default.toSpeakableText) {
- console.warn('The outputSpokenText module is not loaded.');
- return "";
- }
-
- options = options || {};
- options.macros = options.macros || {};
- Object.assign(options.macros, _definitions.default.MACROS);
-
- var mathlist = _parser.default.parseTokens(_lexer.default.tokenize(latex), 'math', null, options.macros);
-
- return _mathAtom.default.toSpeakableText(mathlist, options);
-}
-
-function removeHighlight(node) {
- node.classList.remove('highlight');
-
- if (node.children) {
- Array.from(node.children).forEach(function (x) {
- removeHighlight(x);
- });
- }
-}
-/**
- * Highlight the span corresponding to the specified atomID
- * This is used for TTS with synchronized highlighting (read aloud)
- *
- * @param {string} atomID
- *
- */
-
-
-function highlightAtomID(node, atomID) {
- if (!atomID || node.dataset.atomId === atomID) {
- node.classList.add('highlight');
-
- if (node.children && node.children.length > 0) {
- Array.from(node.children).forEach(function (x) {
- highlightAtomID(x);
- });
- }
- } else {
- node.classList.remove('highlight');
-
- if (node.children && node.children.length > 0) {
- Array.from(node.children).forEach(function (x) {
- highlightAtomID(x, atomID);
- });
- }
- }
-}
-
-function speak(text, config) {
- if (!config && window && window.mathlive) {
- config = window.mathlive.config;
- }
-
- config = config || {};
-
- if (!config.speechEngine || config.speechEngine === 'local') {
- // On ChromeOS: chrome.accessibilityFeatures.spokenFeedback
- // See also https://developer.chrome.com/apps/tts
- var utterance = new SpeechSynthesisUtterance(text);
-
- if (window) {
- window.speechSynthesis.speak(utterance);
- } else {
- console.log('Speak: ', text);
- }
- } else if (config.speechEngine === 'amazon') {
- if (!window || !window.AWS) {
- console.warn('AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk');
- } else {
- var polly = new window.AWS.Polly({
- apiVersion: '2016-06-10'
- });
- var params = {
- OutputFormat: 'mp3',
- VoiceId: config.speechEngineVoice || 'Joanna',
- // SampleRate: '16000',
- Text: text,
- TextType: 'ssml' // SpeechMarkTypes: ['ssml]'
-
- };
- polly.synthesizeSpeech(params, function (err, data) {
- if (err) {
- console.warn('polly.synthesizeSpeech() error:', err, err.stack);
- } else {
- if (data && data.AudioStream) {
- var uInt8Array = new Uint8Array(data.AudioStream);
- var blob = new Blob([uInt8Array.buffer], {
- type: 'audio/mpeg'
- });
- var url = URL.createObjectURL(blob);
- var audioElement = new Audio(url);
- audioElement.play().catch(function (err) {
- return console.log(err);
- });
- } else {
- console.log('polly.synthesizeSpeech():' + data);
- }
- }
- }); // Can call AWS.Request() on the result of synthesizeSpeech()
- }
- } else if (config.speechEngine === 'google') {
- console.warn('The Google speech engine is not supported yet. Please come again.'); // @todo: implement support for Google Text-to-Speech API,
- // using config.speechEngineToken, config.speechEngineVoice and
- // config.speechEngineAudioConfig
- // 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
- }
-}
-/**
- * "Read Aloud" is an asynchronous operation that reads the
- * reading with synchronized highlighting
- *
- * @param {DOMElement} element - The DOM element to highlight
- * @param {string} text - The text to speak
- * @param {object} config
- * @private
- * @function module:mathlive#readAloud
- */
-
-
-function readAloud(element, text, config) {
- if (!window) {
- return;
- }
-
- if (!config && window.mathlive) {
- config = window.mathlive.config;
- }
-
- config = config || {};
-
- if (config.speechEngine !== 'amazon') {
- console.warn('Use Amazon TTS Engine for synchronized highlighting');
- if (config.handleSpeak) config.handleSpeak(text);
- return;
- }
-
- if (!window.AWS) {
- console.warn('AWS SDK not loaded. See https://www.npmjs.com/package/aws-sdk');
- return;
- }
-
- var polly = new window.AWS.Polly({
- apiVersion: '2016-06-10'
- });
- var params = {
- OutputFormat: 'json',
- VoiceId: config.speechEngineVoice || 'Joanna',
- Text: text,
- TextType: 'ssml',
- SpeechMarkTypes: ['ssml']
- };
- window.mathlive = window.mathlive || {};
- window.mathlive.readAloudElement = element;
- var status = config.onReadAloudStatus || window.mathlive.onReadAloudStatus; // Request the mark points
-
- polly.synthesizeSpeech(params, function (err, data) {
- if (err) {
- console.warn('polly.synthesizeSpeech() error:', err, err.stack);
- } else {
- if (data && data.AudioStream) {
- var response = new TextDecoder('utf-8').decode(new Uint8Array(data.AudioStream));
- window.mathlive.readAloudMarks = response.split('\n').map(function (x) {
- return x ? JSON.parse(x) : {};
- });
- window.mathlive.readAloudTokens = [];
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
-
- try {
- for (var _iterator = window.mathlive.readAloudMarks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
- var mark = _step.value;
-
- if (mark.value) {
- window.mathlive.readAloudTokens.push(mark.value);
- }
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return != null) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
- }
- }
-
- window.mathlive.readAloudCurrentMark = ''; // Request the audio
-
- params.OutputFormat = 'mp3';
- params.SpeechMarkTypes = [];
- polly.synthesizeSpeech(params, function (err, data) {
- if (err) {
- console.warn('polly.synthesizeSpeech(', text, ') error:', err, err.stack);
- } else {
- if (data && data.AudioStream) {
- var uInt8Array = new Uint8Array(data.AudioStream);
- var blob = new Blob([uInt8Array.buffer], {
- type: 'audio/mpeg'
- });
- var url = URL.createObjectURL(blob);
-
- if (!window.mathlive.readAloudAudio) {
- window.mathlive.readAloudAudio = new Audio();
- window.mathlive.readAloudAudio.addEventListener('ended', function () {
- 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', function () {
- var 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.
-
- var target = window.mathlive.readAloudAudio.currentTime * 1000 + 100; // Find the smallest element which is bigger than the target time
-
- var _iteratorNormalCompletion2 = true;
- var _didIteratorError2 = false;
- var _iteratorError2 = undefined;
-
- try {
- for (var _iterator2 = window.mathlive.readAloudMarks[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
- var mark = _step2.value;
-
- if (mark.time < target) {
- value = mark.value;
- }
- }
- } catch (err) {
- _didIteratorError2 = true;
- _iteratorError2 = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
- _iterator2.return();
- }
- } finally {
- if (_didIteratorError2) {
- throw _iteratorError2;
- }
- }
- }
-
- 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 {
- window.mathlive.readAloudAudio.pause();
- }
-
- window.mathlive.readAloudAudio.src = url;
-
- if (status) {
- status(window.mathlive.readAloudMathField, 'playing');
- }
-
- window.mathlive.readAloudAudio.play();
- } else {// console.log('polly.synthesizeSpeech():' + data);
- }
- }
- });
- } else {
- console.log('polly.synthesizeSpeech():' + data);
- }
- }
- });
-}
-/**
- * Return the status of a Read Aloud operation (reading with synchronized
- * highlighting).
- *
- * Possible values include:
- * - `ready`
- * - `playing`
- * - `paused`
- * - `unavailable`
- *
- * **See** {@linkcode module:editor-mathfield#speak speak}
- * @return {string}
- * @function module:mathlive#readAloudStatus
- */
-
-
-function readAloudStatus() {
- if (!window) return 'unavailable';
- window.mathlive = window.mathlive || {};
- if (!window.mathlive.readAloudAudio) return 'ready';
- if (window.mathlive.readAloudAudio.paused) return 'paused';
- if (!window.mathlive.readAloudAudio.ended) return 'playing';
- return 'ready';
-}
-/**
- * If a Read Aloud operation is in progress, stop it.
- *
- * **See** {@linkcode module:editor/mathfield#speak speak}
- * @function module:mathlive#pauseReadAloud
- */
-
-
-function pauseReadAloud() {
- if (!window) return;
- window.mathlive = window.mathlive || {};
-
- if (window.mathlive.readAloudAudio) {
- if (window.mathlive.onReadAloudStatus) {
- window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'paused');
- }
-
- window.mathlive.readAloudAudio.pause();
- }
-}
-/**
- * If a Read Aloud operation is paused, resume it
- *
- * **See** {@linkcode module:editor-mathfield#speak speak}
- * @function module:mathlive#resumeReadAloud
- */
-
-
-function resumeReadAloud() {
- if (!window) return;
- window.mathlive = window.mathlive || {};
-
- if (window.mathlive.readAloudAudio) {
- if (window.mathlive.onReadAloudStatus) {
- window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'playing');
- }
-
- window.mathlive.readAloudAudio.play();
- }
-}
-/**
- * If a Read Aloud operation is in progress, read from a specified token
- *
- * **See** {@linkcode module:editor-mathfield#speak speak}
- *
- * @param {string} token
- * @param {number} [count]
- * @function module:mathlive#playReadAloud
- */
-
-
-function playReadAloud(token, count) {
- if (!window) return;
- window.mathlive = window.mathlive || {};
-
- if (window.mathlive.readAloudAudio) {
- var timeIndex = 0;
- window.mathlive.readAloudFinalToken = null;
-
- if (token) {
- window.mathlive.readAloudMarks = window.mathlive.readAloudMarks || [];
- var _iteratorNormalCompletion3 = true;
- var _didIteratorError3 = false;
- var _iteratorError3 = undefined;
-
- try {
- for (var _iterator3 = window.mathlive.readAloudMarks[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
- var mark = _step3.value;
-
- if (mark.value === token) {
- timeIndex = mark.time / 1000;
- }
- }
- } catch (err) {
- _didIteratorError3 = true;
- _iteratorError3 = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
- _iterator3.return();
- }
- } finally {
- if (_didIteratorError3) {
- throw _iteratorError3;
- }
- }
- }
-
- var tokenIndex = window.mathlive.readAloudTokens.indexOf(token);
-
- if (tokenIndex >= 0) {
- tokenIndex += count;
-
- if (tokenIndex < window.mathlive.readAloudTokens.length) {
- window.mathlive.readAloudFinalToken = tokenIndex;
- }
- }
- }
-
- window.mathlive.readAloudAudio.currentTime = timeIndex;
-
- if (window.mathlive.onReadAloudStatus) {
- window.mathlive.onReadAloudStatus(window.mathlive.readAloudMathField, 'playing');
- }
-
- window.mathlive.readAloudAudio.play();
- }
-}
-/**
- * Transform all the elements in the document body that contain LaTeX code
- * into typeset math.
- *
- * **Note:** This is a very expensive call, as it needs to parse the entire
- * DOM tree to determine which elements need to be processed. In most cases
- * this should only be called once per document, once the DOM has been loaded.
- * To render a specific element, use {@linkcode module:mathlive#renderMathInElement renderMathInElement()}
- *
- * **See:** {@tutorial USAGE_GUIDE}
- *
- * @param {object} [options={}] See {@linkcode module:mathlive#renderMathInElement renderMathInElement()}
- * for details
- * @example
- * import MathLive from 'dist/mathlive.mjs';
- * document.addEventListener("load", () => {
- * MathLive.renderMathInDocument();
- * });
- *
- */
-
-
-function renderMathInDocument(options) {
- renderMathInElement(document.body, options);
-}
-
-function getElement(element) {
- var result = element;
-
- if (typeof element === 'string') {
- result = document.getElementById(element);
-
- if (!result) {
- throw Error("The element with ID \"".concat(element, "\" could not be found."));
- }
- }
-
- return result;
-}
-/**
- * Transform all the children of `element`, recursively, that contain LaTeX code
- * into typeset math.
- *
- * **See:** {@tutorial USAGE_GUIDE}
- *
- * @param {HTMLElement|string} element An HTML DOM element, or a string containing
- * the ID of an element.
- * @param {object} [options={}]
- *
- * @param {string} [options.namespace=''] - Namespace that is added to `data-`
- * attributes to avoid collisions with other libraries.
- *
- * It is empty by default.
- *
- * The namespace should be a string of lowercase letters.
- *
- * @param {object[]} [options.macros={}] - Custom LaTeX macros
- *
- * @param {string[]} [options.skipTags=['noscript', 'style', 'textarea', 'pre', 'code', 'annotation', 'annotation-xml'] ]
- * an array of tag names whose content will
- * not be scanned for delimiters (unless their class matches the `processClass`
- * pattern below.
- *
- * @param {string} [options.ignoreClass='tex2jax_ignore'] a string used as a
- * regular expression of class names of elements whose content will not be
- * scanned for delimiters
-
- * @param {string} [options.processClass='tex2jax_process'] a string used as a
- * regular expression of class names of elements whose content **will** be
- * scanned for delimiters, even if their tag name or parent class name would
- * have prevented them from doing so.
- *
- * @param {string} [options.processScriptType="math/tex"] `
-
+
diff --git a/docs/EditableMathlist.html b/docs/EditableMathlist.html
index 0e9ac6bda..67bcdb129 100644
--- a/docs/EditableMathlist.html
+++ b/docs/EditableMathlist.html
@@ -7,7 +7,7 @@
-
+
@@ -40,7 +40,7 @@
This is usually done automatically, but if the font-size, or other geometric
attributes are modified, outside of MathLive, this function may need to be
called explicitly.