niti: fix type in tool description
[nit.git] / src / doc / doc_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 # HTML templates used by Nitdoc to generate API documentation
16 # Pages are assembled using `Template`
17 module doc_templates
18
19 import template
20
21 # A documentation page
22 class TplPage
23 super Template
24
25 # Page title in HTML header
26 var title: String is writable, noinit
27
28 # Directory where css, js and other assets can be found
29 var shareurl: String is writable, noinit
30
31 # Attributes of the body tag element
32 var body_attrs = new Array[TagAttribute]
33
34 # Top menu template if any
35 var topmenu: TplTopMenu is writable, noinit
36
37 # Sidebar template if any
38 var sidebar: nullable TplSidebar = null is writable
39
40 # Content of the page in form a TplSection
41 var sections = new Array[TplSection]
42
43 # Footer content if any
44 var footer: nullable Streamable = null is writable
45
46 # JS scripts to append at the end of the body
47 var scripts = new Array[TplScript]
48
49 init do end
50
51 # Add a section to this page
52 fun add_section(section: TplSection) do
53 sections.add section
54 end
55
56 # Render the html header
57 private fun render_head do
58 add "<!DOCTYPE html>"
59 add "<head>"
60 add " <meta charset='utf-8'/>"
61 add " <!--link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css'/-->"
62 add " <link rel='stylesheet' href='{shareurl}/vendors/bootstrap/css/bootstrap.min.css'/>"
63 add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.bootstrap.css'/>"
64 add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.css'/>"
65 add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css'/>"
66 add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css'/>"
67 add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css'/>"
68 add " <title>{title}</title>"
69 add "</head>"
70 add "<body"
71 for attr in body_attrs do add attr
72 add ">"
73 end
74
75 # Render the topmenu template
76 private fun render_topmenu do
77 add " <div class='row'>"
78 add topmenu
79 add " </div>"
80 end
81
82 # Render the sidebar
83 # Sidebar is automatically populated with a summary of all sections
84 fun render_sidebar do
85 if sidebar == null then return
86 var summary = new TplSummary.with_order(0)
87 for section in sections do
88 section.render_summary summary
89 end
90 sidebar.boxes.add summary
91 add sidebar.as(not null)
92 end
93 # Render the footer and content
94 private fun render_content do
95 for section in sections do add section
96 if footer != null then
97 add "<div class='well footer'>"
98 add footer.as(not null)
99 add "</div>"
100 end
101 end
102
103 # Render JS scripts
104 private fun render_footer do
105 add "<script src='{shareurl}/vendors/jquery/jquery-1.11.1.min.js'></script>"
106 add "<script src='{shareurl}/vendors/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
107 add "<script src='{shareurl}/vendors/bootstrap/js/bootstrap.min.js'></script>"
108 add "<script data-main='{shareurl}/js/nitdoc' src='{shareurl}/js/lib/require.js'</script>"
109 for script in scripts do add script
110 add """<script>
111 $(function () {
112 $("[data-toggle='tooltip']").tooltip();
113 $("[data-toggle='popover']").popover();
114 });
115 </script>"""
116 add "</body>"
117 add "</html>"
118 end
119
120 # Render the whole page
121 redef fun rendering do
122 render_head
123 add "<div class='container-fluid'>"
124 render_topmenu
125 add " <div class='row' id='content'>"
126 if sidebar != null then
127 add "<div class='col col-xs-3 col-lg-2'>"
128 render_sidebar
129 add "</div>"
130 add "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
131 render_content
132 add "</div>"
133 else
134 add "<div class='col col-xs-12'>"
135 render_content
136 add "</div>"
137 end
138 add " </div>"
139 add "</div>"
140 render_footer
141 end
142 end
143
144 #########################
145 # general layout elements
146 #########################
147
148 # Top menu bar template
149 class TplTopMenu
150 super Template
151
152 # Brand link to display in first position of the top menu
153 private var brand: nullable Streamable = null is writable
154 # Elements of the topmenu
155 private var elts = new Array[Streamable]
156
157 init do end
158
159 # Add a content between `<li>` tags
160 fun add_item(content: Streamable, is_active: Bool) do
161 var tpl = new Template
162 tpl.add "<li"
163 if is_active then
164 tpl.add " class='active'"
165 end
166 tpl.add ">"
167 tpl.add content
168 tpl.add "</li>"
169 add_raw(tpl)
170 end
171
172 # Add a raw content to the menu
173 fun add_raw(content: Streamable) do
174 elts.add content
175 end
176
177 redef fun rendering do
178 if brand == null and elts.is_empty then return
179 add "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
180 add " <div class='container-fluid'>"
181 add " <div class='navbar-header'>"
182 add " <button type='button' class='navbar-toggle' "
183 add " data-toggle='collapse' data-target='#topmenu-collapse'>"
184 add " <span class='sr-only'>Toggle menu</span>"
185 add " <span class='icon-bar'></span>"
186 add " <span class='icon-bar'></span>"
187 add " <span class='icon-bar'></span>"
188 add " </button>"
189 if brand != null then add brand.as(not null)
190 add " </div>"
191 add " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
192 if not elts.is_empty then
193 add "<ul class='nav navbar-nav'>"
194 for elt in elts do add elt
195 add "</ul>"
196 end
197 add " </div>"
198 add " </div>"
199 add "</nav>"
200 end
201 end
202
203 # A sidebar template
204 class TplSidebar
205 super Template
206
207 # Sidebar contains sidebar element templates called boxes
208 var boxes = new Array[TplSidebarElt]
209
210 # Sort boxes by order priority
211 private fun order_boxes do
212 var sorter = new OrderComparator
213 sorter.sort(boxes)
214 end
215
216 redef fun rendering do
217 if boxes.is_empty then return
218 order_boxes
219 add "<div id='sidebar'>"
220 for box in boxes do add box
221 add "</div>"
222 end
223 end
224
225 # Comparator used to sort boxes by order
226 private class OrderComparator
227 super Comparator[TplSidebarElt]
228
229 redef fun compare(a, b) do
230 if a.order < b.order then return -1
231 if a.order > b.order then return 1
232 return 0
233 end
234 end
235
236 # Something that can be put in the sidebar
237 class TplSidebarElt
238 super Template
239
240 # Order of the box in the sidebar
241 var order: Int = 1
242
243 init with_order(order: Int) do self.order = order
244 end
245
246 # Agenericbox that can be added to sidebar
247 class TplSideBox
248 super TplSidebarElt
249
250 # Title of the box to display
251 # Title is also a placeholder for the collapse link
252 var title: String
253
254 # Box HTML id
255 # equals to `title.to_cmangle` by default
256 # Used for collapsing
257 var id: String
258
259 # Content to display in the box
260 # box will not be rendered if the content is null
261 var content: nullable Streamable writable
262
263 # Is the box opened by default
264 # otherwise, the user will have to clic on the title to display the content
265 var is_open writable = false
266
267 init(title: String) do
268 self.title = title
269 self.id = title.to_cmangle
270 end
271
272 init with_content(title: String, content: Streamable) do
273 init(title)
274 self.content = content
275 end
276
277 redef fun rendering do
278 if content == null then return
279 var open = ""
280 if is_open then open = "in"
281 add "<div class='panel'>"
282 add " <div class='panel-heading'>"
283 add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
284 add title
285 add " </a>"
286 add " </div>"
287 add " <div id='box_{id}' class='panel-body collapse {open}'>"
288 add content.as(not null)
289 add " </div>"
290 add "</div>"
291 end
292 end
293
294 # Something that can go on a summary template
295 class TplSummaryElt
296 super Template
297
298 # Add an element to the summary
299 fun add_child(child: TplSummaryElt) is abstract
300 end
301
302 # A summary that can go on the sidebar
303 # If the page contains a sidebar, the summary is automatically placed
304 # on top of the sidebarauto-generated
305 # summary contains anchors to all sections displayed in the page
306 class TplSummary
307 super TplSidebarElt
308 super TplSummaryElt
309
310 # Summary elements to display
311 var children = new Array[TplSummaryElt]
312
313 redef fun add_child(child) do children.add child
314
315 redef fun rendering do
316 if children.is_empty then return
317 add "<div class='panel'>"
318 add " <div class='panel-heading'>"
319 add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
320 add "Summary"
321 add " </a>"
322 add " </div>"
323 add " <div id='box-sum' class='summary collapse in'>"
324 add " <ul class='nav'>"
325 for entry in children do add entry
326 add " </ul>"
327 add " </div>"
328 add "</div>"
329 end
330 end
331
332 # A summary entry
333 class TplSummaryEntry
334 super TplSummaryElt
335
336 # Text to display
337 var text: Streamable
338
339 # Children of this entry
340 # Will be displayed as a tree
341 var children = new Array[TplSummaryElt]
342
343 init(text: Streamable) do self.text = text
344
345 redef fun add_child(child) do children.add child
346
347 redef fun rendering do
348 add "<li>"
349 add text
350 if not children.is_empty then
351 add "<ul class='nav'>"
352 for entry in children do add entry
353 add "</ul>"
354 end
355 add "</li>"
356 end
357 end
358
359 # Something that can go in a section
360 # Sections are automatically collected to populate the menu
361 class TplSectionElt
362 super Template
363
364 # HTML anchor id
365 var id: String
366
367 # Title to display if any
368 # if both `title` and `summary_title` are null then
369 # the section will not appear in the summary
370 var title: nullable Streamable writable
371
372 # Subtitle to display if any
373 var subtitle: nullable Streamable writable
374
375 # Title that appear in the summary
376 # if null use `title` instead
377 var summary_title: nullable String writable
378
379 # CSS classes to apply on the section element
380 var css_classes = new Array[String]
381
382 # CSS classes to apply on the title heading element
383 var title_classes = new Array[String]
384
385 # Parent article/section if any
386 var parent: nullable TplSectionElt
387
388 init(id: String) do self.id = id
389
390 init with_title(id: String, title: Streamable) do
391 init(id)
392 self.title = title
393 end
394
395 # Level <hX> for HTML heading
396 protected fun hlvl: Int do
397 if parent == null then return 1
398 return parent.hlvl + 1
399 end
400
401 # Elements contained by this section
402 var children = new Array[TplSectionElt]
403
404 # Add an element in this section
405 fun add_child(child: TplSectionElt) do
406 child.parent = self
407 children.add child
408 end
409
410 # Is the section empty (no content at all)
411 fun is_empty: Bool do return children.is_empty
412
413 # Render this section in the summary
414 fun render_summary(parent: TplSummaryElt) do
415 if is_empty then return
416 var title = summary_title
417 if title == null and self.title != null then title = self.title.write_to_string
418 if title == null then return
419 var lnk = new TplLink("#{id}", title)
420 var entry = new TplSummaryEntry(lnk)
421 for child in children do
422 child.render_summary(entry)
423 end
424 parent.add_child entry
425 end
426 end
427
428 # A HTML <section> element
429 class TplSection
430 super TplSectionElt
431
432 redef fun rendering do
433 add "<section id='{id}' class='{css_classes.join(" ")}'>"
434 if title != null then
435 var lvl = hlvl
436 if lvl == 2 then title_classes.add "well well-sm"
437 add "<h{lvl} class='{title_classes.join(" ")}'>"
438 add title.as(not null)
439 add "</h{lvl}>"
440 end
441 if subtitle != null then
442 add "<div class='info subtitle'>"
443 add subtitle.as(not null)
444 add "</div>"
445 end
446 for child in children do
447 add child
448 end
449 add "</section>"
450 end
451 end
452
453 # A page article that can go in a section
454 class TplArticle
455 super TplSectionElt
456
457 # Content for this article
458 var content: nullable Streamable writable = null
459 var source_link: nullable Streamable writable = null
460
461 init with_content(id: String, title: Streamable, content: Streamable) do
462 with_title(id, title)
463 self.content = content
464 end
465
466 redef fun render_summary(parent) do
467 if is_empty then return
468 var title = summary_title
469 if title == null and self.title != null then title = self.title.write_to_string
470 if title == null then return
471 var lnk = new TplLink("#{id}", title)
472 parent.add_child new TplSummaryEntry(lnk)
473 end
474
475 redef fun rendering do
476 if is_empty then return
477 add "<article id='{id}' class='{css_classes.join(" ")}'>"
478 if source_link != null then
479 add "<div class='source-link'>"
480 add source_link.as(not null)
481 add "</div>"
482 end
483 if title != null then
484 var lvl = hlvl
485 if lvl == 2 then title_classes.add "well well-sm"
486 add "<h{lvl} class='{title_classes.join(" ")}'>"
487 add title.as(not null)
488 add "</h{lvl}>"
489 end
490 if subtitle != null then
491 add "<div class='info subtitle'>"
492 add subtitle.as(not null)
493 add "</div>"
494 end
495 if content != null then
496 add content.as(not null)
497 end
498 for child in children do
499 add child
500 end
501 add """</article>"""
502 end
503
504 redef fun is_empty: Bool do
505 return title == null and subtitle == null and content == null
506 end
507 end
508
509 # A module / class / prop definition
510 class TplDefinition
511 super Template
512
513 # Comment to display
514 var comment: nullable Streamable = null is writable
515
516 # Namespace for this definition
517 var namespace: nullable Streamable = null is writable
518
519 # Location link to display
520 var location: nullable Streamable = null is writable
521
522 private fun render_info do
523 add "<div class='info text-right'>"
524 if namespace != null then
525 if comment == null then
526 add "<span class=\"noComment\">no comment for </span>"
527 end
528 add namespace.as(not null)
529 end
530 if location != null then
531 add " "
532 add location.as(not null)
533 end
534 add "</div>"
535 end
536
537 private fun render_comment do
538 if comment != null then add comment.as(not null)
539 end
540
541 redef fun rendering do
542 add "<div class='definition'>"
543 render_comment
544 render_info
545 add "</div>"
546 end
547 end
548
549 # Class definition
550 class TplClassDefinition
551 super TplDefinition
552
553 var intros = new Array[TplListElt]
554 var redefs = new Array[TplListElt]
555
556 init do end
557
558 redef fun rendering do
559 add "<div class='definition'>"
560 render_comment
561 render_info
562 render_list("Introduces", intros)
563 render_list("Redefines", redefs)
564 add "</div>"
565 end
566
567 private fun render_list(name: String, elts: Array[TplListElt]) do
568 if elts.is_empty then return
569 add "<h5>{name}</h5>"
570 add "<ul class='list-unstyled list-definition'>"
571 for elt in elts do add elt
572 add "</ul>"
573 end
574 end
575
576 # Layout for Search page
577 class TplSearchPage
578 super TplSectionElt
579
580 var modules = new Array[Streamable]
581 var classes = new Array[Streamable]
582 var props = new Array[Streamable]
583
584 redef fun rendering do
585 var title = self.title
586 if title != null then add "<h1>{title}</h1>"
587 add "<div class='container-fluid'>"
588 add " <div class='row'>"
589 if not modules.is_empty then
590 add "<div class='col-xs-4'>"
591 add "<h3>Modules</h3>"
592 add "<ul>"
593 for m in modules do
594 add "<li>"
595 add m
596 add "</li>"
597 end
598 add "</ul>"
599 add "</div>"
600 end
601 if not classes.is_empty then
602 add "<div class='col-xs-4'>"
603 add "<h3>Classes</h3>"
604 add "<ul>"
605 for c in classes do
606 add "<li>"
607 add c
608 add "</li>"
609 end
610 add "</ul>"
611 add "</div>"
612 end
613 if not props.is_empty then
614 add "<div class='col-xs-4'>"
615 add "<h3>Properties</h3>"
616 add "<ul>"
617 for p in props do
618 add "<li>"
619 add p
620 add "</li>"
621 end
622 add "</ul>"
623 add "</div>"
624 end
625 add " </div>"
626 add "</div>"
627 end
628 end
629
630 #####################
631 # Basiv HTML elements
632 #####################
633
634 # A html link <a>
635 class TplLink
636 super Template
637
638 # Link href
639 var href: String writable
640
641 # Text to display in the link
642 var text: String writable
643
644 # Optional title
645 var title: nullable String writable
646
647 init(href, text: String) do
648 self.href = href
649 self.text = text
650 end
651
652 init with_title(href, text, title: String) do
653 init(href, text)
654 self.title = title
655 end
656
657 redef fun rendering do
658 add "<a href=\""
659 add href
660 add "\""
661 if title != null then
662 add " title=\""
663 add title.as(not null)
664 add "\""
665 end
666 add ">"
667 add text
668 add "</a>"
669 end
670 end
671
672 # A <ul> list
673 class TplList
674 super TplListElt
675
676 # Elements contained in this list
677 # can be <li> or <ul> elements
678 var elts = new Array[TplListElt]
679
680 # CSS classes of the <ul> element
681 var css_classes = new Array[String]
682
683 # Add content wrapped in a <li> element
684 fun add_li(content: Streamable) do elts.add new TplListItem.with_content(content)
685
686 init do end
687
688 init with_classes(classes: Array[String]) do self.css_classes = classes
689
690 fun is_empty: Bool do return elts.is_empty
691
692 redef fun rendering do
693 if elts.is_empty then return
694 add "<ul class='{css_classes.join(" ")}'>"
695 for elt in elts do add elt
696 add "</ul>"
697 end
698 end
699
700 # Something that can be added to a TplList
701 class TplListElt
702 super Template
703 end
704
705 # A list item <li>
706 class TplListItem
707 super TplListElt
708
709 # Content of the list item
710 var content = new Template
711
712 # CSS classes of the <li> element
713 var css_classes = new Array[String]
714
715 init do end
716
717 init with_content(content: Streamable) do append(content)
718
719 init with_classes(content: Streamable, classes: Array[String]) do
720 with_content(content)
721 css_classes = classes
722 end
723
724 # Append `content` to the item
725 # similar to `self.content.add`
726 fun append(content: Streamable) do self.content.add content
727
728 redef fun rendering do
729 add "<li class='"
730 for cls in css_classes do add " {cls}"
731 add "'>"
732 add content
733 add "</li>"
734 end
735 end
736
737 # A label with a text content
738 class TplLabel
739 super Template
740
741 # Content of the label if any
742 var content: nullable Streamable
743
744 # CSS classes of the <span> element
745 var css_classes = new Array[String]
746
747 init do end
748 init with_content(content: Streamable) do self.content = content
749 init with_classes(classes: Array[String]) do self.css_classes = classes
750
751 redef fun rendering do
752 add "<span class='label {css_classes.join(" ")}'>"
753 if content != null then add content.as(not null)
754 add "</span>"
755 end
756 end
757
758 # A label with an icon
759 class TplIcon
760 super TplLabel
761
762 # Bootsrap icon name
763 # see: http://getbootstrap.com/components/#glyphicons
764 var icon: String
765
766 init with_icon(icon: String) do self.icon = icon
767
768 redef fun rendering do
769 add "<span class='glyphicon glyphicon-{icon} {css_classes.join(" ")}'>"
770 if content != null then add content.as(not null)
771 add "</span>"
772 end
773 end
774
775 # A HTML tag attribute
776 # `<tag attr="value">`
777 class TagAttribute
778 super Template
779
780 var name: String
781 var value: nullable String
782
783 init(name: String, value: nullable String) do
784 self.name = name
785 self.value = value
786 end
787
788 redef fun rendering do
789 var value = self.value
790 if value == null then
791 add(" {name}")
792 else
793 add(" {name}=\"{value}\"")
794 end
795 end
796 end
797
798 # Javacript template
799 class TplScript
800 super Template
801
802 var attrs = new Array[TagAttribute]
803 var content: nullable Streamable = null is writable
804
805 init do
806 attrs.add(new TagAttribute("type", "text/javascript"))
807 end
808
809 protected fun render_content do
810 if content != null then add content.as(not null)
811 end
812
813 redef fun rendering do
814 add "<script"
815 for attr in attrs do add attr
816 add ">"
817 render_content
818 add "</script>"
819 end
820 end
821
822 # JS script for Piwik Tracker
823 class TplPiwikScript
824 super TplScript
825
826 var tracker_url: String
827 var site_id: String
828
829 init(tracker_url, site_id: String) do
830 super
831 self.tracker_url = tracker_url
832 self.site_id = site_id
833 end
834
835 redef fun render_content do
836 add "<!-- Piwik -->"
837 add "var _paq = _paq || [];"
838 add " _paq.push([\"trackPageView\"]);"
839 add " _paq.push([\"enableLinkTracking\"]);"
840 add "(function() \{"
841 add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
842 add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
843 add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
844 add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
845 add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
846 add "\})();"
847 end
848 end
849