src/doc: rename `tpl_anchor` into `html_link_to_anchor` and use bootstrap template
[nit.git] / src / doc / doc_phases / doc_html.nit
index a4bdeb0..e92e4de 100644 (file)
@@ -23,6 +23,7 @@ import doc_structure
 import doc_hierarchies
 import doc_intros_redefs
 import doc_graphs
+import html_templates
 
 redef class ToolContext
 
@@ -86,7 +87,7 @@ redef class ToolContext
                var git_dir = opt_github_gitdir
                var opts = [upstream.value, base_sha.value, git_dir.value]
                if not opts.has_only(null) and opts.has(null) then
-                       print "Error: Options {upstream.names.first}, " +
+                       print "Option Error: options {upstream.names.first}, " +
                                "{base_sha.names.first} and {git_dir.names.first} " +
                                "are required to enable the GitHub plugin"
                        exit 1
@@ -104,7 +105,7 @@ class RenderHTMLPhase
        redef fun apply do
                init_output_dir
                for page in doc.pages do
-                       page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
+                       page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}")
                end
        end
 
@@ -119,7 +120,7 @@ class RenderHTMLPhase
                        var dir = ctx.nit_dir
                        sharedir = dir/"share/nitdoc"
                        if not sharedir.file_exists then
-                               print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
+                               print "Error: cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
                                abort
                        end
                end
@@ -156,52 +157,41 @@ end
 redef class DocPage
 
        # Render the page as a html template.
-       private fun render(v: RenderHTMLPhase, doc: DocModel): TplPage do
+       private fun render(v: RenderHTMLPhase, doc: DocModel): Writable do
                var shareurl = "."
                if v.ctx.opt_shareurl.value != null then
                        shareurl = v.ctx.opt_shareurl.value.as(not null)
                end
 
+               # init page options
+               self.shareurl = shareurl
+               self.footer = v.ctx.opt_custom_footer.value
+               self.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
+
                # build page
-               var tpl = new TplPage
-               tpl.title = tpl_title(v, doc)
-               tpl.url = page_url
-               tpl.shareurl = shareurl
-               tpl.topmenu = tpl_topmenu(v, doc)
-               tpl.add_section tpl_content(v, doc)
-               tpl.footer = v.ctx.opt_custom_footer.value
-               tpl.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
-               tpl.sidebar = tpl_sidebar(v, doc)
+               init_title(v, doc)
+               init_sidebar(v, doc)
+               init_topmenu(v, doc)
+               init_content(v, doc)
 
                # piwik tracking
                var tracker_url = v.ctx.opt_piwik_tracker.value
                var site_id = v.ctx.opt_piwik_site_id.value
                if tracker_url != null and site_id != null then
-                       tpl.scripts.add new TplPiwikScript(tracker_url, site_id)
+                       self.scripts.add new TplPiwikScript(tracker_url, site_id)
                end
-               return tpl
+               return self
        end
 
        # FIXME diff hack
        # all properties below are roughly copied from `doc_pages`
 
-       # URL to this page.
-       fun page_url: String is abstract
-
-       # Build page sidebar if any
-       fun tpl_sidebar(v: RenderHTMLPhase, doc: DocModel): nullable TplSidebar do return null
-
        # Build page title string
-       fun tpl_title(v: RenderHTMLPhase, doc: DocModel): String do
-               if v.ctx.opt_custom_title.value != null then
-                       return v.ctx.opt_custom_title.value.to_s
-               end
-               return "Nitdoc"
-       end
+       fun init_title(v: RenderHTMLPhase, doc: DocModel) is abstract
 
-       # Build top menu template
-       fun tpl_topmenu(v: RenderHTMLPhase, doc: DocModel): TplTopMenu do
-               var topmenu = new TplTopMenu(page_url)
+       # Build top menu template if any.
+       fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
+               topmenu = new DocTopMenu
                var brand = v.ctx.opt_custom_brand.value
                if brand != null then
                        var tpl = new Template
@@ -210,30 +200,38 @@ redef class DocPage
                        tpl.add "</span>"
                        topmenu.brand = tpl
                end
