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 rendering
do
339 addn
"<a id=\"{html_id}\
"></a>"
342 addn
"<section{render_css_classes} id=\"{html_id}\
">"
349 redef class DocArticle
352 redef fun rendering
do
353 if is_hidden
then return
354 addn
"<article{render_css_classes} id=\"{html_id}\
">"
361 redef class TabbedGroup
362 redef fun render_body
do
363 var tabs
= new DocTabs("{html_id}.tabs", "")
364 for child
in children
do
365 if child
.is_hidden
then continue
366 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
367 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
373 redef class PanelGroup
374 redef var html_title
= null
375 redef var toc_title
is lazy
do return title
or else ""
376 redef var is_toc_hidden
= true
379 redef class HomeArticle
380 redef var html_title
= "Overview"
382 # HTML content to display on the home page.
384 # This attribute is set by the `doc_render` phase who knows the context.
385 var content
: nullable String is noinit
, writable
387 redef fun render_body
do
388 var content
= self.content
389 if content
!= null then add content
394 redef class IndexArticle
395 redef var html_title
= "Index"
397 redef fun render_body
do
398 addn
"<div class='container-fluid'>"
399 addn
" <div class='row'>"
400 render_list
("Modules", mmodules
)
401 render_list
("Classes", mclasses
)
402 render_list
("Properties", mprops
)
407 # Displays a list from the content of `mentities`.
408 private fun render_list
(title
: String, mentities
: Array[MEntity]) do
409 if mentities
.is_empty
then return
410 addn
"<div class='col-xs-4'>"
411 addn
new Header(3, title
)
412 var lst
= new UnorderedList
413 for mentity
in mentities
do
414 if mentity
isa MProperty then
415 var tpl
= new Template
416 tpl
.add mentity
.intro
.html_link
418 tpl
.add mentity
.intro
.mclassdef
.mclass
.html_link
420 lst
.add_li
new ListItem(tpl
)
422 lst
.add_li
new ListItem(mentity
.html_link
)
430 redef class MEntityComposite
431 redef var html_title
is lazy
do return mentity
.nitdoc_name
434 redef class MEntitySection
435 redef var html_title
is lazy
do return mentity
.html_name
436 redef var html_subtitle
is lazy
do return mentity
.html_declaration
439 redef class ConcernSection
440 redef var html_title
is lazy
do return "in {mentity.nitdoc_name}"
443 redef class IntroArticle
444 redef var html_title
= null
446 # Link to source to display if any.
447 var html_source_link
: nullable Writable is noinit
, writable
449 redef fun render_body
do
450 var tabs
= new DocTabs("{html_id}.tabs", "")
451 var comment
= mentity
.html_documentation
452 if mentity
isa MPackage then
453 comment
= mentity
.html_synopsis
455 if comment
!= null then
456 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
458 for child
in children
do
459 if child
.is_hidden
then continue
460 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
461 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
463 var lnk
= html_source_link
465 tabs
.drop_list
.items
.add
new ListItem(lnk
)
471 redef class ConcernsArticle
472 redef var html_title
= "Concerns"
473 redef fun render_body
do add concerns
.html_list
476 redef class DefinitionListArticle
477 redef var html_title
is lazy
do
478 var title
= new Template
479 title
.add mentity
.html_icon
480 title
.add mentity
.html_link
484 redef var html_subtitle
is lazy
do return mentity
.html_namespace
485 redef var html_toc_title
is lazy
do return mentity
.html_name
488 redef class DefinitionArticle
489 redef var html_title
is lazy
do return mentity
.html_name
490 redef var html_subtitle
is lazy
do return mentity
.html_declaration
492 # Does `self` display only it's title and no body?
495 var is_no_body
: Bool = false is writable
497 # Does `self` display only the short content as definition?
500 var is_short_comment
: Bool = false is writable
502 # Link to source to display if any.
503 var html_source_link
: nullable Writable is noinit
, writable
505 redef fun render_body
do
506 var tabs
= new DocTabs("{html_id}.tabs", "")
507 if not is_no_body
then
509 if is_short_comment
or mentity
isa MPackage then
510 comment
= mentity
.html_synopsis
512 comment
= mentity
.html_documentation
514 if comment
!= null then
515 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
518 for child
in children
do
519 if child
.is_hidden
then continue
520 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
521 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)
523 var lnk
= html_source_link
525 tabs
.drop_list
.items
.add
new ListItem(lnk
)
531 redef class MEntitiesListArticle
532 redef fun render_body
do
533 var lst
= new UnorderedList
534 lst
.css_classes
.add
"list-unstyled list-definition"
535 for mentity
in mentities
do
536 lst
.add_li mentity
.html_list_item
542 redef class DefinitionLinArticle
543 redef fun render_body
do
544 var lst
= new UnorderedList
545 lst
.css_classes
.add
"list-unstyled list-labeled"
546 for mentity
in mentities
do
547 if not mentity
isa MPropDef then continue # TODO handle all mentities
548 var tpl
= new Template
549 tpl
.add mentity
.mclassdef
.html_namespace
550 var comment
= mentity
.mclassdef
.html_synopsis
551 if comment
!= null then
555 var li
= new ListItem(tpl
)
556 li
.css_classes
.add
"signature"
563 redef class GraphArticle
564 redef var html_title
= null
566 # Graph in SVG with clickable map.
568 # This attribute is set by the `doc_render` phase who knows the context.
569 var svg
: nullable String = null is writable
571 redef fun render_body
do
572 addn
"<div class=\"text-center\
">"
574 if svg
!= null then add svg
579 redef class ReadmeSection
580 redef var html_id
is lazy
do
581 return markdown_processor
.emitter
.decorator
.strip_id
(html_title
.as(not null).to_s
)
584 redef var html_title
is lazy
do
585 return markdown_processor
.process
(title
.as(not null))
589 redef class ReadmeArticle
590 redef var html_id
= ""
591 redef var html_title
= null
592 redef var is_toc_hidden
= true
594 redef fun render_body
do
595 add markdown_processor
.process
(md
.trim
.write_to_string
)
599 redef class DocumentationArticle
600 redef var html_title
is lazy
do
601 var synopsis
= mentity
.html_synopsis
602 if synopsis
== null then return mentity
.html_link
603 return "{mentity.html_link.write_to_string} – {synopsis.write_to_string}"
606 redef var html_subtitle
is lazy
do return null
607 redef var html_toc_title
is lazy
do return mentity
.html_name
608 redef var is_toc_hidden
is lazy
do return depth
> 3
610 redef fun render_body
do
611 var tabs
= new DocTabs("{html_id}.tabs", "")
612 var comment
= mentity
.html_comment
613 if comment
!= null then
614 tabs
.add_panel
new DocTabPanel("{html_tab_id}-comment", "Comment", comment
)
616 for child
in children
do
617 if child
.is_hidden
then continue
618 var title
= child
.html_toc_title
or else child
.toc_title
or else ""
619 tabs
.add_panel
new DocTabPanel(child
.html_tab_id
, title
, child
)