Example #1
0
 def __init__(self, config, doc_src_path, site_config, logger=None):
     '''
         @config a dict object
         @logger teedoc.logger.Logger object
     '''
     self.logger = Fake_Logger() if not logger else logger
     self.doc_src_path = doc_src_path
     self.site_config = site_config
     self.config = Plugin.defautl_config
     self.config.update(config)
     self.logger.i("-- plugin <{}> init".format(self.name))
     self.logger.i("-- plugin <{}> config: {}".format(
         self.name, self.config))
     self._extention = {
         "toc": {
             "depth": config["toc_depth"] if "toc_depth" in config else 3
         },
         "metadata": None,
         "fenced-code-blocks": None,
         "highlightjs-lang": None,
         "break-on-newline": None,
         "code-friendly": None,
         "cuddled-lists": None,
         "footnotes": None,
         "strike": None,
         "spoiler": None,
         "tables": None,
         "task_list": None
     }
Example #2
0
 def on_init(self,
             config,
             doc_src_path,
             site_config,
             logger=None,
             multiprocess=True,
             **kw_args):
     '''
         @config a dict object
         @logger teedoc.logger.Logger object
     '''
     self.multiprocess = multiprocess
     self.logger = Fake_Logger() if not logger else logger
     self.doc_src_path = doc_src_path
     self.site_config = site_config
     self.config = Plugin.defautl_config
     mathjax_config = self.config["mathjax"]
     if "mathjax" in config:
         for k, v in config["mathjax"].items():
             if type(v) != dict:
                 mathjax_config[k] = v
             else:
                 mathjax_config[k].update(v)
     self.config.update(config)
     self.config["mathjax"] = mathjax_config
     self.logger.i("-- plugin <{}> init".format(self.name))
     self.logger.i("-- plugin <{}> config: {}".format(
         self.name, self.config))
     if not self.multiprocess:
         from .renderer import create_markdown_parser
         from .parse_metadata import Meta_Parser
         self.create_markdown_parser = create_markdown_parser
         self.Meta_Parser = Meta_Parser
Example #3
0
    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.html_header_items = []

        # set site_root_url env value
        if not "id" in config:
            self.logger.e('can not find config["id"] in plugin {}'.format(
                self.name))
            return
        code_raw = '''    <script async src="https://www.googletagmanager.com/gtag/js?id={}"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){{dataLayer.push(arguments);}}
      gtag('js', new Date());
  
      gtag('config', '{}');
    </script>'''.format(config["id"], config["id"])
        self.html_header_items = [code_raw]
Example #4
0
    def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))
        
        # set site_root_url env value
        if not "code" in config:
            self.logger.e('can not find config["code"] in plugin {}'.format(self.name))
            return
        baidu_tongji_code = '''<script>
var _hmt = _hmt || [];
(function() {{
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?{}";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
}})();
</script>'''.format(config["code"])
        self.html_header_items = [baidu_tongji_code]
Example #5
0
    def __init__(self, config, doc_src_path, site_config, logger=None):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_search")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        self.css = {
            "/static/css/search/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
        }
        self.footer_js = {
            "/static/js/search/main.js":
            os.path.join(self.assets_abs_path, "main.js")
        }
        self.images = {
            "/static/image/search/close.svg":
            os.path.join(self.assets_abs_path, "close.svg"),
            "/static/image/search/search.svg":
            os.path.join(self.assets_abs_path, "search.svg"),
        }

        # set site_root_url env value
        if not "env" in config:
            config['env'] = {}
        config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = config["env"]
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)

        self.html_js_items = self._generate_html_js_items()
        self.content = {"articles": {}, "pages": {}}
Example #6
0
 def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args):
     '''
         @config a dict object
         @logger teedoc.logger.Logger object
     '''
     self.logger = Fake_Logger() if not logger else logger
     self.doc_src_path = doc_src_path
     self.site_config = site_config
     self.config = Plugin.defautl_config
     self.config.update(config)
     self.logger.i("-- plugin <{}> init".format(self.name))
     self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))
Example #7
0
 def on_init(self,
             config,
             doc_src_path,
             site_config,
             logger=None,
             multiprocess=True,
             **kw_args):
     '''
         @config a dict object
         @logger teedoc.logger.Logger object
     '''
     self.multiprocess = multiprocess
     self.logger = Fake_Logger() if not logger else logger
     self.doc_src_path = doc_src_path
     self.site_config = site_config
     self.config = Plugin.defautl_config
     self.config.update(config)
     self.logger.i("-- plugin <{}> init".format(self.name))
     self.logger.i("-- plugin <{}> config: {}".format(
         self.name, self.config))
     self.temp_dir = os.path.join(tempfile.gettempdir(),
                                  "teedoc_plugin_blog")
     if os.path.exists(self.temp_dir):
         shutil.rmtree(self.temp_dir)
     os.makedirs(self.temp_dir)
     self.assets_abs_path = os.path.join(
         os.path.dirname(os.path.abspath(__file__)), "assets")
     self.assets = {
         "/static/js/plugin_blog/main.js":
         os.path.join(self.assets_abs_path, "main.js"),
     }
     vars = {"site_root_url": self.site_config["site_root_url"]}
     self.assets = self._update_file_var(self.assets, vars, self.temp_dir)
     self.files_to_copy = self.assets.copy()  # must use copy
     blog_url = list(self.site_config["route"]["blog"].keys())
     if len(blog_url) > 1:
         self.logger.e("only support one blog url path")
         raise Exception("only support one blog url path")
     self.blog_url = blog_url[0]
     self.blog_dir = os.path.join(
         self.doc_src_path,
         self.site_config["route"]["blog"][self.blog_url]).replace(
             "\\", "/")
     self.index_content = {"items": {}}
Example #8
0
    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.module_path = os.path.abspath(
            os.path.dirname(os.path.abspath(__file__)))
        self.assets_abs_path = os.path.join(self.module_path, "assets")
        self.temp_dir = self.get_temp_dir()

        self.footer_js = {
            # don't use ad(advertisement) keyword, may blocked by browser plugin
            "/static/js/add_hint/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
            "/static/js/add_hint/main.js":
            os.path.join(self.assets_abs_path, "main.js")
        }
        self.html_footer_items = []
        for url in self.footer_js:
            if url.endswith(".css"):
                item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                    url)
            else:
                item = '<script src="{}"></script>'.format(url)
            self.html_footer_items.append(item)
        vars = self.config
        self.footer_js = self.update_file_var(self.footer_js, vars,
                                              self.temp_dir)
        self.files_to_copy = self.footer_js
Example #9
0
 def on_init(self,
             config,
             doc_src_path,
             site_config,
             logger=None,
             multiprocess=True,
             **kw_args):
     '''
         @config a dict object
         @logger teedoc.logger.Logger object
     '''
     self.logger = Fake_Logger() if not logger else logger
     self.doc_src_path = doc_src_path
     self.site_config = site_config
     self.config = Plugin.defautl_config
     self.config.update(config)
     self.logger.i("-- plugin <{}> init".format(self.name))
     self.logger.i("-- plugin <{}> config: {}".format(
         self.name, self.config))
     self.module_path = os.path.abspath(
         os.path.dirname(os.path.abspath(__file__)))
     self.assets_abs_path = os.path.join(self.module_path, "assets")
Example #10
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-markdown-parser"
    desc = "markdown parser plugin for teedoc"
    defautl_config = {"parse_files": ["md"]}

    def __init__(self, config, doc_src_path, site_config, logger=None):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self._extention = {
            "toc": {
                "depth": config["toc_depth"] if "toc_depth" in config else 3
            },
            "metadata": None,
            "fenced-code-blocks": None,
            "highlightjs-lang": None,
            "break-on-newline": None,
            "code-friendly": None,
            "cuddled-lists": None,
            "footnotes": None,
            "strike": None,
            "spoiler": None,
            "tables": None,
            "task_list": None
        }

    def on_parse_files(self, files):
        # result, format must be this
        result = {"ok": False, "msg": "", "htmls": OrderedDict()}
        # function parse md file is disabled
        if not "md" in self.config["parse_files"]:
            result[
                "msg"] = "disabled markdown parse, but only support markdown"
            return result
        self.logger.d("-- plugin <{}> parse {} files".format(
            self.name, len(files)))
        # self.logger.d("files: {}".format(files))

        for file in files:
            ext = os.path.splitext(file)[1].lower()
            if ext.endswith("md"):
                with open(file, encoding="utf-8") as f:
                    content = f.read().strip()
                    content = self._update_link(content)
                    parser = markdown2.Markdown(extras=self._extention)
                    parser._toc_html = ""
                    html = parser.convert(content)
                    if "title" in html.metadata:
                        title = html.metadata["title"]
                    else:
                        title = ""
                    if "keywords" in html.metadata:
                        keywords = html.metadata["keywords"].split(",")
                    else:
                        keywords = []
                    if "tags" in html.metadata:
                        tags = html.metadata["tags"].split(",")
                    else:
                        tags = []
                    if "desc" in html.metadata:
                        desc = html.metadata["desc"]
                    else:
                        desc = []
                    result["htmls"][file] = {
                        "title": title,
                        "desc": desc,
                        "keywords": keywords,
                        "tags": tags,
                        "body": html,
                        "toc": html.toc_html if html.toc_html else "",
                        "metadata": html.metadata,
                        "raw": content
                    }
            else:
                result["htmls"][file] = None
        result['ok'] = True
        return result

    def on_parse_pages(self, files):
        result = self.on_parse_files(files)
        return result

    def on_add_html_header_items(self):
        items = []
        items.append(
            '<meta name="markdown-generator" content="teedoc-plugin-markdown-parser">'
        )
        return items

    def _update_link(self, content):
        def re_del(c):
            ret = c[0].replace(".md", ".html")
            ret = re.sub("README.md", "index.html", c[0], flags=re.I)
            ret = re.sub(r".md", ".html", ret, re.I)
            return ret

        content = re.sub(r'\[.*?\]\(.*?\.md\)', re_del, content, flags=re.I)
        return content
