Переглянути джерело

moved latex to render_math; latex now symbolic link

Barry Steyn 10 роки тому
батько
коміт
5af9d08c06
7 змінених файлів з 310 додано та 207 видалено
  1. 1 0
      latex
  2. 0 95
      latex/Readme.md
  3. 0 1
      latex/__init__.py
  4. 166 0
      render_math/Readme.md
  5. 1 0
      render_math/__init__.py
  6. 112 111
      latex/latex.py
  7. 30 0
      render_math/mathjax_script.txt

+ 1 - 0
latex

@@ -0,0 +1 @@
+render_math/

+ 0 - 95
latex/Readme.md

@@ -1,95 +0,0 @@
-Latex Plugin For Pelican
-========================
-
-This plugin allows you to write mathematical equations in your articles using Latex and MathMl.
-It uses the MathJax Latex JavaScript library to render *Latex* and *MathMl* that is embedded in
-your site.
-
-### Latex
-Anything between `$..$` (inline math) and `$$..$$` (displayed math) will be recognized as
-Latex. In addition, anything between between `\begin` and `\end` macros will also be 
-recognized as Latex. For example, `\begin{equation}`...`\end{equation}` would be used to 
-render math equations with numbering.
-
-Within recognized Latex as described above, Latex macros can be used.
-
-### MathMl
-Anything between `<math>` and `</math>` tags will be recognized as *MathMl*.
-
-Installation
-------------
-To enable, ensure that `latex.py` is put somewhere that is accessible.
-Then use as follows by adding the following to your settings.py:
-
-    PLUGINS = ["latex"]
-
-Your site is now capable of rendering math math using the mathjax JavaScript
-library. No alterations to the template file is needed.
-
-### Typogrify
-Typogrify will now play nicely with Latex (i.e. typogrify can be enabled
-and Latex will be rendered correctly). In order for this to happen,
-version 2.07 (or above) of typogrify is required. In fact, this plugin expects
-that at least version 2.07 is present and will fail without it.
-
-### Summaries
-Summaries that contain math are processed to ensure that math is not off. If
-math is cut off, it will add it back into the summary.
-
-### Templates
-No alteration is needed to a template for this plugin to work. Just install
-the plugin and start writing your Math.
-
-Usage
------
-### Backward Compatibility
-This plugin is backward compatible in the sense that it
-will render previous setups correctly. This is because those
-settings and metadata information is ignored by this version. Therefore
-you can remove them to neaten up your site
-
-### Settings File
-Extra options regarding how mathjax renders math can be set in the settings
-file. These options are in a dictionary variable called `LATEX` in the pelican
-settings file.
-
-The dictionary can be set with the following keys:
-
- * `wrap`: controls the tags that math is wrapped with inside the resulting
-html. For example, setting `wrap` to `'mathjax'` would wrap all math inside
-`<mathjax>...</mathjax>` tags. If typogrify is set to True, then math needs
-to be wrapped in tags and `wrap` will therefore default to `mathjax` if not
-set. `wrap` cannot be set to `'math'` because this tag is reserved for 
-mathml notation
- * `align`: controls how displayed math will be aligned. Can be set to either
-`left`, `right` or `center` (default is `center`).
- * `indent`: if `align` not set to `center`, then this controls the indent
-level (default is `0em`).
- * `show_menu`: controls whether the mathjax contextual menu is shown.
- * `process_escapes`: controls whether mathjax processes escape sequences.
- * `preview`: controls the preview message users are seen while mathjax is
-loading.
- * `color`: controls the color of the mathjax rendered font.
-
-For example, in settings.py, the following would make math render in blue and
-displaymath align to the left:
-
-    LATEX = {'color':'blue','align':left}
-
-Latex Examples
---------------
-###Inline
-Latex between `$`..`$`, for example, `$`x^2`$`, will be rendered inline
-with respect to the current html block.
-
-###Displayed Math
-Latex between `$$`..`$$`, for example, `$$`x^2`$$`, will be rendered centered in a
-new paragraph.
-
-###Equations
-Latex between `\begin` and `\end`, for example, `begin{equation}` x^2 `\end{equation}`,
-will be rendered centered in a new paragraph with a right justified equation number
-at the top of the paragraph. 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}`$`.

+ 0 - 1
latex/__init__.py

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

