nitdoc: migrate templates to bootstrap
authorAlexandre Terrasa <alexandre@moz-code.org>
Fri, 6 Jun 2014 07:20:36 +0000 (03:20 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Fri, 6 Jun 2014 18:43:41 +0000 (14:43 -0400)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/doc/doc_templates.nit [new file with mode: 0644]

diff --git a/src/doc/doc_templates.nit b/src/doc/doc_templates.nit
new file mode 100644 (file)
index 0000000..788cb85
--- /dev/null
@@ -0,0 +1,811 @@
+# 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.
+
+# HTML templates used by Nitdoc to generate API documentation
+# Pages are assembled using `Template`
+module doc_templates
+
+import template
+
+# A documentation page
+class TplPage
+       super Template
+
+       # Page title in HTML header
+       var title: String writable
+
+       # Directory where css, js and other assets can be found
+       var shareurl: String writable
+
+       # Attributes of the body tag element
+       var body_attrs = new Array[TagAttribute]
+
+       # Top menu template if any
+       var topmenu: TplTopMenu writable
+
+       # Sidebar template if any
+       var sidebar: nullable TplSidebar writable
+
+       # Content of the page in form a TplSection
+       var sections = new Array[TplSection]
+
+       # Footer content if any
+       var footer: nullable Streamable writable
+
+       # JS scripts to append at the end of the body
+       var scripts = new Array[TplScript]
+
+       init do end
+
+       # Add a section to this page
+       fun add_section(section: TplSection) do
+               sections.add section
+       end
+
+       # Render the html header
+       private fun render_head do
+               add "<!DOCTYPE html>"
+               add "<head>"
+               add " <meta charset='utf-8'/>"
+               add " <!--link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css'/-->"
+               add " <link rel='stylesheet' href='{shareurl}/vendors/bootstrap/css/bootstrap.min.css'/>"
+               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.bootstrap.css'/>"
+               add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.css'/>"
+               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css'/>"
+               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css'/>"
+               add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css'/>"
+               add " <title>{title}</title>"
+               add "</head>"
+               add "<body"
+               for attr in body_attrs do add attr
+               add ">"
+       end
+
+       # Render the topmenu template
+       private fun render_topmenu do
+               add " <div class='row'>"
+               add topmenu
+               add " </div>"
+       end
+
+       # Render the sidebar
+       # Sidebar is automatically populated with a summary of all sections
+       fun render_sidebar do
+               if sidebar == null then return
+               var summary = new TplSummary.with_order(0)
+               for section in sections do
+                       section.render_summary summary
+               end
+               sidebar.boxes.add summary
+               add sidebar.as(not null)
+       end
+       # Render the footer and content
+       private fun render_content do
+               for section in sections do add section
+               if footer != null then
+                       add "<div class='well footer'>"
+                       add footer.as(not null)
+                       add "</div>"
+               end
+       end
+
+       # Render JS scripts
+       private fun render_footer do
+               add "<script src='{shareurl}/vendors/jquery/jquery-1.11.1.min.js'></script>"
+               add "<script src='{shareurl}/vendors/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
+               add "<script src='{shareurl}/vendors/bootstrap/js/bootstrap.min.js'></script>"
+               add "<script data-main='{shareurl}/js/nitdoc' src='{shareurl}/js/lib/require.js'</script>"
+               for script in scripts do add script
+               add """<script>
+                       $(function () {
+                               $("[data-toggle='tooltip']").tooltip();
+                               $("[data-toggle='popover']").popover();
+                       });
+               </script>"""
+               add "</body>"
+               add "</html>"
+       end
+
+       # Render the whole page
+       redef fun rendering do
+               render_head
+               add "<div class='container-fluid'>"
+               render_topmenu
+               add " <div class='row' id='content'>"
+               if sidebar != null then
+                       add "<div class='col col-xs-3 col-lg-2'>"
+                       render_sidebar
+                       add "</div>"
+                       add "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
+                       render_content
+                       add "</div>"
+               else
+                       add "<div class='col col-xs-12'>"
+                       render_content
+                       add "</div>"
+               end
+               add " </div>"
+               add "</div>"
+               render_footer
+       end
+end
+
+#########################
+# general layout elements
+#########################
+
+# Top menu bar template
+class TplTopMenu
+       super Template
+
+       # Elements of the topmenu
+       private var elts = new Array[Streamable]
+
+       # Add a new link to the menu
+       fun add_link(href, name: String, is_active: Bool) do
+               var tpl = new Template
+               tpl.add "<li"
+               if is_active then
+                       tpl.add " class='active'"
+               end
+               tpl.add ">"
+               tpl.add new TplLink(href, name)
+               tpl.add "</li>"
+               add_raw(tpl)
+       end
+
+       # Add a raw content to the menu
+       fun add_raw(content: Streamable) do
+               elts.add content
+       end
+
+       redef fun rendering do
+               add "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+               add " <div class='container-fluid'>"
+               if not elts.is_empty then
+                       add "<ul class='nav navbar-nav'>"
+                       for elt in elts do add(elt)
+                       add "</ul>"
+               end
+               add " </div>"
+               add "</nav>"
+       end
+end
+
+# A sidebar template
+class TplSidebar
+       super Template
+
+       # Sidebar contains sidebar element templates called boxes
+       var boxes = new Array[TplSidebarElt]
+
+       # Sort boxes by order priority
+       private fun order_boxes do
+               var sorter = new OrderComparator
+               sorter.sort(boxes)
+       end
+
+       redef fun rendering do
+               if boxes.is_empty then return
+               order_boxes
+               add "<div id='sidebar'>"
+               for box in boxes do add box
+               add "</div>"
+       end
+end
+
+# Comparator used to sort boxes by order
+private class OrderComparator
+       super Comparator[TplSidebarElt]
+
+       redef fun compare(a, b) do
+               if a.order < b.order then return -1
+               if a.order > b.order then return 1
+               return 0
+       end
+end
+
+# Something that can be put in the sidebar
+class TplSidebarElt
+       super Template
+
+       # Order of the box in the sidebar
+       var order: Int = 1
+
+       init with_order(order: Int) do self.order = order
+end
+
+# Agenericbox that can be added to sidebar
+class TplSideBox
+       super TplSidebarElt
+
+       # Title of the box to display
+       # Title is also a placeholder for the collapse link
+       var title: String
+
+       # Box HTML id
+       # equals to `title.to_cmangle` by default
+       # Used for collapsing
+       var id: String
+
+       # Content to display in the box
+       # box will not be rendered if the content is null
+       var content: nullable Streamable writable
+
+       # Is the box opened by default
+       # otherwise, the user will have to clic on the title to display the content
+       var is_open writable = false
+
+       init(title: String) do
+               self.title = title
+               self.id = title.to_cmangle
+       end
+
+       init with_content(title: String, content: Streamable) do
+               init(title)
+               self.content = content
+       end
+
+       redef fun rendering do
+               if content == null then return
+               var open = ""
+               if is_open then open = "in"
+               add "<div class='panel'>"
+               add " <div class='panel-heading'>"
+               add "  <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
+               add title
+               add "  </a>"
+               add " </div>"
+               add " <div id='box_{id}' class='panel-body collapse {open}'>"
+               add content.as(not null)
+               add " </div>"
+               add "</div>"
+       end
+end
+
+# Something that can go on a summary template
+class TplSummaryElt
+       super Template
+
+       # Add an element to the summary
+       fun add_child(child: TplSummaryElt) is abstract
+end
+
+# A summary that can go on the sidebar
+# If the page contains a sidebar, the summary is automatically placed
+# on top of the sidebarauto-generated
+# summary contains anchors to all sections displayed in the page
+class TplSummary
+       super TplSidebarElt
+       super TplSummaryElt
+
+       # Summary elements to display
+       var children = new Array[TplSummaryElt]
+
+       redef fun add_child(child) do children.add child
+
+       redef fun rendering do
+               if children.is_empty then return
+               add "<div class='panel'>"
+               add " <div class='panel-heading'>"
+               add "  <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
+               add "Summary"
+               add "  </a>"
+               add " </div>"
+               add " <div id='box-sum' class='summary collapse in'>"
+               add " <ul class='nav'>"
+               for entry in children do add entry
+               add " </ul>"
+               add " </div>"
+               add "</div>"
+       end
+end
+
+# A summary entry
+class TplSummaryEntry
+       super TplSummaryElt
+
+       # Text to display
+       var text: Streamable
+
+       # Children of this entry
+       # Will be displayed as a tree
+       var children = new Array[TplSummaryElt]
+
+       init(text: Streamable) do self.text = text
+
+       redef fun add_child(child) do children.add child
+
+       redef fun rendering do
+               add "<li>"
+               add text
+               if not children.is_empty then
+                       add "<ul class='nav'>"
+                       for entry in children do add entry
+                       add "</ul>"
+               end
+               add "</li>"
+       end
+end
+
+# Something that can go in a section
+# Sections are automatically collected to populate the menu
+class TplSectionElt
+       super Template
+
+       # HTML anchor id
+       var id: String
+
+       # Title to display if any
+       # if both `title` and `summary_title` are null then
+       # the section will not appear in the summary
+       var title: nullable Streamable writable
+
+       # Subtitle to display if any
+       var subtitle: nullable Streamable writable
+
+       # Title that appear in the summary
+       # if null use `title` instead
+       var summary_title: nullable String writable
+
+       # Parent section of this section if any
+       var parent: nullable TplSection
+
+       init(id: String) do self.id = id
+
+       init with_title(id: String, title: Streamable) do
+               init(id)
+               self.title = title
+       end
+
+       # Level <hX> for HTML heading
+       protected fun hlvl: Int do
+               if parent == null then return 1
+               return parent.hlvl + 1
+       end
+
+       # Render this section in the summary
+       protected fun render_summary(parent: TplSummaryElt) is abstract
+
+       # Is the section empty (no content at all)
+       fun is_empty: Bool is abstract
+end
+
+# A HTML <section> element
+class TplSection
+       super TplSectionElt
+
+       # Elements contained by this section
+       var children = new Array[TplSectionElt]
+
+       # Add an element in this section
+       fun add_child(child: TplSectionElt) do
+               child.parent = self
+               children.add child
+       end
+
+       redef fun is_empty: Bool do return children.is_empty
+
+       redef fun render_summary(parent) do
+               if is_empty then return
+               var title = summary_title
+               if title == null and self.title != null then title = self.title.write_to_string
+               if title == null then return
+               var lnk = new TplLink("#{id}", title)
+               var entry = new TplSummaryEntry(lnk)
+               for child in children do
+                       child.render_summary(entry)
+               end
+               parent.add_child entry
+       end
+
+       redef fun rendering do
+               if is_empty then return
+               add "<section id='{id}'>"
+               if title != null then
+                       var lvl = hlvl
+                       add "<h{lvl}>"
+                       add title.as(not null)
+                       add "</h{lvl}>"
+               end
+               if subtitle != null then
+                       add "<div class='info subtitle'>"
+                       add subtitle.as(not null)
+                       add "</div>"
+               end
+               for child in children do
+                       add child
+               end
+               add "</section>"
+       end
+end
+
+# A page article that can go in a section
+class TplArticle
+       super TplSectionElt
+
+       # Content for this article
+       var content: nullable Streamable writable = null
+
+       # CSS classes to apply on the article title heading element
+       var title_classes = new Array[String]
+
+       redef fun render_summary(parent) do
+               if is_empty then return
+               var title = summary_title
+               if title == null and self.title != null then title = self.title.write_to_string
+               if title == null then return
+               var lnk = new TplLink("#{id}", title)
+               parent.add_child new TplSummaryEntry(lnk)
+       end
+
+       redef fun rendering do
+               add "<article id='{id}'>"
+               if title != null then
+                       var lvl = hlvl
+                       add "<h{lvl} class='{title_classes.join(" ")}'>"
+                       add title.as(not null)
+                       add "</h{lvl}>"
+               end
+               if subtitle != null then
+                       add "<div class='info subtitle'>"
+                       add subtitle.as(not null)
+                       add "</div>"
+               end
+               if content != null then
+                       add content.as(not null)
+               end
+               add """</article>"""
+       end
+
+       redef fun is_empty: Bool do return content == null
+end
+
+# A module / class / prop definition
+class TplDefinition
+       super Template
+
+       # Comment to display
+       var comment: nullable Streamable writable
+
+       # Namespace for this definition
+       var namespace: Streamable writable
+
+       # Location link to display
+       var location: nullable Streamable writable
+
+       init do end
+
+       private fun render_info do
+               add "<div class='info text-right'>"
+               if comment == null then
+                       add "<span class=\"noComment\">no comment for </span>"
+               end
+               add namespace
+               if location != null then
+                       add " "
+                       add location.as(not null)
+               end
+               add "</div>"
+       end
+
+       private fun render_comment do
+               if comment != null then add comment.as(not null)
+       end
+
+       redef fun rendering do
+               add "<div class='definition'>"
+               render_comment
+               render_info
+               add "</div>"
+       end
+end
+
+# Class definition
+class TplClassDefinition
+       super TplDefinition
+
+       var intros = new Array[TplListElt]
+       var redefs = new Array[TplListElt]
+
+       init do end
+
+       redef fun rendering do
+               add "<div class='definition'>"
+               render_comment
+               render_info
+               render_list("Introduces", intros)
+               render_list("Redefines", redefs)
+               add "</div>"
+       end
+
+       private fun render_list(name: String, elts: Array[TplListElt]) do
+               if elts.is_empty then return
+               add "<h5>{name}</h5>"
+               add "<ul class='list-unstyled list-definition'>"
+               for elt in elts do add elt
+               add "</ul>"
+       end
+end
+
+# Layout for Search page
+class TplSearchPage
+       super TplSectionElt
+
+       var modules = new Array[Streamable]
+       var classes = new Array[Streamable]
+       var props = new Array[Streamable]
+
+       redef fun rendering do
+               if title != null then add "<h1>{title}</h1>"
+               add "<div class='container-fluid'>"
+               add " <div class='row'>"
+               if not modules.is_empty then
+                       add "<div class='col-xs-4'>"
+                       add "<h3>Modules</h3>"
+                       add "<ul>"
+                       for m in modules do
+                               add "<li>"
+                               add m
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</div>"
+               end
+               if not classes.is_empty then
+                       add "<div class='col-xs-4'>"
+                       add "<h3>Classes</h3>"
+                       add "<ul>"
+                       for c in classes do
+                               add "<li>"
+                               add c
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</div>"
+               end
+               if not props.is_empty then
+                       add "<div class='col-xs-4'>"
+                       add "<h3>Properties</h3>"
+                       add "<ul>"
+                       for p in props do
+                               add "<li>"
+                               add p
+                               add "</li>"
+                       end
+                       add "</ul>"
+                       add "</div>"
+               end
+               add " </div>"
+               add "</div>"
+       end
+end
+
+#####################
+# Basiv HTML elements
+#####################
+
+# A html link <a>
+class TplLink
+       super Template
+
+       # Link href
+       var href: String writable
+
+       # Text to display in the link
+       var text: String writable
+
+       # Optional title
+       var title: nullable String writable
+
+       init(href, text: String) do
+               self.href = href
+               self.text = text
+       end
+
+       init with_title(href, text, title: String) do
+               init(href, text)
+               self.title = title
+       end
+
+       redef fun rendering do
+               add "<a href=\""
+               add href
+               add "\""
+               if title != null then
+                       add " title=\""
+                       add title.as(not null)
+                       add "\""
+               end
+               add ">"
+               add text
+               add "</a>"
+       end
+end
+
+# A <ul> list
+class TplList
+       super TplListElt
+
+       # Elements contained in this list
+       # can be <li> or <ul> elements
+       var elts = new Array[TplListElt]
+
+       # CSS classes of the <ul> element
+       var css_classes = new Array[String]
+
+       # Add content wrapped in a <li> element
+       fun add_li(content: Streamable) do elts.add new TplListItem.with_content(content)
+
+       init do end
+
+       init with_classes(classes: Array[String]) do self.css_classes = classes
+
+       redef fun rendering do
+               if elts.is_empty then return
+               add "<ul class='{css_classes.join(" ")}'>"
+               for elt in elts do add elt
+               add "</ul>"
+       end
+end
+
+# Something that can be added to a TplList
+class TplListElt
+       super Template
+end
+
+# A list item <li>
+class TplListItem
+       super TplListElt
+
+       # Content of the list item
+       var content = new Template
+
+       # CSS classes of the <li> element
+       var css_classes = new Array[String]
+
+       init do end
+
+       init with_content(content: Streamable) do append(content)
+
+       init with_classes(content: Streamable, classes: Array[String]) do
+               with_content(content)
+               css_classes = classes
+       end
+
+       # Append `content` to the item
+       # similar to `self.content.add`
+       fun append(content: Streamable) do self.content.add content
+
+       redef fun rendering do
+               add "<li class='"
+               for cls in css_classes do add " {cls}"
+               add "'>"
+               add content
+               add "</li>"
+       end
+end
+
+# A label with a text content
+class TplLabel
+       super Template
+
+       # Content of the label if any
+       var content: nullable Streamable
+
+       # CSS classes of the <span> element
+       var css_classes = new Array[String]
+
+       init do end
+       init with_content(content: Streamable) do self.content = content
+       init with_classes(classes: Array[String]) do self.css_classes = classes
+
+       redef fun rendering do
+               add "<span class='label {css_classes.join(" ")}'>"
+               if content != null then add content.as(not null)
+               add "</span>"
+       end
+end
+
+# A label with an icon
+class TplIcon
+       super TplLabel
+
+       # Bootsrap icon name
+       # see: http://getbootstrap.com/components/#glyphicons
+       var icon: String
+
+       init with_icon(icon: String) do self.icon = icon
+
+       redef fun rendering do
+               add "<span class='glyphicon glyphicon-{icon} {css_classes.join(" ")}'>"
+               if content != null then add content.as(not null)
+               add "</span>"
+       end
+end
+
+# A HTML tag attribute
+#  `<tag attr="value">`
+class TagAttribute
+       super Template
+
+       var name: String
+       var value: nullable String
+
+       init(name: String, value: nullable String) do
+               self.name = name
+               self.value = value
+       end
+
+       redef fun rendering do
+               if value == null then
+                       add(" {name}")
+               else
+                       add(" {name}=\"{value}\"")
+               end
+       end
+end
+
+# Javacript template
+class TplScript
+       super Template
+
+       var attrs = new Array[TagAttribute]
+       var content: nullable Streamable writable
+
+       init do
+               attrs.add(new TagAttribute("type", "text/javascript"))
+       end
+
+       protected fun render_content do
+               if content != null then add content.as(not null)
+       end
+
+       redef fun rendering do
+               add "<script"
+               for attr in attrs do add attr
+               add ">"
+               render_content
+               add "</script>"
+       end
+end
+
+# JS script for Piwik Tracker
+class TplPiwikScript
+       super TplScript
+
+       var tracker_url: String
+       var site_id: String
+
+       init(tracker_url, site_id: String) do
+               super
+               self.tracker_url = tracker_url
+               self.site_id = site_id
+       end
+
+       redef fun render_content do
+               add "<!-- Piwik -->"
+               add "var _paq = _paq || [];"
+               add " _paq.push([\"trackPageView\"]);"
+               add " _paq.push([\"enableLinkTracking\"]);"
+               add "(function() \{"
+               add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
+               add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
+               add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
+               add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
+               add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
+               add "\})();"
+       end
+end
+