Example #11
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-jupyter-notebook-parser"
    desc = "jupyter notebook parser plugin for teedoc"
    defautl_config = {
        "parse_files": ["ipynb"]
    }

    def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))

        

    def on_parse_files(self, files):
        # result, format must be this
        result = {
            "ok": False,
            "msg": "",
            "htmls": OrderedDict()
        }
        # function parse md file is disabled
        if not "ipynb" in self.config["parse_files"]:
            result["msg"] = "disabled notebook parse, but only support notebook"
            return result
        self.logger.d("-- plugin <{}> parse {} files".format(self.name, len(files)))
        # self.logger.d("files: {}".format(files))
        
        for file in files:
            name = os.path.basename(file)
            # ignore temp file
            if name.startswith(".~"):
                result["htmls"][file] = None
                continue
            ext = os.path.splitext(file)[1].lower()
            if ext.endswith("ipynb"):
                html = convert_ipynb_to_html(file)
                html.body = self._update_link_html(html.body)
                metadata = html.metadata
                date = None
                ts = int(os.stat(file).st_mtime)
                if "date" in metadata:
                    date = metadata["date"].strip().lower()
                    # set date to false to disable date display
                    if date and (date == "false" or date == "none"):
                        date = ""
                    else:
                        GMT_FORMAT = '%Y-%m-%d'
                        try:
                            date_obj = datetime.strptime(date, GMT_FORMAT)
                            ts = int(date_obj.timestamp())
                        except Exception as e:
                            pass
                if "author" in metadata:
                    author = metadata["author"]
                else:
                    author = ""
                result["htmls"][file] = {
                    "title": html.title,
                    "desc": html.desc,
                    "keywords": html.keywords,
                    "tags": html.tags,
                    "body": html.body,
                    "author": author,
                    "date": date,
                    "ts": ts,
                    "toc": html.toc,
                    "metadata": metadata,
                    "raw": html.raw
                }
            else:
                result["htmls"][file] = None
        result['ok'] = True
        return result
    
    def on_parse_pages(self, files):
        result = self.on_parse_files(files)
        return result

    
    def on_add_html_header_items(self, type_name):
        items = []
        items.append('<meta name="html-generator" content="teedoc-plugin-jupyter-notebook-parser">')
        return items
    
    def _update_link_html(self, content):
        def re_del(c):
            ret = c[0]
            links = re.findall('href="(.*?)"', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.md", "index.html", c[0], flags=re.I)
                        ret = re.sub(r".md", ".html", ret, re.I)
                        return ret
            return ret
        def re_del_ipynb(c):
            ret = c[0]
            links = re.findall('href="(.*?)"', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.ipynb", "index.html", c[0], flags=re.I)
                        ret = re.sub(r".ipynb", ".html", ret, re.I)
                        return ret
            return ret
        # <a class="anchor-link" href="#&#38142;&#25509;"> </a></h2><p><a href="./syntax_markdown.md">markdown 语法</a>
        content = re.sub(r'\<a.*?href=.*?\.md.*?\</a\>', re_del, content, flags=re.I)
        content = re.sub(r'\<a.*?href=.*?\.ipynb.*?\</a\>', re_del_ipynb, content, flags=re.I)
        return content
Example #12
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-theme-default"
    desc = "default theme for teedoc"
    defautl_config = {
        "light": True
    }

    def __init__(self, config, doc_src_path, site_config, logger = None):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))
        self.assets_abs_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")

        self.dark_css  = {
            "/static/css/theme_default/dark.css": os.path.join(self.assets_abs_path, "dark.css")
        }
        self.light_css = {
            "/static/css/theme_default/light.css": os.path.join(self.assets_abs_path, "light.css")
        }
        self.css = {
            "/static/css/theme_default/prism.min.css": os.path.join(self.assets_abs_path, "prism.min.css"),
        }
        # js files
        self.dark_js = {

        }
        self.light_js = {
        }
        self.header_js = {
            "/static/js/theme_default/jquery.min.js": os.path.join(self.assets_abs_path, "jquery.min.js"),
            "/static/js/theme_default/pre_main.js": os.path.join(self.assets_abs_path, "pre_main.js")
        }
        self.footer_js = {
            "/static/js/theme_default/main.js": os.path.join(self.assets_abs_path, "main.js"),
            "/static/css/theme_default/prism.min.js": os.path.join(self.assets_abs_path, "prism.min.js")
        }
        self.images = {
            "/static/image/theme_default/indicator.svg": os.path.join(self.assets_abs_path, "indicator.svg"),
            "/static/image/theme_default/menu.svg": os.path.join(self.assets_abs_path, "menu.svg"),
            "/static/image/theme_default/to-top.svg": os.path.join(self.assets_abs_path, "to-top.svg"),
            "/static/image/theme_default/light_mode.svg": os.path.join(self.assets_abs_path, "light_mode.svg"),
            "/static/image/theme_default/dark_mode.svg": os.path.join(self.assets_abs_path, "dark_mode.svg")
        }
        # set site_root_url env value
        if not "env" in config:
            config['env'] = {}
        config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = config["env"]
        self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_theme_default")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
        self.dark_css  = self._update_file_var(self.dark_css, vars, self.temp_dir)
        self.light_css = self._update_file_var(self.light_css, vars, self.temp_dir)
        self.css       = self._update_file_var(self.css, vars, self.temp_dir)
        self.header_js = self._update_file_var(self.header_js, vars, self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        if self.config["dark"]:
            self.files_to_copy.update(self.dark_css)
            self.files_to_copy.update(self.dark_js)
        self.files_to_copy.update(self.light_css)
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.light_js)
        self.files_to_copy.update(self.header_js)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)
        if self.config["dark"]:
            self.themes_btn = '<a id="themes" class="light"></a>'
        else:
            self.themes_btn = ""

        self.html_js_items = self._generate_html_js_items()

    def __del__(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def _generate_html_header_items(self):
        items = []
        # css
        for url in self.css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(url)
            items.append(item)
        if self.config["dark"]:
            for url in self.dark_css:
                item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(url)
                items.append(item)
        for url in self.light_css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(url)
            items.append(item)
        if "css" in self.config:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(self.config["css"])
            items.append(item)
        # header_js
        for url in self.header_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        if self.config["dark"]:
            for url in self.dark_js:
                item = '<script src="{}"></script>'.format(url)
                items.append(item)
        for url in self.light_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        return items

    def _generate_html_js_items(self):
        items = []
        for url in self.footer_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        if "js" in self.config:
            item = '<script src="{}"></script>'.format(self.config["js"])
            items.append(item)
        return items

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace("${}{}{}".format("{", k.strip(), "}"), v)
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files
        

    def on_add_html_header_items(self):
        return self.html_header_items
    
    def on_add_html_js_items(self):
        return self.html_js_items
    
    def on_add_navbar_items(self, new_config):
        items = [self.themes_btn]
        return items
    
    def on_copy_files(self):
        return self.files_to_copy
Example #13
0
    def __init__(self, config, doc_src_path, site_config, logger = None):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))
        self.assets_abs_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")

        self.dark_css  = {
            "/static/css/theme_default/dark.css": os.path.join(self.assets_abs_path, "dark.css")
        }
        self.light_css = {
            "/static/css/theme_default/light.css": os.path.join(self.assets_abs_path, "light.css")
        }
        self.css = {
            "/static/css/theme_default/prism.min.css": os.path.join(self.assets_abs_path, "prism.min.css"),
        }
        # js files
        self.dark_js = {

        }
        self.light_js = {
        }
        self.header_js = {
            "/static/js/theme_default/jquery.min.js": os.path.join(self.assets_abs_path, "jquery.min.js"),
            "/static/js/theme_default/pre_main.js": os.path.join(self.assets_abs_path, "pre_main.js")
        }
        self.footer_js = {
            "/static/js/theme_default/main.js": os.path.join(self.assets_abs_path, "main.js"),
            "/static/css/theme_default/prism.min.js": os.path.join(self.assets_abs_path, "prism.min.js")
        }
        self.images = {
            "/static/image/theme_default/indicator.svg": os.path.join(self.assets_abs_path, "indicator.svg"),
            "/static/image/theme_default/menu.svg": os.path.join(self.assets_abs_path, "menu.svg"),
            "/static/image/theme_default/to-top.svg": os.path.join(self.assets_abs_path, "to-top.svg"),
            "/static/image/theme_default/light_mode.svg": os.path.join(self.assets_abs_path, "light_mode.svg"),
            "/static/image/theme_default/dark_mode.svg": os.path.join(self.assets_abs_path, "dark_mode.svg")
        }
        # set site_root_url env value
        if not "env" in config:
            config['env'] = {}
        config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = config["env"]
        self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_theme_default")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
        self.dark_css  = self._update_file_var(self.dark_css, vars, self.temp_dir)
        self.light_css = self._update_file_var(self.light_css, vars, self.temp_dir)
        self.css       = self._update_file_var(self.css, vars, self.temp_dir)
        self.header_js = self._update_file_var(self.header_js, vars, self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        if self.config["dark"]:
            self.files_to_copy.update(self.dark_css)
            self.files_to_copy.update(self.dark_js)
        self.files_to_copy.update(self.light_css)
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.light_js)
        self.files_to_copy.update(self.header_js)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)
        if self.config["dark"]:
            self.themes_btn = '<a id="themes" class="light"></a>'
        else:
            self.themes_btn = ""

        self.html_js_items = self._generate_html_js_items()
