5194e08cc5d50882d5398633bc8b05f537ad0361
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`
17 module html_components
23 # A documentation page
28 var url
: String is writable, noinit
30 # Directory where css, js and other assets can be found
31 var shareurl
: String is writable, noinit
33 # Attributes of the body tag element
34 var body_attrs
= new Array[TagAttribute]
36 # Top menu template if any
37 var topmenu
: TplTopMenu is writable, noinit
39 # Sidebar template if any
40 var sidebar
: nullable TplSidebar = null is writable
42 # Content of the page in form a TplSection
43 var sections
= new Array[TplSection]
45 # Footer content if any
46 var footer
: nullable Writable = null is writable
48 # JS scripts to append at the end of the body
49 var scripts
= new Array[TplScript]
51 # Add a section to this page
52 fun add_section
(section
: TplSection) do
56 # Render the html header
57 private fun render_head
do
58 var css
= (self.shareurl
/ "css").html_escape
59 var vendors
= (self.shareurl
/ "vendors").html_escape
61 addn
"<!DOCTYPE html>"
63 addn
" <meta charset='utf-8'/>"
64 addn
" <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
65 addn
" <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
66 addn
" <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
67 addn
" <link rel='stylesheet' href='{css}/nitdoc.css'/>"
68 addn
" <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
69 addn
" <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
70 addn
" <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
71 addn
" <title>{title.html_escape}</title>"
74 for attr
in body_attrs
do add attr
78 # Render the topmenu template
79 private fun render_topmenu
do
80 addn
" <div class='row'>"
86 # Sidebar is automatically populated with a summary of all sections
88 if sidebar
== null then return
89 var summary
= new TplSummary.with_order
(0)
90 for section
in sections
do
91 section
.render_summary summary
93 sidebar
.boxes
.add summary
94 add sidebar
.as(not null)
96 # Render the footer and content
97 private fun render_content
do
98 for section
in sections
do add section
99 if footer
!= null then
100 addn
"<div class='well footer'>"
101 add footer
.as(not null)
107 private fun render_footer
do
108 var vendors
= (self.shareurl
/ "vendors").html_escape
109 var js
= (self.shareurl
/ "js").html_escape
111 addn
"<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
112 addn
"<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
113 addn
"<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
114 addn
"<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
115 for script
in scripts
do add script
118 $("[data-toggle='tooltip']").tooltip();
119 $("[data-toggle='popover']").popover();
126 # Render the whole page
127 redef fun rendering
do
129 addn
"<div class='container-fluid'>"
131 addn
" <div class='row' id='content'>"
132 if sidebar
!= null then
133 addn
"<div class='col col-xs-3 col-lg-2'>"
136 addn
"<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
140 addn
"<div class='col col-xs-12'>"
150 #########################
151 # general layout elements
152 #########################
154 # Top menu bar template
158 # Brand link to display in first position of the top menu
159 private var brand
: nullable Writable = null is writable
160 # Elements of the topmenu
161 private var elts
= new Array[Writable]
163 # The page url where the top menu is displayed.
165 # Used to select the active link.
166 private var current_url
: String
168 # Add a new link to the menu.
169 fun add_link
(content
: TplLink) do
170 var is_active
= content
.href
== current_url
171 add_item
(content
, is_active
)
174 # Add a content between `<li>` tags
175 fun add_item
(content
: Writable, is_active
: Bool) do
176 var tpl
= new Template
179 tpl
.add
" class='active'"
187 # Add a raw content to the menu
188 fun add_raw
(content
: Writable) do
192 redef fun rendering
do
193 if brand
== null and elts
.is_empty
then return
194 addn
"<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
195 addn
" <div class='container-fluid'>"
196 addn
" <div class='navbar-header'>"
197 add
" <button type='button' class='navbar-toggle' "
198 addn
" data-toggle='collapse' data-target='#topmenu-collapse'>"
199 addn
" <span class='sr-only'>Toggle menu</span>"
200 addn
" <span class='icon-bar'></span>"
201 addn
" <span class='icon-bar'></span>"
202 addn
" <span class='icon-bar'></span>"
204 if brand
!= null then add brand
.as(not null)
206 addn
" <div class='collapse navbar-collapse' id='topmenu-collapse'>"
207 if not elts
.is_empty
then
208 addn
"<ul class='nav navbar-nav'>"
209 for elt
in elts
do add elt
222 # Sidebar contains sidebar element templates called boxes
223 var boxes
= new Array[TplSidebarElt]
225 # Sort boxes by order priority
226 private fun order_boxes
do
227 var sorter
= new OrderComparator
231 redef fun rendering
do
232 if boxes
.is_empty
then return
234 addn
"<div id='sidebar'>"
235 for box
in boxes
do add box
240 # Comparator used to sort boxes by order
241 private class OrderComparator
244 redef type COMPARED: TplSidebarElt
246 redef fun compare
(a
, b
) do
247 if a
.order
< b
.order
then return -1
248 if a
.order
> b
.order
then return 1
253 # Something that can be put in the sidebar
257 # Order of the box in the sidebar
260 init with_order
(order
: Int) do self.order
= order
263 # Agenericbox that can be added to sidebar
267 # Title of the box to display
268 # Title is also a placeholder for the collapse link
272 # equals to `title.to_cmangle` by default
273 # Used for collapsing
274 var id
: String is noinit
276 # Content to display in the box
277 # box will not be rendered if the content is null
278 var content
: nullable Writable = null is writable
280 # Is the box opened by default
281 # otherwise, the user will have to clic on the title to display the content
282 var is_open
= false is writable
285 self.id
= title
.to_cmangle
288 init with_content
(title
: String, content
: Writable) do
290 self.content
= content
293 redef fun rendering
do
294 if content
== null then return
296 if is_open
then open
= "in"
297 addn
"<div class='panel'>"
298 addn
" <div class='panel-heading'>"
299 add
" <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
303 addn
" <div id='box_{id}' class='panel-body collapse {open}'>"
304 add content
.as(not null)
310 # Something that can go on a summary template
314 # Add an element to the summary
315 fun add_child
(child
: TplSummaryElt) is abstract
318 # A summary that can go on the sidebar
319 # If the page contains a sidebar, the summary is automatically placed
320 # on top of the sidebarauto-generated
321 # summary contains anchors to all sections displayed in the page
326 # Summary elements to display
327 var children
= new Array[TplSummaryElt]
329 redef fun add_child
(child
) do children
.add child
331 redef fun rendering
do
332 if children
.is_empty
then return
333 addn
"<div class='panel'>"
334 addn
" <div class='panel-heading'>"
335 add
" <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
339 addn
" <div id='box-sum' class='summary collapse in'>"
340 addn
" <ul class='nav'>"
341 for entry
in children
do add entry
349 class TplSummaryEntry
355 # Children of this entry
356 # Will be displayed as a tree
357 var children
= new Array[TplSummaryElt]
359 redef fun add_child
(child
) do children
.add child
361 redef fun rendering
do
364 if not children
.is_empty
then
365 addn
"\n<ul class='nav'>"
366 for entry
in children
do add entry
373 # Something that can go in a section
374 # Sections are automatically collected to populate the menu
381 # Title to display if any
382 # if both `title` and `summary_title` are null then
383 # the section will not appear in the summary
384 var title
: nullable Writable = null is writable
386 # Subtitle to display if any
387 var subtitle
: nullable Writable = null is writable
389 # Title that appear in the summary
390 # if null use `title` instead
391 var summary_title
: nullable String = null is writable
393 # CSS classes to apply on the section element
394 var css_classes
= new Array[String]
396 # CSS classes to apply on the title heading element
397 var title_classes
= new Array[String]
399 # Parent article/section if any
400 var parent
: nullable TplSectionElt = null
402 init with_title
(id
: String, title
: Writable) do
407 # Level <hX> for HTML heading
408 protected fun hlvl
: Int do
409 if parent
== null then return 1
410 return parent
.hlvl
+ 1
413 # Elements contained by this section
414 var children
= new Array[TplSectionElt]
416 # Add an element in this section
417 fun add_child
(child
: TplSectionElt) do
422 # Is the section empty (no content at all)
423 fun is_empty
: Bool do return children
.is_empty
425 # Render this section in the summary
426 fun render_summary
(parent
: TplSummaryElt) do
427 if is_empty
then return
428 var title
= summary_title
429 if title
== null and self.title
!= null then title
= self.title
.write_to_string
430 if title
== null then return
431 var lnk
= new TplLink("#{id}", title
)
432 var entry
= new TplSummaryEntry(lnk
)
433 for child
in children
do
434 child
.render_summary
(entry
)
436 parent
.add_child entry
440 # A HTML <section> element
444 redef fun rendering
do
445 addn
"<section id='{id}' class='{css_classes.join(" ")}'>"
446 if title
!= null then
448 if lvl
== 2 then title_classes
.add
"well well-sm"
449 addn
"<h{lvl} class='{title_classes.join(" ")}'>"
450 addn title
.as(not null)
453 if subtitle
!= null then
454 addn
"<div class='info subtitle'>"
455 addn subtitle
.as(not null)
458 for child
in children
do
465 # A page article that can go in a section
469 # Content for this article
470 var content
: nullable Writable = null is writable
471 var source_link
: nullable Writable = null is writable
473 init with_content
(id
: String, title
: Writable, content
: Writable) do
474 with_title
(id
, title
)
475 self.content
= content
478 redef fun render_summary
(parent
) do
479 if is_empty
then return
480 var title
= summary_title
481 if title
== null and self.title
!= null then title
= self.title
.write_to_string
482 if title
== null then return
483 var lnk
= new TplLink("#{id}", title
)
484 parent
.add_child
new TplSummaryEntry(lnk
)
487 redef fun rendering
do
488 if is_empty
then return
489 addn
"<article id='{id}' class='{css_classes.join(" ")}'>"
490 if source_link
!= null then
491 add
"<div class='source-link'>"
492 add source_link
.as(not null)
495 if title
!= null then
497 if lvl
== 2 then title_classes
.add
"well well-sm"
498 add
"<h{lvl} class='{title_classes.join(" ")}'>"
499 add title
.as(not null)
502 if subtitle
!= null then
503 add
"<div class='info subtitle'>"
504 add subtitle
.as(not null)
507 if content
!= null then
508 add content
.as(not null)
510 for child
in children
do
513 addn
"""</article>"""
516 redef fun is_empty
: Bool do
517 return title
== null and subtitle
== null and content
== null and children
.is_empty
521 # A module / class / prop definition
526 var comment
: nullable Writable = null is writable
528 # Namespace for this definition
529 var namespace
: nullable Writable = null is writable
531 # Location link to display
532 var location
: nullable Writable = null is writable
534 private fun render_info
do
535 addn
"<div class='info text-right'>"
536 if namespace
!= null then
537 if comment
== null then
538 add
"<span class=\"noComment\
">no comment for </span>"
540 add namespace
.as(not null)
542 if location
!= null then
544 add location
.as(not null)
549 private fun render_comment
do
550 if comment
!= null then add comment
.as(not null)
553 redef fun rendering
do
554 addn
"<div class='definition'>"
562 class TplClassDefinition
565 var intros
= new Array[TplListElt]
566 var redefs
= new Array[TplListElt]
568 redef fun rendering
do
569 addn
"<div class='definition'>"
572 render_list
("Introduces", intros
)
573 render_list
("Redefines", redefs
)
577 private fun render_list
(name
: String, elts
: Array[TplListElt]) do
578 if elts
.is_empty
then return
579 addn
"<h5>{name.html_escape}</h5>"
580 addn
"<ul class='list-unstyled list-definition'>"
581 for elt
in elts
do add elt
586 # Layout for Search page
590 var modules
= new Array[Writable]
591 var classes
= new Array[Writable]
592 var props
= new Array[Writable]
594 redef fun rendering
do
595 var title
= self.title
596 if title
!= null then addn
"<h1>{title.to_s.html_escape}</h1>"
597 addn
"<div class='container-fluid'>"
598 addn
" <div class='row'>"
599 if not modules
.is_empty
then
600 addn
"<div class='col-xs-4'>"
601 addn
"<h3>Modules</h3>"
611 if not classes
.is_empty
then
612 addn
"<div class='col-xs-4'>"
613 addn
"<h3>Classes</h3>"
623 if not props
.is_empty
then
624 addn
"<div class='col-xs-4'>"
625 addn
"<h3>Properties</h3>"
640 #####################
641 # Basiv HTML elements
642 #####################
649 var href
: String is writable
651 # The raw HTML content to display in the link
652 var text
: Writable is writable
654 # The unescaped optional title.
655 var title
: nullable String = null is writable
657 init with_title
(href
, text
, title
: String) do
662 redef fun rendering
do
666 if title
!= null then
668 add title.as(not null).html_escape
681 # Elements contained in this list
682 # can be <li> or <ul> elements
683 var elts
= new Array[TplListElt]
685 # CSS classes of the <ul> element
686 var css_classes
= new Array[String]
688 # Add content wrapped in a <li> element
689 fun add_li
(item
: TplListItem) do elts
.add item
691 init with_classes
(classes
: Array[String]) do self.css_classes
= classes
693 fun is_empty
: Bool do return elts
.is_empty
695 redef fun rendering
do
696 if elts
.is_empty
then return
697 addn
"<ul class='{css_classes.join(" ")}'>"
698 for elt
in elts
do add elt
703 # Something that can be added to a TplList
712 # Content of the list item
713 var content
= new Template
715 # CSS classes of the <li> element
716 var css_classes
= new Array[String]
718 init with_content
(content
: Writable) do append
(content
)
720 init with_classes
(content
: Writable, classes
: Array[String]) do
721 with_content
(content
)
722 css_classes
= classes
725 # Append `content` to the item
726 # similar to `self.content.add`
727 fun append
(content
: Writable) do self.content
.add content
729 redef fun rendering
do
730 add
"<li class='{css_classes.join(" ")}'>"
736 # A Bootstrap tab component that contains `TplTabPanel`.
740 # Panels contained in the tab.
741 var panels
= new Array[TplTabPanel]
744 fun add_panel
(panel
: TplTabPanel) do panels
.add panel
746 # CSS classes of the tab component.
747 var css_classes
= new Array[String]
749 redef fun rendering
do
750 addn
"<div class='tab-content'>"
751 for panel
in panels
do add panel
756 # A panel that goes in a `TplTab`.
760 # CSS classes of the pane element.
761 var css_classes
= new Array[String]
765 # Used to show/hide panel.
766 var id
: String is noinit
770 # Displayed in the tab header or in the pointing link.
773 # Is the panel visible by default?
774 var is_active
= false is writable
777 var content
: nullable Writable = null is writable
779 # Get a link pointing to this panel.
780 fun tpl_link_to
: Writable do
781 var lnk
= new Template
782 lnk
.add
"<a data-target='#{id}' data-toggle='pill'>"
788 redef fun rendering
do
789 add
"<div class='tab-pane {css_classes.join(" ")}"
790 if is_active
then add
"active"
792 if content
!= null then add content
.as(not null)
797 # A label with a text content
801 # Content of the label if any
802 var content
: nullable Writable = null is writable
804 # CSS classes of the <span> element
805 var css_classes
= new Array[String]
807 init with_content
(content
: Writable) do self.content
= content
808 init with_classes
(classes
: Array[String]) do self.css_classes
= classes
810 redef fun rendering
do
811 add
"<span class='label {css_classes.join(" ")}'>"
812 if content
!= null then add content
.as(not null)
817 # A label with an icon
822 # see: http://getbootstrap.com/components/#glyphicons
825 init with_icon
(icon
: String) do self.icon
= icon
827 redef fun rendering
do
828 add
"<span class='glyphicon glyphicon-{icon} {css_classes.join(" ")}'>"
829 if content
!= null then add content
.as(not null)
834 # A HTML tag attribute
835 # `<tag attr="value">`
838 # var attr: TagAttribute
840 # attr = new TagAttribute("foo", null)
841 # assert attr.write_to_string == " foo=\"\""
843 # attr = new TagAttribute("foo", "bar<>")
844 # assert attr.write_to_string == " foo=\"bar<>\""
850 var value
: nullable String
852 redef fun rendering
do
853 var value
= self.value
854 if value
== null then
855 # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
856 add
" {name.html_escape}=\"\
""
858 add
" {name.html_escape}=\"{value.html_escape}\
""
867 var attrs
= new Array[TagAttribute]
868 var content
: nullable Writable = null is writable
871 attrs
.add
(new TagAttribute("type", "text/javascript"))
874 protected fun render_content
do
875 if content
!= null then add content
.as(not null)
878 redef fun rendering
do
880 for attr
in attrs
do add attr
887 # JS script for Piwik Tracker
891 var tracker_url
: String
894 redef fun render_content
do
895 var site_id
= self.site_id
.to_json
896 var tracker_url
= self.tracker_url
.trim
897 if tracker_url
.chars
.last
!= '/' then tracker_url
+= "/"
898 tracker_url
= "://{tracker_url}".to_json
900 addn
"<!-- Piwik -->"
901 addn
"var _paq = _paq || [];"
902 addn
" _paq.push([\"trackPageView\
"]);"
903 addn
" _paq.push([\"enableLinkTracking\
"]);"
904 addn
"(function() \{"
905 addn
" var u=((\"https
:\
" == document.location.protocol) ? \"https\
" : \"http\
") + {tracker_url};"
906 addn
" _paq.push([\"setTrackerUrl\
", u+\"piwik
.php\
"]);"
907 addn
" _paq.push([\"setSiteId\
", {site_id}]);"
908 addn
" var d=document, g=d.createElement(\"script\
"), s=d.getElementsByTagName(\"script\
")[0]; g.type=\"text
/javascript\
";"
909 addn
" g.defer=true; g.async=true; g.src=u+\"piwik
.js\
"; s.parentNode.insertBefore(g,s);"