ec7f7dff3f75f13c4bf3bbf3c28c7a7a265b0b8a
[nit.git] / src / doc / doc_phases / doc_html.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 # Render the DocModel pages as HTML pages.
16 #
17 # FIXME this module is all f*cked up to maintain compatibility with
18 # the original `doc_templates` and `doc_model` modules.
19 # This will change in further refactorings.
20 module doc_html
21
22 import doc_structure
23 import doc_hierarchies
24 import doc_intros_redefs
25 import doc_graphs
26 import html_templates
27
28 redef class ToolContext
29
30 # File pattern used to link documentation to source code.
31 var opt_source = new OptionString("link for source (%f for filename, " +
32 "%l for first line, %L for last line)", "--source")
33
34 # Directory where the CSS and JS is stored.
35 var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
36
37 # Use a shareurl instead of copy shared files.
38 #
39 # This is usefull if you don't want to store the Nitdoc templates with your
40 # documentation.
41 var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
42
43 # Use a custom title for the homepage.
44 var opt_custom_title = new OptionString("custom title for homepage", "--custom-title")
45
46 # Display a custom brand or logo in the documentation top menu.
47 var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
48
49 # Display a custom introduction text before the projects overview.
50 var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
51 # Display a custom footer on each documentation page.
52 #
53 # Generally used to display the documentation or product version.
54 var opt_custom_footer = new OptionString("custom footer text", "--custom-footer-text")
55
56 # Piwik tracker URL.
57 #
58 # If you want to monitor your visitors.
59 var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
60
61 # Piwik tracker site id.
62 var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
63
64 # These options are not currently used in Nitdoc.
65
66 # FIXME redo the plugin
67 var opt_github_upstream = new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
68 # FIXME redo the plugin
69 var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
70 # FIXME redo the plugin
71 var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
72
73 redef init do
74 super
75
76 option_context.add_option(
77 opt_source, opt_sharedir, opt_shareurl, opt_custom_title,
78 opt_custom_footer, opt_custom_intro, opt_custom_brand,
79 opt_github_upstream, opt_github_base_sha1, opt_github_gitdir,
80 opt_piwik_tracker, opt_piwik_site_id)
81 end
82
83 redef fun process_options(args) do
84 super
85 var upstream = opt_github_upstream
86 var base_sha = opt_github_base_sha1
87 var git_dir = opt_github_gitdir
88 var opts = [upstream.value, base_sha.value, git_dir.value]
89 if not opts.has_only(null) and opts.has(null) then
90 print "Option Error: options {upstream.names.first}, " +
91 "{base_sha.names.first} and {git_dir.names.first} " +
92 "are required to enable the GitHub plugin"
93 exit 1
94 end
95 end
96 end
97
98 # Render the Nitdoc as a HTML website.
99 class RenderHTMLPhase
100 super DocPhase
101
102 # Used to sort sidebar elements by name.
103 var name_sorter = new MEntityNameSorter
104
105 redef fun apply do
106 init_output_dir
107 for page in doc.pages do
108 page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}")
109 end
110 end
111
112 # Creates the output directory and imports assets files form `resources/`.
113 fun init_output_dir do
114 # create destination dir if it's necessary
115 var output_dir = ctx.output_dir
116 if not output_dir.file_exists then output_dir.mkdir
117 # locate share dir
118 var sharedir = ctx.opt_sharedir.value
119 if sharedir == null then
120 var dir = ctx.nit_dir
121 sharedir = dir/"share/nitdoc"
122 if not sharedir.file_exists then
123 print "Error: cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
124 abort
125 end
126 end
127 # copy shared files
128 if ctx.opt_shareurl.value == null then
129 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
130 else
131 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
132 end
133
134 end
135
136 # A source link template for a given location
137 fun tpl_showsource(location: nullable Location): nullable String
138 do
139 if location == null then return null
140 var source = ctx.opt_source.value
141 if source == null then
142 var url = location.file.filename.simplify_path
143 return "<a target='_blank' title='Show source' href=\"{url.html_escape}\">View Source</a>"
144 end
145 # THIS IS JUST UGLY ! (but there is no replace yet)
146 var x = source.split_with("%f")
147 source = x.join(location.file.filename.simplify_path)
148 x = source.split_with("%l")
149 source = x.join(location.line_start.to_s)
150 x = source.split_with("%L")
151 source = x.join(location.line_end.to_s)
152 source = source.simplify_path
153 return "<a target='_blank' title='Show source' href=\"{source.to_s.html_escape}\">View Source</a>"
154 end
155 end
156
157 redef class DocPage
158
159 # Render the page as a html template.
160 private fun render(v: RenderHTMLPhase, doc: DocModel): Writable do
161 var shareurl = "."
162 if v.ctx.opt_shareurl.value != null then
163 shareurl = v.ctx.opt_shareurl.value.as(not null)
164 end
165
166 # init page options
167 self.shareurl = shareurl
168 self.footer = v.ctx.opt_custom_footer.value
169 self.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
170
171 # build page
172 init_title(v, doc)
173 init_sidebar(v, doc)
174 init_topmenu(v, doc)
175 init_content(v, doc)
176
177 # piwik tracking
178 var tracker_url = v.ctx.opt_piwik_tracker.value
179 var site_id = v.ctx.opt_piwik_site_id.value
180 if tracker_url != null and site_id != null then
181 self.scripts.add new TplPiwikScript(tracker_url, site_id)
182 end
183 return self
184 end
185
186 # FIXME diff hack
187 # all properties below are roughly copied from `doc_pages`
188
189 # Build page title string
190 fun init_title(v: RenderHTMLPhase, doc: DocModel) is abstract
191
192 # Build top menu template if any.
193 fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
194 topmenu = new DocTopMenu
195 var brand = v.ctx.opt_custom_brand.value
196 if brand != null then
197 var tpl = new Template
198 tpl.add "<span class='navbar-brand'>"
199 tpl.add brand
200 tpl.add "</span>"
201 topmenu.brand = tpl
202 end
203 var title = "Overview"
204 if v.ctx.opt_custom_title.value != null then
205 title = v.ctx.opt_custom_title.value.to_s
206 end
207 topmenu.add_li new ListItem(new Link("index.html", title))
208 topmenu.add_li new ListItem(new Link("search.html", "Index"))
209 topmenu.active_item = topmenu.items.first
210 end
211
212 # Build page sidebar if any.
213 fun init_sidebar(v: RenderHTMLPhase, doc: DocModel) do
214 sidebar = new TplSidebar
215 end
216
217 # Build page content template.
218 fun init_content(v: RenderHTMLPhase, doc: DocModel) do
219 root.init_html_render(v, doc, self)
220 end
221 end
222
223 redef class OverviewPage
224 redef var html_url = "index.html"
225
226 redef fun init_title(v, doc) do
227 title = "Overview"
228 if v.ctx.opt_custom_title.value != null then
229 title = v.ctx.opt_custom_title.value.to_s
230 end
231 end
232
233 # TODO this should be done in StructurePhase.
234 redef fun init_content(v, doc) do
235 # intro text
236 var section = new TplSection.with_title("overview", title)
237 var article = new TplArticle("intro")
238 if v.ctx.opt_custom_intro.value != null then
239 article.content = v.ctx.opt_custom_intro.value.to_s
240 end
241 section.add_child article
242 # Projects list
243 var mprojects = doc.model.mprojects.to_a
244 var sorter = new MConcernRankSorter
245 sorter.sort mprojects
246 var ssection = new TplSection.with_title("projects", "Projects")
247 for mproject in mprojects do
248 var sarticle = new TplArticle(mproject.nitdoc_id)
249 var title = new Template
250 title.add mproject.html_icon
251 title.add mproject.html_link
252 sarticle.title = title
253 sarticle.title_classes.add "signature"
254 sarticle.summary_title = mproject.html_name
255 sarticle.subtitle = mproject.html_declaration
256 var comment = mproject.html_short_comment
257 if comment != null then
258 sarticle.content = comment
259 end
260 ssection.add_child sarticle
261 end
262 section.add_child ssection
263 self.add_section section
264 end
265
266 redef fun init_sidebar(v, doc) do sidebar = new TplSidebar
267 end
268
269 redef class SearchPage
270 redef var html_url = "search.html"
271 redef fun init_title(v, doc) do title = "Index"
272
273 redef fun init_topmenu(v, doc) do
274 super
275 topmenu.active_item = topmenu.items.last
276 end
277
278 redef fun init_sidebar(v, doc) do end
279
280 # TODO this should be done in StructurePhase.
281 redef fun init_content(v, doc) do
282 var tpl = new TplSearchPage("search_all")
283 var section = new TplSection("search")
284 # title
285 tpl.title = "Index"
286 # modules list
287 for mmodule in modules_list(v, doc) do
288 tpl.modules.add mmodule.html_link
289 end
290 # classes list
291 for mclass in classes_list(v, doc) do
292 tpl.classes.add mclass.html_link
293 end
294 # properties list
295 for mproperty in mprops_list(v, doc) do
296 var m = new Template
297 m.add mproperty.intro.html_link
298 m.add " ("
299 m.add mproperty.intro.mclassdef.mclass.html_link
300 m.add ")"
301 tpl.props.add m
302 end
303 section.add_child tpl
304 self.add_section section
305 end
306
307 # Extract mmodule list to display (sorted by name)
308 private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
309 var sorted = new Array[MModule]
310 for mmodule in doc.model.mmodule_importation_hierarchy do
311 if mmodule.is_fictive or mmodule.is_test_suite then continue
312 sorted.add mmodule
313 end
314 v.name_sorter.sort(sorted)
315 return sorted
316 end
317
318 # Extract mclass list to display (sorted by name)
319 private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
320 var sorted = doc.mclasses.to_a
321 v.name_sorter.sort(sorted)
322 return sorted
323 end
324
325 # Extract mproperty list to display (sorted by name)
326 private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
327 var sorted = doc.mproperties.to_a
328 v.name_sorter.sort(sorted)
329 return sorted
330 end
331 end
332
333 redef class MEntityPage
334 redef var html_url is lazy do return mentity.nitdoc_url
335 redef fun init_title(v, doc) do title = mentity.html_name
336 redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
337 end
338
339 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
340 # doc phases. This is to preserve the compatibility with the current
341 # `doc_templates` module.
342
343 redef class MGroupPage
344 redef fun init_topmenu(v, doc) do
345 super
346 var mproject = mentity.mproject
347 if not mentity.is_root then
348 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
349 end
350 topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
351 topmenu.active_item = topmenu.items.last
352 end
353
354 redef fun init_sidebar(v, doc) do
355 super
356 var mclasses = new HashSet[MClass]
357 mclasses.add_all intros
358 mclasses.add_all redefs
359 if mclasses.is_empty then return
360 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
361
362 var sorted = mclasses.to_a
363 v.name_sorter.sort(sorted)
364 for mclass in sorted do
365 list.add_li tpl_sidebar_item(mclass)
366 end
367 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
368 end
369
370 private fun tpl_sidebar_item(def: MClass): TplListItem do
371 var classes = def.intro.css_classes
372 if intros.has(def) then
373 classes.add "intro"
374 else
375 classes.add "redef"
376 end
377 var lnk = new Template
378 lnk.add new TplLabel.with_classes(classes)
379 lnk.add def.html_link
380 return new TplListItem.with_content(lnk)
381 end
382 end
383
384 redef class MModulePage
385 redef fun init_topmenu(v, doc) do
386 super
387 var mproject = mentity.mproject
388 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
389 topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
390 topmenu.active_item = topmenu.items.last
391 end
392
393 # Class list to display in sidebar
394 redef fun init_sidebar(v, doc) do
395 # TODO filter here?
396 super
397 var mclasses = new HashSet[MClass]
398 mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
399 mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
400 if mclasses.is_empty then return
401 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
402
403 var sorted = mclasses.to_a
404 v.name_sorter.sort(sorted)
405 for mclass in sorted do
406 list.add_li tpl_sidebar_item(mclass)
407 end
408 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
409 end
410
411 private fun tpl_sidebar_item(def: MClass): TplListItem do
412 var classes = def.intro.css_classes
413 if def.intro_mmodule == self.mentity then
414 classes.add "intro"
415 else
416 classes.add "redef"
417 end
418 var lnk = new Template
419 lnk.add new TplLabel.with_classes(classes)
420 lnk.add def.html_link
421 return new TplListItem.with_content(lnk)
422 end
423 end
424
425 redef class MClassPage
426
427 redef fun init_topmenu(v, doc) do
428 super
429 var mproject = mentity.intro_mmodule.mgroup.mproject
430 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
431 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
432 topmenu.active_item = topmenu.items.last
433 end
434
435 redef fun init_sidebar(v, doc) do
436 super
437 var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
438 var summary = new TplList.with_classes(["list-unstyled"])
439
440 by_kind.sort_groups(v.name_sorter)
441 for g in by_kind.groups do tpl_sidebar_list(g, summary)
442 sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
443 end
444
445 private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
446 if mprops.is_empty then return
447 var entry = new TplListItem.with_content(mprops.title)
448 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
449 for mprop in mprops do
450 list.add_li tpl_sidebar_item(mprop)
451 end
452 entry.append list
453 summary.elts.add entry
454 end
455
456 private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
457 var classes = mprop.intro.css_classes
458 if not mprop_is_local(mprop) then
459 classes.add "inherit"
460 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
461 var def_url = "{cls_url}#{mprop.nitdoc_id}"
462 var lnk = new TplLink(def_url, mprop.html_name)
463 var mdoc = mprop.intro.mdoc_or_fallback
464 if mdoc != null then lnk.title = mdoc.short_comment
465 var item = new Template
466 item.add new TplLabel.with_classes(classes)
467 item.add lnk
468 return new TplListItem.with_content(item)
469 end
470 if mpropdefs.has(mprop.intro) then
471 classes.add "intro"
472 else
473 classes.add "redef"
474 end
475 var lnk = new Template
476 lnk.add new TplLabel.with_classes(classes)
477 lnk.add mprop.html_link_to_anchor
478 return new TplListItem.with_content(lnk)
479 end
480
481 private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
482 var res = new HashSet[MProperty]
483 var local = mentity.local_mproperties(v.ctx.min_visibility)
484 for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
485 if local.has(mprop) then continue
486 #if mprop isa MMethod and mprop.is_init then continue
487 if mprop.intro.mclassdef.mclass.name == "Object" and
488 (mprop.visibility == protected_visibility or
489 mprop.intro.mclassdef.mmodule.name != "kernel") then continue
490 res.add mprop
491 end
492 res.add_all local
493 return res
494 end
495
496 private fun mprop_is_local(mprop: MProperty): Bool do
497 for mpropdef in mprop.mpropdefs do
498 if self.mpropdefs.has(mpropdef) then return true
499 end
500 return false
501 end
502 end
503
504 redef class MPropertyPage
505 redef fun init_title(v, doc) do
506 title = "{mentity.html_name}{mentity.html_short_signature.write_to_string}"
507 end
508
509 redef fun init_topmenu(v, doc) do
510 super
511 var mmodule = mentity.intro_mclassdef.mmodule
512 var mproject = mmodule.mgroup.mproject
513 var mclass = mentity.intro_mclassdef.mclass
514 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
515 topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
516 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
517 topmenu.active_item = topmenu.items.last
518 end
519 end
520
521 redef class DocComposite
522 # Render this DocComposite as HTML.
523 #
524 # FIXME needed to maintain TplSection compatibility.
525 fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
526
527 # Prepares the HTML rendering for this element.
528 #
529 # This visit is mainly used to set template attributes before rendering.
530 fun init_html_render(v: RenderHTMLPhase, doc: DocModel, page: DocPage) do
531 for child in children do child.init_html_render(v, doc, page)
532 end
533 end
534
535 redef class DocRoot
536
537 # Start the rendering from root.
538 #
539 # FIXME needed to maintain TplSection compatibility.
540 fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
541 var section = new TplSection("top")
542 var mentity = page.mentity
543 section.title = mentity.html_name
544 section.subtitle = mentity.html_declaration
545 # FIXME ugly hack to avoid diff
546 if mentity isa MGroup and mentity.is_root then
547 section.title = mentity.mproject.html_name
548 section.subtitle = mentity.mproject.html_declaration
549 else if mentity isa MProperty then
550 section.title = "{mentity.html_name}{mentity.intro.html_signature.write_to_string}"
551 section.subtitle = mentity.html_namespace
552 section.summary_title = mentity.html_name
553 end
554 render(v, doc, page, section)
555 return section
556 end
557
558 redef fun render(v, doc, page, parent) do
559 for child in children do
560 child.render(v, doc, page, parent)
561 end
562 end
563 end
564
565 redef class ConcernSection
566 redef fun render(v, doc, page, parent) do
567 var section = new TplSection(mentity.nitdoc_id)
568 var mentity = self.mentity
569 # FIXME hideous hacks to avoid diff
570 if page.mentity isa MModule and mentity isa MModule then
571 render_concern_mmodule(page, section, mentity)
572 else if page.mentity isa MClass and mentity isa MModule then
573 render_concern_other(page, section, mentity)
574 else if page.mentity isa MProperty and mentity isa MModule then
575 render_concern_other(page, section, mentity)
576 end
577 for child in children do
578 child.render(v, doc, page, section)
579 end
580 parent.add_child section
581 end
582
583 private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
584 var title = new Template
585 if mmodule == page.mentity then
586 title.add "in "
587 section.summary_title = "in {mmodule.html_name}"
588 else
589 title.add "from "
590 section.summary_title = "from {mmodule.html_name}"
591 end
592 title.add mmodule.html_namespace
593 section.title = title
594 end
595
596 private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
597 var title = new Template
598 title.add "in "
599 title.add mmodule.html_namespace
600 section.title = title
601 section.summary_title = "in {mmodule.html_name}"
602 end
603 end
604
605 redef class MEntitySection
606 redef fun render(v, doc, page, parent) do
607 for child in children do child.render(v, doc, page, parent)
608 end
609 end
610
611 redef class IntroArticle
612 redef fun render(v, doc, page, parent) do
613 var article = new TplArticle("intro")
614 var mentity = self.mentity
615 if mentity isa MModule then
616 article.source_link = v.tpl_showsource(mentity.location)
617 else if mentity isa MClassDef then
618 article.source_link = v.tpl_showsource(mentity.location)
619 else if mentity isa MPropDef then
620 article.source_link = v.tpl_showsource(mentity.location)
621 end
622 # article.subtitle = mentity.html_declaration
623 article.content = write_to_string
624 parent.add_child article
625 end
626 end
627
628 redef class ConcernsArticle
629 redef fun render(v, doc, page, parent) do
630 parent.add_child new TplArticle.
631 with_content("concerns", "Concerns", write_to_string)
632 end
633 end
634
635 redef class DefinitionArticle
636 redef fun render(v, doc, page, parent) do
637 var title = new Template
638 title.add mentity.html_icon
639 title.add mentity.html_name
640
641 var article = new TplArticle(mentity.nitdoc_id)
642 article.title = title
643 article.title_classes.add "signature"
644 article.subtitle = mentity.html_declaration
645 article.summary_title = mentity.html_name
646 article.content = write_to_string
647
648 # FIXME less hideous hacks...
649 var mentity = self.mentity
650 if mentity isa MModule then
651 title = new Template
652 title.add mentity.html_icon
653 title.add mentity.html_namespace
654 article.title = title
655 else if mentity isa MClass then
656 title = new Template
657 title.add mentity.html_icon
658 title.add mentity.html_link
659 article.title = title
660 article.subtitle = mentity.html_namespace
661 article.content = null
662 else if mentity isa MClassDef then
663 title = new Template
664 title.add "in "
665 title.add mentity.mmodule.html_namespace
666 article.title = mentity.html_declaration
667 article.subtitle = title
668 article.source_link = v.tpl_showsource(mentity.location)
669 if mentity.is_intro and mentity.mmodule != page.mentity then
670 article.content = mentity.html_short_comment
671 end
672 else if mentity isa MPropDef then
673 if page.mentity isa MClass then
674 title = new Template
675 title.add mentity.html_icon
676 title.add mentity.html_declaration
677 article.title = title
678 article.subtitle = mentity.html_namespace
679 # TODO move in its own phase? let's see after doc_template refactoring.
680 # Add linearization
681 var all_defs = new HashSet[MPropDef]
682 for local_def in local_defs(page.as(MClassPage), mentity.mproperty) do
683 all_defs.add local_def
684 var smpropdef = local_def
685 while not smpropdef.is_intro do
686 smpropdef = smpropdef.lookup_next_definition(
687 doc.mainmodule, smpropdef.mclassdef.bound_mtype)
688 all_defs.add smpropdef
689 end
690 end
691 var lin = all_defs.to_a
692 doc.mainmodule.linearize_mpropdefs(lin)
693 if lin.length > 1 then
694 var lin_article = new TplArticle("{mentity.nitdoc_id}.lin")
695 lin_article.title = "Inheritance"
696 var lst = new UnorderedList
697 lst.css_classes.add("list-unstyled list-labeled")
698 for smpropdef in lin do
699 lst.add_li tpl_inheritance_item(smpropdef)
700 end
701 lin_article.content = lst
702 article.add_child lin_article
703 end
704 else
705 title = new Template
706 title.add "in "
707 title.add mentity.mclassdef.html_link
708 article.title = title
709 article.summary_title = "in {mentity.mclassdef.html_name}"
710 end
711 article.source_link = v.tpl_showsource(mentity.location)
712 end
713 for child in children do
714 child.render(v, doc, page, article)
715 end
716 parent.add_child article
717 end
718
719 # Filter `page.mpropdefs` for this `mpropertie`.
720 #
721 # FIXME compatability with current templates.
722 private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
723 var mpropdefs = new HashSet[MPropDef]
724 for mpropdef in page.mpropdefs do
725 if mpropdef.mproperty == mproperty then
726 mpropdefs.add mpropdef
727 end
728 end
729 return mpropdefs
730 end
731
732 private fun tpl_inheritance_item(mpropdef: MPropDef): ListItem do
733 var lnk = new Template
734 lnk.add new TplLabel.with_classes(css_classes)
735 lnk.add mpropdef.mclassdef.mmodule.html_namespace
736 lnk.add "::"
737 var atext = mpropdef.mclassdef.html_link.text
738 var ahref = "{mpropdef.mclassdef.mclass.nitdoc_url}#{mpropdef.mproperty.nitdoc_id}"
739 var atitle = mpropdef.mclassdef.html_link.title
740 var anchor = new Link.with_title(ahref, atext, atitle)
741 lnk.add anchor
742 var comment = mpropdef.html_short_comment
743 if comment != null then
744 lnk.add ": "
745 lnk.add comment
746 end
747 var li = new ListItem(lnk)
748 li.css_classes.add "signature"
749 return li
750 end
751 end
752
753 redef class IntrosRedefsListArticle
754 redef fun render(v, doc, page, parent) do
755 if mentities.is_empty then return
756 var article = new TplArticle.with_title(list_title.to_lower, list_title)
757 article.content = write_to_string
758 parent.add_child article
759 end
760 end
761
762 # FIXME compatibility with doc_templates.
763 redef class ImportationListSection
764 redef fun render(v, doc, page, parent) do
765 var section = new TplSection.with_title("dependencies", "Dependencies")
766 for child in children do
767 child.render(v, doc, page, section)
768 end
769 parent.add_child section
770 end
771 end
772
773 # FIXME compatibility with doc_templates.
774 redef class InheritanceListSection
775 redef fun render(v, doc, page, parent) do
776 var section = new TplSection.with_title("inheritance", "Inheritance")
777 for child in children do
778 child.render(v, doc, page, section)
779 end
780 parent.add_child section
781 end
782 end
783
784 # FIXME compatibility with doc_templates.
785 redef class HierarchyListArticle
786 redef fun render(v, doc, page, parent) do
787 if mentities.is_empty then return
788 var article = new TplArticle.with_title(list_title.to_lower, list_title)
789 article.content = write_to_string
790 parent.add_child article
791 end
792 end
793
794 redef class GraphArticle
795 redef fun render(v, doc, page, parent) do
796 var output_dir = v.ctx.output_dir
797 var path = output_dir / id
798 var path_sh = path.escape_to_sh
799 var file = new FileWriter.open("{path}.dot")
800 file.write(dot)
801 file.close
802 sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
803 var fmap = new FileReader.open("{path}.map")
804 map = fmap.read_all
805 fmap.close
806
807 var article = new TplArticle("graph")
808 article.css_classes.add "text-center"
809 article.content = write_to_string
810 parent.add_child article
811 end
812 end
813
814 redef class Location
815 # Github url based on this location
816 fun github(gitdir: String): String do
817 var base_dir = getcwd.join_path(gitdir).simplify_path
818 var file_loc = getcwd.join_path(file.filename).simplify_path
819 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
820 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
821 end
822 end