Example #14
0
    def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        # check config
        for key in self.config["env"]:
            if not key in config["env"]:
                self.logger.e('you MUST set env var "{}" for gitalk plugin in site_config'.format(key))
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))

        self.files_to_copy = {}
        self.html_header_items = []
        self.html_footer_items = []
        for item in self.config["header_items"]:
            if item.startswith("/"):
                path = os.path.join(self.doc_src_path, item[1:])
                if os.path.exists(path):
                    if path.endswith(".js"):
                        self.html_header_items.append(f'<script src="{item}"></script>')
                        self.files_to_copy[item] = path
                    elif path.endswith(".css"):
                        self.html_header_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                        self.files_to_copy[item] = path
                    else:
                        self.logger.e(f"config: url {item} not support! you can use html tag instead")
                else:
                    self.logger.e(f"config: url {item} wrong, file {path} no found ")
            else:
                self.html_header_items.append(item)
        for item in self.config["footer_items"]:
            if item.startswith("/"):
                path = os.path.join(self.doc_src_path, item[1:])
                if os.path.exists(path):
                    if path.endswith(".js"):
                        self.html_footer_items.append(f'<script src="{item}"></script>')
                        self.files_to_copy[item] = path
                    elif path.endswith(".css"):
                        self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                        self.files_to_copy[item] = path
                    else:
                        self.logger.e(f"config: url {item} not support! you can use html tag instead")
                else:
                    self.logger.e(f"config: url {item} wrong, file {path} no found ")
            elif item.startswith("http"):
                if item.endswith(".js"):
                    self.html_footer_items.append(f'<script src="{item}"></script>')
                elif item.endswith(".css"):
                    self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                else:
                    self.logger.e(f"config: url {item} not support! you can use html tag instead")
            else:
                self.html_footer_items.append(item)

        self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_assets")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
            
        self.files_to_copy  = self._update_file_var(self.files_to_copy, self.config["env"], self.temp_dir)
Example #15
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-assets"
    desc = "add assets(css js) support for teedoc"
    defautl_config = {
        "header_items": [],
        "footer_items": [],
        "env":{}
    }

    def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        # check config
        for key in self.config["env"]:
            if not key in config["env"]:
                self.logger.e('you MUST set env var "{}" for gitalk plugin in site_config'.format(key))
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config))

        self.files_to_copy = {}
        self.html_header_items = []
        self.html_footer_items = []
        for item in self.config["header_items"]:
            if item.startswith("/"):
                path = os.path.join(self.doc_src_path, item[1:])
                if os.path.exists(path):
                    if path.endswith(".js"):
                        self.html_header_items.append(f'<script src="{item}"></script>')
                        self.files_to_copy[item] = path
                    elif path.endswith(".css"):
                        self.html_header_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                        self.files_to_copy[item] = path
                    else:
                        self.logger.e(f"config: url {item} not support! you can use html tag instead")
                else:
                    self.logger.e(f"config: url {item} wrong, file {path} no found ")
            else:
                self.html_header_items.append(item)
        for item in self.config["footer_items"]:
            if item.startswith("/"):
                path = os.path.join(self.doc_src_path, item[1:])
                if os.path.exists(path):
                    if path.endswith(".js"):
                        self.html_footer_items.append(f'<script src="{item}"></script>')
                        self.files_to_copy[item] = path
                    elif path.endswith(".css"):
                        self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                        self.files_to_copy[item] = path
                    else:
                        self.logger.e(f"config: url {item} not support! you can use html tag instead")
                else:
                    self.logger.e(f"config: url {item} wrong, file {path} no found ")
            elif item.startswith("http"):
                if item.endswith(".js"):
                    self.html_footer_items.append(f'<script src="{item}"></script>')
                elif item.endswith(".css"):
                    self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>')
                else:
                    self.logger.e(f"config: url {item} not support! you can use html tag instead")
            else:
                self.html_footer_items.append(item)

        self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_assets")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
            
        self.files_to_copy  = self._update_file_var(self.files_to_copy, self.config["env"], self.temp_dir)


    def on_add_html_header_items(self, type_name):
        return self.html_header_items

    def on_add_html_footer_js_items(self, type_name):
        return self.html_footer_items

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res

    def on_del(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace("${}{}{}".format("{", k.strip(), "}"), str(v))
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files
Example #16
0
    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        env = self.config["env"]
        if "env" in config:
            env.update(config["env"])
        self.config.update(config)
        self.config["env"] = env
        if self.config["mobile_navbar_collapsed"]:
            self.config["env"]["mobile_navbar_collapsed"] = "none"
        else:
            self.config["env"]["mobile_navbar_collapsed"] = "block"
        if self.config["dark"] and self.config["default_dark"]:
            self.config["env"]["default_theme"] = "dark"
        else:
            self.config["env"]["default_theme"] = "light"
        if self.config["show_print_page"]:
            self.config["env"]["show_print_page"] = "true"
        else:
            self.config["env"]["show_print_page"] = "false"
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")

        self.dark_css = {
            "/static/css/theme_default/dark.css":
            os.path.join(self.assets_abs_path, "dark.css")
        }
        self.light_css = {
            "/static/css/theme_default/light.css":
            os.path.join(self.assets_abs_path, "light.css")
        }
        # code hilight css file
        if "code_highlight_css" in self.config and self.config[
                "code_highlight_css"]:
            self.css = {}
            self.code_highlight_css = self.config["code_highlight_css"]
        else:
            self.code_highlight_css = None
            self.css = {
                "/static/css/theme_default/prism.min.css":
                os.path.join(self.assets_abs_path, "prism.min.css"),
            }
        # image viewer
        self.css["/static/css/theme_default/viewer.min.css"] = os.path.join(
            self.assets_abs_path, "viewer.min.css")
        # js files
        self.dark_js = {}
        self.light_js = {}
        self.header_js = {
            "/static/js/theme_default/split.js":
            os.path.join(self.assets_abs_path, "split.js"),
            "/static/js/theme_default/jquery.min.js":
            os.path.join(self.assets_abs_path, "jquery.min.js"),
            "/static/js/theme_default/pre_main.js":
            os.path.join(self.assets_abs_path, "pre_main.js")
        }
        self.footer_js = {
            "/static/js/theme_default/tocbot.min.js":
            os.path.join(self.assets_abs_path, "tocbot.min.js"),
            "/static/js/theme_default/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
            "/static/js/theme_default/viewer.min.js":
            os.path.join(self.assets_abs_path, "viewer.min.js")
        }
        # code hilight js file
        if "code_highlight_js" in self.config and self.config[
                "code_highlight_js"]:
            self.code_highlight_js = self.config["code_highlight_js"]
        else:
            self.code_highlight_js = None
            self.footer_js[
                "/static/css/theme_default/prism.min.js"] = os.path.join(
                    self.assets_abs_path, "prism.min.js")
        self.images = {
            "/static/image/theme_default/indicator.svg":
            os.path.join(self.assets_abs_path, "indicator.svg"),
            "/static/image/theme_default/menu.svg":
            os.path.join(self.assets_abs_path, "menu.svg"),
            "/static/image/theme_default/to-top.svg":
            os.path.join(self.assets_abs_path, "to-top.svg"),
            "/static/image/theme_default/light_mode.svg":
            os.path.join(self.assets_abs_path, "light_mode.svg"),
            "/static/image/theme_default/dark_mode.svg":
            os.path.join(self.assets_abs_path, "dark_mode.svg"),
            "/static/image/theme_default/print.svg":
            os.path.join(self.assets_abs_path, "print.svg")
        }
        # set site_root_url env value
        self.config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = self.config["env"]
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_theme_default")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
        self.dark_css = self._update_file_var(self.dark_css, vars,
                                              self.temp_dir)
        self.light_css = self._update_file_var(self.light_css, vars,
                                               self.temp_dir)
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.header_js = self._update_file_var(self.header_js, vars,
                                               self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        if self.config["dark"]:
            self.files_to_copy.update(self.dark_css)
            self.files_to_copy.update(self.dark_js)
        self.files_to_copy.update(self.light_css)
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.light_js)
        self.files_to_copy.update(self.header_js)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)
        if self.config["dark"]:
            self.themes_btn = '<a id="themes" class="light"></a>'
        else:
            self.themes_btn = ""

        self.html_js_items = self._generate_html_js_items()
