# This file is part of NIT ( http://www.nitlanguage.org ). # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Introduces templates that compose the documentation HTML rendering. module html_templates import html_model import html::bootstrap import doc_phases::doc_structure import doc_phases::doc_hierarchies import doc_phases::doc_graphs import doc_phases::doc_intros_redefs import doc_phases::doc_lin import doc_phases::doc_readme intrude import doc_down # Renders the page as HTML. redef class DocPage super Template # Page url. var html_url: String is writable, noinit # Directory where css, js and other assets can be found. var shareurl: String is writable, noinit # Attributes of the body tag element. var body_attrs = new Array[TagAttribute] # Top menu template if any. var topmenu: DocTopMenu is writable, noinit # Sidebar template if any. var sidebar: nullable DocSideBar = null is writable # Footer content if any. var footer: nullable Writable = null is writable # JS scripts to append at the end of the body var scripts = new Array[TplScript] # Renders the html ``. private fun render_head do var css = (self.shareurl / "css").html_escape var vendors = (self.shareurl / "vendors").html_escape addn "" addn "" addn " " addn " " addn " " addn " " addn " " addn " " addn " " addn " " addn " {title.html_escape}" addn "" add "" end # Renders the footer and content. private fun render_content do add root if footer != null then addn "" end end # Render JS scripts private fun render_footer do var vendors = (self.shareurl / "vendors").html_escape var js = (self.shareurl / "js").html_escape addn "" addn "" addn "" addn "" addn "" addn "" addn "" for script in scripts do add script addn """""" addn "" addn "" end # Render the whole page redef fun rendering do render_head addn "
" addn "
" add topmenu addn "
" addn "
" var sidebar = self.sidebar if sidebar != null then addn "
" add sidebar addn "
" addn "
" render_content addn "
" else addn "
" render_content addn "
" end addn "
" addn "
" render_footer end # Render table of content for this page. fun html_toc: UnorderedList do var lst = new UnorderedList lst.css_classes.add "nav" for child in root.children do child.render_toc_item(lst) end return lst end end # Top menu bar template. # # FIXME should be a Bootstrap component template # At this moment, the topmenu structure stills to specific to Nitdoc to use the # generic component. class DocTopMenu super UnorderedList # Brand link to display in first position of the top menu. # # This is where you want to put your logo. var brand: nullable Writable is noinit, writable # Active menu item. # # Depends on the current page, this allows to hilighted the current item. # # FIXME should be using Boostrap breadcrumbs component. # This will still like this to avoid diff and be changed in further fixes # when we will modify the output. var active_item: nullable ListItem is noinit, writable redef fun rendering do addn "" end end # Nitdoc sidebar template. class DocSideBar super Template # Sidebar contains `DocSideBox`. var boxes = new Array[DocSideBox] redef fun rendering do if boxes.is_empty then return addn "" end end # Something that can be put in a DocSideBar. class DocSideBox super Template # Box HTML id, used for Bootstrap collapsing feature. # # Use `html_title.to_cmangle` by default. var id: String is lazy do return title.write_to_string.to_cmangle # Title of the box to display. var title: Writable # Content to display in the box. var content: Writable # Is the box opened by default? # # Otherwise, the user will have to clic on the title to display the content. # # Default is `true`. var is_open = true is writable redef fun rendering do var open = "" if is_open then open = "in" addn "
" addn "
" add " " add title addn " " addn "
" addn "
" add content addn "
" addn "
" end end redef class DocComposite super Template # HTML anchor id var html_id: String is writable, lazy do return id # Title to display if any. # # This title can be decorated with HTML. var html_title: nullable Writable is writable, lazy do return title # Subtitle to display if any. var html_subtitle: nullable Writable is noinit, writable # Render the element title and subtitle. private fun render_title do if html_title != null then var header = new Header(hlvl, html_title.write_to_string) header.css_classes.add "signature" addn header end if html_subtitle != null then addn "
" addn html_subtitle.write_to_string addn "
" end end # Render the element body. private fun render_body do for child in children do addn child.write_to_string end redef fun rendering do if is_hidden then return render_title render_body end # Level for HTML heading. private fun hlvl: Int do return depth # A short, undecorated title that goes in the table of contents. # # By default, returns `html_title.to_s`, subclasses should redefine it. var html_toc_title: nullable String is lazy, writable do if html_title == null then return toc_title return html_title.write_to_string end # Render this element in a table of contents. private fun render_toc_item(lst: UnorderedList) do if is_toc_hidden or html_toc_title == null then return var content = new Template content.add new Link("#{html_id}", html_toc_title.to_s) if not children.is_empty then var sublst = new UnorderedList sublst.css_classes.add "nav" for child in children do child.render_toc_item(sublst) end content.add sublst end lst.add_li new ListItem(content) end # ID used in HTML tab labels. # # We sanitize it for Boostrap JS panels that do not like ":" and "." in ids. var html_tab_id: String is lazy do var id = html_id.replace(":", "") id = id.replace(".", "") return "{id}-tab" end end redef class DocRoot redef fun rendering do for child in children do addn child.write_to_string end end redef class DocSection super BSComponent redef fun rendering do if is_hidden then addn "" return end addn "" render_title render_body addn "" end end redef class DocArticle super BSComponent redef fun rendering do if is_hidden then return addn "" render_title render_body addn "" end end redef class TabbedGroup redef fun render_body do var tabs = new DocTabs("{html_id}.tabs", "") for child in children do if child.is_hidden then continue var title = child.html_toc_title or else child.toc_title or else "" tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end addn tabs end end redef class PanelGroup redef var html_title = null redef var toc_title is lazy do return title or else "" redef var is_toc_hidden = true end redef class HomeArticle redef var html_title = "Overview" # HTML content to display on the home page. # # This attribute is set by the `doc_render` phase who knows the context. var content: nullable String is noinit, writable redef fun render_body do var content = self.content if content != null then add content super end end redef class IndexArticle redef var html_title = "Index" redef fun render_body do addn "
" addn "
" render_list("Modules", mmodules) render_list("Classes", mclasses) render_list("Properties", mprops) addn "
" addn "
" end # Displays a list from the content of `mentities`. private fun render_list(title: String, mentities: Array[MEntity]) do if mentities.is_empty then return addn "
" addn new Header(3, title) var lst = new UnorderedList for mentity in mentities do if mentity isa MProperty then var tpl = new Template tpl.add mentity.intro.html_link tpl.add " (" tpl.add mentity.intro.mclassdef.mclass.html_link tpl.add ")" lst.add_li new ListItem(tpl) else lst.add_li new ListItem(mentity.html_link) end end addn lst addn "
" end end redef class MEntityComposite redef var html_title is lazy do return mentity.nitdoc_name end redef class MEntitySection redef var html_title is lazy do return mentity.html_name redef var html_subtitle is lazy do return mentity.html_declaration end redef class ConcernSection redef var html_title is lazy do return "in {mentity.nitdoc_name}" end redef class IntroArticle redef var html_title = null # Link to source to display if any. var html_source_link: nullable Writable is noinit, writable redef fun render_body do var tabs = new DocTabs("{html_id}.tabs", "") var comment = mentity.html_documentation if mentity isa MPackage then comment = mentity.html_synopsis end if comment != null then tabs.add_panel new DocTabPanel("{html_tab_id}-comment", "Comment", comment) end for child in children do if child.is_hidden then continue var title = child.html_toc_title or else child.toc_title or else "" tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end var lnk = html_source_link if lnk != null then tabs.drop_list.items.add new ListItem(lnk) end addn tabs end end redef class ConcernsArticle redef var html_title = "Concerns" redef fun render_body do add concerns.html_list end redef class DefinitionListArticle redef var html_title is lazy do var title = new Template title.add mentity.html_icon title.add mentity.html_link return title end redef var html_subtitle is lazy do return mentity.html_namespace redef var html_toc_title is lazy do return mentity.html_name end redef class DefinitionArticle redef var html_title is lazy do return mentity.html_name redef var html_subtitle is lazy do return mentity.html_declaration # Does `self` display only it's title and no body? # # FIXME diff hack var is_no_body: Bool = false is writable # Does `self` display only the short content as definition? # # FIXME diff hack var is_short_comment: Bool = false is writable # Link to source to display if any. var html_source_link: nullable Writable is noinit, writable redef fun render_body do var tabs = new DocTabs("{html_id}.tabs", "") if not is_no_body then var comment if is_short_comment or mentity isa MPackage then comment = mentity.html_synopsis else comment = mentity.html_documentation end if comment != null then tabs.add_panel new DocTabPanel("{html_tab_id}-comment", "Comment", comment) end end for child in children do if child.is_hidden then continue var title = child.html_toc_title or else child.toc_title or else "" tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end var lnk = html_source_link if lnk != null then tabs.drop_list.items.add new ListItem(lnk) end addn tabs end end redef class MEntitiesListArticle redef fun render_body do var lst = new UnorderedList lst.css_classes.add "list-unstyled list-definition" for mentity in mentities do lst.add_li mentity.html_list_item end add lst end end redef class DefinitionLinArticle redef fun render_body do var lst = new UnorderedList lst.css_classes.add "list-unstyled list-labeled" for mentity in mentities do if not mentity isa MPropDef then continue # TODO handle all mentities var tpl = new Template tpl.add mentity.mclassdef.html_namespace var comment = mentity.mclassdef.html_synopsis if comment != null then tpl.add ": " tpl.add comment end var li = new ListItem(tpl) li.css_classes.add "signature" lst.add_li li end add lst end end redef class GraphArticle redef var html_title = null # Graph in SVG with clickable map. # # This attribute is set by the `doc_render` phase who knows the context. var svg: nullable String = null is writable redef fun render_body do addn "
" var svg = self.svg if svg != null then add svg addn "
" end end redef class ReadmeSection redef var html_id is lazy do return markdown_processor.decorator.strip_id(html_title.as(not null).to_s) end redef var html_title is lazy do return markdown_processor.process(title.as(not null)) end end redef class ReadmeArticle redef var html_id = "" redef var html_title = null redef var is_toc_hidden = true redef fun render_body do add markdown_processor.process(md.trim.write_to_string) end end redef class DocumentationArticle redef var html_title is lazy do var synopsis = mentity.html_synopsis if synopsis == null then return mentity.html_link return "{mentity.html_link.write_to_string} – {synopsis.write_to_string}" end redef var html_subtitle is lazy do return null redef var html_toc_title is lazy do return mentity.html_name redef var is_toc_hidden is lazy do return depth > 3 redef fun render_body do var tabs = new DocTabs("{html_id}.tabs", "") var comment = mentity.html_comment if comment != null then tabs.add_panel new DocTabPanel("{html_tab_id}-comment", "Comment", comment) end for child in children do if child.is_hidden then continue var title = child.html_toc_title or else child.toc_title or else "" tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end addn tabs end end