-               topmenu.add_link new TplLink("index.html", "Overview")
-               topmenu.add_link new TplLink("search.html", "Index")
-               return topmenu
+               var title = "Overview"
+               if v.ctx.opt_custom_title.value != null then
+                       title = v.ctx.opt_custom_title.value.to_s
+               end
+               topmenu.add_li new ListItem(new Link("index.html", title))
+               topmenu.add_li new ListItem(new Link("search.html", "Index"))
+               topmenu.active_item = topmenu.items.first
+       end
+
+       # Build page sidebar if any.
+       fun init_sidebar(v: RenderHTMLPhase, doc: DocModel) do
+               sidebar = new TplSidebar
        end
 
-       # Build page content template
-       fun tpl_content(v: RenderHTMLPhase, doc: DocModel): TplSection is abstract
+       # Build page content template.
+       fun init_content(v: RenderHTMLPhase, doc: DocModel) do end
 end
 
 redef class OverviewPage
-       redef fun page_url do return "index.html"
+       redef var html_url = "index.html"
 
-       redef fun tpl_title(v, doc) do
+       redef fun init_title(v, doc) do
+               title = "Overview"
                if v.ctx.opt_custom_title.value != null then
-                       return v.ctx.opt_custom_title.value.to_s
-               else
-                       return "Overview"
+                       title = v.ctx.opt_custom_title.value.to_s
                end
        end
 
        # TODO this should be done in StructurePhase.
-       redef fun tpl_content(v, doc) do
+       redef fun init_content(v, doc) do
                # intro text
-               var section = new TplSection.with_title("overview", tpl_title(v, doc))
+               var section = new TplSection.with_title("overview", title)
                var article = new TplArticle("intro")
                if v.ctx.opt_custom_intro.value != null then
                        article.content = v.ctx.opt_custom_intro.value.to_s
@@ -255,41 +253,48 @@ redef class OverviewPage
                        ssection.add_child sarticle
                end
                section.add_child ssection
-               return section
+               self.add_section section
        end
 
-       redef fun tpl_sidebar(v, doc) do return new TplSidebar
+       redef fun init_sidebar(v, doc) do sidebar = new TplSidebar
 end
 
 redef class SearchPage
-       redef fun page_url do return "search.html"
-       redef fun tpl_title(v, doc) do return "Index"
+       redef var html_url = "search.html"
+       redef fun init_title(v, doc) do title = "Index"
+
+       redef fun init_topmenu(v, doc) do
+               super
+               topmenu.active_item = topmenu.items.last
+       end
+
+       redef fun init_sidebar(v, doc) do end
 
        # TODO this should be done in StructurePhase.
-       redef fun tpl_content(v, doc) do
+       redef fun init_content(v, doc) do
                var tpl = new TplSearchPage("search_all")
                var section = new TplSection("search")
                # title
                tpl.title = "Index"
                # modules list
                for mmodule in modules_list(v, doc) do
-                       tpl.modules.add mmodule.tpl_link
+                       tpl.modules.add mmodule.html_link
                end
                # classes list
                for mclass in classes_list(v, doc) do
-                       tpl.classes.add mclass.tpl_link
+                       tpl.classes.add mclass.html_link
                end
                # properties list
                for mproperty in mprops_list(v, doc) do
                        var m = new Template
-                       m.add mproperty.intro.tpl_link
+                       m.add mproperty.intro.html_link
                        m.add " ("
-                       m.add mproperty.intro.mclassdef.mclass.tpl_link
+                       m.add mproperty.intro.mclassdef.mclass.html_link
                        m.add ")"
                        tpl.props.add m
                end
                section.add_child tpl
-               return section
+               self.add_section section
        end
 
        # Extract mmodule list to display (sorted by name)
@@ -319,9 +324,9 @@ redef class SearchPage
 end
 
 redef class MEntityPage
-       redef fun page_url do return mentity.nitdoc_url
-       redef fun tpl_title(v, doc) do return mentity.nitdoc_name
-       redef fun tpl_content(v, doc) do return root.start_rendering(v, doc, self)
+       redef var html_url is lazy do return mentity.nitdoc_url
+       redef fun init_title(v, doc) do title = mentity.html_name
+       redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
 end
 
 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
@@ -329,22 +334,22 @@ end
 # `doc_templates` module.
 
 redef class MGroupPage
