nitikiwi: fix `src_path` and stop losing the first character
[nit.git] / contrib / nitiwiki / src / wiki_html.nit
index 3427016..a937351 100644 (file)
 # HTML wiki rendering
 module wiki_html
 
-import wiki_base
+import wiki_links
+import markdown::decorators
 
 redef class Nitiwiki
 
        # Render HTML output looking for changes in the markdown sources.
-       fun render do
+       redef fun render do
+               super
                if not root_section.is_dirty and not force_render then return
                var out_dir = expand_path(config.root_dir, config.out_dir)
                out_dir.mkdir
@@ -44,16 +46,24 @@ redef class Nitiwiki
                sitemap.is_dirty = true
                return sitemap
        end
-end
 
-redef class WikiEntry
+       # Markdown processor used for inline element such as titles in TOC.
+       private var inline_processor: MarkdownProcessor is lazy do
+               var proc = new MarkdownProcessor
+               proc.emitter.decorator = new InlineDecorator
+               return proc
+       end
 
-       # Url to `self` once generated.
-       fun url: String do return wiki.config.root_url.join_path(breadcrumbs.join("/"))
+       # Inline markdown (remove h1, p, ... elements).
+       private fun inline_md(md: Writable): Writable do
+               return inline_processor.process(md.write_to_string)
+       end
+end
 
+redef class WikiEntry
        # Get a `<a>` template link to `self`
-       fun tpl_link: Writable do
-               return "<a href=\"{url}\">{title}</a>"
+       fun tpl_link(context: WikiEntry): Writable do
+               return "<a href=\"{href_from(context)}\">{title}</a>"
        end
 end
 
@@ -103,18 +113,7 @@ redef class WikiSection
                end
        end
 
-       # The index page for this section.
-       #
-       # If no file `index.md` exists for this section,
-       # a summary is generated using contained articles.
-       var index: WikiArticle is lazy do
-               for child in children.values do
-                       if child isa WikiArticle and child.is_index then return child
-               end
-               return new WikiSectionIndex(wiki, "index", self)
-       end
-
-       redef fun tpl_link do return index.tpl_link
+       redef fun tpl_link(context) do return index.tpl_link(context)
 
        # Render the section hierarchy as a html tree.
        #
@@ -134,15 +133,15 @@ redef class WikiSection
        # </ul>
        # ~~~
        fun tpl_tree(limit: Int): Template do
-               return tpl_tree_intern(limit, 1)
+               return tpl_tree_intern(limit, 1, self)
        end
 
        # Build the template tree for this section recursively.
-       protected fun tpl_tree_intern(limit, count: Int): Template do
+       protected fun tpl_tree_intern(limit, count: Int, context: WikiEntry): Template do
                var out = new Template
                var index = index
                out.add "<li>"
-               out.add tpl_link
+               out.add tpl_link(context)
                if (limit < 0 or count < limit) and
                   (children.length > 1 or (children.length == 1)) then
                        out.add " <ul>"
@@ -150,10 +149,10 @@ redef class WikiSection
                                if child == index then continue
                                if child isa WikiArticle then
                                        out.add "<li>"
-                                       out.add child.tpl_link
+                                       out.add child.tpl_link(context)
                                        out.add "</li>"
                                else if child isa WikiSection and not child.is_hidden then
-                                       out.add child.tpl_tree_intern(limit, count + 1)
+                                       out.add child.tpl_tree_intern(limit, count + 1, context)
                                end
                        end
                        out.add " </ul>"
@@ -173,32 +172,31 @@ redef class WikiArticle
                end
        end
 
-       redef fun url do
-               if parent == null then
-                       return wiki.config.root_url.join_path("{name}.html")
-               else
-                       return parent.url.join_path("{name}.html")
-               end
-       end
-
-       # Is `self` an index page?
-       #
-       # Checks if `self.name == "index"`.
-       fun is_index: Bool do return name == "index"
-
        redef fun render do
+               super
                if not is_dirty and not wiki.force_render then return
                wiki.message("Render article {name}", 2)
                var file = out_full_path
                file.dirname.mkdir
                tpl_page.write_to_file file
-               super
        end
 
 
+       # Load a template and resolve page-related macros
+       fun load_template(template_file: String): TemplateString do
+               var tpl = wiki.load_template(template_file)
+               if tpl.has_macro("ROOT_URL") then
+                       var root_dir = href.dirname.relpath("")
+                       # Avoid issues if the macro is just followed by a `/` (as with url prefix)
+                       if root_dir == "" then root_dir = "."
+                       tpl.replace("ROOT_URL", root_dir)
+               end
+               return tpl
+       end
+
        # Replace macros in the template by wiki data.
        private fun tpl_page: TemplateString do
-               var tpl = wiki.load_template(template_file)
+               var tpl = load_template(template_file)
                if tpl.has_macro("TOP_MENU") then
                        tpl.replace("TOP_MENU", tpl_menu)
                end
@@ -218,21 +216,30 @@ redef class WikiArticle
        fun tpl_header: Writable do
                var file = header_file
                if not wiki.has_template(file) then return ""
-               return wiki.load_template(file)
+               return load_template(file)
        end
 
        # Generate the HTML page for this article.
        fun tpl_article: TplArticle do
                var article = new TplArticle
                article.body = content
