Browse Source

add math rendering

add favicon
master
Schoenberger, Philipp 6 years ago
parent
commit
e1c9e0028d
  1. 14
      Makefile
  2. 31
      content/blog/03_quadrocopter_en.md
  3. 5
      content/blog/04_keyboad_en.md
  4. BIN
      content/extra/favicon.ico
  5. BIN
      content/images_org/favicon.xcf
  6. BIN
      content/images_org/quad/prop.jpg
  7. BIN
      content/images_org/quad/prop_d.jpg
  8. BIN
      content/images_org/quad/prop_pitch.jpg
  9. 16
      pelicanconf.py
  10. 2
      plugins/extended-sitemap/__init__.py
  11. 164
      plugins/render_math/Readme.md
  12. 1
      plugins/render_math/__init__.py
  13. 367
      plugins/render_math/math.py
  14. 61
      plugins/render_math/mathjax_script_template
  15. 158
      plugins/render_math/pelican_mathjax_markdown_extension.py
  16. 1
      themes/bootstrap-4-blog-theme/templates/base.html

14
Makefile

@ -17,18 +17,18 @@ OUTPUTDIR=$(BASEDIR)/output
CONFFILE=$(BASEDIR)/pelicanconf.py
PUBLISHCONF=$(BASEDIR)/publishconf.py
FTP_HOST=localhost
FTP_USER=anonymous
FTP_TARGET_DIR=/
# FTP_HOST=localhost
# FTP_USER=anonymous
# FTP_TARGET_DIR=/
SSH_HOST=173.249.40.201
SSH_PORT=21
SSH_USER=pschoen
SSH_TARGET_DIR=/data/nginx/phschoen.de/
S3_BUCKET=my_s3_bucket
# S3_BUCKET=my_s3_bucket
DROPBOX_DIR=~/Dropbox/Public/
# DROPBOX_DIR=~/Dropbox/Public/
help:
@echo 'Makefile for a pelican Web site '
@ -81,7 +81,7 @@ $(foreach size, $(IMG_SIZES), \
define convert-rule
$(1):$(2)
mkdir -p $(dir $(1))
convert $(2) -resize $(3)x$(3) $(1)
convert $(2) -resize $(3)x$(3)^ $(1)
endef
@ -127,7 +127,7 @@ stopserver:
publish:
killall $(PY) pelican || true
$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
$(PELICAN) --debug $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
ssh_upload: publish
scp -vP $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)

31
content/blog/03_quadrocopter_en.md