-       redef fun tpl_topmenu(v, doc) do
-               var topmenu = super
+       redef fun init_topmenu(v, doc) do
+               super
                var mproject = mentity.mproject
                if not mentity.is_root then
-                       topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
                end
-               topmenu.add_link new TplLink(page_url, mproject.nitdoc_name)
-               return topmenu
+               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
-       redef fun tpl_sidebar(v, doc) do
-               var sidebar = new TplSidebar
+       redef fun init_sidebar(v, doc) do
+               super
                var mclasses = new HashSet[MClass]
                mclasses.add_all intros
                mclasses.add_all redefs
-               if mclasses.is_empty then return sidebar
+               if mclasses.is_empty then return
                var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
 
                var sorted = mclasses.to_a
@@ -353,7 +358,6 @@ redef class MGroupPage
                        list.add_li tpl_sidebar_item(mclass)
                end
                sidebar.boxes.add new TplSideBox.with_content("All classes", list)
-               return sidebar
        end
 
        private fun tpl_sidebar_item(def: MClass): TplListItem do
@@ -365,28 +369,28 @@ redef class MGroupPage
                end
                var lnk = new Template
                lnk.add new TplLabel.with_classes(classes)
-               lnk.add def.tpl_link
+               lnk.add def.html_link
                return new TplListItem.with_content(lnk)
        end
 end
 
 redef class MModulePage
-       redef fun tpl_topmenu(v, doc) do
-               var topmenu = super
+       redef fun init_topmenu(v, doc) do
+               super
                var mproject = mentity.mproject
-               topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
-               topmenu.add_link new TplLink(mentity.nitdoc_url, mentity.nitdoc_name)
-               return topmenu
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        # Class list to display in sidebar
-       redef fun tpl_sidebar(v, doc) do
+       redef fun init_sidebar(v, doc) do
                # TODO filter here?
-               var sidebar = new TplSidebar
+               super
                var mclasses = new HashSet[MClass]
                mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
                mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
-               if mclasses.is_empty then return sidebar
+               if mclasses.is_empty then return
                var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
 
                var sorted = mclasses.to_a
@@ -395,7 +399,6 @@ redef class MModulePage
                        list.add_li tpl_sidebar_item(mclass)
                end
                sidebar.boxes.add new TplSideBox.with_content("All classes", list)
-               return sidebar
        end
 
        private fun tpl_sidebar_item(def: MClass): TplListItem do
@@ -407,34 +410,29 @@ redef class MModulePage
                end
                var lnk = new Template
                lnk.add new TplLabel.with_classes(classes)
-               lnk.add def.tpl_link
+               lnk.add def.html_link
                return new TplListItem.with_content(lnk)
        end
 end
 
 redef class MClassPage
 
-       redef fun tpl_title(v, doc) do
-               return "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
-       end
-
-       redef fun tpl_topmenu(v, doc) do
-               var topmenu = super
+       redef fun init_topmenu(v, doc) do
+               super
                var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink(page_url, mentity.nitdoc_name)
-               return topmenu
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
-       redef fun tpl_sidebar(v, doc) do
-               var sidebar = new TplSidebar
+       redef fun init_sidebar(v, doc) do
+               super
                var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
                var summary = new TplList.with_classes(["list-unstyled"])
 
                by_kind.sort_groups(v.name_sorter)
                for g in by_kind.groups do tpl_sidebar_list(g, summary)
                sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
-               return sidebar
        end
 
        private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
@@ -454,7 +452,7 @@ redef class MClassPage
                        classes.add "inherit"
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink(def_url, mprop.nitdoc_name)
+                       var lnk = new TplLink(def_url, mprop.html_name)
                        var mdoc = mprop.intro.mdoc_or_fallback
                        if mdoc != null then lnk.title = mdoc.short_comment
                        var item = new Template
@@ -469,7 +467,7 @@ redef class MClassPage
                end
                var lnk = new Template
                lnk.add new TplLabel.with_classes(classes)
-               lnk.add mprop.tpl_anchor
+               lnk.add mprop.html_link_to_anchor
                return new TplListItem.with_content(lnk)
        end
 
