Source code for algebraixlib.util.html

"""A conversion utility that manipulates a math object into a LaTeX representation."""

# $Id: html.py 22614 2015-07-15 18:14:53Z gfiedler $
# Copyright Algebraix Data Corporation 2015 - $Date: 2015-07-15 13:14:53 -0500 (Wed, 15 Jul 2015) $
#
# This file is part of algebraixlib <http://github.com/AlgebraixData/algebraixlib>.
#
# algebraixlib is free software: you can redistribute it and/or modify it under the terms of version
# 3 of the GNU Lesser General Public License as published by the Free Software Foundation.
#
# algebraixlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with algebraixlib.
# If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------------------------------------
import collections as _collections
import html as _html
import io as _io

import algebraixlib.mathobjects as _mo
from algebraixlib.util.latexprinter import math_object_to_latex as _math_object_to_latex

# Named Tuple for containing information about a math object.
# DataAlgebraHtmlDescriptor contains
# input_title: A string (optional) which can serve as a name, origin expression or title
# data_algebra_construct: The math object or container of math objects.
# description_brief: A string Optional to offer up a little more detail
DataAlgebraHtmlDescriptor = _collections.namedtuple(
    'DataAlgebraHtmlDescriptor',
    'input_title data_algebra_construct description_brief')


[docs]def math_object_as_html(title: str, data_algebra_html_descriptors: [], header_template: str=None, footer_template: str=None, mathobject_template: str=None) -> str: """Return the contents of an HTML webpage representing a math object, using templates. :param title: The title for this page of math objects. :param data_algebra_html_descriptors: An array of ``DataAlgebraHtmlDescriptor`` instances (containing math objects and their related descriptive strings). :param header_template: HTML markup that starts the webpage. May contain the template ``page_title``; it is set to the value of ``title``. :param footer_template: HTML markup that ends the page. :param mathobject_template: The HTML markup that is emited for each math object. May contain the templates ``input_title``, ``description_brief`` and ``data_algebra_construct``, which are replaced with the respective values in the associated ``DataAlgebraHtmlDescriptor``. :return: The final HTML webpage. """ # The default header template. Start the web page and set up some basic styles for the various # display elements. Requires the template argument 'page_title' (the title for the document that # is being created). default_header_template = """\ <html> <head> <script src='https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'> </script> <script type="text/javascript"> //<![CDATA[ //]]> </script> <style> body {{background-color: #F8F8FF}} #page_title{{}} #input_title{{}} #description_brief{{ border: 1px solid black; padding: 5px; background-color: white; }} #data_algebra_construct{{ border: 1px solid black; padding: 5px; background-color: white; }} </style> </head> <body> <h1 id="page_title">{page_title}</h1> """ if header_template is None: header_template = default_header_template # The default footer. Only closes the body and html tags, assumed to have been opened by the # header. It is not an actual template. default_footer = """</body></html>""" if footer_template is None: footer_template = default_footer # The default math object template. Add a section to the page that displays a math object with # associated descriptive text. Requires three template arguments (the names match the members of # DataAlgebraHtmlDescriptor): # - input_title: A string naming the math object, displayed in an h2 header. May contain HTML # markup, but it needs to be consistent with being used in an h2 header. # - description_brief: A description of the mathobject, displayed in a preformatted section. May # contain HTML markup, but it needs to be consistent with being used in preformatted text. # - data_algebra_construct: Normally the LaTeX representation of the mathobject, but could also # be HTML markup, or a simple string representation of the math object. Is shown as standard # text. default_mathobject_template = """\ <h2 id="input_title">{input_title}</h2> <div id="description_brief"><pre>{description_brief}</pre></div> <div id="data_algebra_construct">{data_algebra_construct}</div> """ if mathobject_template is None: mathobject_template = default_mathobject_template writer = _io.StringIO() # Start the web page by appending the header, and injecting the title. writer.write(header_template.format(page_title=as_html_handle_basic_parameter(title))) # Appends the template, with replaced elements from the descriptors, for each description. # Makes use of delegate functions for rendering the different parameters. writer.write(''.join( [mathobject_template.format( input_title=as_html_handle_basic_parameter(dataAlgebraDescriptor.input_title), description_brief=as_html_handle_basic_parameter(dataAlgebraDescriptor.description_brief), data_algebra_construct=as_html_handle_data_algebra(dataAlgebraDescriptor.data_algebra_construct)) for dataAlgebraDescriptor in data_algebra_html_descriptors]) ) # Ends the web page with the provided footer. writer.write(footer_template) html_out = writer.getvalue() # print(html_out) return html_out
[docs]def as_html_handle_basic_parameter(html_input: str) -> str: """Convert the string of ``html_input`` into an HTML-safe character sequence. :param html_input: The value to convert so that it can be added to HTML content. :return: An HTML-safe string. """ return _html.escape(str(html_input))
[docs]def as_html_handle_data_algebra(mathobj): """Add some logic to allow the client to provide the math object in several ways: - If it is a mathobject, it will be turnied into LaTeX and wrapped in the mathjax escape token. - If it is a container of mathobjects, then each one will be turned into LaTeX and presented on its own line. - If it is not a mathobject then the str function will be invoked. :param mathobj: The data algebra construct to be rendered on HTML :return: The HTML snippet of the mathobject. """ if isinstance(mathobj, _mo.MathObject): # print this one math object return "$$" + _html.escape(_math_object_to_latex(mathobj)) + "$$" elif isinstance(mathobj, _collections.Iterable): temp = "" for elem in mathobj: if isinstance(elem, _mo.MathObject): # latex temp += "$$\(\\require{color}\)\(\\require{xcolor}\)" + \ _html.escape(_math_object_to_latex(elem)) + "$$ <br //>" else: # str temp += _html.escape(str(elem)) + "<br //>" return temp else: # print this one non-math object using str(mathobjects) return _html.escape(str(mathobj))
[docs]def build_descriptors_from_math_obj(mathobjects): """ A utility function if a client does not wish to create their own descriptor objects. This function will create a descriptor array from a list of mathobjects. :param mathobjects: List to build descriptors out of. :return: DataAlgebraHtmlDescriptors """ data_alg_descriptors = [] for mathobj in mathobjects: data_alg_descriptors.append( DataAlgebraHtmlDescriptor(str(mathobj), mathobj, "No Description,")) return data_alg_descriptors
[docs]def create_simple_web_page(mathobj: _mo.MathObject) -> str: """Convert a math object into an HTML file. This does not offer much client specification or HTML injection. Create a basic webpage for one mathobject. :param mathobj: The mathobject to create a webpage for. :return: The web page (HTML) for ``mathobj``. """ web_template = """\ <html> <head> <script src='https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'> </script> <script type="text/javascript"> //<![CDATA[ //]]> </script> <style> body {{background-color: #F8F8FF}} #latexArea, #dataAlgebraArea{{ width: 1000px; height: 200px; border: 1px solid black; padding: 5px; overflow: scroll; background-color: white; resize: both; }} </style> </head> <body> <h1>MathJax is Easy!</h1> <h2>Input:</h2> <div id="dataAlgebraArea">{data_algebra_in!s}</div> <h2>Output:</h2> <div id="latexArea">$$\(\\require{color}\){latex_out}$$</div> </body></html> """ web_out = web_template.format(data_algebra_in=mathobj, latex_out=_math_object_to_latex(mathobj)) print(web_out) return web_out # # Build unit test up here for now #
import unittest
[docs]class DataAlgToWebTest(unittest.TestCase): """Test the latex printer functions.""" # Test Input Data _a1 = _mo.Atom('scooby') _a2 = _mo.Atom('doo') _c1 = _mo.Couplet(left=_a1, right=_a2) _a3 = _mo.Atom('shaggy') _a4 = _mo.Atom('rogers') _c2 = _mo.Couplet(left=_a3, right=_a4) _a5 = _mo.Atom('mystery') _a6 = _mo.Atom('van') _c3 = _mo.Couplet(left=_a5, right=_a6) _s1 = _mo.Set([_c1, _c2, _c3]) _a7 = _mo.Atom('velma') _a8 = _mo.Atom('dinkley') _c4 = _mo.Couplet(left=_a7, right=_a8) _a9 = _mo.Atom('fred') _a10 = _mo.Atom('jones') _c5 = _mo.Couplet(left=_a9, right=_a10) _a11 = _mo.Atom('daphne') _a12 = _mo.Atom('blake') _c6 = _mo.Couplet(left=_a11, right=_a12) _a13 = _mo.Atom('mystery') _a14 = _mo.Atom('team') _c7 = _mo.Couplet(left=_a13, right=_a14) _s2 = _mo.Set([_c4, _c5, _c6, _c7]) _s3 = _mo.Set([_s1, _s2]) @unittest.skip('This test creates non-deterministic results, so sometimes fails.')
[docs] def test_data_alg_to_web_simple(self): # large comparisons needs diff size increased self.maxDiff = None print("test_data_alg_to_web_simple Begin:") # Actual LaTeX Output Data html_output = create_simple_web_page(self._s3) # Expected LaTeX Output Data html_output_ex = """<html> <head> <script src='https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'> </script> <script type="text/javascript"> //<![CDATA[ //]]> </script> <style> body {background-color: #F8F8FF} #latexArea, #dataAlgebraArea{ width: 1000px; height: 200px; border: 1px solid black; padding: 5px; overflow: scroll; background-color: white; resize: both; } </style> </head> <body> <h1>MathJax is Easy!</h1> <h2>Input:</h2> <div id="dataAlgebraArea">{{('doo'^'scooby'), ('rogers'^'shaggy'), ('van'^'mystery')}, {('dinkley'^'velma'), ('team'^'mystery'), ('jones'^'fred'), ('blake'^'daphne')}}</div> <h2>Output:</h2> <div id="latexArea"> $$\left\{\ \\begin{array}{l}\\\\ \quad\left\{\ (\mbox{'blake'}^{\mbox{'daphne'}}),\ (\mbox{'jones'}^{\mbox{'fred'}}),\ (\mbox{'team'}^{\mbox{'mystery'}}),\ (\mbox{'dinkley'}^{\mbox{'velma'}})\ \\right\},\\\\ \quad\left\{\ (\mbox{'van'}^{\mbox{'mystery'}}),\ (\mbox{'doo'}^{\mbox{'scooby'}}),\ (\mbox{'rogers'}^{\mbox{'shaggy'}})\ \\right\}\\\\ \end{array}\\right\}$$</div> </body></html>""" self.assertEqual(html_output_ex, html_output) print("Test End.") # @unittest.skip('Skipping this test as it is more an example program at the moment.') # def test_data_alg_to_web(self): # #large comparisons needs diff size increased # self.maxDiff = None # print("test_data_alg_to_web Begin:") # # Actual LaTeX Output Data # html_output = create_web_page([self._s1, self._s2, self._s3]) # # Expected LaTeX Output Data # html_output_ex = """Insert something like expected results here.""" # self.assertEqual(html_output_ex, html_output) # print("Test End.")
@unittest.skip('Skipping this test as it is more an example program at the moment.')
[docs] def test_data_alg_to_web(self): # large comparisons needs diff size increased self.maxDiff = None print("test_data_alg_to_web Begin:") # Actual LaTeX Output Data html_output = math_object_as_html("TestTitle", build_descriptors_from_math_obj( [self._s1, self._s2, self._s3])) # Expected LaTeX Output Data html_output_ex = """Insert something like expected results here.""" self.assertEqual(html_output_ex, html_output) print("Test End.")