Example #17
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-markdown-parser"
    desc = "markdown parser plugin for teedoc"
    defautl_config = {
        "parse_files": ["md"],
        "mathjax": {
            "enable": True,
            "file_name":
            "tex-mml-chtml",  # http://docs.mathjax.org/en/latest/web/components/index.html
            "config": {
                "loader": {
                    "load": ['output/svg']
                },
                "tex": {
                    "inlineMath": [['$', '$'], ['\\(', '\\)']]
                },
                "svg": {
                    "fontCache": 'global'
                }
            }
        }
    }

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.multiprocess = multiprocess
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        mathjax_config = self.config["mathjax"]
        if "mathjax" in config:
            for k, v in config["mathjax"].items():
                if type(v) != dict:
                    mathjax_config[k] = v
                else:
                    mathjax_config[k].update(v)
        self.config.update(config)
        self.config["mathjax"] = mathjax_config
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        if not self.multiprocess:
            from .renderer import create_markdown_parser
            from .parse_metadata import Meta_Parser
            self.create_markdown_parser = create_markdown_parser
            self.Meta_Parser = Meta_Parser

    def on_new_process_init(self):
        '''
            for multiple processing, for below func, will be called in new process,
            every time create a new process, this func will be invoke
        '''
        from .renderer import create_markdown_parser
        from .parse_metadata import Meta_Parser
        self.md_parser = create_markdown_parser()
        self.meta_parser = Meta_Parser()

    def on_new_process_del(self):
        '''
            for multiple processing, for below func, will be called in new process,
            every time exit a new process, this func will be invoke
        '''
        del self.md_parser
        del self.meta_parser

    def on_parse_files(self, files):
        # result, format must be this
        result = {"ok": False, "msg": "", "htmls": OrderedDict()}
        # function parse md file is disabled
        if not "md" in self.config["parse_files"]:
            result[
                "msg"] = "disabled markdown parse, but only support markdown"
            return result
        self.logger.d("-- plugin <{}> parse {} files".format(
            self.name, len(files)))
        # self.logger.d("files: {}".format(files))

        for file in files:
            ext = os.path.splitext(file)[1].lower()
            if ext.endswith("md"):
                with open(file, encoding="utf-8") as f:
                    content = f.read().strip()
                    content = self._update_link(content)
                    try:
                        if not self.multiprocess:
                            md_parser = self.create_markdown_parser()
                            meta_parser = self.Meta_Parser()
                        else:
                            md_parser = self.md_parser
                            meta_parser = self.meta_parser
                        metadata, content_no_meta = meta_parser.parse_meta(
                            content)
                        html = md_parser(content_no_meta)
                    except Exception as e:
                        import io, traceback
                        traceback.print_exc()
                        self.logger.w(
                            "parse markdown file {} fail, please check markdown content format"
                            .format(file))
                        continue
                    if "title" in metadata:
                        title = metadata["title"]
                    else:
                        title = ""
                    if "keywords" in metadata and not metadata[
                            "keywords"].strip() == "":
                        keywords = metadata["keywords"].split(",")
                    else:
                        keywords = []
                    if "tags" in metadata and not metadata["tags"].strip(
                    ) == "":
                        tags = metadata["tags"].split(",")
                    else:
                        tags = []
                    if "desc" in metadata:
                        desc = metadata["desc"]
                    else:
                        desc = ""
                    date = None
                    ts = int(os.stat(file).st_mtime)
                    if "date" in metadata:
                        date = metadata["date"].strip().lower()
                        # set date to false to disable date display
                        if date and (date == "false" or date == "none"):
                            date = ""
                        else:
                            GMT_FORMAT = '%Y-%m-%d'
                            try:
                                date_obj = datetime.strptime(date, GMT_FORMAT)
                                ts = int(date_obj.timestamp())
                            except Exception as e:
                                pass
                    if "author" in metadata:
                        author = metadata["author"]
                    else:
                        author = ""
                    result["htmls"][file] = {
                        "title": title,
                        "desc": desc,
                        "keywords": keywords,
                        "tags": tags,
                        "body": html,
                        "date": date,
                        "ts": ts,
                        "author": author,
                        # "toc": html.toc_html if html.toc_html else "",
                        "toc":
                        "",  # just empty, toc generated by js but not python
                        "metadata": metadata,
                        "raw": content
                    }
            else:
                result["htmls"][file] = None
        result['ok'] = True
        return result

    def on_parse_pages(self, files):
        result = self.on_parse_files(files)
        return result

    def on_add_html_header_items(self, type_name):
        items = []
        items.append(
            '<meta name="markdown-generator" content="teedoc-plugin-markdown-parser">'
        )
        if self.config["mathjax"]["enable"]:
            items.append('''<script>
MathJax = {};
</script>'''.format(json.dumps(self.config["mathjax"]["config"])))
            items.append(
                '<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>'
            )
            items.append(
                '<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/{}.js"></script>'
                .format(self.config["mathjax"]["file_name"]))
        return items

    def _update_link(self, content):
        def re_del(c):
            ret = c[0]
            links = re.findall('\((.*?)\)', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.md",
                                     "index.html",
                                     c[0],
                                     flags=re.I)
                        ret = re.sub(r".md", ".html", ret, re.I)
                        return ret
            return ret

        def re_del_ipynb(c):
            ret = c[0]
            links = re.findall('\((.*?)\)', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.ipynb",
                                     "index.html",
                                     c[0],
                                     flags=re.I)
                        ret = re.sub(r".ipynb", ".html", ret, re.I)
                        return ret
            return ret

        # <a class="anchor-link" href="#&#38142;&#25509;"> </a></h2><p><a href="./syntax_markdown.md">markdown 语法</a>
        content = re.sub(r'\[.*?\]\(.*?\.md\)', re_del, content, flags=re.I)
        content = re.sub(r'\[.*?\]\(.*?\.ipynb\)',
                         re_del_ipynb,
                         content,
                         flags=re.I)
        return content
Example #18
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-comments-gitalk"
    desc = "gitalk comment support for teedoc"
    defautl_config = {
        "contrainer": "comments-container",
        "env": {
            "clientID":
            'GitHub Application Client ID',
            "clientSecret":
            'GitHub Application Client Secret',
            "repo":
            'GitHub repo',
            "owner":
            'GitHub repo owner',
            "admin": [
                'GitHub repo owner and collaborators, only these guys can initialize github issues'
            ],
            # "id": location.pathname,      // Ensure uniqueness and length less than 50
            # "distractionFreeMode": false  // Facebook-like distraction free mode
            # "main_color": "#4caf7d",
            # "second_color": "#0a7d43"
        },
    }

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        # check config
        for key in self.config["env"]:
            if not key in config["env"]:
                self.logger.e(
                    'you MUST set env var "{}" for gitalk plugin in site_config'
                    .format(key))
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")

        self.files_to_copy = {
            "/static/js/gitalk/gitalk.min.js":
            os.path.join(self.assets_abs_path, "gitalk.min.js"),
            "/static/js/gitalk/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
            "/static/css/gitalk/gitalk.css":
            os.path.join(self.assets_abs_path, "gitalk.css")
        }
        self.html_header_items = [
            '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                "/static/css/gitalk/gitalk.css"),
        ]
        self.html_js_items = [
            '<script src="{}"></script>'.format(
                "/static/js/gitalk/gitalk.min.js"),
            '<script src="{}"></script>'.format("/static/js/gitalk/main.js")
        ]

        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_comments_gitalk")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        # custom main color
        custom_color_vars = {}
        if "main_color" in self.config["env"]:
            self.logger.i("-- plugin <{}> get main_color {}".format(
                self.name, self.config["env"]["main_color"]))
            self.html_header_items.append(
                '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                    "/static/css/gitalk/custom_gitalk.css"))
            self.files_to_copy[
                "/static/css/gitalk/custom_gitalk.css"] = os.path.join(
                    self.assets_abs_path, "custom_gitalk.css")
            # remove color vars from env, for env used by js
            if not "second_color" in self.config["env"]:
                self.config["env"]["second_color"] = self.config["env"][
                    "main_color"]
            custom_color_vars["main_color"] = self.config["env"]["main_color"]
            custom_color_vars["second_color"] = self.config["env"][
                "second_color"]
            self.config["env"].pop("main_color")
            self.config["env"].pop("second_color")
        else:
            self.logger.i("-- plugin <{}> use default color")
        vars = {
            "comment_contrainer_id": self.config["contrainer"],
            "config": json.dumps(self.config["env"])
        }
        vars.update(custom_color_vars)
        self.files_to_copy = self._update_file_var(self.files_to_copy, vars,
                                                   self.temp_dir)

    def on_add_html_header_items(self, type_name):
        return self.html_header_items

    def on_add_html_footer_js_items(self, type_name):
        return self.html_js_items

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res

    def on_del(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace(
                        "${}{}{}".format("{", k.strip(), "}"), str(v))
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files
Example #19
0
    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        if not self.config["content_type"] in self.supported_content_type:
            self.logger.e(
                "-- plugin <{}> config content_type error: {}, should be in {}"
                .format(self.name, self.config["content_type"],
                        self.supported_content_type))
        if self.config["content_type"] == "raw":
            self.content_from = "raw"
        else:
            self.content_from = "body"
        self.module_path = os.path.abspath(
            os.path.dirname(os.path.abspath(__file__)))
        self.assets_abs_path = os.path.join(self.module_path, "assets")
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_search")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        self.css = {
            "/static/css/search/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
        }
        self.footer_js = {
            "/static/js/search/search_main.js":
            os.path.join(self.assets_abs_path, "search_main.js")
        }
        self.images = {
            "/static/image/search/close.svg":
            os.path.join(self.assets_abs_path, "close.svg"),
            "/static/image/search/search.svg":
            os.path.join(self.assets_abs_path, "search.svg"),
        }

        # set site_root_url env value
        if not "env" in self.config:
            self.config['env'] = {}
        self.config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = self.config["env"]
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)

        self.html_js_items = self._generate_html_js_items()
        self.content = {"articles": {}, "pages": {}}
        self.docs_name = {}