+ 166 - 0
render_math/Readme.md

@@ -0,0 +1,166 @@
+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. Both
+[LaTex](http://en.wikipedia.org/wiki/LaTeX) and [MathML](http://en.wikipedia.org/wiki/MathML) 
+can be rendered within the content.
+
+The plugin also ensures that pelican and recognized math "play" nicely together, by
+ensuring [Typogrify](https://github.com/mintchaos/typogrify) does not alter math content
+and summaries that get cut off are repaired.
+
+Recognized math in the context of this plugin is either LaTex or MathML as described below.
+
+### LaTex
+Anything between `$`...`$` (inline math) and `$$`..`$$` (displayed math) will be recognized as
+LaTex. In addition, anything the `\begin` and `\end` LaTex macros will also be 
+recognized as LaTex. For example, `\begin{equation}`...`\end{equation}` would be used to 
+render math equations with numbering.
+
+Within recognized LaTex as described above, any supported LaTex macro can be used.
+
+### MathML
+Anything between `<math>` and `</math>` tags will be recognized as MathML
+
+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!
+
+### 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 recitified in this plugin, but it requires [Typogrify version 2.04](https://pypi.python.org/pypi/typogrify)
+(or higher). In fact, this plugin will not work with lower versions of Typogrfrify.
+
+Usage
+-----
+### Backward Compatibility
+This plugin is backward compatible in the sense that it
+will render previous setups correctly. This is because those
+settings and metadata information is ignored by this version. Therefore
+you can remove them to neaten up your site
+
+### Templates
+No alteration is needed to a template for this plugin to work. Just install
+the plugin and start writing your Math. 
+
+If on the other hand, you are template designer and want total control
+over the MathJax JavaScript, you can set the `auto_insert` setting to 
+`False` which will cause no MathJax JavaScript to be added to the content.
+
+If you choose this option, you should really know what you are doing. Therefore
+only do this if you are designing your template. There is no real advantage to
+to letting template logic handle the insertion of the MathJax JavaScript other
+than it being slightly neater.
+
+By setting `auto_insert` to `False`, metadata with `key` value of `mathjax`
+will be present in all pages and articles where MathJax should be present.
+The template designer can detect this and then use the `MATHJAXSCRIPT` setting
+which will contain the user specified MathJax script to insert into the content.
+
+For example, this code could be used:
+```
+{% if not MATH['auto_insert'] %}
+    {% if page and page.mathjax or article and article.mathjax %}
+        {{ MATHJAXSCRIPT }}
+    {% endif %}
+{% endif %}
+```
+
+### Settings
+Certain MathJax rendering options can be set. These options 
+are in a dictionary variable called `MATH` in the pelican
+settings file.
+
+The dictionary can be set with the following keys:
+
+ * `auto_insert`: controls whether plugin should automatically insert
+MathJax JavaScript in content that has Math. It is only recommended
+to set this to False if you are a template designer and you want
+extra control over where the MathJax JavaScript is renderd. **Default Value**:
+True
+ * `wrap_latex`: controls the tags that LaTex math is wrapped with inside the resulting
+html. For example, setting `wrap_latex` to `mathjax` would wrap all LaTex math inside
+`<mathjax>...</mathjax>` tags. If typogrify is set to True, then math needs
+to be wrapped in tags and `wrap_latex` will therefore default to `mathjax` if not
+set. `wrap_latex` cannot be set to `'math'` because this tag is reserved for 
+mathml notation. **Default Value**: None unless Typogrify is enabled in which case, 
+it defaults to `mathjax`
+ * `align`: controls how displayed math will be aligned. Can be set to either
+`left`, `right` or `center`. **Default Value**: `center`.
+ * `indent`: if `align` not set to `center`, then this controls the indent
+level. **Default Value**: `0em`.
+ * `show_menu`: a boolean value that controls whether the mathjax contextual 
+menu is shown. **Default Value**: True
+ * `process_escapes`: a boolean value that controls whether mathjax processes escape 
+sequences. **Default Value**: True
+ * `latex_preview`: controls the preview message users are seen 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`: controls the color of the mathjax rendered font. **Default Value**: `black`
+
+For example, in settings.py, the following would make math render in blue and
+displaymath align to the left:
+
+    MATH = {'color':'blue','align':left}
+
+LaTex Examples
+--------------
+###Inline
+LaTex between `$`..`$`, for example, `$`x^2`$`, will be rendered inline
+with respect to the current html block.
+
+###Displayed Math
+LaTex between `$$`..`$$`, for example, `$$`x^2`$$`, will be rendered centered in a
+new paragraph.
+
+###Equations
+LaTex between `\begin` and `\end`, for example, `begin{equation}` x^2 `\end{equation}`,
+will be rendered centered in a new paragraph with a right justified equation number
+at the top of the paragraph. 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}`$`.
+
+MathML Examples
+---------------
+The following will render the Quadratic formula:
+```
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 
+  <mrow>
+    <mi>x</mi>
+    <mo>=</mo>
+    <mfrac>
+      <mrow>
+        <mo>&#x2212;</mo>
+        <mi>b</mi>
+        <mo>&#xB1;</mo>
+        <msqrt>
+          <mrow>
+            <msup>
+              <mi>b</mi>
+              <mn>2</mn>
+            </msup>
+            <mo>&#x2212;</mo>
+            <mn>4</mn>
+            <mi>a</mi>
+            <mi>c</mi>
+          </mrow>
+        </msqrt>
+      </mrow>
+      <mrow>
+        <mn>2</mn>
+        <mi>a</mi>
+      </mrow>
+    </mfrac>
+  </mrow>
+</math>
+```

+ 1 - 0
render_math/__init__.py

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

+ 112 - 111
latex/latex.py

@@ -1,19 +1,14 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 """
 """
-Latex Plugin For Pelican
-========================
-
-This plugin allows you to write mathematical equations in your articles using Latex.
-It uses the MathJax Latex JavaScript library to render latex that is embedded in
-between `$..$` for inline math and `$$..$$` for displayed math. It also allows for
-writing equations in by using `\begin{equation}`...`\end{equation}`. No
-alteration to a template is required for this plugin to work, just install and
-use.
+Math Render Plugin For Pelican
+==============================
+This plugin allows your site to render Math. It supports both LaTex and MathML
+using the MathJax JavaScript engine.
 
 
 Typogrify Compatibility
 Typogrify Compatibility
 -----------------------
 -----------------------
 This plugin now plays nicely with typogrify, but it requires
 This plugin now plays nicely with typogrify, but it requires
-typogrify version 2.07 or above.
+typogrify version 2.04 or above.
 
 
 User Settings
 User Settings
 -------------
 -------------
@@ -25,45 +20,17 @@ See README for more details.
 
 
 from pelican import signals
 from pelican import signals
 from pelican import contents
 from pelican import contents
-import re
+import re, os
 
 
 # Global Variables
 # Global Variables
 _TYPOGRIFY = False  # used to determine if we should process typogrify
 _TYPOGRIFY = False  # used to determine if we should process typogrify
-_WRAP_TAG = None  # the tag to wrap mathjax in (needed to play nicely with typogrify or for template designers)
-_LATEX_REGEX = re.compile(r'(\$\$|\$|\\begin\{(.+?)\}|<(math).*?>).*?(\1|\\end\{\2\}|</\3>)', re.DOTALL | re.IGNORECASE) #  used to detect latex
-_LATEX_SUMMARY_REGEX = None  # used to match latex in summary
-_LATEX_PARTIAL_REGEX = None  # used to match latex that has been cut off in summary
+_WRAP_LATEX = None  # the tag to wrap LaTex math in (needed to play nicely with typogrify or for template designers)
+_MATH_REGEX = re.compile(r'(\$\$|\$|\\begin\{(.+?)\}|<(math)(?:\s.*?)?>).*?(\1|\\end\{\2\}|</\3>)', re.DOTALL | re.IGNORECASE) #  used to detect math
+_MATH_SUMMARY_REGEX = None  # used to match math in summary
+_MATH_INCOMPLETE_TAG_REGEX = None  # used to match math that has been cut off in summary
 _MATHJAX_SETTINGS = {}  # settings that can be specified by the user, used to control mathjax script settings
 _MATHJAX_SETTINGS = {}  # settings that can be specified by the user, used to control mathjax script settings
-_MATHJAX_SCRIPT="""
-<script type= "text/javascript">
-    if (!document.getElementById('mathjaxscript_pelican')) {{
-        var s = document.createElement('script');
-        s.id = 'mathjaxscript_pelican';
-        s.type = 'text/javascript'; s.src = 'https:' == document.location.protocol ? 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js' : 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
-        s[(window.opera ? "innerHTML" : "text")] =
-            "MathJax.Hub.Config({{" +
-            "    config: ['MMLorHTML.js']," +
-            "    TeX: {{ extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: {{ autoNumber: 'AMS' }} }}," +
-            "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
-            "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
-            "    displayAlign: '{align}'," +
-            "    displayIndent: '{indent}'," +
-            "    showMathMenu: {show_menu}," +
-            "    tex2jax: {{ " +
-            "        inlineMath: [ [\'$\',\'$\'] ], " +
-            "        displayMath: [ [\'$$\',\'$$\'] ]," +
-            "        processEscapes: {process_escapes}," +
-            "        preview: '{preview}'," +
-            "    }}, " +
-            "    'HTML-CSS': {{ " +
-            "        styles: {{ '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {{color: '{color} ! important'}} }}" +
-            "    }} " +
-            "}}); ";
-        (document.body || document.getElementsByTagName('head')[0]).appendChild(s);
-    }}
-</script>
-"""
-
+with open (os.path.dirname(os.path.realpath(__file__))+'/mathjax_script.txt', 'r') as mathjax_script:  # Read the mathjax javascript from file
+    _MATHJAX_SCRIPT=mathjax_script.read()
 
 
 # Python standard library for binary search, namely bisect is cool but I need
 # Python standard library for binary search, namely bisect is cool but I need
 # specific business logic to evaluate my search predicate, so I am using my
 # specific business logic to evaluate my search predicate, so I am using my
@@ -103,7 +70,7 @@ def ignore_content(content):
 
 
     # used to detect all <pre> and <code> tags. NOTE: Alter this regex should
     # used to detect all <pre> and <code> tags. NOTE: Alter this regex should
     # additional tags need to be ignored
     # additional tags need to be ignored
-    ignore_regex = re.compile(r'<(pre|code).*?>.*?</(\1)>', re.DOTALL | re.IGNORECASE)
+    ignore_regex = re.compile(r'<(pre|code)(?:\s.*?)?>.*?</(\1)>', re.DOTALL | re.IGNORECASE)
 
 
     for match in ignore_regex.finditer(content):
     for match in ignore_regex.finditer(content):
         ignore_within.append(match.span())
         ignore_within.append(match.span())
@@ -111,31 +78,32 @@ def ignore_content(content):
     return ignore_within
     return ignore_within
 
 
 
 
-def wrap_latex(content, ignore_within):
-    """Wraps latex in user specified tags.
+def wrap_math(content, ignore_within):
+    """Wraps math in user specified tags.
 
 
-    This is needed for typogrify to play nicely with latex but it can also be
+    This is needed for typogrify to play nicely with math but it can also be
     styled by template providers
     styled by template providers
     """
     """
-    wrap_latex.foundlatex = False
+
+    wrap_math.found_math = False
 
 
     def math_tag_wrap(match):
     def math_tag_wrap(match):
         """function for use in re.sub"""
         """function for use in re.sub"""
 
 
         # determine if the tags are within <pre> and <code> blocks
         # determine if the tags are within <pre> and <code> blocks
-        ignore = binary_search(match.span(1), ignore_within) and binary_search(match.span(2), ignore_within)
+        ignore = binary_search(match.span(1), ignore_within) or binary_search(match.span(4), ignore_within)
 
 
         if ignore or match.group(3) == 'math':
         if ignore or match.group(3) == 'math':
             if match.group(3) == 'math':
             if match.group(3) == 'math':
                 # Will detect mml, but not wrap anything around it
                 # Will detect mml, but not wrap anything around it
-                wrap_latex.foundlatex = True
+                wrap_math.found_math = True
 
 
             return match.group(0)
             return match.group(0)
         else:
         else:
-            wrap_latex.foundlatex = True
-            return '<%s>%s</%s>' % (_WRAP_TAG, match.group(0), _WRAP_TAG)
+            wrap_math.found_math = True
+            return '<%s>%s</%s>' % (_WRAP_LATEX, match.group(0), _WRAP_LATEX)
 
 
-    return (_LATEX_REGEX.sub(math_tag_wrap, content), wrap_latex.foundlatex)
+    return (_MATH_REGEX.sub(math_tag_wrap, content), wrap_math.found_math)
 
 
 
 
 def process_summary(instance, ignore_within):
 def process_summary(instance, ignore_within):
@@ -146,41 +114,51 @@ def process_summary(instance, ignore_within):
     """
     """
 
 
     process_summary.altered_summary = False
     process_summary.altered_summary = False
-    insert_mathjax_script = False
-    end_tag = '</%s>' % _WRAP_TAG if _WRAP_TAG != None else ''
+    insert_mathjax = False
+    end_tag = '</%s>' % _WRAP_LATEX if _WRAP_LATEX != None else ''
 
 
     # use content's _get_summary method to obtain summary
     # use content's _get_summary method to obtain summary
     summary = instance._get_summary()
     summary = instance._get_summary()
 
 
     # Determine if there is any math in the summary which are not within the
     # Determine if there is any math in the summary which are not within the
     # ignore_within tags
     # ignore_within tags
-    mathitem = None
-    for mathitem in _LATEX_SUMMARY_REGEX.finditer(summary):
-        if binary_search(mathitem.span(), ignore_within):
-            mathitem = None # In <code> or <pre> tags, so ignore
+    math_item = None
+    for math_item in _MATH_SUMMARY_REGEX.finditer(summary):
+        ignore = binary_search(math_item.span(2), ignore_within)
+        if '...' not in math_item.group(5):
+            ignore = ignore or binary_search(math_item.span(5), ignore_within)
+        else:
+            ignore = ignore or binary_search(math_item.span(6), ignore_within)
+
+        if ignore:
+            math_item = None # In <code> or <pre> tags, so ignore
         else:
         else:
-            insert_mathjax_script = True
+            insert_mathjax = True
 
 
-    # Repair the latex if it was cut off mathitem will be the final latex
+    # Repair the math if it was cut off math_item will be the final math
     # code  matched that is not within <pre> or <code> tags
     # code  matched that is not within <pre> or <code> tags
-    if mathitem and '...' in mathitem.group(6):
-        if mathitem.group(3) is not None:
-            end = r'\end{%s}' % mathitem.group(3)
-        elif mathitem.group(4) is not None:
+    if math_item and '...' in math_item.group(5):
+        if math_item.group(3) is not None:
+            end = r'\end{%s}' % math_item.group(3)
+        elif math_item.group(4) is not None:
             end = r'</math>'
             end = r'</math>'
-        elif mathitem.group(2) is not None:
-            end = mathitem.group(2)
+        elif math_item.group(2) is not None:
+            end = math_item.group(2)
 
 
-        search_regex = r'%s(%s.*?%s)' % (re.escape(instance._content[0:mathitem.start(1)]), re.escape(mathitem.group(1)), re.escape(end))
-        latex_match = re.search(search_regex, instance._content, re.DOTALL | re.IGNORECASE)
+        search_regex = r'%s(%s.*?%s)' % (re.escape(instance._content[0:math_item.start(1)]), re.escape(math_item.group(1)), re.escape(end))
+        math_match = re.search(search_regex, instance._content, re.DOTALL | re.IGNORECASE)
 
 
-        if latex_match:
-            new_summary = summary.replace(mathitem.group(0), latex_match.group(1)+'%s ...' % end_tag)
+        if math_match:
+            new_summary = summary.replace(math_item.group(0), math_match.group(1)+'%s ...' % end_tag)
 
 
             if new_summary != summary:
             if new_summary != summary:
-                return new_summary+_MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS)
+                if _MATHJAX_SETTINGS['auto_insert']:
+                    return new_summary+_MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS)
+                else:
+                    instance.mathjax = True
+                    return new_summary
 
 
-    def partial_regex(match):
+    def incomplete_end_latex_tag(match):
         """function for use in re.sub"""
         """function for use in re.sub"""
         if binary_search(match.span(3), ignore_within):
         if binary_search(match.span(3), ignore_within):
             return match.group(0)
             return match.group(0)
@@ -188,15 +166,20 @@ def process_summary(instance, ignore_within):
         process_summary.altered_summary = True
         process_summary.altered_summary = True
         return match.group(1) + match.group(4)
         return match.group(1) + match.group(4)
 
 
-    # check for partial latex tags at end. These must be removed
+    # check for partial math tags at end. These must be removed
 
 
-    summary = _LATEX_PARTIAL_REGEX.sub(partial_regex, summary)
+    summary = _MATH_INCOMPLETE_TAG_REGEX.sub(incomplete_end_latex_tag, summary)
 
 
-    if process_summary.altered_summary:
-        return summary+_MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS) if insert_mathjax_script else summary
+    if process_summary.altered_summary or insert_mathjax:
+        if insert_mathjax:
+            if _MATHJAX_SETTINGS['auto_insert']:
+                summary+= _MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS)
+            else:
+                instance.mathjax = True
 
 
-    return summary+_MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS) if insert_mathjax_script else None
+        return summary
 
 
+    return None  # Making it explicit that summary was not altered
 
 
 def process_settings(settings):
 def process_settings(settings):
     """Sets user specified MathJax settings (see README for more details)"""
     """Sets user specified MathJax settings (see README for more details)"""
@@ -213,9 +196,18 @@ def process_settings(settings):
     _MATHJAX_SETTINGS['indent'] = '0em'  # if above is not set to 'center', then this setting acts as an indent
     _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['show_menu'] = 'true'  # controls whether to attach mathjax contextual menu
     _MATHJAX_SETTINGS['process_escapes'] = 'true'  # controls whether escapes are processed
     _MATHJAX_SETTINGS['process_escapes'] = 'true'  # controls whether escapes are processed
-    _MATHJAX_SETTINGS['preview'] = 'TeX'  # controls what user sees as preview
+    _MATHJAX_SETTINGS['latex_preview'] = 'TeX'  # controls what user sees while waiting for LaTex to render
     _MATHJAX_SETTINGS['color'] = 'black'  # controls color math is rendered in
     _MATHJAX_SETTINGS['color'] = 'black'  # controls color math is rendered in
 
 
+    # This next setting controls whether the mathjax script should be automatically
+    # inserted into the content. The mathjax script will not be inserted into
+    # the content if no math is detected. For summaries that are present in the
+    # index listings, mathjax script will also be automatically inserted.
+    # Setting this value to false means the template must be altered if this
+    # plugin is to work, and so it is only recommended for the template
+    # designer who wants maximum control.
+    _MATHJAX_SETTINGS['auto_insert'] = True # controls whether mathjax script is automatically inserted into the content
+
     if not isinstance(settings, dict):
     if not isinstance(settings, dict):
         return
         return
 
 
@@ -223,6 +215,9 @@ def process_settings(settings):
     # Iterate over dictionary in a way that is compatible with both version 2
     # Iterate over dictionary in a way that is compatible with both version 2
     # and 3 of python
     # and 3 of python
     for key, value in ((key, settings[key]) for key in settings):
     for key, value in ((key, settings[key]) for key in settings):
+        if key == 'auto_insert' and isinstance(value, bool):
+            _MATHJAX_SETTINGS[key] = value
+
         if key == 'align' and isinstance(value, str):
         if key == 'align' and isinstance(value, str):
             if value == 'left' or value == 'right' or value == 'center':
             if value == 'left' or value == 'right' or value == 'center':
                 _MATHJAX_SETTINGS[key] = value
                 _MATHJAX_SETTINGS[key] = value
@@ -238,7 +233,7 @@ def process_settings(settings):
         if key == 'process_escapes' and isinstance(value, bool):
         if key == 'process_escapes' and isinstance(value, bool):
             _MATHJAX_SETTINGS[key] = 'true' if value else 'false'
             _MATHJAX_SETTINGS[key] = 'true' if value else 'false'
 
 
-        if key == 'preview' and isinstance(value, str):
+        if key == 'latex_preview' and isinstance(value, str):
             _MATHJAX_SETTINGS[key] = value
             _MATHJAX_SETTINGS[key] = value
 
 
         if key == 'color' and isinstance(value, str):
         if key == 'color' and isinstance(value, str):
@@ -247,7 +242,7 @@ def process_settings(settings):
 
 
 def process_content(instance):
 def process_content(instance):
     """Processes content, with logic to ensure that typogrify does not clash
     """Processes content, with logic to ensure that typogrify does not clash
-    with latex.
+    with math.
 
 
     In addition, mathjax script is inserted at the end of the content thereby
     In addition, mathjax script is inserted at the end of the content thereby
     making it independent of the template
     making it independent of the template
@@ -258,31 +253,36 @@ def process_content(instance):
 
 
     ignore_within = ignore_content(instance._content)
     ignore_within = ignore_content(instance._content)
 
 
-    if _WRAP_TAG:
-        instance._content, latex = wrap_latex(instance._content, ignore_within)
+    if _WRAP_LATEX:
+        instance._content, math = wrap_math(instance._content, ignore_within)
     else:
     else:
-        latex = True if _LATEX_REGEX.search(instance._content) else False
+        math = True if _MATH_REGEX.search(instance._content) else False
 
 
     # The user initially set typogrify to be True, but since it would clash
     # The user initially set typogrify to be True, but since it would clash
-    # with latex, we set it to False. This means that the default reader will
+    # with math, we set it to False. This means that the default reader will
     # not call typogrify, so it is called here, where we are able to control
     # not call typogrify, so it is called here, where we are able to control
-    # logic for it ignore latex if necessary
+    # logic for it ignore math if necessary
     if _TYPOGRIFY:
     if _TYPOGRIFY:
-        # Tell typogrify to ignore the tags that latex has been wrapped in
+        # Tell typogrify to ignore the tags that math has been wrapped in
         # also, typogrify must always ignore mml (math) tags
         # also, typogrify must always ignore mml (math) tags
-        ignore_tags = [_WRAP_TAG,'math'] if _WRAP_TAG else ['math']
+        ignore_tags = [_WRAP_LATEX,'math'] if _WRAP_LATEX else ['math']
 
 
         # Exact copy of the logic as found in the default reader
         # Exact copy of the logic as found in the default reader
         from typogrify.filters import typogrify
         from typogrify.filters import typogrify
         instance._content = typogrify(instance._content, ignore_tags)
         instance._content = typogrify(instance._content, ignore_tags)
         instance.metadata['title'] = typogrify(instance.metadata['title'], ignore_tags)
         instance.metadata['title'] = typogrify(instance.metadata['title'], ignore_tags)
 
 
-    if latex:
-        # Mathjax script added to the end of article. Now it does not need to
-        # be explicitly added to the template
-        instance._content += _MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS)
+    if math:
+        if _MATHJAX_SETTINGS['auto_insert']:
+            # Mathjax script added to content automatically. Now it
+            # does not need to be explicitly added to the template
+            instance._content += _MATHJAX_SCRIPT.format(**_MATHJAX_SETTINGS)
+        else:
+            # Place the burden on ensuring mathjax script is available to
+            # browser on the template designer (see README for more details)
+            instance.mathjax = True
 
 
-        # The summary needs special care because latex math cannot just be cut
+        # The summary needs special care because math math cannot just be cut
         # off
         # off
         summary = process_summary(instance, ignore_within)
         summary = process_summary(instance, ignore_within)
         if summary != None:
         if summary != None:
@@ -295,12 +295,12 @@ def pelican_init(pelicanobj):
     """
     """
 
 
     global _TYPOGRIFY
     global _TYPOGRIFY
-    global _WRAP_TAG
-    global _LATEX_SUMMARY_REGEX
-    global _LATEX_PARTIAL_REGEX
+    global _WRAP_LATEX
+    global _MATH_SUMMARY_REGEX
+    global _MATH_INCOMPLETE_TAG_REGEX
 
 
     try:
     try:
-        settings = pelicanobj.settings['LATEX']
+        settings = pelicanobj.settings['MATH']
     except:
     except:
         settings = None
         settings = None
 
 
@@ -314,30 +314,31 @@ def pelican_init(pelicanobj):
     try:
     try:
         if pelicanobj.settings['TYPOGRIFY'] == True:
         if pelicanobj.settings['TYPOGRIFY'] == True:
             pelicanobj.settings['TYPOGRIFY'] = False
             pelicanobj.settings['TYPOGRIFY'] = False
-            _WRAP_TAG = 'mathjax' # default to wrap mathjax content inside of
+            _WRAP_LATEX = 'mathjax' # default to wrap mathjax content inside of
             _TYPOGRIFY = True
             _TYPOGRIFY = True
     except KeyError:
     except KeyError:
         pass
         pass
 
 
-    # Set _WRAP_TAG to the settings tag if defined. The idea behind this is
+    # Set _WRAP_LATEX to the settings tag if defined. The idea behind this is
     # to give template designers control over how math would be rendered
     # to give template designers control over how math would be rendered
     try:
     try:
-        if pelicanobj.settings['LATEX']['wrap']:
-            _WRAP_TAG = pelicanobj.settings['LATEX']['wrap']
+        if pelicanobj.settings['MATH']['wrap_latex']:
+            _WRAP_LATEX = pelicanobj.settings['MATH']['wrap_latex']
     except (KeyError, TypeError):
     except (KeyError, TypeError):
         pass
         pass
 
 
-    # regular expressions that depend on _WRAP_TAG are set here
-    tag_start= r'<%s>' % _WRAP_TAG if not _WRAP_TAG is None else ''
-    tag_end = r'</%s>' % _WRAP_TAG if not _WRAP_TAG is None else ''
-    latex_summary_regex = r'((\$\$|\$|\\begin\{(.+?)\}|<(math)(\s.*?)?>).+?)(\2|\\end\{\3\}|</\4>|\s?\.\.\.)(%s|</\4>)?' % tag_end
+    # regular expressions that depend on _WRAP_LATEX are set here
+    tag_start= r'<%s>' % _WRAP_LATEX if not _WRAP_LATEX is None else ''
+    tag_end = r'</%s>' % _WRAP_LATEX if not _WRAP_LATEX is None else ''
+    math_summary_regex = r'((\$\$|\$|\\begin\{(.+?)\}|<(math)(?:\s.*?)?>).+?)(\2|\\end\{\3\}|</\4>|\s?\.\.\.)(%s|</\4>)?' % tag_end
 
 
     # NOTE: The logic in _get_summary will handle <math> correctly because it
     # NOTE: The logic in _get_summary will handle <math> correctly because it
-    # is perceived as an html tag. Therefore we are only interested in handling non mml
-    latex_partial_regex = r'(.*)(%s)(\\\S*?|\$)\s*?(\s?\.\.\.)(%s)?$' % (tag_start, tag_end)
+    # is perceived as an html tag. Therefore we are only interested in handling
+    # non mml (i.e. LaTex)
+    incomplete_end_latex_tag = r'(.*)(%s)(\\\S*?|\$)\s*?(\s?\.\.\.)(%s)?$' % (tag_start, tag_end)
 
 
-    _LATEX_SUMMARY_REGEX = re.compile(latex_summary_regex, re.DOTALL | re.IGNORECASE)
-    _LATEX_PARTIAL_REGEX = re.compile(latex_partial_regex, re.DOTALL | re.IGNORECASE)
+    _MATH_SUMMARY_REGEX = re.compile(math_summary_regex, re.DOTALL | re.IGNORECASE)
+    _MATH_INCOMPLETE_TAG_REGEX = re.compile(incomplete_end_latex_tag, re.DOTALL | re.IGNORECASE)
 
 
 
 
 def register():
 def register():

+ 30 - 0
render_math/mathjax_script.txt

@@ -0,0 +1,30 @@
+<script type= "text/javascript">
+    if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {{
+        var mathjaxscript = document.createElement('script');
+        mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
+        mathjaxscript.type = 'text/javascript';
+        mathjaxscript.src = 'https:' == document.location.protocol
+		? 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js'
+		: 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
+        mathjaxscript[(window.opera ? "innerHTML" : "text")] =
+            "MathJax.Hub.Config({{" +
+            "    config: ['MMLorHTML.js']," +
+            "    TeX: {{ extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: {{ autoNumber: 'AMS' }} }}," +
+            "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
+            "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
+            "    displayAlign: '{align}'," +
+            "    displayIndent: '{indent}'," +
+            "    showMathMenu: {show_menu}," +
+            "    tex2jax: {{ " +
+            "        inlineMath: [ ['$','$'] ], " +
+            "        displayMath: [ ['$$','$$'] ]," +
+            "        processEscapes: {process_escapes}," +
+            "        preview: '{latex_preview}'," +
+            "    }}, " +
+            "    'HTML-CSS': {{ " +
+            "        styles: {{ '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {{color: '{color} ! important'}} }}" +
+            "    }} " +
+            "}}); ";
+        (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
+    }}
+</script>