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 # Introduces templates that compose the documentation HTML rendering.
19 import html
::bootstrap
20 import doc_phases
::doc_structure
21 import doc_phases
::doc_hierarchies
22 import doc_phases
::doc_graphs
23 import doc_phases
::doc_intros_redefs
24 import doc_phases
::doc_lin
25 import doc_phases
::doc_readme
26 intrude import doc_down
28 # Renders the page as HTML.
33 var html_url
: String is writable, noinit
35 # Directory where css, js and other assets can be found.
36 var shareurl
: String is writable, noinit
38 # Attributes of the body tag element.
39 var body_attrs
= new Array[TagAttribute]
41 # Top menu template if any.
42 var topmenu
: DocTopMenu is writable, noinit
44 # Sidebar template if any.
45 var sidebar
: nullable DocSideBar = null is writable
47 # Footer content if any.
48 var footer
: nullable Writable = null is writable
50 # JS scripts to append at the end of the body
51 var scripts
= new Array[TplScript]
53 # Renders the html `<head>`.
54 private fun render_head
do
55 var css
= (self.shareurl
/ "css").html_escape
56 var vendors
= (self.shareurl
/ "vendors").html_escape
58 addn
"<!DOCTYPE html>"
60 addn
" <meta charset='utf-8'/>"
61 addn
" <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
62 addn
" <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
63 addn
" <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
64 addn
" <link rel='stylesheet' href='{css}/nitdoc.css'/>"
65 addn
" <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
66 addn
" <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
67 addn
" <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
68 addn
" <title>{title.html_escape}</title>"
71 for attr
in body_attrs
do add attr
75 # Renders the footer and content.
76 private fun render_content
do
78 if footer
!= null then
79 addn
"<div class='well footer'>"
80 add footer
.as(not null)
86 private fun render_footer
do
87 var vendors
= (self.shareurl
/ "vendors").html_escape
88 var js
= (self.shareurl
/ "js").html_escape
90 addn
"<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
91 addn
"<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
92 addn
"<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
93 addn
"<script src='{js}/lib/utils.js'></script>"
94 addn
"<script src='{js}/plugins/filtering.js'></script>"
95 addn
"<script src='quicksearch-list.js'></script>"
96 addn
"<script src='{js}/plugins/quicksearch.js'></script>"
97 for script
in scripts
do add script
100 $("[data-toggle='tooltip']").tooltip();
101 $("[data-toggle='popover']").popover();
108 # Render the whole page
109 redef fun rendering
do
111 addn
"<div class='container-fluid'>"
112 addn
" <div class='row'>"
115 addn
" <div class='row' id='content'>"
116 var sidebar
= self.sidebar
117 if sidebar
!= null then
118 addn
"<div class='col col-xs-3 col-lg-2'>"
121 addn
"<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
125 addn
"<div class='col col-xs-12'>"
134 # Render table of content for this page.
135 fun html_toc
: UnorderedList do
136 var lst
= new UnorderedList
137 lst
.css_classes
.add
"nav"
138 for child
in root
.children
do
139 child
.render_toc_item
(lst
)
145 # Top menu bar template.
147 # FIXME should be a Bootstrap component template
148 # At this moment, the topmenu structure stills to specific to Nitdoc to use the
153 # Brand link to display in first position of the top menu.
155 # This is where you want to put your logo.
156 var brand
: nullable Writable is noinit
, writable
160 # Depends on the current page, this allows to hilighted the current item.
162 # FIXME should be using Boostrap breadcrumbs component.
163 # This will still like this to avoid diff and be changed in further fixes
164 # when we will modify the output.
165 var active_item
: nullable ListItem is noinit
, writable
167 redef fun rendering
do
168 addn
"<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
169 addn
" <div class='container-fluid'>"
170 addn
" <div class='navbar-header'>"
171 add
" <button type='button' class='navbar-toggle' "
172 addn
" data-toggle='collapse' data-target='#topmenu-collapse'>"
173 addn
" <span class='sr-only'>Toggle menu</span>"
174 addn
" <span class='icon-bar'></span>"
175 addn
" <span class='icon-bar'></span>"
176 addn
" <span class='icon-bar'></span>"
178 if brand
!= null then
179 add
"<span class='navbar-brand'>"
180 add brand
.write_to_string
184 addn
" <div class='collapse navbar-collapse' id='topmenu-collapse'>"
185 addn
" <ul class='nav navbar-nav'>"
187 if item
== active_item
then item
.css_classes
.add
"active"
188 add item
.write_to_string
197 # Nitdoc sidebar template.
201 # Sidebar contains `DocSideBox`.
202 var boxes
= new Array[DocSideBox]
204 redef fun rendering
do
205 if boxes
.is_empty
then return
206 addn
"<div id='sidebar'>"
207 for box
in boxes
do add box
212 # Something that can be put in a DocSideBar.
216 # Box HTML id, used for Bootstrap collapsing feature.
218 # Use `html_title.to_cmangle` by default.
219 var id
: String is lazy
do return title
.write_to_string
.to_cmangle
221 # Title of the box to display.
224 # Content to display in the box.
225 var content
: Writable
227 # Is the box opened by default?
229 # Otherwise, the user will have to clic on the title to display the content.
232 var is_open
= true is writable
234 redef fun rendering
do
236 if is_open
then open
= "in"
237 addn
"<div class='panel'>"
238 addn
" <div class='panel-heading'>"
239 add
" <a data-toggle='collapse' data-parent='#sidebar'"
240 add
" data-target='#box_{id}' href='#'>"
244 addn
" <div id='box_{id}' class='summary panel-body collapse {open}'>"
251 redef class DocComposite
255 var html_id
: String is writable, lazy
do return id
257 # Title to display if any.
259 # This title can be decorated with HTML.
260 var html_title
: nullable Writable is writable, lazy
do return title
262 # Subtitle to display if any.
263 var html_subtitle
: nullable Writable is noinit
, writable
265 # Render the element title and subtitle.
266 private fun render_title
do
267 if html_title
!= null then
268 var header
= new Header(hlvl
, html_title
.write_to_string
)
269 header
.css_classes
.add
"signature"
272 if html_subtitle
!= null then
273 addn
"<div class='info subtitle'>"
274 addn html_subtitle
.write_to_string
279 # Render the element body.
280 private fun render_body
do
281 for child
in children
do addn child
.write_to_string
284 redef fun rendering
do
285 if is_hidden
then return
290 # Level <hX> for HTML heading.
291 private fun hlvl
: Int do return depth
293 # A short, undecorated title that goes in the table of contents.
295 # By default, returns `html_title.to_s`, subclasses should redefine it.
296 var html_toc_title
: nullable String is lazy
, writable do
297 if html_title
== null then return toc_title
298 return html_title
.write_to_string
301 # Render this element in a table of contents.
302 private fun render_toc_item
(lst
: UnorderedList) do
303 if is_toc_hidden
or html_toc_title
== null then return
305 var content
= new Template
306 content
.add
new Link("#{html_id}", html_toc_title
.to_s
)
307 if not children
.is_empty
then
308 var sublst
= new UnorderedList
309 sublst
.css_classes
.add
"nav"
310 for child
in children
do
311 child
.render_toc_item
(sublst
)
315 lst
.add_li
new ListItem(content
)
318 # ID used in HTML tab labels.
320 # We sanitize it for Boostrap JS panels that do not like ":" and "." in ids.
321 var html_tab_id
: String is lazy
do
322 var id
= html_id
.replace
(":", "")
323 id
= id
.replace
(".", "")
329 redef fun rendering
do
330 for child
in children
do addn child
.write_to_string
334 redef class DocSection
337 redef fun css_classes
do return new Array[String]
339 redef fun rendering
do
341 addn
"<a id=\"{html_id}\
"></a>"
344 addn
"<section{render_css_classes} id=\"{html_id}\
">"
351 redef class DocArticle
354 redef fun css_classes
do return new Array[String]
356 redef fun rendering
do
357 if is_hidden
then return
358 addn
"<article{render_css_classes} id=\"{html_id}\
">"
365 redef class TabbedGroup
366 redef fun render_body
do
367 var tabs
= new DocTabs("{html_id}.tabs", "")
368 for child
in children
do
369 if child
.is_hidden
then continue
370 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
371 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
377 redef class PanelGroup
378 redef var html_title
= null
379 redef var toc_title
is lazy
do return title
or else ""
380 redef var is_toc_hidden
= true
383 redef class HomeArticle
384 redef var html_title
= "Overview"
386 # HTML content to display on the home page.
388 # This attribute is set by the `doc_render` phase who knows the context.
389 var content
: nullable String is noinit
, writable
391 redef fun render_body
do
392 var content
= self.content
393 if content
!= null then add content
398 redef class IndexArticle
399 redef var html_title
= "Index"
401 redef fun render_body
do
402 addn
"<div class='container-fluid'>"
403 addn
" <div class='row'>"
404 render_list
("Modules", mmodules
)
405 render_list
("Classes", mclasses
)
406 render_list
("Properties", mprops
)
411 # Displays a list from the content of `mentities`.
412 private fun render_list
(title
: String, mentities
: Array[MEntity]) do
413 if mentities
.is_empty
then return
414 addn
"<div class='col-xs-4'>"
415 addn
new Header(3, title
)
416 var lst
= new UnorderedList
417 for mentity
in mentities
do
418 if mentity
isa MProperty then
419 var tpl
= new Template
420 tpl
.add mentity
.intro
.html_link
422 tpl
.add mentity
.intro
.mclassdef
.mclass
.html_link
424 lst
.add_li
new ListItem(tpl
)
426 lst
.add_li
new ListItem(mentity
.html_link
)
434 redef class MEntityComposite
435 redef var html_title
is lazy
do return mentity
.nitdoc_name
438 redef class MEntitySection
439 redef var html_title
is lazy
do return mentity
.html_name
440 redef var html_subtitle
is lazy
do return mentity
.html_declaration
443 redef class ConcernSection
444 redef var html_title
is lazy
do return "in {mentity.nitdoc_name}"
447 redef class IntroArticle
448 redef var html_title
= null
450 # Link to source to display if any.
451 var html_source_link
: nullable Writable is noinit
, writable
453 redef fun render_body
do
454 var tabs
= new DocTabs("{html_id}.tabs", "")
455 var comment
= mentity
.html_documentation
456 if mentity
isa MPackage then
457 comment
= mentity
.html_synopsis
459 if comment
!= null then
460 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
462 for child
in children
do
463 if child
.is_hidden
then continue
464 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
465 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
467 var lnk
= html_source_link
469 tabs
.drop_list
.items
.add
new ListItem(lnk
)
475 redef class ConcernsArticle
476 redef var html_title
= "Concerns"
477 redef fun render_body
do add concerns
.html_list
480 redef class DefinitionListArticle
481 redef var html_title
is lazy
do
482 var title
= new Template
483 title
.add mentity
.html_icon
484 title
.add mentity
.html_link
488 redef var html_subtitle
is lazy
do return mentity
.html_namespace
489 redef var html_toc_title
is lazy
do return mentity
.html_name
492 redef class DefinitionArticle
493 redef var html_title
is lazy
do return mentity
.html_name
494 redef var html_subtitle
is lazy
do return mentity
.html_declaration
496 # Does `self` display only it's title and no body?
499 var is_no_body
: Bool = false is writable
501 # Does `self` display only the short content as definition?
504 var is_short_comment
: Bool = false is writable
506 # Link to source to display if any.
507 var html_source_link
: nullable Writable is noinit
, writable
509 redef fun render_body
do
510 var tabs
= new DocTabs("{html_id}.tabs", "")
511 if not is_no_body
then
513 if is_short_comment
or mentity
isa MPackage then
514 comment
= mentity
.html_synopsis
516 comment
= mentity
.html_documentation
518 if comment
!= null then
519 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
522 for child
in children
do
523 if child
.is_hidden
then continue
524 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
525 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
527 var lnk
= html_source_link
529 tabs
.drop_list
.items
.add
new ListItem(lnk
)
535 redef class MEntitiesListArticle
536 redef fun render_body
do
537 var lst
= new UnorderedList
538 lst
.css_classes
.add
"list-unstyled list-definition"
539 for mentity
in mentities
do
540 lst
.add_li mentity
.html_list_item
546 redef class DefinitionLinArticle
547 redef fun render_body
do
548 var lst
= new UnorderedList
549 lst
.css_classes
.add
"list-unstyled list-labeled"
550 for mentity
in mentities
do
551 if not mentity
isa MPropDef then continue # TODO handle all mentities
552 var tpl
= new Template
553 tpl
.add mentity
.mclassdef
.html_namespace
554 var comment
= mentity
.mclassdef
.html_synopsis
555 if comment
!= null then
559 var li
= new ListItem(tpl
)
560 li
.css_classes
.add
"signature"
567 redef class GraphArticle
568 redef var html_title
= null
570 # Graph in SVG with clickable map.
572 # This attribute is set by the `doc_render` phase who knows the context.
573 var svg
: nullable String = null is writable
575 redef fun render_body
do
576 addn
"<div class=\"text-center\
">"
578 if svg
!= null then add svg
583 redef class ReadmeSection
584 redef var html_id
is lazy
do
585 return markdown_processor
.decorator
.strip_id
(html_title
.as(not null).to_s
)
588 redef var html_title
is lazy
do
589 return markdown_processor
.process
(title
.as(not null))
593 redef class ReadmeArticle
594 redef var html_id
= ""
595 redef var html_title
= null
596 redef var is_toc_hidden
= true
598 redef fun render_body
do
599 add markdown_processor
.process
(md
.trim
.write_to_string
)
603 redef class DocumentationArticle
604 redef var html_title
is lazy
do
605 var synopsis
= mentity
.html_synopsis
606 if synopsis
== null then return mentity
.html_link
607 return "{mentity.html_link.write_to_string} – {synopsis.write_to_string}"
610 redef var html_subtitle
is lazy
do return null
611 redef var html_toc_title
is lazy
do return mentity
.html_name
612 redef var is_toc_hidden
is lazy
do return depth
> 3
614 redef fun render_body
do
615 var tabs
= new DocTabs("{html_id}.tabs", "")
616 var comment
= mentity
.html_comment
617 if comment
!= null then
618 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
620 for child
in children
do
621 if child
.is_hidden
then continue
622 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
623 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)