Example #20
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-search"
    desc = "search support for teedoc"
    defautl_config = {
        "content_type": "raw",  # supported_content_type
        "search_hint": "Search",
        "input_hint": "Keywords separated by space",
        "loading_hint": "Loading, wait please ...",
        "download_err_hint":
        "Download error, please check network and refresh again",
        "other_docs_result_hint": "Result from other docs",
        "curr_doc_result_hint": "Result from current doc",
        "env": {
            "main_color": "#4caf7d",
            "main_color_dark": "#1b4c33",
            "hint_shadow_color": "rgba(76, 175, 125, 0.38)"
        }
    }
    supported_content_type = ["raw", "html"]

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        if not self.config["content_type"] in self.supported_content_type:
            self.logger.e(
                "-- plugin <{}> config content_type error: {}, should be in {}"
                .format(self.name, self.config["content_type"],
                        self.supported_content_type))
        if self.config["content_type"] == "raw":
            self.content_from = "raw"
        else:
            self.content_from = "body"
        self.module_path = os.path.abspath(
            os.path.dirname(os.path.abspath(__file__)))
        self.assets_abs_path = os.path.join(self.module_path, "assets")
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_search")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        self.css = {
            "/static/css/search/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
        }
        self.footer_js = {
            "/static/js/search/search_main.js":
            os.path.join(self.assets_abs_path, "search_main.js")
        }
        self.images = {
            "/static/image/search/close.svg":
            os.path.join(self.assets_abs_path, "close.svg"),
            "/static/image/search/search.svg":
            os.path.join(self.assets_abs_path, "search.svg"),
        }

        # set site_root_url env value
        if not "env" in self.config:
            self.config['env'] = {}
        self.config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = self.config["env"]
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)

        self.html_js_items = self._generate_html_js_items()
        self.content = {"articles": {}, "pages": {}}
        self.docs_name = {}

    def on_del(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def _generate_html_header_items(self):
        items = []
        # css
        for url in self.css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                url)
            items.append(item)
        return items

    def _generate_html_js_items(self):
        items = []
        for url in self.footer_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        return items

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace(
                        "${}{}{}".format("{", k.strip(), "}"), v)
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files

    def _get_conf(self, config, new_config, conf_name):
        if conf_name in new_config:
            return True, new_config[conf_name]
        return False, config[conf_name]

    def on_parse_start(self, type_name, url, dirs, doc_config, new_config):
        if not "name" in doc_config:
            self.logger.w(f'doc dir "{dirs[0]}"\'s config no "name" keyword')
            self.docs_name[url] = url
        else:
            self.docs_name[url] = doc_config["name"]
        self.doc_locale = doc_config[
            "locale"] if "locale" in doc_config else None
        # self.new_config = copy.deepcopy(self.config)
        # self.new_config = update_config(self.new_config, new_config)
        self.new_config = new_config

    def on_add_html_header_items(self, type_name):
        return self.html_header_items

    def on_add_html_footer_js_items(self, type_name):
        return self.html_js_items

    def on_add_navbar_items(self):
        '''
            @config config cover self.config
        '''
        # i18n
        # set default or custom settings
        names = [
            "search_hint", "input_hint", "loading_hint", "download_err_hint",
            "other_docs_result_hint", "curr_doc_result_hint"
        ]
        flags = [False] * len(names)  # flags have costum settings
        configs = [""] * len(names)
        for i, conf in enumerate(names):
            flags[i], configs[i] = self._get_conf(self.config, self.new_config,
                                                  conf)
        # get translation if don't have custom setting
        if False in flags and self.doc_locale:
            import gettext
            try:
                lang = gettext.translation('messages',
                                           localedir=os.path.join(
                                               self.module_path, 'locales'),
                                           languages=[self.doc_locale])
                lang.install()
                _ = lang.gettext
                if not flags[0]:
                    configs[0] = _("search_hint")
                if not flags[1]:
                    configs[1] = _("search_input_hint")
                if not flags[2]:
                    configs[2] = _("search_loading_hint")
                if not flags[3]:
                    configs[3] = _("search_download_err_hint")
                if not flags[4]:
                    configs[4] = _("search_other_docs_result_hint")
                if not flags[5]:
                    configs[5] = _("search_curr_doc_result_hint")
            except Exception as e:
                pass
        configs = tuple(configs)
        search_btn = '''<a id="search"><span class="icon"></span><span class="placeholder">%s</span>
                            <div id="search_hints">
                                <span id="search_input_hint">%s</span>
                                <span id="search_loading_hint">%s</span>
                                <span id="search_download_err_hint">%s</span>
                                <span id="search_other_docs_result_hint">%s</span>
                                <span id="search_curr_doc_result_hint">%s</span>
                            </div></a>''' % configs
        items = [search_btn]
        return items

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res

    def on_htmls(self, htmls_files, htmls_pages, htmls_blog=None):
        '''
            update htmls, may not all html, just partially
            htmls_files: {
                "/get_started/zh":{
                    "url":{
                                "title": "",
                                "desc": "",
                                "keywords": [],
                                "body": html,
                                "url": "",
                                "raw": ""
                          }
                }
            }
        '''
        # for file, html in htmls_files.items():
        #     self.content["articles"][html["url"]] = html["raw"]
        # for file, html in htmls_pages.items():
        #     self.content["pages"][html["url"]] = html["raw"]
        self.logger.i("generate search index")
        if htmls_blog:
            htmls_pages.update(copy.deepcopy(htmls_blog))
        docs_url = list(htmls_files.keys())
        pages_url = list(htmls_pages.keys())
        index_content = {}
        sub_index_path = []
        generated_index_json = {}
        for i, url in enumerate(docs_url):
            index_content[url] = [
                self.docs_name[url],
                "{}static/search_index/index_{}.json".format(
                    self.site_config["site_root_url"], i)
            ]
            path = os.path.join(self.temp_dir, "index_{}.json".format(i))
            sub_index_path.append(path)
            #   write content to sub index file
            content = {}
            for page_url in htmls_files[url]:
                content[page_url] = {
                    "title": htmls_files[url][page_url]["title"],
                    "content": htmls_files[url][page_url][self.content_from]
                }
            with open(path, "w", encoding="utf-8") as f:
                json.dump(content, f, ensure_ascii=False)
        for i, url in enumerate(pages_url, len(docs_url)):
            index_content[url] = [
                self.docs_name[url],
                "{}static/search_index/index_{}.json".format(
                    self.site_config["site_root_url"], i)
            ]
            path = os.path.join(self.temp_dir, "index_{}.json".format(i))
            sub_index_path.append(path)
            #   write content to sub index file
            content = {}
            for page_url in htmls_pages[url]:
                content[page_url] = {
                    "title": htmls_pages[url][page_url]["title"],
                    "content": htmls_pages[url][page_url][self.content_from]
                }
            with open(path, "w", encoding="utf-8") as f:
                json.dump(content, f, ensure_ascii=False)
        # write content to files
        #   index file
        index_path = os.path.join(self.temp_dir, "index.json")
        with open(index_path, "w", encoding="utf-8") as f:
            json.dump(index_content, f, ensure_ascii=False)

        # add to copy file list
        generated_index_json["/static/search_index/index.json"] = index_path
        for i, path in enumerate(sub_index_path):
            generated_index_json["/static/search_index/index_{}.json".format(
                i)] = path
        self.files_to_copy.update(generated_index_json)
        return True
