1# vim: ts=8:sts=8:sw=8:noexpandtab 2 3# This file is part of python-markups module 4# License: 3-clause BSD, see LICENSE file 5# Copyright: (C) Dmitry Shachnev, 2012-2021 6 7from __future__ import annotations 8 9from typing import Any, Dict, Tuple, Optional 10 11whole_html_template = """<!doctype html> 12<html> 13<head> 14<meta http-equiv="content-type" content="text/html; charset=utf-8"> 15{custom_headers}<title>{title}</title> 16{stylesheet}{javascript}</head> 17<body> 18{body} 19</body> 20</html> 21""" 22 23 24class AbstractMarkup: 25 """Abstract class for markup languages. 26 27 :param filename: optional name of the file 28 """ 29 30 #: name of the markup visible to user 31 name: str 32 #: various attributes, like links to website and syntax documentation 33 attributes: Dict[int, Any] 34 #: indicates which file extensions are associated with the markup 35 file_extensions: Tuple[str, ...] 36 #: the default file extension 37 default_extension: str 38 39 def __init__(self, filename: Optional[str] = None): 40 self.filename = filename 41 42 @staticmethod 43 def available() -> bool: 44 """ 45 :returns: whether the markup is ready for use 46 47 (for example, whether the required third-party 48 modules are importable) 49 """ 50 return True 51 52 def convert(self, text: str) -> ConvertedMarkup: 53 """ 54 :returns: a ConvertedMarkup instance (or a subclass thereof) 55 containing the markup converted to HTML 56 """ 57 raise NotImplementedError 58 59 60class ConvertedMarkup: 61 """This class encapsulates the title, body, stylesheet and javascript 62 of a converted document. 63 64 Instances of this class are created by :meth:`.AbstractMarkup.convert` 65 method, usually it should not be instantiated directly. 66 """ 67 68 def __init__(self, body: str, title: str = '', 69 stylesheet: str = '', javascript: str = ''): 70 self.title = title 71 self.stylesheet = stylesheet 72 self.javascript = javascript 73 self.body = body 74 75 def get_document_title(self) -> str: 76 """ 77 :returns: the document title 78 """ 79 return self.title 80 81 def get_document_body(self) -> str: 82 """ 83 :returns: the contents of the ``<body>`` HTML tag 84 """ 85 return self.body 86 87 def get_stylesheet(self) -> str: 88 """ 89 :returns: the contents of ``<style type="text/css">`` HTML tag 90 """ 91 return self.stylesheet 92 93 def get_javascript(self, webenv: bool = False) -> str: 94 """ 95 :returns: one or more HTML tags to be inserted into the document 96 ``<head>``. 97 :param webenv: if true, the specific markups may optimize the 98 document for being used in the World Wide Web (for 99 example, a remote version of MathJax script can be 100 inserted instead of the local one). 101 """ 102 return self.javascript 103 104 def get_whole_html(self, custom_headers: str = '', include_stylesheet: bool = True, 105 fallback_title: str = '', webenv: bool = False) -> str: 106 """ 107 :returns: the full contents of the HTML document (unless overridden 108 this is a combination of the previous methods) 109 :param custom_headers: custom HTML to be inserted into the document 110 ``<head>`` 111 :param include_stylesheet: if false, the stylesheet will not 112 be included in the document ``<head>`` 113 :param fallback_title: when impossible to get the ``<title>`` from 114 the document, this string can be used as a 115 fallback 116 :param webenv: like in :meth:`~.ConvertedMarkup.get_javascript` 117 above 118 """ 119 stylesheet = ('<style type="text/css">\n' + self.get_stylesheet() 120 + '</style>\n' if include_stylesheet else '') 121 122 context = { 123 "body": self.get_document_body(), 124 "title": self.get_document_title() or fallback_title, 125 "javascript": self.get_javascript(webenv), 126 "stylesheet": stylesheet, 127 "custom_headers": custom_headers, 128 } 129 return whole_html_template.format(**context) 130