1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # HTML templates used by Nitdoc to generate API documentation
16 # Pages are assembled using `Template`
22 # A documentation page
26 # The unescaped page title to put in the HTML header.
27 var title
: String is writable, noinit
30 var url
: String is writable, noinit
32 # Directory where css, js and other assets can be found
33 var shareurl
: String is writable, noinit
35 # Attributes of the body tag element
36 var body_attrs
= new Array[TagAttribute]
38 # Top menu template if any
39 var topmenu
: TplTopMenu is writable, noinit
41 # Sidebar template if any
42 var sidebar
: nullable TplSidebar = null is writable
44 # Content of the page in form a TplSection
45 var sections
= new Array[TplSection]
47 # Footer content if any
48 var footer
: nullable Streamable = null is writable
50 # JS scripts to append at the end of the body
51 var scripts
= new Array[TplScript]
53 # Add a section to this page
54 fun add_section
(section
: TplSection) do
58 # Render the html header
59 private fun render_head
do
60 var css
= (self.shareurl
/ "css").html_escape
61 var vendors
= (self.shareurl
/ "vendors").html_escape
63 addn
"<!DOCTYPE html>"
65 addn
" <meta charset='utf-8'/>"
66 addn
" <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
67 addn
" <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
68 addn
" <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
69 addn
" <link rel='stylesheet' href='{css}/nitdoc.css'/>"
70 addn
" <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
71 addn
" <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
72 addn
" <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
73 addn
" <title>{title.html_escape}</title>"
76 for attr
in body_attrs
do add attr
80 # Render the topmenu template
81 private fun render_topmenu
do
82 addn
" <div class='row'>"
88 # Sidebar is automatically populated with a summary of all sections
90 if sidebar
== null then return
91 var summary
= new TplSummary.with_order
(0)
92 for section
in sections
do
93 section
.render_summary summary
95 sidebar
.boxes
.add summary
96 add sidebar
.as(not null)
98 # Render the footer and content
99 private fun render_content
do
100 for section
in sections
do add section
101 if footer
!= null then
102 addn
"<div class='well footer'>"
103 add footer
.as(not null)
109 private fun render_footer
do
110 var vendors
= (self.shareurl
/ "vendors").html_escape
111 var js
= (self.shareurl
/ "js").html_escape
113 addn
"<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
114 addn
"<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
115 addn
"<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
116 addn
"<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
117 for script
in scripts
do add script
120 $("[data-toggle='tooltip']").tooltip();
121 $("[data-toggle='popover']").popover();
128 # Render the whole page
129 redef fun rendering
do
131 addn
"<div class='container-fluid'>"
133 addn
" <div class='row' id='content'>"
134 if sidebar
!= null then
135 addn
"<div class='col col-xs-3 col-lg-2'>"
138 addn
"<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
142 addn
"<div class='col col-xs-12'>"
152 #########################
153 # general layout elements
154 #########################
156 # Top menu bar template
160 # Brand link to display in first position of the top menu
161 private var brand
: nullable Streamable = null is writable
162 # Elements of the topmenu
163 private var elts
= new Array[Streamable]
165 # The page url where the top menu is displayed.
167 # Used to select the active link.
168 private var current_url
: String
170 # Add a new link to the menu.
171 fun add_link
(content
: TplLink) do
172 var is_active
= content
.href
== current_url
173 add_item
(content
, is_active
)
176 # Add a content between `<li>` tags
177 fun add_item
(content
: Streamable, is_active
: Bool) do
178 var tpl
= new Template
181 tpl
.add
" class='active'"
189 # Add a raw content to the menu
190 fun add_raw
(content
: Streamable) do
194 redef fun rendering
do
195 if brand
== null and elts
.is_empty
then return
196 addn
"<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
197 addn
" <div class='container-fluid'>"
198 addn
" <div class='navbar-header'>"
199 add
" <button type='button' class='navbar-toggle' "
200 addn
" data-toggle='collapse' data-target='#topmenu-collapse'>"
201 addn
" <span class='sr-only'>Toggle menu</span>"
202 addn
" <span class='icon-bar'></span>"
203 addn
" <span class='icon-bar'></span>"
204 addn
" <span class='icon-bar'></span>"
206 if brand
!= null then add brand
.as(not null)
208 addn
" <div class='collapse navbar-collapse' id='topmenu-collapse'>"
209 if not elts
.is_empty
then
210 addn
"<ul class='nav navbar-nav'>"
211 for elt
in elts
do add elt
224 # Sidebar contains sidebar element templates called boxes
225 var boxes
= new Array[TplSidebarElt]
227 # Sort boxes by order priority
228 private fun order_boxes
do
229 var sorter
= new OrderComparator
233 redef fun rendering
do
234 if boxes
.is_empty
then return
236 addn
"<div id='sidebar'>"
237 for box
in boxes
do add box
242 # Comparator used to sort boxes by order
243 private class OrderComparator
246 redef type COMPARED: TplSidebarElt
248 redef fun compare
(a
, b
) do
249 if a
.order
< b
.order
then return -1
250 if a
.order
> b
.order
then return 1
255 # Something that can be put in the sidebar
259 # Order of the box in the sidebar
262 init with_order
(order
: Int) do self.order
= order
265 # Agenericbox that can be added to sidebar
269 # Title of the box to display
270 # Title is also a placeholder for the collapse link
274 # equals to `title.to_cmangle` by default
275 # Used for collapsing
276 var id
: String is noinit
278 # Content to display in the box
279 # box will not be rendered if the content is null
280 var content
: nullable Streamable = null is writable
282 # Is the box opened by default
283 # otherwise, the user will have to clic on the title to display the content
284 var is_open
= false is writable
287 self.id
= title
.to_cmangle
290 init with_content
(title
: String, content
: Streamable) do
292 self.content
= content
295 redef fun rendering
do
296 if content
== null then return
298 if is_open
then open
= "in"
299 addn
"<div class='panel'>"
300 addn
" <div class='panel-heading'>"
301 add
" <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
305 addn
" <div id='box_{id}' class='panel-body collapse {open}'>"
306 add content
.as(not null)
312 # Something that can go on a summary template
316 # Add an element to the summary
317 fun add_child
(child
: TplSummaryElt) is abstract
320 # A summary that can go on the sidebar
321 # If the page contains a sidebar, the summary is automatically placed
322 # on top of the sidebarauto-generated
323 # summary contains anchors to all sections displayed in the page
328 # Summary elements to display
329 var children
= new Array[TplSummaryElt]
331 redef fun add_child
(child
) do children
.add child
333 redef fun rendering
do
334 if children
.is_empty
then return
335 addn
"<div class='panel'>"
336 addn
" <div class='panel-heading'>"
337 add
" <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
341 addn
" <div id='box-sum' class='summary collapse in'>"
342 addn
" <ul class='nav'>"
343 for entry
in children
do add entry
351 class TplSummaryEntry
357 # Children of this entry
358 # Will be displayed as a tree
359 var children
= new Array[TplSummaryElt]
361 redef fun add_child
(child
) do children
.add child
363 redef fun rendering
do
366 if not children
.is_empty
then
367 addn
"\n<ul class='nav'>"
368 for entry
in children
do add entry
375 # Something that can go in a section
376 # Sections are automatically collected to populate the menu
383 # Title to display if any
384 # if both `title` and `summary_title` are null then
385 # the section will not appear in the summary
386 var title
: nullable Streamable = null is writable
388 # Subtitle to display if any
389 var subtitle
: nullable Streamable = null is writable
391 # Title that appear in the summary
392 # if null use `title` instead
393 var summary_title
: nullable String = null is writable
395 # CSS classes to apply on the section element
396 var css_classes
= new Array[String]
398 # CSS classes to apply on the title heading element
399 var title_classes
= new Array[String]
401 # Parent article/section if any
402 var parent
: nullable TplSectionElt = null
404 init with_title
(id
: String, title
: Streamable) do
409 # Level <hX> for HTML heading
410 protected fun hlvl
: Int do
411 if parent
== null then return 1
412 return parent
.hlvl
+ 1
415 # Elements contained by this section
416 var children
= new Array[TplSectionElt]
418 # Add an element in this section
419 fun add_child
(child
: TplSectionElt) do
424 # Is the section empty (no content at all)
425 fun is_empty
: Bool do return children
.is_empty
427 # Render this section in the summary
428 fun render_summary
(parent
: TplSummaryElt) do
429 if is_empty
then return
430 var title
= summary_title
431 if title
== null and self.title
!= null then title
= self.title
.write_to_string
432 if title
== null then return
433 var lnk
= new TplLink("#{id}", title
)
434 var entry
= new TplSummaryEntry(lnk
)
435 for child
in children
do
436 child
.render_summary
(entry
)
438 parent
.add_child entry
442 # A HTML <section> element
446 redef fun rendering
do
447 addn
"<section id='{id}' class='{css_classes.join(" ")}'>"
448 if title
!= null then
450 if lvl
== 2 then title_classes
.add
"well well-sm"
451 addn
"<h{lvl} class='{title_classes.join(" ")}'>"
452 addn title
.as(not null)
455 if subtitle
!= null then
456 addn
"<div class='info subtitle'>"
457 addn subtitle
.as(not null)
460 for child
in children
do
467 # A page article that can go in a section
471 # Content for this article
472 var content
: nullable Streamable = null is writable
473 var source_link
: nullable Streamable = null is writable
475 init with_content
(id
: String, title
: Streamable, content
: Streamable) do
476 with_title
(id
, title
)
477 self.content
= content
480 redef fun render_summary
(parent
) do
481 if is_empty
then return
482 var title
= summary_title
483 if title
== null and self.title
!= null then title
= self.title
.write_to_string
484 if title
== null then return
485 var lnk
= new TplLink("#{id}", title
)
486 parent
.add_child
new TplSummaryEntry(lnk
)
489 redef fun rendering
do
490 if is_empty
then return
491 addn
"<article id='{id}' class='{css_classes.join(" ")}'>"
492 if source_link
!= null then
493 add
"<div class='source-link'>"
494 add source_link
.as(not null)
497 if title
!= null then
499 if lvl
== 2 then title_classes
.add
"well well-sm"
500 add
"<h{lvl} class='{title_classes.join(" ")}'>"
501 add title
.as(not null)
504 if subtitle
!= null then
505 add
"<div class='info subtitle'>"
506 add subtitle
.as(not null)
509 if content
!= null then
510 add content
.as(not null)
512 for child
in children
do
515 addn
"""</article>"""
518 redef fun is_empty
: Bool do
519 return title
== null and subtitle
== null and content
== null and children
.is_empty
523 # A module / class / prop definition
528 var comment
: nullable Streamable = null is writable
530 # Namespace for this definition
531 var namespace
: nullable Streamable = null is writable
533 # Location link to display
534 var location
: nullable Streamable = null is writable
536 private fun render_info
do
537 addn
"<div class='info text-right'>"
538 if namespace
!= null then
539 if comment
== null then
540 add
"<span class=\"noComment\
">no comment for </span>"
542 add namespace
.as(not null)
544 if location
!= null then
546 add location
.as(not null)
551 private fun render_comment
do
552 if comment
!= null then add comment
.as(not null)
555 redef fun rendering
do
556 addn
"<div class='definition'>"
564 class TplClassDefinition
567 var intros
= new Array[TplListElt]
568 var redefs
= new Array[TplListElt]
570 redef fun rendering
do
571 addn
"<div class='definition'>"
574 render_list
("Introduces", intros
)
575 render_list
("Redefines", redefs
)
579 private fun render_list
(name
: String, elts
: Array[TplListElt]) do
580 if elts
.is_empty
then return
581 addn
"<h5>{name.html_escape}</h5>"
582 addn
"<ul class='list-unstyled list-definition'>"
583 for elt
in elts
do add elt
588 # Layout for Search page
592 var modules
= new Array[Streamable]
593 var classes
= new Array[Streamable]
594 var props
= new Array[Streamable]
596 redef fun rendering
do
597 var title
= self.title
598 if title
!= null then addn
"<h1>{title.to_s.html_escape}</h1>"
599 addn
"<div class='container-fluid'>"
600 addn
" <div class='row'>"
601 if not modules
.is_empty
then
602 addn
"<div class='col-xs-4'>"
603 addn
"<h3>Modules</h3>"
613 if not classes
.is_empty
then
614 addn
"<div class='col-xs-4'>"
615 addn
"<h3>Classes</h3>"
625 if not props
.is_empty
then
626 addn
"<div class='col-xs-4'>"
627 addn
"<h3>Properties</h3>"
642 #####################
643 # Basiv HTML elements
644 #####################
651 var href
: String is writable
653 # The raw HTML content to display in the link
654 var text
: Streamable is writable
656 # The unescaped optional title.
657 var title
: nullable String = null is writable
659 init with_title
(href
, text
, title
: String) do
664 redef fun rendering
do
668 if title
!= null then
670 add title.as(not null).html_escape
683 # Elements contained in this list
684 # can be <li> or <ul> elements
685 var elts
= new Array[TplListElt]
687 # CSS classes of the <ul> element
688 var css_classes
= new Array[String]
690 # Add content wrapped in a <li> element
691 fun add_li
(item
: TplListItem) do elts
.add item
693 init with_classes
(classes
: Array[String]) do self.css_classes
= classes
695 fun is_empty
: Bool do return elts
.is_empty
697 redef fun rendering
do
698 if elts
.is_empty
then return
699 addn
"<ul class='{css_classes.join(" ")}'>"
700 for elt
in elts
do add elt
705 # Something that can be added to a TplList
714 # Content of the list item
715 var content
= new Template
717 # CSS classes of the <li> element
718 var css_classes
= new Array[String]
720 init with_content
(content
: Streamable) do append
(content
)
722 init with_classes
(content
: Streamable, classes
: Array[String]) do
723 with_content
(content
)
724 css_classes
= classes
727 # Append `content` to the item
728 # similar to `self.content.add`
729 fun append
(content
: Streamable) do self.content
.add content
731 redef fun rendering
do
732 add
"<li class='{css_classes.join(" ")}'>"
738 # A Bootstrap tab component that contains `TplTabPanel`.
742 # Panels contained in the tab.
743 var panels
= new Array[TplTabPanel]
746 fun add_panel
(panel
: TplTabPanel) do panels
.add panel
748 # CSS classes of the tab component.
749 var css_classes
= new Array[String]
751 redef fun rendering
do
752 addn
"<div class='tab-content'>"
753 for panel
in panels
do add panel
758 # A panel that goes in a `TplTab`.
762 # CSS classes of the pane element.
763 var css_classes
= new Array[String]
767 # Used to show/hide panel.
768 var id
: String is noinit
772 # Displayed in the tab header or in the pointing link.
775 # Is the panel visible by default?
776 var is_active
= false is writable
779 var content
: nullable Streamable = null is writable
781 # Get a link pointing to this panel.
782 fun tpl_link_to
: Streamable do
783 var lnk
= new Template
784 lnk
.add
"<a data-target='#{id}' data-toggle='pill'>"
790 redef fun rendering
do
791 add
"<div class='tab-pane {css_classes.join(" ")}"
792 if is_active
then add
"active"
794 if content
!= null then add content
.as(not null)
799 # A label with a text content
803 # Content of the label if any
804 var content
: nullable Streamable = null is writable
806 # CSS classes of the <span> element
807 var css_classes
= new Array[String]
809 init with_content
(content
: Streamable) do self.content
= content
810 init with_classes
(classes
: Array[String]) do self.css_classes
= classes
812 redef fun rendering
do
813 add
"<span class='label {css_classes.join(" ")}'>"
814 if content
!= null then add content
.as(not null)
819 # A label with an icon
824 # see: http://getbootstrap.com/components/#glyphicons
827 init with_icon
(icon
: String) do self.icon
= icon
829 redef fun rendering
do
830 add
"<span class='glyphicon glyphicon-{icon} {css_classes.join(" ")}'>"
831 if content
!= null then add content
.as(not null)
836 # A HTML tag attribute
837 # `<tag attr="value">`
840 # var attr: TagAttribute
842 # attr = new TagAttribute("foo", null)
843 # assert attr.write_to_string == " foo=\"\""
845 # attr = new TagAttribute("foo", "bar<>")
846 # assert attr.write_to_string == " foo=\"bar<>\""
852 var value
: nullable String
854 redef fun rendering
do
855 var value
= self.value
856 if value
== null then
857 # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
858 add
" {name.html_escape}=\"\
""
860 add
" {name.html_escape}=\"{value.html_escape}\
""
869 var attrs
= new Array[TagAttribute]
870 var content
: nullable Streamable = null is writable
873 attrs
.add
(new TagAttribute("type", "text/javascript"))
876 protected fun render_content
do
877 if content
!= null then add content
.as(not null)
880 redef fun rendering
do
882 for attr
in attrs
do add attr
889 # JS script for Piwik Tracker
893 var tracker_url
: String
896 redef fun render_content
do
897 var site_id
= self.site_id
.to_json
898 var tracker_url
= self.tracker_url
.trim
899 if tracker_url
.chars
.last
!= '/' then tracker_url
+= "/"
900 tracker_url
= "://{tracker_url}".to_json
902 addn
"<!-- Piwik -->"
903 addn
"var _paq = _paq || [];"
904 addn
" _paq.push([\"trackPageView\
"]);"
905 addn
" _paq.push([\"enableLinkTracking\
"]);"
906 addn
"(function() \{"
907 addn
" var u=((\"https
:\
" == document.location.protocol) ? \"https\
" : \"http\
") + {tracker_url};"
908 addn
" _paq.push([\"setTrackerUrl\
", u+\"piwik
.php\
"]);"
909 addn
" _paq.push([\"setSiteId\
", {site_id}]);"
910 addn
" var d=document, g=d.createElement(\"script\
"), s=d.getElementsByTagName(\"script\
")[0]; g.type=\"text
/javascript\
";"
911 addn
" g.defer=true; g.async=true; g.src=u+\"piwik
.js\
"; s.parentNode.insertBefore(g,s);"