Example #21
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-google-translate"
    desc = "Google translate support for teedoc"
    defautl_config = {
        "lang": "auto",  # source page language
        "doc_types": ["page", "doc", "blog"],
        "domain": "/"  # translate.google.com / translate.google.cn
    }

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.module_path = os.path.abspath(
            os.path.dirname(os.path.abspath(__file__)))
        self.assets_abs_path = os.path.join(self.module_path, "assets")

    def on_del(self):
        pass

    def on_copy_files(self):
        res = {
            "/static/image/google_translate/translate.svg":
            os.path.join(self.assets_abs_path, "translate.svg"),
            "/static/image/google_translate/cleardot.gif":
            os.path.join(self.assets_abs_path, "cleardot.gif"),
            "/static/js/google_translate/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
            "/static/js/google_translate/element_main.js":
            os.path.join(self.assets_abs_path, "element_main.js"),
            "/static/js/google_translate/element.js":
            os.path.join(self.assets_abs_path, "element.js"),
        }
        return res

    def on_parse_start(self, type_name, url, dirs, doc_config, new_config):
        # self.doc_locale = doc_config["locale"] if "locale" in doc_config else None
        self.new_config = copy.deepcopy(self.config)
        self.new_config = update_config(self.new_config, new_config)
        self.type_name = type_name

    def on_add_html_header_items(self, type_name):
        return []

    def on_add_html_footer_js_items(self, type_name):
        if not type_name in self.new_config["doc_types"]:
            return []
        lang = self.new_config["lang"]
        domain = self.new_config["domain"]
        return [
            '''<script type="text/javascript">
                var transLoaded = false;
                var loading = false;
                var domain = "''' + domain + '''";
                var domainDefault = domain;
                var storeDomain = localStorage.getItem("googleTransDomain");
                if(storeDomain){
                    domain = storeDomain;
                }
                function getUrl(domain){
                    if(domain == "/")
                        return "/static/js/google_translate/element.js?cb=googleTranslateElementInit";
                    else
                        return "https://" + domain + "/translate_a/element.js?cb=googleTranslateElementInit";
                }
                var url = getUrl(domain);
                function googleTranslateElementInit() {
                    new google.translate.TranslateElement({pageLanguage: "''' +
            lang +
            '''", layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');
                }
                function loadJS( url, callback ){
                    var script = document.createElement('script');
                    fn = callback || function(){ };
                    script.type = 'text/javascript';
                    if(script.readyState){
                        script.onreadystatechange = function(){
                            if( script.readyState == 'loaded' || script.readyState == 'complete' ){
                                script.onreadystatechange = null;
                                fn();
                            }
                        };
                    }else{
                        script.onload = function(){
                            fn();
                        };
                    }
                    script.src = url;
                    document.getElementsByTagName('head')[0].appendChild(script);
                }
                function removeHint(){
                    var hint = document.getElementById("loadingTranslate");
                    if(hint){
                        hint.remove();
                    }
                }
                var btn = document.getElementById("google_translate_element");
                btn.onclick = function(){
                    if(transLoaded) return;
                    if(loading){
                        var flag = confirm("loading from " + domain + ", please wait, or change domain?");
                        if(flag){
                            newDomain = prompt("domain, default: " + domainDefault + ", now: " + domain);
                            if(newDomain){
                                domain = newDomain;
                                console.log(domain);
                                url = getUrl(domain);
                                loadJS(url, function(){
                                    localStorage.setItem("googleTransDomain", domain);
                                    removeHint()
                                    transLoaded = true;
                                });
                            }
                        }
                        return;
                    }
                    btn.innerHTML = '<span id="loadingTranslate"><img class="icon" src="/static/image/google_translate/translate.svg"/>Loading ...</span>';
                    loading = true;
                    loadJS(url, function(){
                        localStorage.setItem("googleTransDomain", domain);
                        removeHint()
                        transLoaded = true;
                    });
                }
                </script>
            ''',
            # f'<script type="text/javascript" src="//{domain}/translate_a/element.js?cb=googleTranslateElementInit"></script>'
        ]

    def on_add_navbar_items(self):
        if not self.type_name in self.new_config["doc_types"]:
            return []
        trans_btn = '<a id="google_translate_element"><img class="icon" src="/static/image/google_translate/translate.svg"/>Translate</a>'
        items = [trans_btn]
        return items
Example #22
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-blog"
    desc = "markdown parser plugin for teedoc"
    defautl_config = {"parse_files": ["md"]}

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.multiprocess = multiprocess
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_blog")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")
        self.assets = {
            "/static/js/plugin_blog/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
        }
        vars = {"site_root_url": self.site_config["site_root_url"]}
        self.assets = self._update_file_var(self.assets, vars, self.temp_dir)
        self.files_to_copy = self.assets.copy()  # must use copy
        blog_url = list(self.site_config["route"]["blog"].keys())
        if len(blog_url) > 1:
            self.logger.e("only support one blog url path")
            raise Exception("only support one blog url path")
        self.blog_url = blog_url[0]
        self.blog_dir = os.path.join(
            self.doc_src_path,
            self.site_config["route"]["blog"][self.blog_url]).replace(
                "\\", "/")
        self.index_content = {"items": {}}

    def on_new_process_init(self):
        '''
            for multiple processing, for below func, will be called in new process,
            every time create a new process, this func will be invoke
        '''
        self.md_parser = create_markdown_parser()
        self.meta_parser = Meta_Parser()

    def on_new_process_del(self):
        '''
            for multiple processing, for below func, will be called in new process,
            every time exit a new process, this func will be invoke
        '''
        del self.md_parser
        del self.meta_parser

    def on_parse_blog(self, files):
        # result, format must be this
        result = {"ok": False, "msg": "", "htmls": OrderedDict()}
        # function parse md file is disabled
        if not "md" in self.config["parse_files"]:
            result[
                "msg"] = "disabled markdown parse, but only support markdown"
            return result
        self.logger.d("-- plugin <{}> parse {} files".format(
            self.name, len(files)))
        # self.logger.d("files: {}".format(files))

        for file in files:
            ext = os.path.splitext(file)[1].lower()
            if ext.endswith("md"):
                with open(file, encoding="utf-8") as f:
                    content = f.read().strip()
                    content = self._update_link(content)
                    blog_index_file_path = os.path.join(
                        self.blog_dir, "readme.md").replace("\\", "/").lower()
                    is_blog_index = file.lower() == blog_index_file_path
                    if is_blog_index:
                        content += '\n<div id="blog_list"></div>'
                    if not self.multiprocess:
                        md_parser = create_markdown_parser()
                        meta_parser = Meta_Parser()
                    else:
                        md_parser = self.md_parser
                        meta_parser = self.meta_parser
                    metadata, content_no_meta = meta_parser.parse_meta(content)
                    html = md_parser(content_no_meta)
                    if "<!-- more -->" in html:
                        brief = html[:html.find("<!-- more -->")].strip()
                    else:
                        brief = html[:500].strip()
                    if "title" in metadata:
                        title = metadata["title"]
                    else:
                        title = ""
                    if "keywords" in metadata and not metadata[
                            "keywords"].strip() == "":
                        keywords = metadata["keywords"].split(",")
                    else:
                        keywords = []
                    if "tags" in metadata and not metadata["tags"].strip(
                    ) == "":
                        tags = metadata["tags"].split(",")
                    else:
                        tags = []
                    if "desc" in metadata:
                        desc = metadata["desc"]
                    else:
                        desc = ""
                    html_str = '<span id="blog_start"></span>' + html
                    # date default last edit time
                    ts = int(os.stat(file).st_mtime)
                    date_file_edit = time.strftime("%Y-%m-%d",
                                                   time.localtime(ts))
                    if "date" in metadata:
                        date = metadata["date"].strip().lower()
                        # set date to false to disable date display
                        if date and (date == "false" or date == "none"):
                            date = ""
                        else:
                            GMT_FORMAT = '%Y-%m-%d'
                            try:
                                date_obj = datetime.strptime(date, GMT_FORMAT)
                                ts = int(date_obj.timestamp())
                            except Exception as e:
                                date = date_file_edit
                    else:
                        date = date_file_edit
                    if "author" in metadata:
                        author = metadata["author"]
                    else:
                        author = ""
                    result["htmls"][file] = {
                        "title": title,
                        "desc": desc,
                        "keywords": keywords,
                        "tags": tags,
                        "body": html_str,
                        # "toc": html.toc_html if html.toc_html else "",
                        "toc":
                        "",  # just empty, toc generated by js but not python
                        "metadata": metadata,
                        "raw": content,
                        "date": date,
                        "ts": ts,
                        "author": author,
                        "brief": brief
                    }
            else:
                result["htmls"][file] = None
        result['ok'] = True
        return result

    def on_add_html_header_items(self, type_name):
        items = []
        items.append(
            '<meta name="blog-generator" content="teedoc-plugin-blog">')
        return items

    def _update_link(self, content):
        def re_del(c):
            ret = c[0]
            links = re.findall('\((.*?)\)', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.md",
                                     "index.html",
                                     c[0],
                                     flags=re.I)
                        ret = re.sub(r".md", ".html", ret, re.I)
                        return ret
            return ret

        def re_del_ipynb(c):
            ret = c[0]
            links = re.findall('\((.*?)\)', c[0])
            if len(links) > 0:
                for link in links:
                    if link.startswith(".") or os.path.isabs(link):
                        ret = re.sub("README.ipynb",
                                     "index.html",
                                     c[0],
                                     flags=re.I)
                        ret = re.sub(r".ipynb", ".html", ret, re.I)
                        return ret
            return ret

        # <a class="anchor-link" href="#&#38142;&#25509;"> </a></h2><p><a href="./syntax_markdown.md">markdown 语法</a>
        content = re.sub(r'\[.*?\]\(.*?\.md\)', re_del, content, flags=re.I)
        content = re.sub(r'\[.*?\]\(.*?\.ipynb\)',
                         re_del_ipynb,
                         content,
                         flags=re.I)
        return content

    def on_htmls(self, htmls_files, htmls_pages, htmls_blog=None):
        '''
            update htmls, may not all html, just partially
            htmls_blog: {
                "/blog/":{
                    "url":{
                                "title": "",
                                "desc": "",
                                "keywords": [],
                                "body": html,
                                "tags": [],
                                "url": "",
                                "raw": "",
                                "date": date,
                                "ts": 12344566,
                                "author": author,
                                "brief": "",
                                "metadata": {}
                          }
                }
            }
        '''
        if not htmls_blog:
            return True
        blog_url = list(htmls_blog.keys())
        if len(blog_url) == 0:
            return True
        index_url = ""
        blog_url = blog_url[0]
        index_url = "{}static/blog_index/index.json".format(
            self.site_config["site_root_url"])
        index_path = os.path.join(self.temp_dir, "index.json")
        for url, item in htmls_blog[blog_url].items():
            # except blog index.html
            if url == os.path.join(blog_url, "index.html"):
                continue
            new_item = {
                "title": item["title"],
                "desc": item["desc"],
                "keywords": item["keywords"],
                "tags": item["tags"],
                "url": url,
                "date": item["date"],
                "ts": item["ts"],
                "author": item["author"],
                "brief": item["brief"],
            }
            self.index_content["items"][url] = new_item
        # sort by date
        self.index_content["items"] = OrderedDict(
            sorted(self.index_content["items"].items(),
                   key=lambda v: v[1]["ts"],
                   reverse=True))
        #   write content to sub index file
        with open(index_path, "w", encoding="utf-8") as f:
            json.dump(self.index_content, f, ensure_ascii=False)

        # add to copy file list
        generated_index_json = {"/static/blog_index/index.json": index_path}
        self.files_to_copy.update(generated_index_json)
        return True

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res

    def on_add_html_footer_js_items(self, type_name):
        for url in self.assets:
            html_js_items = ['<script src="{}"></script>'.format(url)]
        return html_js_items

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace(
                        "${}{}{}".format("{", k.strip(), "}"), v)
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files
Example #23
0
    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        # check config
        for key in self.config["env"]:
            if not key in config["env"]:
                self.logger.e(
                    'you MUST set env var "{}" for gitalk plugin in site_config'
                    .format(key))
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")

        self.files_to_copy = {
            "/static/js/gitalk/gitalk.min.js":
            os.path.join(self.assets_abs_path, "gitalk.min.js"),
            "/static/js/gitalk/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
            "/static/css/gitalk/gitalk.css":
            os.path.join(self.assets_abs_path, "gitalk.css")
        }
        self.html_header_items = [
            '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                "/static/css/gitalk/gitalk.css"),
        ]
        self.html_js_items = [
            '<script src="{}"></script>'.format(
                "/static/js/gitalk/gitalk.min.js"),
            '<script src="{}"></script>'.format("/static/js/gitalk/main.js")
        ]

        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_comments_gitalk")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        # custom main color
        custom_color_vars = {}
        if "main_color" in self.config["env"]:
            self.logger.i("-- plugin <{}> get main_color {}".format(
                self.name, self.config["env"]["main_color"]))
            self.html_header_items.append(
                '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                    "/static/css/gitalk/custom_gitalk.css"))
            self.files_to_copy[
                "/static/css/gitalk/custom_gitalk.css"] = os.path.join(
                    self.assets_abs_path, "custom_gitalk.css")
            # remove color vars from env, for env used by js
            if not "second_color" in self.config["env"]:
                self.config["env"]["second_color"] = self.config["env"][
                    "main_color"]
            custom_color_vars["main_color"] = self.config["env"]["main_color"]
            custom_color_vars["second_color"] = self.config["env"][
                "second_color"]
            self.config["env"].pop("main_color")
            self.config["env"].pop("second_color")
        else:
            self.logger.i("-- plugin <{}> use default color")
        vars = {
            "comment_contrainer_id": self.config["contrainer"],
            "config": json.dumps(self.config["env"])
        }
        vars.update(custom_color_vars)
        self.files_to_copy = self._update_file_var(self.files_to_copy, vars,
                                                   self.temp_dir)
Example #24
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-ad-hint"
    desc = "advertisement adn hint support for teedoc"
    defautl_config = {
        "type": "hint",  # new warning ad
        "label": "New",
        # "brief": "",
        "content": "",
        # "target": "_self",
        # "url": "#",
        "show_times":
        2,  # disapear after visit show_times pages, always show if <= 0
        "show_after_s": 60 * 60 * 24 * 5,  # show again after 5 days
        "date":
        None,  # latest hint date, if changed, message will automatically show, if now datetime < date, hint always show
        "color": "#a0421d",
        "link_color": "#e53935",
        "link_bg_color": "#e6ae5c",
        "bg_color": "#ffcf89",
        "color_hover": "white",
        "bg_color_hover": "#f57c00",
        "close_color": "#eab971"
    }

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.module_path = os.path.abspath(
            os.path.dirname(os.path.abspath(__file__)))
        self.assets_abs_path = os.path.join(self.module_path, "assets")
        self.temp_dir = self.get_temp_dir()

        self.footer_js = {
            # don't use ad(advertisement) keyword, may blocked by browser plugin
            "/static/js/add_hint/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
            "/static/js/add_hint/main.js":
            os.path.join(self.assets_abs_path, "main.js")
        }
        self.html_footer_items = []
        for url in self.footer_js:
            if url.endswith(".css"):
                item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                    url)
            else:
                item = '<script src="{}"></script>'.format(url)
            self.html_footer_items.append(item)
        vars = self.config
        self.footer_js = self.update_file_var(self.footer_js, vars,
                                              self.temp_dir)
        self.files_to_copy = self.footer_js

    def on_parse_start(self, type_name, url, dirs, doc_config, new_config):
        '''
            call when start parse one doc
            @type_name canbe "doc" "page" "blog"
            #url doc url, e.g. /get_started/zh/
            @doc_config config of doc, get from config.json or config.yaml
            @new_config this plugin's config from doc_config
        '''
        # can update plugin config from site_config with new_config by teedoc.utils.update_config
        self.new_config = copy.deepcopy(self.config)
        self.new_config = update_config(self.new_config, new_config)

    def on_add_html_footer_js_items(self, type_name):
        return self.html_footer_items

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res

    def on_js_vars(self):
        return self.new_config