-               article.breadcrumbs = new TplBreadcrumbs(self)
-               tpl_sidebar.blocks.add tpl_summary
+               if wiki.config.auto_breadcrumbs then
+                       article.breadcrumbs = new TplBreadcrumbs(self)
+               end
                article.sidebar = tpl_sidebar
+               article.sidebar_pos = wiki.config.sidebar
                return article
        end
 
        # Sidebar for this page.
-       var tpl_sidebar = new TplSidebar
+       var tpl_sidebar: TplSidebar is lazy do
+               var res = new TplSidebar
+               if wiki.config.auto_summary then
+                       res.blocks.add tpl_summary
+               end
+               res.blocks.add_all sidebar.blocks
+               return res
+       end
 
        # Generate the HTML summary for this article.
        #
@@ -245,8 +252,7 @@ redef class WikiArticle
                while iter.is_ok do
                        var hl = iter.item
                        # parse title as markdown
-                       var title = hl.title.md_to_html.to_s
-                       title = title.substring(3, title.length - 8)
+                       var title = wiki.inline_md(hl.title)
                        tpl.add "<li><a href=\"#{hl.id}\">{title}</a>"
                        iter.next
                        if iter.is_ok then
@@ -268,7 +274,7 @@ redef class WikiArticle
        fun tpl_menu: Writable do
                var file = menu_file
                if not wiki.has_template(file) then return ""
-               var tpl = wiki.load_template(file)
+               var tpl = load_template(file)
                if tpl.has_macro("MENUS") then
                        var items = new Template
                        for child in wiki.root_section.children.values do
@@ -279,7 +285,7 @@ redef class WikiArticle
                                        items.add " class=\"active\""
                                end
                                items.add ">"
-                               items.add child.tpl_link
+                               items.add child.tpl_link(self)
                                items.add "</li>"
                        end
                        tpl.replace("MENUS", items)
@@ -291,7 +297,7 @@ redef class WikiArticle
        fun tpl_footer: Writable do
                var file = footer_file
                if not wiki.has_template(file) then return ""
-               var tpl = wiki.load_template(file)
+               var tpl = load_template(file)
                var time = new Tm.gmtime
                if tpl.has_macro("YEAR") then
                        tpl.replace("YEAR", (time.year + 1900).to_s)
@@ -299,6 +305,14 @@ redef class WikiArticle
                if tpl.has_macro("GEN_TIME") then
                        tpl.replace("GEN_TIME", time.to_s)
                end
+               if tpl.has_macro("LAST_CHANGES") then
+                       var url = "{wiki.config.last_changes}{src_path or else ""}"
+                       tpl.replace("LAST_CHANGES", url)
+               end
+               if tpl.has_macro("EDIT") then
+                       var url = "{wiki.config.edit}{src_path or else ""}"
+                       tpl.replace("EDIT", url)
+               end
                return tpl
        end
 end
@@ -317,15 +331,7 @@ class WikiSitemap
 end
 
 # A `WikiArticle` that contains the section index tree.
-class WikiSectionIndex
-       super WikiArticle
-
-       # The section described by `self`.
-       var section: WikiSection
-
-       redef fun title do return section.title
-
-       redef fun url do return section.url
+redef class WikiSectionIndex
 
        redef var is_dirty = false
 
@@ -350,6 +356,11 @@ class TplArticle
        # Sidebar of this article (if any).
        var sidebar: nullable TplSidebar = null
 
+       # Position of the sidebar.
+       #
+       # See `WikiConfig::sidebar`.
+       var sidebar_pos: String = "left"
+
        # Breadcrumbs from wiki root to this article.
        var breadcrumbs: nullable TplBreadcrumbs = null
 
@@ -359,13 +370,11 @@ class TplArticle
        end
 
        redef fun rendering do
-               if sidebar != null then
-                       add "<div class=\"col-sm-3 sidebar\">"
-                       add sidebar.as(not null)
-                       add "</div>"
-                       add "<div class=\"col-sm-9 content\">"
-               else
+               if sidebar_pos == "left" then render_sidebar
+               if sidebar == null then
                        add "<div class=\"col-sm-12 content\">"
+               else
+                       add "<div class=\"col-sm-9 content\">"
                end
                if body != null then
                        add "<article>"
@@ -381,6 +390,14 @@ class TplArticle
                        add " </article>"
                end
                add "</div>"
+               if sidebar_pos == "right" then render_sidebar
+       end
+
+       private fun render_sidebar do
+               if sidebar == null then return
+               add "<div class=\"col-sm-3 sidebar\">"
+               add sidebar.as(not null)
+               add "</div>"
        end
 end
 
@@ -393,9 +410,9 @@ class TplSidebar
 
        redef fun rendering do
                for block in blocks do
-                       add "<div class=\"sideblock\">"
+                       add "<nav class=\"sideblock\">"
                        add block
-                       add "</div>"
+                       add "</nav>"
                end
        end
 end
@@ -419,7 +436,7 @@ class TplBreadcrumbs
                        else
                                if article.parent == entry and article.is_index then continue
                                add "<li>"
-                               add entry.tpl_link
+                               add entry.tpl_link(article)
                                add "</li>"
                        end
                end