@@ -497,22 +495,20 @@ redef class MClassPage
 end
 
 redef class MPropertyPage
-       redef fun tpl_topmenu(v, doc) do
-               var topmenu = super
+       redef fun init_title(v, doc) do
+               title = "{mentity.html_name}{mentity.tpl_signature.write_to_string}"
+       end
+
+       redef fun init_topmenu(v, doc) do
+               super
                var mmodule = mentity.intro_mclassdef.mmodule
                var mproject = mmodule.mgroup.mproject
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
-               topmenu.add_link new TplLink(page_url, mentity.nitdoc_name)
-               return topmenu
-       end
-
-       redef fun tpl_title(v, doc) do
-               return "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
-
-       redef fun tpl_sidebar(v, doc) do return new TplSidebar
 end
 
 redef class DocComposite
@@ -530,18 +526,16 @@ redef class DocRoot
        fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
                var section = new TplSection("top")
                var mentity = page.mentity
-               section.title = mentity.nitdoc_name
+               section.title = mentity.html_name
                section.subtitle = mentity.tpl_declaration
                # FIXME ugly hack to avoid diff
                if mentity isa MGroup and mentity.is_root then
-                       section.title = mentity.mproject.nitdoc_name
+                       section.title = mentity.mproject.html_name
                        section.subtitle = mentity.mproject.tpl_declaration
-               else if mentity isa MClass then
-                       section.title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
                else if mentity isa MProperty then
-                       section.title = "{mentity.nitdoc_name}{mentity.intro.tpl_signature.write_to_string}"
+                       section.title = "{mentity.html_name}{mentity.intro.tpl_signature.write_to_string}"
                        section.subtitle = mentity.tpl_namespace
-                       section.summary_title = mentity.nitdoc_name
+                       section.summary_title = mentity.html_name
                end
                render(v, doc, page, section)
                return section
@@ -576,10 +570,10 @@ redef class ConcernSection
                var title = new Template
                if mmodule == page.mentity then
                        title.add "in "
-                       section.summary_title = "in {mmodule.nitdoc_name}"
+                       section.summary_title = "in {mmodule.html_name}"
                else
                        title.add "from "
-                       section.summary_title = "from {mmodule.nitdoc_name}"
+                       section.summary_title = "from {mmodule.html_name}"
                end
                title.add mmodule.tpl_namespace
                section.title = title
@@ -590,7 +584,13 @@ redef class ConcernSection
                title.add "in "
                title.add mmodule.tpl_namespace
                section.title = title
-               section.summary_title = "in {mmodule.nitdoc_name}"
+               section.summary_title = "in {mmodule.html_name}"
+       end
+end
+
+redef class MEntitySection
+       redef fun render(v, doc, page, parent) do
+               for child in children do child.render(v, doc, page, parent)
        end
 end
 
@@ -700,19 +700,19 @@ redef class DefinitionArticle
                title.add mprop.tpl_icon
                title.add "<span id='{mpropdef.nitdoc_id}'></span>"
                if mpropdef.is_intro then
-                       title.add mprop.tpl_link
+                       title.add mprop.html_link
                        title.add mprop.intro.tpl_signature
                else
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink.with_title(def_url, mprop.nitdoc_name,
+                       var lnk = new TplLink.with_title(def_url, mprop.html_name,
                                        "Go to introduction")
                        title.add "redef "
                        title.add lnk
                end
                article.title = title
                article.title_classes.add "signature"
-               article.summary_title = "{mprop.nitdoc_name}"
+               article.summary_title = "{mprop.html_name}"
                article.subtitle = mpropdef.tpl_namespace
                if mpropdef.mdoc_or_fallback != null then
                        article.content = mpropdef.mdoc_or_fallback.tpl_comment
@@ -818,11 +818,11 @@ redef class GraphArticle
                var output_dir = v.ctx.output_dir
                var path = output_dir / id
                var path_sh = path.escape_to_sh
-               var file = new OFStream.open("{path}.dot")
+               var file = new FileWriter.open("{path}.dot")
                file.write(dot)
                file.close
                sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
-               var fmap = new IFStream.open("{path}.map")
+               var fmap = new FileReader.open("{path}.map")
                var map = fmap.read_all
                fmap.close