Example #25
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-search"
    desc = "search support for teedoc"
    defautl_config = {}

    def __init__(self, config, doc_src_path, site_config, logger=None):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        self.config.update(config)
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_search")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        self.css = {
            "/static/css/search/style.css":
            os.path.join(self.assets_abs_path, "style.css"),
        }
        self.footer_js = {
            "/static/js/search/main.js":
            os.path.join(self.assets_abs_path, "main.js")
        }
        self.images = {
            "/static/image/search/close.svg":
            os.path.join(self.assets_abs_path, "close.svg"),
            "/static/image/search/search.svg":
            os.path.join(self.assets_abs_path, "search.svg"),
        }

        # set site_root_url env value
        if not "env" in config:
            config['env'] = {}
        config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = config["env"]
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)

        self.html_js_items = self._generate_html_js_items()
        self.content = {"articles": {}, "pages": {}}

    def __del__(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def _generate_html_header_items(self):
        items = []
        # css
        for url in self.css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                url)
            items.append(item)
        return items

    def _generate_html_js_items(self):
        items = []
        for url in self.footer_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        return items

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace(
                        "${}{}{}".format("{", k.strip(), "}"), v)
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files

    def on_add_html_header_items(self):
        return self.html_header_items

    def on_add_html_js_items(self):
        return self.html_js_items

    def on_add_navbar_items(self, new_config):
        '''
            @config config cover self.config
        '''
        search_hint = "Search"
        search_input_hint = "Keywords separated by space"
        search_loading_hint = "Loading, wait please ..."
        search_download_err_hint = "Download error, please check network and refresh again"
        search_other_docs_result_hint = "Result from other docs"
        search_curr_doc_result_hint = "Result from current doc"
        if "search_hint" in new_config:
            search_hint = new_config["search_hint"]
        elif "search_hint" in self.config:
            search_hint = self.config["search_hint"]
        if "input_hint" in new_config:
            search_input_hint = new_config["input_hint"]
        elif "input_hint" in self.config:
            search_input_hint = self.config["input_hint"]
        if "loading_hint" in new_config:
            search_loading_hint = new_config["loading_hint"]
        elif "loading_hint" in self.config:
            search_loading_hint = self.config["loading_hint"]
        if "download_err_hint" in new_config:
            search_download_err_hint = new_config["download_err_hint"]
        elif "download_err_hint" in self.config:
            search_download_err_hint = self.config["download_err_hint"]
        if "other_docs_result_hint" in new_config:
            search_other_docs_result_hint = new_config[
                "other_docs_result_hint"]
        elif "other_docs_result_hint" in self.config:
            search_other_docs_result_hint = self.config[
                "other_docs_result_hint"]
        if "curr_doc_result_hint" in new_config:
            search_curr_doc_result_hint = new_config["curr_doc_result_hint"]
        elif "curr_doc_result_hint" in self.config:
            search_curr_doc_result_hint = self.config["curr_doc_result_hint"]
        search_btn = '''<a id="search"><span class="icon"></span><span class="placeholder">{}</span>
                            <div id="search_hints">
                                <span id="search_input_hint">{}</span>
                                <span id="search_loading_hint">{}</span>
                                <span id="search_download_err_hint">{}</span>
                                <span id="search_other_docs_result_hint">{}</span>
                                <span id="search_curr_doc_result_hint">{}</span>
                            </div></a>'''.format(
            search_hint, search_input_hint, search_loading_hint,
            search_download_err_hint, search_other_docs_result_hint,
            search_curr_doc_result_hint)
        items = [search_btn]
        return items

    def on_copy_files(self):
        return self.files_to_copy

    def on_htmls(self, htmls_files, htmls_pages):
        '''
            update htmls, may not all html, just partially
            htmls_files: {
                "/get_started/zh":{
                    "url":{
                                "title": "",
                                "desc": "",
                                "keywords": [],
                                "body": html,
                                "url": "",
                                "raw": ""
                          }
                }
            }
        '''
        # for file, html in htmls_files.items():
        #     self.content["articles"][html["url"]] = html["raw"]
        # for file, html in htmls_pages.items():
        #     self.content["pages"][html["url"]] = html["raw"]
        docs_url = htmls_files.keys()
        pages_url = htmls_pages.keys()
        index_content = {}
        sub_index_path = []
        generated_index_json = {}
        for i, url in enumerate(docs_url):
            index_content[url] = "{}static/search_index/index_{}.json".format(
                self.site_config["site_root_url"], i)
            path = os.path.join(self.temp_dir, "index_{}.json".format(i))
            sub_index_path.append(path)
            #   write content to sub index file
            with open(path, "w", encoding="utf-8") as f:
                htmls_files[url]["body"] = ""  # remove body, only use raw
                json.dump(htmls_files[url], f, ensure_ascii=False)
        for i, url in enumerate(pages_url, len(docs_url)):
            index_content[url] = "{}static/search_index/index_{}.json".format(
                self.site_config["site_root_url"], i)
            path = os.path.join(self.temp_dir, "index_{}.json".format(i))
            sub_index_path.append(path)
            #   write content to sub index file
            with open(path, "w", encoding="utf-8") as f:
                htmls_pages[url]["body"] = ""  # remove body, only use raw
                json.dump(htmls_pages[url], f, ensure_ascii=False)
        # write content to files
        #   index file
        index_path = os.path.join(self.temp_dir, "index.json")
        with open(index_path, "w", encoding="utf-8") as f:
            json.dump(index_content, f, ensure_ascii=False)

        # add to copy file list
        generated_index_json["/static/search_index/index.json"] = index_path
        for i, path in enumerate(sub_index_path):
            generated_index_json["/static/search_index/index_{}.json".format(
                i)] = path
        self.files_to_copy.update(generated_index_json)
