diff --git a/.coveragerc b/.coveragerc index 4a52ddc..71910f2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,14 +2,14 @@ branch = True concurrency = multiprocessing, thread parallel = True -source_pkgs = wagtailmath +source_pkgs = wagtail-polymath omit = **/migrations/* tests/* [paths] source = - src/wagtailmath + src/wagtail_polymath .tox/py*/**/site-packages [report] diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 76fbb1f..33ef5f7 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -20,4 +20,4 @@ jobs: - name: Run ruff working-directory: ./src - run: ruff --output-format=github wagtailmath + run: ruff check --output-format=github diff --git a/CHANGELOG.md b/CHANGELOG.md index 12ed943..24c1916 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - added tests skeleton - Added support for Wagtail 5.2+ - Dropped support for Wagtail < 5.2, Django < 4.2 +- Rename package to wagtail_polymath ## 1.2.0 (2021-05-18) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index b5130de..0000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,13 +0,0 @@ -# Credits - -## Maintainers - -- The Wagtail Nest crew - -## Original development Lead - -- James Ramm (jamessramm@gmail.com) - -# Contributors - -- Andre Bar\'yudin (https://www.baryudin.com/) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..525828c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include CONTRIBUTING.md +include CHANGELOG.md +include LICENSE +include README.md +recursive-include wagtail_polymath *.html *.png *.gif *js *.css *jpg *jpeg *svg *py diff --git a/README.md b/README.md index a4f35ab..56ee519 100644 --- a/README.md +++ b/README.md @@ -13,37 +13,20 @@ - [Discussions](https://github.com/wagtail-nest/wagtail-polymath/discussions) - [Security](https://github.com/wagtail-nest/wagtail-polymath/security) -wagtail-polymath allows you to write equations in your -[Wagtail](https://github.com/wagtail/wagtail) content using markup and -render them beautifully. +`wagtail-polymath` provides robust math typesetting capabilities in LaTeX syntax. +This project supports multiple typesetting engines, including MathJax and KaTeX, allowing users to choose the one that best fits their needs. -wagtail-polymath provides a `MathBlock` so you can write equations in markup -(TeX, MathML, ASCIIMath) and render them with MathJax. It features a -live preview: +- [LaTeX Syntax Support](https://en.wikibooks.org/wiki/LaTeX/Mathematics): Write complex mathematical expressions using familiar LaTeX syntax. +- Multiple Typesetting Engines: Currently, [MathJax](https://www.mathjax.org/) (default) and [KaTeX](https://katex.org/) are supported. +- Live preview.  -`MathBlock` uses MathJax for rendering so there is very little to do on -the front end. Simply include the MathJax JS and render the raw -`MathBlock` content as you would for any other streamfield plain text -block. - -wagtail-polymath even includes a template tag to include the MathJax JS for -you from a CDN. By default, MathJax is configured to accept all -recognised markup (TeX, MathML, ASCIIMath) and renders them to HTML. To -change the configuration, you can pass the desired config command to the -templatetag. See the [MathJax documentation](https://docs.mathjax.org/en/v2.7-latest/config-files.html#combined-configurations) -for possible configurations. - -For help on using the markup languages see the relevant MathJax -documentation (e.g. https://docs.mathjax.org/en/v2.7-latest/tex.html) and -the markup language-specific documentation (e.g. https://en.wikibooks.org/wiki/LaTeX) - ## Quickstart -Install wagtailmath: +Install wagtail-polymath: - pip install wagtailmath + pip install wagtail-polymath Add it to your `INSTALLED_APPS`: @@ -52,7 +35,7 @@ Add it to your `INSTALLED_APPS`: INSTALLED_APPS = ( # ... - "wagtailmath", + "wagtail_polymath", # ... ) ``` @@ -60,26 +43,79 @@ INSTALLED_APPS = ( Use `MathBlock` in your `StreamField` content: ```python -from wagtailmath.blocks import MathBlock +from wagtail_polymath.blocks import MathBlock class MyPage(Page): - body = StreamField([ - ('heading', blocks.CharBlock(classname="full title")), - ('paragraph', blocks.RichTextBlock()), - ('equation', MathBlock()) - ]) + body = StreamField( + [ + ('heading', blocks.CharBlock(classname="full title")), + ('paragraph', blocks.RichTextBlock()), + ('equation', MathBlock()) + ], + use_json_field=True, + ) + + content_panels = Page.content_panels + [FieldPanel("body")] ``` -Use the `mathjax` template tag in your front end template to load the -MathJax library: +Use the `polymath_js` template tag in your front-end template to load the typesetting library: ```django+html -{% load wagtailmath %} -... +{% load wagtail_polymath %} + +{# include this line in css block #} +{% polymath_css %} + +{# include this line in js block #} +{% polymath_js %} +``` + +Now you can use LaTeX syntax in your StreamField editor to create mathematical expressions. +By default, `wagtail-polymath` uses MathJax for rendering, but KaTeX is also supported (see below). + +## Settings + +If you wants to use KaTeX instead of MathJax, simply add the following line to your Django settings: + +```python +WAGTAIL_POLYMATH = "katex" +``` + +For those who want to specify the CDN provider or for internal site hosting. +The rendering javascript library path (file path for static files also supported) can be customized for different use cases. + +Default settings for `MathJax`: + +```python +WAGTAIL_POLYMATH = { + "js": [ + "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-MML-AM_CHTML", + ], +} +``` + +Default settings for `KaTeX`: - +```python +WAGTAIL_POLYMATH = { + "js": [ + "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js", + "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js", + ], + "css": ["https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css"], +} ``` +## Migration from `wagtail-math` + +- Django settings: + - Replace "wagtailmath" with "wagtail_polymath" in `INSTALLED_APPS` +- Import section: + - Replace "from wagtailmath.blocks import MathBlock" with "from wagtail_polymath.blocks import MathBlock" +- HTML template: + - Replace "wagtailmath" with "wagtail_polymath" in the load section + - Add "{% polymath_css %}" to the css block + - Replace "" with "{% polymath_js %}" in the js block ## Contributing diff --git a/docs/index.rst b/docs/index.rst index a378022..fa08630 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to wagtailmath's documentation! +Welcome to wagtail-polymath's documentation! ================================================================= Contents: diff --git a/docs/installation.rst b/docs/installation.rst index aa3c582..e0c5d8c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,9 +4,9 @@ Installation At the command line:: - $ easy_install wagtailmath + $ easy_install wagtail-polymath Or, if you have virtualenvwrapper installed:: - $ mkvirtualenv wagtailmath - $ pip install wagtailmath + $ mkvirtualenv wagtail-polymath + $ pip install wagtail-polymath diff --git a/pyproject.toml b/pyproject.toml index 4b6925e..39ac0aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["flit_core >=3.2,<4"] build-backend = "flit_core.buildapi" [project] -name = "wagtailmath" +name = "wagtail-polymath" authors = [{name = "James Ramm", email = "jamessramm@gmail.com"}] description = "Wagtail StreamField block for rendering mathematical equations" readme = "README.md" @@ -52,7 +52,7 @@ Changelog = "https://github.com/wagtail-nest/wagtail-polymath/blob/main/CHANGELO Documentation = "https://github.com/wagtail-nest/wagtail-polymath/blob/main/docs/" [tool.flit.module] -name = "wagtailmath" +name = "wagtail_polymath" [tool.flit.sdist] exclude = [ diff --git a/src/wagtail_polymath/__init__.py b/src/wagtail_polymath/__init__.py new file mode 100644 index 0000000..8c0d5d5 --- /dev/null +++ b/src/wagtail_polymath/__init__.py @@ -0,0 +1 @@ +__version__ = "2.0.0" diff --git a/src/wagtail_polymath/apps.py b/src/wagtail_polymath/apps.py new file mode 100644 index 0000000..04fdb97 --- /dev/null +++ b/src/wagtail_polymath/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class WagtailPolymathConfig(AppConfig): + name = "wagtail_polymath" diff --git a/src/wagtailmath/blocks.py b/src/wagtail_polymath/blocks.py similarity index 68% rename from src/wagtailmath/blocks.py rename to src/wagtail_polymath/blocks.py index 5d986cb..1fbc78b 100644 --- a/src/wagtailmath/blocks.py +++ b/src/wagtail_polymath/blocks.py @@ -2,12 +2,12 @@ from django.utils.functional import cached_property from wagtail.blocks import TextBlock -from .widgets import MathJaxWidget +from .widgets import PolymathTextareaWidget class MathBlock(TextBlock): @cached_property def field(self): - field_kwargs = {"widget": MathJaxWidget(attrs={"rows": self.rows})} + field_kwargs = {"widget": PolymathTextareaWidget(attrs={"rows": self.rows})} field_kwargs.update(self.field_options) return forms.CharField(**field_kwargs) diff --git a/src/wagtail_polymath/config.py b/src/wagtail_polymath/config.py new file mode 100644 index 0000000..6b5e88e --- /dev/null +++ b/src/wagtail_polymath/config.py @@ -0,0 +1,79 @@ +from django.conf import settings +from django.contrib.staticfiles import finders +from django.core.exceptions import ImproperlyConfigured, ValidationError +from django.core.validators import URLValidator +from wagtail import VERSION as WAGTAIL_VERSION +from wagtail.admin.staticfiles import versioned_static + + +# The path could be static files or external URLs. +DEFAULT_MATHJAX_SETTINGS = { + "js": [ + "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-MML-AM_CHTML", + ], + "widget": [ + "wagtail_polymath/js/polymath-widget-mathjax.js", + ], +} + +DEFAULT_KATEX_SETTINGS = { + "js": [ + "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js", + "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js", + ], + "widget": [ + "wagtail_polymath/js/polymath-widget-katex.js", + ], + "css": ["https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css"], +} + +polymath_settings = getattr(settings, "WAGTAIL_POLYMATH", "mathjax") +if isinstance(polymath_settings, str): + if polymath_settings == "mathjax": + POLYMATH_SETTINGS = DEFAULT_MATHJAX_SETTINGS + elif polymath_settings == "katex": + POLYMATH_SETTINGS = DEFAULT_KATEX_SETTINGS + else: + raise ImproperlyConfigured( + f"WAGTAIL_POLYMATH: invalid typesetting engine: `{polymath_settings}` (valid options: 'mathjax', 'katex')" + ) +elif isinstance(polymath_settings, dict): + POLYMATH_SETTINGS = polymath_settings +else: + raise ImproperlyConfigured("WAGTAIL_POLYMATH: invalid settings") + +if WAGTAIL_VERSION >= (6, 0): + POLYMATH_SETTINGS["widget"].append( + "wagtail_polymath/js/polymath-textarea-controller.js", + ) +else: + POLYMATH_SETTINGS["widget"].append( + "wagtail_polymath/js/polymath-textarea-adapter.js", + ) + + +def get_polymath_config(key): + paths = POLYMATH_SETTINGS.get(key, []) + + validator = URLValidator() + + validated_paths = [] + for path in paths: + if path.startswith("http"): + try: + validator(path) + except ValidationError as e: + raise ImproperlyConfigured( + f"WAGTAIL_POLYMATH: invalid url: `{path}`" + ) from e + validated_paths.append(path) + else: + # Return absolute path to the asset if it's a static file path. + if finders.find(path): + validated_paths.append(versioned_static(path)) + else: + raise ImproperlyConfigured( + f"WAGTAIL_POLYMATH: invalid resource path: `{path}`" + ) + + return validated_paths diff --git a/src/wagtailmath/models.py b/src/wagtail_polymath/models.py similarity index 100% rename from src/wagtailmath/models.py rename to src/wagtail_polymath/models.py diff --git a/src/wagtailmath/static/wagtailmath/js/mathjax-textarea-adapter.js b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-adapter.js similarity index 75% rename from src/wagtailmath/static/wagtailmath/js/mathjax-textarea-adapter.js rename to src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-adapter.js index de5f2e0..0cfc225 100644 --- a/src/wagtailmath/static/wagtailmath/js/mathjax-textarea-adapter.js +++ b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-adapter.js @@ -1,15 +1,15 @@ (function() { - function MathJaxTextarea(html, config) { + function PolymathxTextarea(html, config) { this.html = html; this.baseConfig = config; } - MathJaxTextarea.prototype.render = function(placeholder, name, id, initialState) { + PolymathTextarea.prototype.render = function(placeholder, name, id, initialState) { placeholder.outerHTML = this.html.replace(/__NAME__/g, name).replace(/__ID__/g, id); var element = document.getElementById(id); element.value = initialState; - initMathJaxPreview(id); + initPolymathTextareaPreview(id); // define public API functions for the widget: // https://docs.wagtail.io/en/latest/reference/streamfield/widget_api.html @@ -22,7 +22,7 @@ return element.value; }, setState: function() { - throw new Error('MathJaxTextarea.setState is not implemented'); + throw new Error('PolymathTextarea.setState is not implemented'); }, getTextLabel: function(opts) { if (!element.value) return ''; @@ -36,5 +36,5 @@ }; }; - window.telepath.register('wagtailmath.widgets.MathJaxWidget', MathJaxTextarea); + window.telepath.register('wagtail_polymath.widgets.PolymathTextareaWidget', PolymathxTextarea); })(); diff --git a/src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-controller.js b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-controller.js new file mode 100644 index 0000000..d422497 --- /dev/null +++ b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-textarea-controller.js @@ -0,0 +1,7 @@ +class PolymathTextareaController extends window.StimulusModule.Controller { + connect() { + initPolymathTextareaPreview(this.element.id); + } +} + +window.wagtail.app.register('polymath-textarea-controller', PolymathTextareaController); diff --git a/src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-katex.js b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-katex.js new file mode 100644 index 0000000..b0a7f60 --- /dev/null +++ b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-katex.js @@ -0,0 +1,54 @@ +// Preview class for KaTeX +class Preview { + constructor(previewId, bufferId, inputId) { + this.preview = document.getElementById(previewId); + this.buffer = document.getElementById(bufferId); + this.input = document.getElementById(inputId); + this.delay = 150; // delay after keystroke before updating + this.timeout = null; // store setTimout id + } + + update() { + if (this.timeout) { + clearTimeout(this.timeout); + } + this.timeout = setTimeout(() => { + this.render(); + }, this.delay); + } + + render() { + if (this.preview.innerHTML === this.input.value) { + return; + } + + this.preview.innerHTML = this.input.value; + renderMathInElement(this.preview, { + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + ], + throwOnError: false, + }); + } +} + +function initPolymathTextareaPreview(id) { + window.wagtailPolymathPreviews = window.WagtailPolymathPreviews || {}; + + window.wagtailPolymathPreviews[id] = new Preview( + "PolymathTextareaPreview-" + id, + "PolymathTextareaBuffer-" + id, + id, + ); + + window.wagtailPolymathPreviews[id].update(); + + // attach a keyup event listener so we update the preview + const target = document.getElementById(id); + if (target) { + target.addEventListener("keyup", function () { + window.wagtailPolymathPreviews[id].update(); + }); + } +} diff --git a/src/wagtailmath/static/wagtailmath/js/wagtailmath.js b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-mathjax.js similarity index 80% rename from src/wagtailmath/static/wagtailmath/js/wagtailmath.js rename to src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-mathjax.js index eebfcef..143b8f4 100644 --- a/src/wagtailmath/static/wagtailmath/js/wagtailmath.js +++ b/src/wagtail_polymath/static/wagtail_polymath/js/polymath-widget-mathjax.js @@ -1,3 +1,11 @@ +MathJax.Hub.Config({ + tex2jax: { + inlineMath: [ ["$", "$"] ], + displayMath: [ ["$$", "$$"] ], + processEscapes: true + } +}); + // Update the preview area on input. Lifted directly from mathjax website examples class Preview { @@ -80,25 +88,25 @@ class Preview { } -function initMathJaxPreview(id) { - window.wagtailMathPreviews = window.WagtailMathPreviews || {}; +function initPolymathTextareaPreview(id) { + window.wagtailPolymathPreviews = window.WagtailPolymathPreviews || {}; - window.wagtailMathPreviews[id] = new Preview( - "MathPreview-" + id, - "MathBuffer-" + id, + window.wagtailPolymathPreviews[id] = new Preview( + "PolymathTextareaPreview-" + id, + "PolymathTextareaBuffer-" + id, id ); // Cache a callback to the CreatePreview action - window.wagtailMathPreviews[id].callback = MathJax.Callback(["CreatePreview", window.wagtailMathPreviews[id]]); - window.wagtailMathPreviews[id].callback.autoReset = true; // make sure it can run more than once - window.wagtailMathPreviews[id].Update(); + window.wagtailPolymathPreviews[id].callback = MathJax.Callback(["CreatePreview", window.wagtailPolymathPreviews[id]]); + window.wagtailPolymathPreviews[id].callback.autoReset = true; // make sure it can run more than once + window.wagtailPolymathPreviews[id].Update(); // attach a keyup event listener so we update the preview const target = document.getElementById(id); if (target) { target.addEventListener("keyup", function() { - window.wagtailMathPreviews[id].Update(); + window.wagtailPolymathPreviews[id].Update(); }) } } diff --git a/src/wagtailmath/static/wagtailmath/js/wagtailmath-mathjax-controller.js b/src/wagtail_polymath/static/wagtail_polymath/js/wagtailmath-mathjax-controller.js similarity index 100% rename from src/wagtailmath/static/wagtailmath/js/wagtailmath-mathjax-controller.js rename to src/wagtail_polymath/static/wagtail_polymath/js/wagtailmath-mathjax-controller.js diff --git a/src/wagtailmath/templates/wagtailmath/mathjaxwidget.html b/src/wagtail_polymath/templates/wagtail_polymath/textarea-widget.html similarity index 62% rename from src/wagtailmath/templates/wagtailmath/mathjaxwidget.html rename to src/wagtail_polymath/templates/wagtail_polymath/textarea-widget.html index 991b2eb..3cf5388 100644 --- a/src/wagtailmath/templates/wagtailmath/mathjaxwidget.html +++ b/src/wagtail_polymath/templates/wagtail_polymath/textarea-widget.html @@ -6,5 +6,5 @@