@ -35,7 +35,8 @@ A taller motor most likely result in more power at the upper Throttle/RPM and a
would result in a higher torque at low throttle.
Since I wanted to use motors with a actual data sheet or at least a test measurement how much thrust and
amps would be drawn with certain types of propeller I did take a look at the [T-Motor F20II F20 II 1408 3750KV](https://www.banggood.com/T-Motor-F20II-F20-II-1406-3750KV-Brushless-Motor-2-4S-For-130-140-150-FPV-Racing-Frame-p-1154351.html)
amps would be drawn with certain types of propeller I did take a look at the
[T-Motor F20II F20 II 1408 3750KV](https://www.banggood.com/T-Motor-F20II-F20-II-1406-3750KV-Brushless-Motor-2-4S-For-130-140-150-FPV-Racing-Frame-p-1154351.html)
The where the ones which had a lot of thrust with 532g when they are mounted with 3040 propeller types.
The goal of the quad would be to be below 250g so the thrust to weight ratio would be 1:8 for a quad copter.
@ -52,12 +53,32 @@ For this I selected the three bladed one with close to the 3040 size. The only o
The Number of the Propellers are also representing the size nearly as the motor identification number.
The first two digits are the diameter in inch and the second two ones are representing the pitch of the propeller.
The Pitch is sometimes misunderstood to degrees of the propeller blade.
The actual meaning of it is the forward movement of he propeller if it's rotating 360 degrees
So in this case of a 3042 the diameter is 3 inch and the propeller is moving 4.2 inches forward in case it does one rotation.
The Pitch is sometimes misunderstood. There are 2 value types of the propeller blade.
The actual meaning of it is the forward movement of he propeller if it's rotating 360 degrees. This value is calculated in inch.
So if the upper propeller would be measured this schema the 3042 would represent the diameter as 3 inch and the propeller is moving 4.2 inches forward.
However there exists also the measurement of the angular pitch. This value is common for props which have a non constant angle in order to compare them more easily.
The conversion from one to the other is pretty simple and can be found the in formula below.
$$ p_{inches} = tan\left( p_{angle} * d * \frac{m_{point}}{100} * \pi\right) $$
$$ p_{angle} = atan\left( \frac{p_{inches}}{d * \frac{m_{point}}{100} } * \pi\right) $$
You can imagine the higher the pitch is the more air is moved and the more thrust it should generate with the same rpm.
Side effect of the higher pitch is a higher amp drawn thought.
So you have to be carefully which props you putting on the motor otherwise you could overload the motor and they could burn down
or the ESC can not handle that much amps.
In my case they are measured in degree so the forward pitch angle of $42°$ would result in a pitch blade of 5.09 inches.
[lightgallery
/images/quad/prop.jpg, Geprc 3042 Source: www.banggood.com;
/images/quad/prop_d.jpg, Geprc 3042 diameter in inch visualised Source: www.banggood.com;
/images/quad/prop_pitch.jpg, Geprc 3042 pitch in degree visualised Source: www.banggood.com;
lightgalleryend]
TOBE continued...
part list:
@ -67,6 +88,6 @@ part list:
- [esc](https://www.banggood.com/20x20mm-28A-BLheli_S-BB2-2-4S-4-In-1-ESC-Support-Dshot600-for-XJB-F428-F328-Series-Flytower-p-1203121.html)
- [props](https://www.banggood.com/10-Pairs-Geprc-3042-3x42-Inch-3-Blade-Propeller-M5-Mounting-Hole-CW-CCW-for-Racing-Drone-p-1190428.html)
- [cam](https://www.banggood.com/RunCam-Micro-Sparrow-WDR-700TVL-13-CMOS-2_1mm-FOV-145-Degree-169-FPV-Camera-NTSCPAL-Switchable-p-1198579.html)
- [VTX]()
- [TBS Unify Pro HV Race FPV Video Sender SMA - Team Blacksheep](https://www.team-blacksheep.com/products/prod:unify_pro_hv_race)
- [frsky receiver](https://www.banggood.com/FrSky-R-XSR-Ultra-SBUSCPPM-D16-16CH-Mini-Redundancy-Receiver-1_5g-for-RC-Multirotor-FPV-Racing-Drone-p-1186057.html)
- [beeper](https://www.banggood.com/Super-Mini-1_38g-WS2812-Colorful-LED-with-5V-Active-Alarm-Buzzer-Support-Cleanflight-Betaflight-p-1131891.html?rmmds=myorder&cur_warehouse=CN)

5
content/blog/04_keyboad_en.md

@ -74,7 +74,12 @@ two USB plugs and a textile sleeve to get a awesome optic.
[lightgallery
/images/keyboard/keyboard_v1.jpg, Final assembly of my keyboard with trackpoint;
/images/keyboard/keyboard_v1_1.jpg, Internal cableing of the teensy board and trackpoint
/images/keyboard/keyboard_v1_2.jpg, PCB cutout for he trackpoint stem
/images/keyboard/keyboard_v1_3.jpg, 3d printed trackpoint nibble
/images/keyboard/keyboard_v1_3.jpg, swiches with SIP sockets and cutouts to remove the top cover in oder to lube them without soldering
lightgalleryend]

BIN
content/extra/favicon.ico

BIN
content/images_org/favicon.xcf

BIN
content/images_org/quad/prop.jpg

After

Width: 575  |  Height: 398  |  Size: 24 KiB

BIN
content/images_org/quad/prop_d.jpg

After

Width: 400  |  Height: 300  |  Size: 17 KiB

BIN
content/images_org/quad/prop_pitch.jpg

After

Width: 608  |  Height: 194  |  Size: 14 KiB

16
pelicanconf.py

@ -37,12 +37,12 @@ EXTRA_PATH_METADATA = {
'extra/fonts/lg.svg': {'path': 'fonts/lg.svg'},
'extra/fonts/lg.ttf': {'path': 'fonts/lg.ttf'},
'extra/fonts/lg.woff': {'path': 'fonts/lg.woff'},
'extra/googlec921759af9dae688.html': {'path': 'googlec921759af9dae688.html'},
}
# Base URL this page is hosted at:
SITENAME = 'phschoen.de'
# SITEURL = 'http://skylx125.ndsatcom.com:8000'
SITEURL = 'http://phschoen.de'
SITEURL = 'https://phschoen.de'
# Timezone is GMT+1:
TIMEZONE = 'Europe/Paris'
@ -161,7 +161,13 @@ DEFAULT_CATEGORY = 'uncategorized'
# DEFAULT_PAGINATION = 10
PLUGIN_PATHS = ['plugins', ]
PLUGINS = ['lightgallery', 'i18n_subsites', 'extended-sitemap', 'pelican-bootstrapify']
PLUGINS = [
'lightgallery',
'i18n_subsites',
'extended-sitemap',
'pelican-bootstrapify',
'render_math'
]
SITEMAP = {
'format': 'xml',
@ -186,8 +192,8 @@ EXTENDED_SITEMAP_PLUGIN = {
'changefrequencies': {
'index': 'daily',
'articles': 'weekly',
'pages': 'monthly',
'others': 'monthly',
'pages': 'weekly',
'others': 'weekly',
}
}

2
plugins/extended-sitemap/__init__.py

@ -79,6 +79,8 @@ class SitemapGenerator(object):
raise ConfigurationError('Please specify the TIMEZONE setting!')
self.timezone = timezone(settings.get('TIMEZONE'))
self.url_site = settings.get('SITEURL')
if len(self.url_site) == 0:
self.url_site = "https://phschoen.de"
# Pelican strips off trailing slashes during settings initialization.
# The later used urljoin function strips of path elements not ending with a trailing slash,
# a slash is added here if it is not already present

164
plugins/render_math/Readme.md

@ -0,0 +1,164 @@
Math Render Plugin For Pelican
==============================
This plugin gives pelican the ability to render mathematics. It accomplishes
this by using the [MathJax](http://www.mathjax.org/) javascript engine.
The plugin also ensures that Typogrify and recognized math "play" nicely together, by
ensuring [Typogrify](https://github.com/mintchaos/typogrify) does not alter math content.
Both Markdown and reStructuredText is supported.
Requirements
------------
* Pelican version *3.6* or above is required.
* Typogrify version *2.0.7* or higher is needed for Typogrify to play
"nicely" with this plugin. If this version is not available, Typogrify
will be disabled for the entire site.
* BeautifulSoup4 is required to correct summaries. If BeautifulSoup4 is
not installed, summary processing will be ignored, even if specified
in user settings.
Installation
------------
To enable, ensure that `render_math` plugin is accessible.
Then add the following to settings.py:
PLUGINS = ["render_math"]
Your site is now capable of rendering math math using the mathjax JavaScript
engine. No alterations to the template is needed, just use and enjoy!
However, if you wish, you can set the `auto_insert` setting to `False` which
will disable the mathjax script from being automatically inserted into the
content. You would only want to do this if you had control over the template
and wanted to insert the script manually.
### Typogrify
In the past, using [Typgogrify](https://github.com/mintchaos/typogrify) would
alter the math contents resulting in math that could not be rendered by MathJax.
The only option was to ensure that Typogrify was disabled in the settings.
The problem has been rectified in this plugin, but it requires at a minimum
[Typogrify version 2.0.7](https://pypi.python.org/pypi/typogrify) (or higher).
If this version is not present, the plugin will disable Typogrify for the entire
site.
### BeautifulSoup4
Pelican creates summaries by truncating the contents to a specified user length.
The truncation process is oblivious to any math and can therefore destroy
the math output in the summary.
To restore math, [BeautifulSoup4](https://pypi.python.org/pypi/beautifulsoup4/4.4.0)
is used. If it is not installed, no summary processing will happen.
Usage
-----
### Templates
No alteration is needed to a template for this plugin to work. Just install
the plugin and start writing your Math.
### Settings
Certain MathJax rendering options can be set. These options
are in a dictionary variable called `MATH_JAX` in the pelican
settings file.
The dictionary can be set with the following keys:
* `align`: [string] controls how displayed math will be aligned. Can be set to either
`'left'`, `'right'` or `'center'`. **Default Value**: `'center'`.
* `auto_insert`: [boolean] will insert the mathjax script into content that it is
detected to have math in it. Setting it to false is not recommended.
**Default Value**: `True`
* `indent`: [string] if `align` not set to `'center'`, then this controls the indent
level. **Default Value**: `'0em'`.
* `show_menu`: [boolean] controls whether the mathjax contextual menu is shown.
**Default Value**: `True`
* `process_escapes`: [boolean] controls whether mathjax processes escape sequences.
**Default Value**: `True`
* `mathjax_font`: [string] will force mathjax to use the chosen font. Current choices
for the font is `sanserif`, `typewriter` or `fraktur`. If this is not set, it will
use the default font settings. **Default Value**: `default`
* `latex_preview`: [string] controls the preview message users are shown while mathjax is
rendering LaTex. If set to `'Tex'`, then the TeX code is used as the preview
(which will be visible until it is processed by MathJax). **Default Value**: `'Tex'`
* `color`: [string] controls the color of the mathjax rendered font. **Default Value**: `'inherit'`
* `linebreak_automatic`: [boolean] If set, Mathjax will try to *intelligently* break up displayed math
(Note: It will not work for inline math). This is very useful for a responsive site. It
is turned off by default due to it potentially being CPU expensive. **Default Value**: `False`
* `tex_extensions`: [list] a list of [latex extensions](http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-extensions)
accepted by mathjax. **Default Value**: `[]` (empty list)
* `responsive`: [boolean] tries to make displayed math render responsively. It does by determining if the width
is less than `responsive_break` (see below) and if so, sets `align` to `left`, `indent` to `0em` and `linebreak_automatic` to `True`.
**Default Value**: `False` (defaults to `False` for backward compatibility)
* `responsive_break`: [integer] a number (in pixels) representing the width breakpoint that is used
when setting `responsive_align` to `True`. **Default Value**: 768
* `process_summary`: [boolean] ensures math will render in summaries and fixes math in that were cut off.
Requires [BeautifulSoup4](http://www.crummy.com/software/BeautifulSoup/bs4/doc/) be installed. **Default Value**: `True`
* `message_style`: [string] This value controls the verbosity of the messages in the lower left-hand corner. Set it to `None` to eliminate all messages.
**Default Value**: normal
#### Settings Examples
Make math render in blue and displaymath align to the left:
MATH_JAX = {'color':'blue','align':left}
Use the [color](http://docs.mathjax.org/en/latest/tex.html#color) and
[mhchem](http://docs.mathjax.org/en/latest/tex.html#mhchem) extensions:
MATH_JAX = {'tex_extensions': ['color.js','mhchem.js']}
#### Resulting HTML
Inlined math is wrapped in `span` tags, while displayed math is wrapped in `div` tags.
These tags will have a class attribute that is set to `math` which
can be used by template designers to alter the display of the math.
Markdown
--------
This plugin implements a custom extension for markdown resulting in math
being a "first class citizen" for Pelican.
### Inlined Math
Math between `$`..`$`, for example, `$`x^2`$`, will be rendered inline
with respect to the current html block. Note: To use inline math, there
must *not* be any whitespace before the ending `$`. So for example:
* **Relevant inline math**: `$e=mc^2$`
* **Will not render as inline math**: `$40 vs $50`
### Displayed Math
Math between `$$`..`$$` will be rendered "block style", for example, `$$`x^2`$$`, will be rendered centered in a
new paragraph.
#### Other Latex Display Math commands
The other LaTeX commands which usually invoke display math mode from text mode
are supported,
and are automatically treated like `$$`-style displayed math
in that they are rendered "block" style on their own lines.
For example, `\begin{equation}` x^2 `\end{equation}`,
will be rendered in its own block with a right justified equation number
at the top of the block. This equation number can be referenced in the document.
To do this, use a `label` inside of the equation format and then refer to that label
using `ref`. For example: `\begin{equation}` `\label{eq}` X^2 `\end{equation}`.
Now refer to that equation number by `$`\ref{eq}`$`.
reStructuredText
----------------
If there is math detected in reStructuredText document, the plugin will automatically
set the [math_output](http://docutils.sourceforge.net/docs/user/config.html#math-output) configuration setting to `MathJax`.
### Inlined Math
Inlined math needs to use the [math role](http://docutils.sourceforge.net/docs/ref/rst/roles.html#math):
```
The area of a circle is :math:`A_\text{c} = (\pi/4) d^2`.
```
### Displayed Math
Displayed math uses the [math block](http://docutils.sourceforge.net/docs/ref/rst/directives.html#math):
```
.. math::
α_t(i) = P(O_1, O_2, … O_t, q_t = S_i λ)
```

1
plugins/render_math/__init__.py

@ -0,0 +1 @@
from .math import *

367
plugins/render_math/math.py

@ -0,0 +1,367 @@
# -*- coding: utf-8 -*-
"""
Math Render Plugin for Pelican
==============================
This plugin allows your site to render Math. It uses
the MathJax JavaScript engine.
For markdown, the plugin works by creating a Markdown
extension which is used during the markdown compilation
stage. Math therefore gets treated like a "first class
citizen" in Pelican
For reStructuredText, the plugin instructs the rst engine
to output Mathjax for all math.
The mathjax script is by default automatically inserted
into the HTML.
Typogrify Compatibility
-----------------------
This plugin now plays nicely with Typogrify, but it
requires Typogrify version 2.07 or above.
User Settings
-------------
Users are also able to pass a dictionary of settings
in the settings file which will control how the MathJax
library renders things. This could be very useful for
template builders that want to adjust the look and feel of
the math. See README for more details.
"""
import os
import sys
from pelican import signals, generators
try:
from bs4 import BeautifulSoup
except ImportError as e:
BeautifulSoup = None
try:
from . pelican_mathjax_markdown_extension import PelicanMathJaxExtension
except ImportError as e:
PelicanMathJaxExtension = None
try:
string_type = basestring
except NameError:
string_type = str
def process_settings(pelicanobj):
"""Sets user specified MathJax settings (see README for more details)"""
mathjax_settings = {}
# NOTE TO FUTURE DEVELOPERS: Look at the README and what is happening in
# this function if any additional changes to the mathjax settings need to
# be incorporated. Also, please inline comment what the variables
# will be used for
# Default settings
mathjax_settings['auto_insert'] = True # if set to true, it will insert mathjax script automatically into content without needing to alter the template.
mathjax_settings['align'] = 'center' # controls alignment of of displayed equations (values can be: left, right, center)
mathjax_settings['indent'] = '0em' # if above is not set to 'center', then this setting acts as an indent
mathjax_settings['show_menu'] = 'true' # controls whether to attach mathjax contextual menu
mathjax_settings['process_escapes'] = 'true' # controls whether escapes are processed
mathjax_settings['latex_preview'] = 'TeX' # controls what user sees while waiting for LaTex to render
mathjax_settings['color'] = 'inherit' # controls color math is rendered in
mathjax_settings['linebreak_automatic'] = 'false' # Set to false by default for performance reasons (see http://docs.mathjax.org/en/latest/output.html#automatic-line-breaking)
mathjax_settings['tex_extensions'] = '' # latex extensions that can be embedded inside mathjax (see http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-extensions)
mathjax_settings['responsive'] = 'false' # Tries to make displayed math responsive
mathjax_settings['responsive_break'] = '768' # The break point at which it math is responsively aligned (in pixels)
mathjax_settings['mathjax_font'] = 'default' # forces mathjax to use the specified font.
mathjax_settings['process_summary'] = BeautifulSoup is not None # will fix up summaries if math is cut off. Requires beautiful soup
mathjax_settings['message_style'] = 'normal' # This value controls the verbosity of the messages in the lower left-hand corner. Set it to "none" to eliminate all messages
mathjax_settings['font_list'] = ['STIX', 'TeX'] # Include in order of preference among TeX, STIX-Web, Asana-Math, Neo-Euler, Gyre-Pagella, Gyre-Termes and Latin-Modern
mathjax_settings['equation_numbering'] = 'none' # AMS, auto, none
# Source for MathJax
mathjax_settings['source'] = "'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML'"
# Get the user specified settings
try:
settings = pelicanobj.settings['MATH_JAX']
except:
settings = None
# If no settings have been specified, then return the defaults
if not isinstance(settings, dict):
return mathjax_settings
# The following mathjax settings can be set via the settings dictionary
for key, value in ((key, settings[key]) for key in settings):
# Iterate over dictionary in a way that is compatible with both version 2
# and 3 of python
if key == 'align':
typeVal = isinstance(value, string_type)
if not typeVal:
continue
if value == 'left' or value == 'right' or value == 'center':
mathjax_settings[key] = value
else:
mathjax_settings[key] = 'center'
if key == 'indent':
mathjax_settings[key] = value
if key == 'source':
mathjax_settings[key] = value
if key == 'show_menu' and isinstance(value, bool):
mathjax_settings[key] = 'true' if value else 'false'
if key == 'message_style':
mathjax_settings[key] = value if value is not None else 'none'
if key == 'auto_insert' and isinstance(value, bool):
mathjax_settings[key] = value
if key == 'process_escapes' and isinstance(value, bool):
mathjax_settings[key] = 'true' if value else 'false'
if key == 'latex_preview':
typeVal = isinstance(value, string_type)
if not typeVal:
continue
mathjax_settings[key] = value
if key == 'color':
typeVal = isinstance(value, string_type)
if not typeVal:
continue
mathjax_settings[key] = value
if key == 'linebreak_automatic' and isinstance(value, bool):
mathjax_settings[key] = 'true' if value else 'false'
if key == 'process_summary' and isinstance(value, bool):
if value and BeautifulSoup is None:
print("BeautifulSoup4 is needed for summaries to be processed by render_math\nPlease install it")
value = False
mathjax_settings[key] = value
if key == 'responsive' and isinstance(value, bool):
mathjax_settings[key] = 'true' if value else 'false'
if key == 'responsive_break' and isinstance(value, int):
mathjax_settings[key] = str(value)
if key == 'tex_extensions' and isinstance(value, list):
# filter string values, then add '' to them
value = filter(lambda string: isinstance(string, string_type), value)
value = map(lambda string: "'%s'" % string, value)
mathjax_settings[key] = ',' + ','.join(value)
if key == 'mathjax_font':
typeVal = isinstance(value, string_type)
if not typeVal:
continue
value = value.lower()
if value == 'sanserif':
value = 'SansSerif'
elif value == 'fraktur':
value = 'Fraktur'
elif value == 'typewriter':
value = 'Typewriter'
else:
value = 'default'
mathjax_settings[key] = value
if key == 'font_list' and isinstance(value, list):
# make an array string from the list
value = filter(lambda string: isinstance(string, string_type), value)
value = map(lambda string: ",'%s'" % string, value)
mathjax_settings[key] = ''.join(value)[1:]
if key == 'equation_numbering':
mathjax_settings[key] = value if value is not None else 'none'
return mathjax_settings
def process_summary(article):
"""Ensures summaries are not cut off. Also inserts
mathjax script so that math will be rendered"""
summary = article.summary
summary_parsed = BeautifulSoup(summary, 'html.parser')
math = summary_parsed.find_all(class_='math')
if len(math) > 0:
last_math_text = math[-1].get_text()
if len(last_math_text) > 3 and last_math_text[-3:] == '...':
content_parsed = BeautifulSoup(article._content, 'html.parser')
full_text = content_parsed.find_all(class_='math')[len(math)-1].get_text()
math[-1].string = "%s ..." % full_text
summary = summary_parsed.decode()
# clear memoization cache
import functools
if isinstance(article.get_summary, functools.partial):
memoize_instance = article.get_summary.func.__self__
memoize_instance.cache.clear()
article._summary = "%s<script type='text/javascript'>%s</script>" % (summary, process_summary.mathjax_script)
def configure_typogrify(pelicanobj, mathjax_settings):
"""Instructs Typogrify to ignore math tags - which allows Typogrify
to play nicely with math related content"""
# If Typogrify is not being used, then just exit
if not pelicanobj.settings.get('TYPOGRIFY', False):
return
try:
import typogrify
from distutils.version import LooseVersion
if LooseVersion(typogrify.__version__) < LooseVersion('2.0.7'):
raise TypeError('Incorrect version of Typogrify')
from typogrify.filters import typogrify
# At this point, we are happy to use Typogrify, meaning
# it is installed and it is a recent enough version
# that can be used to ignore all math
# Instantiate markdown extension and append it to the current extensions
pelicanobj.settings['TYPOGRIFY_IGNORE_TAGS'].extend(['.math', 'script']) # ignore math class and script
except (ImportError, TypeError) as e:
pelicanobj.settings['TYPOGRIFY'] = False # disable Typogrify
if isinstance(e, ImportError):
print("\nTypogrify is not installed, so it is being ignored.\nIf you want to use it, please install via: pip install typogrify\n")
if isinstance(e, TypeError):
print("\nA more recent version of Typogrify is needed for the render_math module.\nPlease upgrade Typogrify to the latest version (anything equal or above version 2.0.7 is okay).\nTypogrify will be turned off due to this reason.\n")
def process_mathjax_script(mathjax_settings):
"""Load the mathjax script template from file, and render with the settings"""
# Read the mathjax javascript template from file
with open (os.path.dirname(os.path.realpath(__file__))
+ '/mathjax_script_template', 'r') as mathjax_script_template:
mathjax_template = mathjax_script_template.read()
return mathjax_template.format(**mathjax_settings)
def mathjax_for_markdown(pelicanobj, mathjax_script, mathjax_settings):
"""Instantiates a customized markdown extension for handling mathjax
related content"""
# Create the configuration for the markdown template
config = {}
config['mathjax_script'] = mathjax_script
config['math_tag_class'] = 'math'
config['auto_insert'] = mathjax_settings['auto_insert']
# Instantiate markdown extension and append it to the current extensions
try:
if isinstance(pelicanobj.settings.get('MD_EXTENSIONS'), list): # pelican 3.6.3 and earlier
pelicanobj.settings['MD_EXTENSIONS'].append(PelicanMathJaxExtension(config))
else:
pelicanobj.settings['MARKDOWN'].setdefault('extensions', []).append(PelicanMathJaxExtension(config))
except:
sys.excepthook(*sys.exc_info())
sys.stderr.write("\nError - the pelican mathjax markdown extension failed to configure. MathJax is non-functional.\n")
sys.stderr.flush()
def mathjax_for_rst(pelicanobj, mathjax_script, mathjax_settings):
"""Setup math for RST"""
docutils_settings = pelicanobj.settings.get('DOCUTILS_SETTINGS', {})
docutils_settings.setdefault('math_output', 'MathJax %s' % mathjax_settings['source'])
pelicanobj.settings['DOCUTILS_SETTINGS'] = docutils_settings
rst_add_mathjax.mathjax_script = mathjax_script
def pelican_init(pelicanobj):
"""
Loads the mathjax script according to the settings.
Instantiate the Python markdown extension, passing in the mathjax
script as config parameter.
"""
# Process settings, and set global var
mathjax_settings = process_settings(pelicanobj)
# Generate mathjax script
mathjax_script = process_mathjax_script(mathjax_settings)
# Configure Typogrify
configure_typogrify(pelicanobj, mathjax_settings)
# Configure Mathjax For Markdown
if PelicanMathJaxExtension:
mathjax_for_markdown(pelicanobj, mathjax_script, mathjax_settings)
# Configure Mathjax For RST
mathjax_for_rst(pelicanobj, mathjax_script, mathjax_settings)
# Set process_summary's mathjax_script variable
process_summary.mathjax_script = None
if mathjax_settings['process_summary']:
process_summary.mathjax_script = mathjax_script
def rst_add_mathjax(content):
"""Adds mathjax script for reStructuredText"""
# .rst is the only valid extension for reStructuredText files
_, ext = os.path.splitext(os.path.basename(content.source_path))
if ext != '.rst':
return
# If math class is present in text, add the javascript
# note that RST hardwires mathjax to be class "math"
if 'class="math"' in content._content:
content._content += "<script type='text/javascript'>%s</script>" % rst_add_mathjax.mathjax_script
def process_rst_and_summaries(content_generators):
"""
Ensure mathjax script is applied to RST and summaries are
corrected if specified in user settings.
Handles content attached to ArticleGenerator and PageGenerator objects,
since the plugin doesn't know how to handle other Generator types.
For reStructuredText content, examine both articles and pages.
If article or page is reStructuredText and there is math present,
append the mathjax script.
Also process summaries if present (only applies to articles)
and user wants summaries processed (via user settings)
"""
for generator in content_generators:
if isinstance(generator, generators.ArticlesGenerator):
for article in (
generator.articles +
generator.translations +
generator.drafts):
rst_add_mathjax(article)
#optionally fix truncated formulae in summaries.
if process_summary.mathjax_script is not None:
process_summary(article)
elif isinstance(generator, generators.PagesGenerator):
for page in generator.pages:
rst_add_mathjax(page)
for page in generator.hidden_pages:
rst_add_mathjax(page)
def register():
"""Plugin registration"""
signals.initialized.connect(pelican_init)
signals.all_generators_finalized.connect(process_rst_and_summaries)

61
plugins/render_math/mathjax_script_template

@ -0,0 +1,61 @@
if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {{
var align = "{align}",
indent = "{indent}",
linebreak = "{linebreak_automatic}";
if ({responsive}) {{
align = (screen.width < {responsive_break}) ? "left" : align;
indent = (screen.width < {responsive_break}) ? "0em" : indent;
linebreak = (screen.width < {responsive_break}) ? 'true' : linebreak;
}}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = {source};
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({{" +
" config: ['MMLorHTML.js']," +
" TeX: {{ extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'{tex_extensions}], equationNumbers: {{ autoNumber: '{equation_numbering}' }} }}," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: {show_menu}," +
" messageStyle: '{message_style}'," +
" tex2jax: {{ " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: {process_escapes}," +
" preview: '{latex_preview}'," +
" }}, " +
" 'HTML-CSS': {{ " +
" availableFonts: {font_list}," +
" preferredFont: 'STIX'," +
" styles: {{ '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {{color: '{color} ! important'}} }}," +
" linebreaks: {{ automatic: "+ linebreak +", width: '90% container' }}," +
" }}, " +
"}}); " +
"if ('{mathjax_font}' !== 'default') {{" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {{" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_{mathjax_font}');" +
"VARIANT['bold'].fonts.unshift('MathJax_{mathjax_font}-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_{mathjax_font}-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_{mathjax_font}-italic');" +
"}});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {{" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_{mathjax_font}');" +
"VARIANT['bold'].fonts.unshift('MathJax_{mathjax_font}-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_{mathjax_font}-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_{mathjax_font}-italic');" +
"}});" +
"}}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}}

158
plugins/render_math/pelican_mathjax_markdown_extension.py

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
"""
Pelican Mathjax Markdown Extension
==================================
An extension for the Python Markdown module that enables
the Pelican python blog to process mathjax. This extension
gives Pelican the ability to use Mathjax as a "first class
citizen" of the blog
"""
import markdown
from markdown.util import etree
from markdown.util import AtomicString
class PelicanMathJaxPattern(markdown.inlinepatterns.Pattern):
"""Inline markdown processing that matches mathjax"""
def __init__(self, pelican_mathjax_extension, tag, pattern):
super(PelicanMathJaxPattern,self).__init__(pattern)
self.math_tag_class = pelican_mathjax_extension.getConfig('math_tag_class')
self.pelican_mathjax_extension = pelican_mathjax_extension
self.tag = tag
def handleMatch(self, m):
node = markdown.util.etree.Element(self.tag)
node.set('class', self.math_tag_class)
prefix = '\\(' if m.group('prefix') == '$' else m.group('prefix')
suffix = '\\)' if m.group('suffix') == '$' else m.group('suffix')
node.text = markdown.util.AtomicString(prefix + m.group('math') + suffix)
# If mathjax was successfully matched, then JavaScript needs to be added
# for rendering. The boolean below indicates this
self.pelican_mathjax_extension.mathjax_needed = True
return node
class PelicanMathJaxCorrectDisplayMath(markdown.treeprocessors.Treeprocessor):
"""Corrects invalid html that results from a <div> being put inside
a <p> for displayed math"""
def __init__(self, pelican_mathjax_extension):
self.pelican_mathjax_extension = pelican_mathjax_extension
def correct_html(self, root, children, div_math, insert_idx, text):
"""Separates out <div class="math"> from the parent tag <p>. Anything
in between is put into its own parent tag of <p>"""
current_idx = 0
for idx in div_math:
el = markdown.util.etree.Element('p')
el.text = text
el.extend(children[current_idx:idx])
# Test to ensure that empty <p> is not inserted
if len(el) != 0 or (el.text and not el.text.isspace()):
root.insert(insert_idx, el)
insert_idx += 1
text = children[idx].tail
children[idx].tail = None
root.insert(insert_idx, children[idx])
insert_idx += 1
current_idx = idx+1
el = markdown.util.etree.Element('p')
el.text = text
el.extend(children[current_idx:])
if len(el) != 0 or (el.text and not el.text.isspace()):
root.insert(insert_idx, el)
def run(self, root):
"""Searches for <div class="math"> that are children in <p> tags and corrects
the invalid HTML that results"""
math_tag_class = self.pelican_mathjax_extension.getConfig('math_tag_class')
for parent in root:
div_math = []
children = list(parent)
for div in parent.findall('div'):
if div.get('class') == math_tag_class:
div_math.append(children.index(div))
# Do not process further if no displayed math has been found
if not div_math:
continue
insert_idx = list(root).index(parent)
self.correct_html(root, children, div_math, insert_idx, parent.text)
root.remove(parent) # Parent must be removed last for correct insertion index
return root
class PelicanMathJaxAddJavaScript(markdown.treeprocessors.Treeprocessor):
"""Tree Processor for adding Mathjax JavaScript to the blog"""
def __init__(self, pelican_mathjax_extension):
self.pelican_mathjax_extension = pelican_mathjax_extension
def run(self, root):
# If no mathjax was present, then exit
if (not self.pelican_mathjax_extension.mathjax_needed):
return root
# Add the mathjax script to the html document
mathjax_script = etree.Element('script')
mathjax_script.set('type','text/javascript')
mathjax_script.text = AtomicString(self.pelican_mathjax_extension.getConfig('mathjax_script'))
root.append(mathjax_script)
# Reset the boolean switch to false so that script is only added
# to other pages if needed
self.pelican_mathjax_extension.mathjax_needed = False
return root
class PelicanMathJaxExtension(markdown.Extension):
"""A markdown extension enabling mathjax processing in Markdown for Pelican"""
def __init__(self, config):
try:
# Needed for markdown versions >= 2.5
self.config['mathjax_script'] = ['', 'Mathjax JavaScript script']
self.config['math_tag_class'] = ['math', 'The class of the tag in which mathematics is wrapped']
self.config['auto_insert'] = [True, 'Determines if mathjax script is automatically inserted into content']
super(PelicanMathJaxExtension,self).__init__(**config)
except AttributeError:
# Markdown versions < 2.5
config['mathjax_script'] = [config['mathjax_script'], 'Mathjax JavaScript script']
config['math_tag_class'] = [config['math_tag_class'], 'The class of the tag in which mathematic is wrapped']
config['auto_insert'] = [config['auto_insert'], 'Determines if mathjax script is automatically inserted into content']
super(PelicanMathJaxExtension,self).__init__(config)
# Used as a flag to determine if javascript
# needs to be injected into a document
self.mathjax_needed = False
def extendMarkdown(self, md, md_globals):
# Regex to detect mathjax
mathjax_inline_regex = r'(?P<prefix>\$)(?P<math>.+?)(?P<suffix>(?<!\s)\2)'
mathjax_display_regex = r'(?P<prefix>\$\$|\\begin\{(.+?)\})(?P<math>.+?)(?P<suffix>\2|\\end\{\3\})'
# Process mathjax before escapes are processed since escape processing will
# intefer with mathjax. The order in which the displayed and inlined math
# is registered below matters
md.inlinePatterns.add('mathjax_displayed', PelicanMathJaxPattern(self, 'div', mathjax_display_regex), '<escape')
md.inlinePatterns.add('mathjax_inlined', PelicanMathJaxPattern(self, 'span', mathjax_inline_regex), '<escape')
# Correct the invalid HTML that results from teh displayed math (<div> tag within a <p> tag)
md.treeprocessors.add('mathjax_correctdisplayedmath', PelicanMathJaxCorrectDisplayMath(self), '>inline')
# If necessary, add the JavaScript Mathjax library to the document. This must
# be last in the ordered dict (hence it is given the position '_end')
if self.getConfig('auto_insert'):
md.treeprocessors.add('mathjax_addjavascript', PelicanMathJaxAddJavaScript(self), '_end')

1
themes/bootstrap-4-blog-theme/templates/base.html

@ -35,6 +35,7 @@
{% endfor %}
{% endif %}
{% endblock head %}
<link href="/favicon.ico" rel="icon" type="image/png"/>
<script src="/js/lightgallery.js"></script>
<script src="/js/lg-pager.js"></script>
<script src="/js/lg-autoplay.js"></script>

Loading…
Cancel
Save