Example #26
0
class Plugin(Plugin_Base):
    name = "teedoc-plugin-theme-default"
    desc = "default theme for teedoc"
    defautl_config = {
        "dark": True,
        "default_dark": False,
        "mobile_navbar_collapsed": True,
        "show_print_page": True,
        "env": {
            "main_color": "#4caf7d",
            "sidebar_width": "300px",
            "sidebar_scrollbar_color": "#b8b8b8"
        }
    }

    def on_init(self,
                config,
                doc_src_path,
                site_config,
                logger=None,
                multiprocess=True,
                **kw_args):
        '''
            @config a dict object
            @logger teedoc.logger.Logger object
        '''
        self.logger = Fake_Logger() if not logger else logger
        self.doc_src_path = doc_src_path
        self.site_config = site_config
        self.config = Plugin.defautl_config
        env = self.config["env"]
        if "env" in config:
            env.update(config["env"])
        self.config.update(config)
        self.config["env"] = env
        if self.config["mobile_navbar_collapsed"]:
            self.config["env"]["mobile_navbar_collapsed"] = "none"
        else:
            self.config["env"]["mobile_navbar_collapsed"] = "block"
        if self.config["dark"] and self.config["default_dark"]:
            self.config["env"]["default_theme"] = "dark"
        else:
            self.config["env"]["default_theme"] = "light"
        if self.config["show_print_page"]:
            self.config["env"]["show_print_page"] = "true"
        else:
            self.config["env"]["show_print_page"] = "false"
        self.logger.i("-- plugin <{}> init".format(self.name))
        self.logger.i("-- plugin <{}> config: {}".format(
            self.name, self.config))
        self.assets_abs_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "assets")

        self.dark_css = {
            "/static/css/theme_default/dark.css":
            os.path.join(self.assets_abs_path, "dark.css")
        }
        self.light_css = {
            "/static/css/theme_default/light.css":
            os.path.join(self.assets_abs_path, "light.css")
        }
        # code hilight css file
        if "code_highlight_css" in self.config and self.config[
                "code_highlight_css"]:
            self.css = {}
            self.code_highlight_css = self.config["code_highlight_css"]
        else:
            self.code_highlight_css = None
            self.css = {
                "/static/css/theme_default/prism.min.css":
                os.path.join(self.assets_abs_path, "prism.min.css"),
            }
        # image viewer
        self.css["/static/css/theme_default/viewer.min.css"] = os.path.join(
            self.assets_abs_path, "viewer.min.css")
        # js files
        self.dark_js = {}
        self.light_js = {}
        self.header_js = {
            "/static/js/theme_default/split.js":
            os.path.join(self.assets_abs_path, "split.js"),
            "/static/js/theme_default/jquery.min.js":
            os.path.join(self.assets_abs_path, "jquery.min.js"),
            "/static/js/theme_default/pre_main.js":
            os.path.join(self.assets_abs_path, "pre_main.js")
        }
        self.footer_js = {
            "/static/js/theme_default/tocbot.min.js":
            os.path.join(self.assets_abs_path, "tocbot.min.js"),
            "/static/js/theme_default/main.js":
            os.path.join(self.assets_abs_path, "main.js"),
            "/static/js/theme_default/viewer.min.js":
            os.path.join(self.assets_abs_path, "viewer.min.js")
        }
        # code hilight js file
        if "code_highlight_js" in self.config and self.config[
                "code_highlight_js"]:
            self.code_highlight_js = self.config["code_highlight_js"]
        else:
            self.code_highlight_js = None
            self.footer_js[
                "/static/css/theme_default/prism.min.js"] = os.path.join(
                    self.assets_abs_path, "prism.min.js")
        self.images = {
            "/static/image/theme_default/indicator.svg":
            os.path.join(self.assets_abs_path, "indicator.svg"),
            "/static/image/theme_default/menu.svg":
            os.path.join(self.assets_abs_path, "menu.svg"),
            "/static/image/theme_default/to-top.svg":
            os.path.join(self.assets_abs_path, "to-top.svg"),
            "/static/image/theme_default/light_mode.svg":
            os.path.join(self.assets_abs_path, "light_mode.svg"),
            "/static/image/theme_default/dark_mode.svg":
            os.path.join(self.assets_abs_path, "dark_mode.svg"),
            "/static/image/theme_default/print.svg":
            os.path.join(self.assets_abs_path, "print.svg")
        }
        # set site_root_url env value
        self.config['env']["site_root_url"] = self.site_config["site_root_url"]
        # replace variable in css with value
        vars = self.config["env"]
        self.temp_dir = os.path.join(tempfile.gettempdir(),
                                     "teedoc_plugin_theme_default")
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)
        self.dark_css = self._update_file_var(self.dark_css, vars,
                                              self.temp_dir)
        self.light_css = self._update_file_var(self.light_css, vars,
                                               self.temp_dir)
        self.css = self._update_file_var(self.css, vars, self.temp_dir)
        self.header_js = self._update_file_var(self.header_js, vars,
                                               self.temp_dir)
        self.footer_js = self._update_file_var(self.footer_js, vars,
                                               self.temp_dir)
        # files to copy
        self.html_header_items = self._generate_html_header_items()
        self.files_to_copy = {}
        if self.config["dark"]:
            self.files_to_copy.update(self.dark_css)
            self.files_to_copy.update(self.dark_js)
        self.files_to_copy.update(self.light_css)
        self.files_to_copy.update(self.css)
        self.files_to_copy.update(self.light_js)
        self.files_to_copy.update(self.header_js)
        self.files_to_copy.update(self.footer_js)
        self.files_to_copy.update(self.images)
        if self.config["dark"]:
            self.themes_btn = '<a id="themes" class="light"></a>'
        else:
            self.themes_btn = ""

        self.html_js_items = self._generate_html_js_items()

    def on_del(self):
        if os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception:
                pass

    def on_html_template(self, type_name):
        if type_name == "doc":
            return os.path.join(curr_path, "templates", "article.html")
        elif type_name == "page":
            return os.path.join(curr_path, "templates", "page.html")
        elif type_name == "blog":
            return os.path.join(curr_path, "templates", "article.html")
        return None

    def _generate_html_header_items(self):
        items = []
        # css
        for url in self.css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                url)
            items.append(item)
        if self.code_highlight_css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                self.code_highlight_css)
            items.append(item)
        if self.config["dark"]:
            for url in self.dark_css:
                item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                    url)
                items.append(item)
        for url in self.light_css:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                url)
            items.append(item)
        if "css" in self.config:
            item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format(
                self.config["css"])
            items.append(item)
        # header_js
        for url in self.header_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        if self.config["dark"]:
            for url in self.dark_js:
                item = '<script src="{}"></script>'.format(url)
                items.append(item)
        for url in self.light_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        return items

    def _generate_html_js_items(self):
        items = []
        for url in self.footer_js:
            item = '<script src="{}"></script>'.format(url)
            items.append(item)
        if "js" in self.config:
            item = '<script src="{}"></script>'.format(self.config["js"])
            items.append(item)
        if self.code_highlight_js:
            item = '<script src="{}"></script>'.format(self.code_highlight_js)
            items.append(item)
        return items

    def _update_file_var(self, files, vars, temp_dir):
        for url, path in files.items():
            with open(path, encoding='utf-8') as f:
                content = f.read()
                for k, v in vars.items():
                    content = content.replace(
                        "${}{}{}".format("{", k.strip(), "}"), str(v))
                temp_path = os.path.join(temp_dir, os.path.basename(path))
                with open(temp_path, "w", encoding='utf-8') as fw:
                    fw.write(content)
                files[url] = temp_path
        return files

    def on_add_html_header_items(self, type_name):
        return self.html_header_items

    def on_add_html_footer_js_items(self, type_name):
        return self.html_js_items

    def on_add_navbar_items(self):
        items = [self.themes_btn]
        return items

    def on_copy_files(self):
        res = self.files_to_copy
        self.files_to_copy = {}
        return res