nitdoc: remove `well` around level 2 titles
[nit.git] / src / doc / html_templates / html_templates.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Introduces templates that compose the documentation HTML rendering.
16 module html_templates
17
18 import html_model
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
26 # Renders the page as HTML.
27 redef class DocPage
28 super Template
29
30 # Page url.
31 var html_url: String is writable, noinit
32
33 # Directory where css, js and other assets can be found.
34 var shareurl: String is writable, noinit
35
36 # Attributes of the body tag element.
37 var body_attrs = new Array[TagAttribute]
38
39 # Top menu template if any.
40 var topmenu: DocTopMenu is writable, noinit
41
42 # Sidebar template if any.
43 var sidebar: nullable DocSideBar = null is writable
44
45 # Footer content if any.
46 var footer: nullable Writable = null is writable
47
48 # JS scripts to append at the end of the body
49 var scripts = new Array[TplScript]
50
51 # Renders the html `<head>`.
52 private fun render_head do
53 var css = (self.shareurl / "css").html_escape
54 var vendors = (self.shareurl / "vendors").html_escape
55
56 addn "<!DOCTYPE html>"
57 addn "<head>"
58 addn " <meta charset='utf-8'/>"
59 addn " <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
60 addn " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
61 addn " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
62 addn " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
63 addn " <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
64 addn " <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
65 addn " <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
66 addn " <title>{title.html_escape}</title>"
67 addn "</head>"
68 add "<body"
69 for attr in body_attrs do add attr
70 addn ">"
71 end
72
73 # Renders the footer and content.
74 private fun render_content do
75 add root
76 if footer != null then
77 addn "<div class='well footer'>"
78 add footer.as(not null)
79 addn "</div>"
80 end
81 end
82
83 # Render JS scripts
84 private fun render_footer do
85 var vendors = (self.shareurl / "vendors").html_escape
86 var js = (self.shareurl / "js").html_escape
87
88 addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
89 addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
90 addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
91 addn "<script src='{js}/lib/utils.js'></script>"
92 addn "<script src='{js}/plugins/filtering.js'></script>"
93 addn "<script src='quicksearch-list.js'></script>"
94 addn "<script src='{js}/plugins/quicksearch.js'></script>"
95 for script in scripts do add script
96 addn """<script>
97 $(function () {
98 $("[data-toggle='tooltip']").tooltip();
99 $("[data-toggle='popover']").popover();
100 });
101 </script>"""
102 addn "</body>"
103 addn "</html>"
104 end
105
106 # Render the whole page
107 redef fun rendering do
108 render_head
109 addn "<div class='container-fluid'>"
110 addn " <div class='row'>"
111 add topmenu
112 addn " </div>"
113 addn " <div class='row' id='content'>"
114 var sidebar = self.sidebar
115 if sidebar != null then
116 addn "<div class='col col-xs-3 col-lg-2'>"
117 add sidebar
118 addn "</div>"
119 addn "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
120 render_content
121 addn "</div>"
122 else
123 addn "<div class='col col-xs-12'>"
124 render_content
125 addn "</div>"
126 end
127 addn " </div>"
128 addn "</div>"
129 render_footer
130 end
131
132 # Render table of content for this page.
133 fun html_toc: UnorderedList do
134 var lst = new UnorderedList
135 lst.css_classes.add "nav"
136 for child in root.children do
137 child.render_toc_item(lst)
138 end
139 return lst
140 end
141 end
142
143 # Top menu bar template.
144 #
145 # FIXME should be a Bootstrap component template
146 # At this moment, the topmenu structure stills to specific to Nitdoc to use the
147 # generic component.
148 class DocTopMenu
149 super UnorderedList
150
151 # Brand link to display in first position of the top menu.
152 #
153 # This is where you want to put your logo.
154 var brand: nullable Writable is noinit, writable
155
156 # Active menu item.
157 #
158 # Depends on the current page, this allows to hilighted the current item.
159 #
160 # FIXME should be using Boostrap breadcrumbs component.
161 # This will still like this to avoid diff and be changed in further fixes
162 # when we will modify the output.
163 var active_item: nullable ListItem is noinit, writable
164
165 redef fun rendering do
166 addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
167 addn " <div class='container-fluid'>"
168 addn " <div class='navbar-header'>"
169 add " <button type='button' class='navbar-toggle' "
170 addn " data-toggle='collapse' data-target='#topmenu-collapse'>"
171 addn " <span class='sr-only'>Toggle menu</span>"
172 addn " <span class='icon-bar'></span>"
173 addn " <span class='icon-bar'></span>"
174 addn " <span class='icon-bar'></span>"
175 addn " </button>"
176 if brand != null then
177 add "<span class='navbar-brand'>"
178 add brand.write_to_string
179 add "</span>"
180 end
181 addn " </div>"
182 addn " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
183 addn " <ul class='nav navbar-nav'>"
184 for item in items do
185 if item == active_item then item.css_classes.add "active"
186 add item.write_to_string
187 end
188 addn " </ul>"
189 addn " </div>"
190 addn " </div>"
191 addn "</nav>"
192 end
193 end
194
195 # Nitdoc sidebar template.
196 class DocSideBar
197 super Template
198
199 # Sidebar contains `DocSideBox`.
200 var boxes = new Array[DocSideBox]
201
202 redef fun rendering do
203 if boxes.is_empty then return
204 addn "<div id='sidebar'>"
205 for box in boxes do add box
206 addn "</div>"
207 end
208 end
209
210 # Something that can be put in a DocSideBar.
211 class DocSideBox
212 super Template
213
214 # Box HTML id, used for Bootstrap collapsing feature.
215 #
216 # Use `html_title.to_cmangle` by default.
217 var id: String is lazy do return title.write_to_string.to_cmangle
218
219 # Title of the box to display.
220 var title: Writable
221
222 # Content to display in the box.
223 var content: Writable
224
225 # Is the box opened by default?
226 #
227 # Otherwise, the user will have to clic on the title to display the content.
228 #
229 # Default is `true`.
230 var is_open = true is writable
231
232 redef fun rendering do
233 var open = ""
234 if is_open then open = "in"
235 addn "<div class='panel'>"
236 addn " <div class='panel-heading'>"
237 add " <a data-toggle='collapse' data-parent='#sidebar'"
238 add " data-target='#box_{id}' href='#'>"
239 add title
240 addn " </a>"
241 addn " </div>"
242 addn " <div id='box_{id}' class='summary panel-body collapse {open}'>"
243 add content
244 addn " </div>"
245 addn "</div>"
246 end
247 end
248
249 redef class DocComposite
250 super Template
251
252 # HTML anchor id
253 var html_id: String is writable, lazy do return id
254
255 # Title to display if any.
256 #
257 # This title can be decorated with HTML.
258 var html_title: nullable Writable is writable, lazy do return title
259
260 # Subtitle to display if any.
261 var html_subtitle: nullable Writable is noinit, writable
262
263 # Render the element title and subtitle.
264 private fun render_title do
265 if html_title != null then
266 var header = new Header(hlvl, html_title.write_to_string)
267 header.css_classes.add "signature"
268 addn header
269 end
270 if html_subtitle != null then
271 addn "<div class='info subtitle'>"
272 addn html_subtitle.write_to_string
273 addn "</div>"
274 end
275 end
276
277 # Render the element body.
278 private fun render_body do
279 for child in children do addn child.write_to_string
280 end
281
282 redef fun rendering do
283 if is_hidden then return
284 render_title
285 render_body
286 end
287
288 # Level <hX> for HTML heading.
289 private fun hlvl: Int do return depth
290
291 # A short, undecorated title that goes in the table of contents.
292 #
293 # By default, returns `html_title.to_s`, subclasses should redefine it.
294 var html_toc_title: nullable String is lazy, writable do
295 if html_title == null then return toc_title
296 return html_title.write_to_string
297 end
298
299 # Render this element in a table of contents.
300 private fun render_toc_item(lst: UnorderedList) do
301 if is_toc_hidden or html_toc_title == null then return
302
303 var content = new Template
304 content.add new Link("#{html_id}", html_toc_title.to_s)
305 if not children.is_empty then
306 var sublst = new UnorderedList
307 sublst.css_classes.add "nav"
308 for child in children do
309 child.render_toc_item(sublst)
310 end
311 content.add sublst
312 end
313 lst.add_li new ListItem(content)
314 end
315
316 # ID used in HTML tab labels.
317 #
318 # We sanitize it for Boostrap JS panels that do not like ":" and "." in ids.
319 var html_tab_id: String is lazy do
320 var id = html_id.replace(":", "")
321 id = id.replace(".", "")
322 return "{id}-tab"
323 end
324 end
325
326 redef class DocRoot
327 redef fun rendering do
328 for child in children do addn child.write_to_string
329 end
330 end
331
332 redef class DocSection
333 super BSComponent
334
335 redef fun rendering do
336 if is_hidden then
337 addn "<a id=\"{html_id}\"></a>"
338 return
339 end
340 addn "<section{render_css_classes} id=\"{html_id}\">"
341 render_title
342 render_body
343 addn "</section>"
344 end
345 end
346
347 redef class DocArticle
348 super BSComponent
349
350 redef fun rendering do
351 if is_hidden then return
352 addn "<article{render_css_classes} id=\"{html_id}\">"
353 render_title
354 render_body
355 addn "</article>"
356 end
357 end
358
359 redef class TabbedGroup
360 redef fun render_body do
361 var tabs = new DocTabs("{html_id}.tabs", "")
362 for child in children do
363 if child.is_hidden then continue
364 var title = child.html_toc_title or else child.toc_title or else ""
365 tabs.add_panel new DocTabPanel(child.html_tab_id, title, child)
366 end
367 addn tabs
368 end
369 end
370
371 redef class PanelGroup
372 redef var html_title = null
373 redef var toc_title is lazy do return title or else ""
374 redef var is_toc_hidden = true
375 end
376
377 redef class HomeArticle
378 redef var html_title = "Overview"
379
380 # HTML content to display on the home page.
381 #
382 # This attribute is set by the `doc_render` phase who knows the context.
383 var content: nullable String is noinit, writable
384
385 redef fun render_body do
386 var content = self.content
387 if content != null then add content
388 super
389 end
390 end
391
392 redef class IndexArticle
393 redef var html_title = "Index"
394
395 redef fun render_body do
396 addn "<div class='container-fluid'>"
397 addn " <div class='row'>"
398 render_list("Modules", mmodules)
399 render_list("Classes", mclasses)
400 render_list("Properties", mprops)
401 addn "</div>"
402 addn "</div>"
403 end
404
405 # Displays a list from the content of `mentities`.
406 private fun render_list(title: String, mentities: Array[MEntity]) do
407 if mentities.is_empty then return
408 addn "<div class='col-xs-4'>"
409 addn new Header(3, title)
410 var lst = new UnorderedList
411 for mentity in mentities do
412 if mentity isa MProperty then
413 var tpl = new Template
414 tpl.add mentity.intro.html_link
415 tpl.add " ("
416 tpl.add mentity.intro.mclassdef.mclass.html_link
417 tpl.add ")"
418 lst.add_li new ListItem(tpl)
419 else
420 lst.add_li new ListItem(mentity.html_link)
421 end
422 end
423 addn lst
424 addn "</div>"
425 end
426 end
427
428 redef class MEntityComposite
429 redef var html_title is lazy do return mentity.nitdoc_name
430 end
431
432 redef class MEntitySection
433 redef var html_title is lazy do return mentity.html_name
434 redef var html_subtitle is lazy do return mentity.html_declaration
435 end
436
437 redef class ConcernSection
438 redef var html_title is lazy do return "in {mentity.nitdoc_name}"
439 end
440
441 redef class IntroArticle
442 redef var html_title = null
443
444 # Link to source to display if any.
445 var html_source_link: nullable Writable is noinit, writable
446
447 redef fun render_body do
448 var tabs = new DocTabs("{html_id}.tabs", "")
449 var comment = mentity.html_comment
450 if comment != null then
451 tabs.add_panel new DocTabPanel("{html_tab_id}-comment", "Comment", comment)
452 end
453 for child in children do
454 if child.is_hidden then continue
455 var title = child.html_toc_title or else child.toc_title or else ""
456 tabs.add_panel new DocTabPanel(child.html_tab_id, title, child)
457 end
458 var lnk = html_source_link
459 if lnk != null then
460 tabs.drop_list.items.add new ListItem(lnk)
461 end
462 addn tabs
463 end
464 end
465
466 redef class ConcernsArticle
467 redef var html_title = "Concerns"
468 redef fun render_body do add concerns.html_list
469 end
470
471 redef class DefinitionListArticle
472 redef var html_title is lazy do
473 var title = new Template
474 title.add mentity.html_icon
475 title.add mentity.html_link
476 return title
477 end
478
479 redef var html_subtitle is lazy do return mentity.html_namespace
480 redef var html_toc_title is lazy do return mentity.html_name
481 end
482
483 redef class DefinitionArticle
484 redef var html_title is lazy do return mentity.html_name
485 redef var html_subtitle is lazy do return mentity.html_declaration
486
487 # Does `self` display only it's title and no body?
488 #
489 # FIXME diff hack
490 var is_no_body: Bool = false is writable
491
492 # Does `self` display only the short content as definition?
493 #
494 # FIXME diff hack
495 var is_short_comment: Bool = false is writable
496
497 # Link to source to display if any.
498 var html_source_link: nullable Writable is noinit, writable
499
500 redef fun render_body do
501 var tabs = new DocTabs("{html_id}.tabs", "")
502 if not is_no_body then
503 var comment
504 if is_short_comment then
505 comment = mentity.html_short_comment
506 else
507 comment = mentity.html_comment
508 end
509 if comment != null then
510 tabs.add_panel new DocTabPanel("{html_tab_id}-comment", "Comment", comment)
511 end
512 end
513 for child in children do
514 if child.is_hidden then continue
515 var title = child.html_toc_title or else child.toc_title or else ""
516 tabs.add_panel new DocTabPanel(child.html_tab_id, title, child)
517 end
518 var lnk = html_source_link
519 if lnk != null then
520 tabs.drop_list.items.add new ListItem(lnk)
521 end
522 addn tabs
523 end
524 end
525
526 redef class MEntitiesListArticle
527 redef fun render_body do
528 var lst = new UnorderedList
529 lst.css_classes.add "list-unstyled list-definition"
530 for mentity in mentities do
531 lst.add_li mentity.html_list_item
532 end
533 add lst
534 end
535 end
536
537 redef class DefinitionLinArticle
538 redef fun render_body do
539 var lst = new UnorderedList
540 lst.css_classes.add "list-unstyled list-labeled"
541 for mentity in mentities do
542 if not mentity isa MPropDef then continue # TODO handle all mentities
543 var tpl = new Template
544 tpl.add mentity.mclassdef.html_namespace
545 var comment = mentity.mclassdef.html_short_comment
546 if comment != null then
547 tpl.add ": "
548 tpl.add comment
549 end
550 var li = new ListItem(tpl)
551 li.css_classes.add "signature"
552 lst.add_li li
553 end
554 add lst
555 end
556 end
557
558 redef class GraphArticle
559 redef var html_title = null
560
561 # HTML map used to display link.
562 #
563 # This attribute is set by the `doc_render` phase who knows the context.
564 var map: String is noinit, writable
565
566 redef fun render_body do
567 addn "<div class=\"text-center\">"
568 addn " <img src='{graph_id}.png' usemap='#{graph_id}' style='margin:auto'"
569 addn " alt='{title or else ""}'/>"
570 add map
571 addn "</div>"
572 end
573 end