src/doc: migrate sidebar to new templates
[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_topmenu(v, doc)
174 init_content(v, doc)
175 init_sidebar(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 DocSideBar
215 sidebar.boxes.add new DocSideBox("Summary", html_toc)
216 end
217
218 # Build page content template.
219 fun init_content(v: RenderHTMLPhase, doc: DocModel) do
220 root.init_html_render(v, doc, self)
221 end
222 end
223
224 redef class OverviewPage
225 redef var html_url = "index.html"
226
227 redef fun init_title(v, doc) do
228 title = "Overview"
229 if v.ctx.opt_custom_title.value != null then
230 title = v.ctx.opt_custom_title.value.to_s
231 end
232 end
233
234 # TODO this should be done in StructurePhase.
235 redef fun init_content(v, doc) do
236 # intro text
237 var section = new TplSection.with_title("overview", title)
238 var article = new TplArticle("intro")
239 if v.ctx.opt_custom_intro.value != null then
240 article.content = v.ctx.opt_custom_intro.value.to_s
241 end
242 section.add_child article
243 # Projects list
244 var mprojects = doc.model.mprojects.to_a
245 var sorter = new MConcernRankSorter
246 sorter.sort mprojects
247 var ssection = new TplSection.with_title("projects", "Projects")
248 for mproject in mprojects do
249 var sarticle = new TplArticle(mproject.nitdoc_id)
250 var title = new Template
251 title.add mproject.html_icon
252 title.add mproject.html_link
253 sarticle.title = title
254 sarticle.title_classes.add "signature"
255 sarticle.summary_title = mproject.html_name
256 sarticle.subtitle = mproject.html_declaration
257 var comment = mproject.html_short_comment
258 if comment != null then
259 sarticle.content = comment
260 end
261 ssection.add_child sarticle
262 end
263 section.add_child ssection
264 self.add_section section
265 end
266 end
267
268 redef class SearchPage
269 redef var html_url = "search.html"
270 redef fun init_title(v, doc) do title = "Index"
271
272 redef fun init_topmenu(v, doc) do
273 super
274 topmenu.active_item = topmenu.items.last
275 end
276
277 redef fun init_sidebar(v, doc) do end
278
279 # TODO this should be done in StructurePhase.
280 redef fun init_content(v, doc) do
281 var tpl = new TplSearchPage("search_all")
282 var section = new TplSection("search")
283 # title
284 tpl.title = "Index"
285 # modules list
286 for mmodule in modules_list(v, doc) do
287 tpl.modules.add mmodule.html_link
288 end
289 # classes list
290 for mclass in classes_list(v, doc) do
291 tpl.classes.add mclass.html_link
292 end
293 # properties list
294 for mproperty in mprops_list(v, doc) do
295 var m = new Template
296 m.add mproperty.intro.html_link
297 m.add " ("
298 m.add mproperty.intro.mclassdef.mclass.html_link
299 m.add ")"
300 tpl.props.add m
301 end
302 section.add_child tpl
303 self.add_section section
304 end
305
306 # Extract mmodule list to display (sorted by name)
307 private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
308 var sorted = new Array[MModule]
309 for mmodule in doc.model.mmodule_importation_hierarchy do
310 if mmodule.is_fictive or mmodule.is_test_suite then continue
311 sorted.add mmodule
312 end
313 v.name_sorter.sort(sorted)
314 return sorted
315 end
316
317 # Extract mclass list to display (sorted by name)
318 private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
319 var sorted = doc.mclasses.to_a
320 v.name_sorter.sort(sorted)
321 return sorted
322 end
323
324 # Extract mproperty list to display (sorted by name)
325 private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
326 var sorted = doc.mproperties.to_a
327 v.name_sorter.sort(sorted)
328 return sorted
329 end
330 end
331
332 redef class MEntityPage
333 redef var html_url is lazy do return mentity.nitdoc_url
334 redef fun init_title(v, doc) do title = mentity.html_name
335 redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
336 end
337
338 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
339 # doc phases. This is to preserve the compatibility with the current
340 # `doc_templates` module.
341
342 redef class MGroupPage
343 redef fun init_topmenu(v, doc) do
344 super
345 var mproject = mentity.mproject
346 if not mentity.is_root then
347 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
348 end
349 topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
350 topmenu.active_item = topmenu.items.last
351 end
352
353 redef fun init_sidebar(v, doc) do
354 super
355 var mclasses = new HashSet[MClass]
356 mclasses.add_all intros
357 mclasses.add_all redefs
358 if mclasses.is_empty then return
359 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
360
361 var sorted = mclasses.to_a
362 v.name_sorter.sort(sorted)
363 for mclass in sorted do
364 list.add_li tpl_sidebar_item(mclass)
365 end
366 sidebar.boxes.add new DocSideBox("All classes", list)
367 sidebar.boxes.last.is_open = false
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 DocSideBox("All classes", list)
409 sidebar.boxes.last.is_open = false
410 end
411
412 private fun tpl_sidebar_item(def: MClass): TplListItem do
413 var classes = def.intro.css_classes
414 if def.intro_mmodule == self.mentity then
415 classes.add "intro"
416 else
417 classes.add "redef"
418 end
419 var lnk = new Template
420 lnk.add new TplLabel.with_classes(classes)
421 lnk.add def.html_link
422 return new TplListItem.with_content(lnk)
423 end
424 end
425
426 redef class MClassPage
427
428 redef fun init_topmenu(v, doc) do
429 super
430 var mproject = mentity.intro_mmodule.mgroup.mproject
431 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
432 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
433 topmenu.active_item = topmenu.items.last
434 end
435
436 redef fun init_sidebar(v, doc) do
437 super
438 var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
439 var summary = new TplList.with_classes(["list-unstyled"])
440
441 by_kind.sort_groups(v.name_sorter)
442 for g in by_kind.groups do tpl_sidebar_list(g, summary)
443 sidebar.boxes.add new DocSideBox("All properties", summary)
444 sidebar.boxes.last.is_open = false
445 end
446
447 private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
448 if mprops.is_empty then return
449 var entry = new TplListItem.with_content(mprops.title)
450 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
451 for mprop in mprops do
452 list.add_li tpl_sidebar_item(mprop)
453 end
454 entry.append list
455 summary.elts.add entry
456 end
457
458 private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
459 var classes = mprop.intro.css_classes
460 if not mprop_is_local(mprop) then
461 classes.add "inherit"
462 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
463 var def_url = "{cls_url}#{mprop.nitdoc_id}"
464 var lnk = new TplLink(def_url, mprop.html_name)
465 var mdoc = mprop.intro.mdoc_or_fallback
466 if mdoc != null then lnk.title = mdoc.short_comment
467 var item = new Template
468 item.add new TplLabel.with_classes(classes)
469 item.add lnk
470 return new TplListItem.with_content(item)
471 end
472 if mpropdefs.has(mprop.intro) then
473 classes.add "intro"
474 else
475 classes.add "redef"
476 end
477 var lnk = new Template
478 lnk.add new TplLabel.with_classes(classes)
479 lnk.add mprop.html_link_to_anchor
480 return new TplListItem.with_content(lnk)
481 end
482
483 private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
484 var res = new HashSet[MProperty]
485 var local = mentity.local_mproperties(v.ctx.min_visibility)
486 for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
487 if local.has(mprop) then continue
488 #if mprop isa MMethod and mprop.is_init then continue
489 if mprop.intro.mclassdef.mclass.name == "Object" and
490 (mprop.visibility == protected_visibility or
491 mprop.intro.mclassdef.mmodule.name != "kernel") then continue
492 res.add mprop
493 end
494 res.add_all local
495 return res
496 end
497
498 private fun mprop_is_local(mprop: MProperty): Bool do
499 for mpropdef in mprop.mpropdefs do
500 if self.mpropdefs.has(mpropdef) then return true
501 end
502 return false
503 end
504 end
505
506 redef class MPropertyPage
507 redef fun init_title(v, doc) do
508 title = "{mentity.html_name}{mentity.html_short_signature.write_to_string}"
509 end
510
511 redef fun init_topmenu(v, doc) do
512 super
513 var mmodule = mentity.intro_mclassdef.mmodule
514 var mproject = mmodule.mgroup.mproject
515 var mclass = mentity.intro_mclassdef.mclass
516 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
517 topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
518 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
519 topmenu.active_item = topmenu.items.last
520 end
521 end
522
523 redef class DocComposite
524 # Render this DocComposite as HTML.
525 #
526 # FIXME needed to maintain TplSection compatibility.
527 fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
528
529 # Prepares the HTML rendering for this element.
530 #
531 # This visit is mainly used to set template attributes before rendering.
532 fun init_html_render(v: RenderHTMLPhase, doc: DocModel, page: DocPage) do
533 for child in children do child.init_html_render(v, doc, page)
534 end
535 end
536
537 redef class DocRoot
538
539 # Start the rendering from root.
540 #
541 # FIXME needed to maintain TplSection compatibility.
542 fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
543 var section = new TplSection("top")
544 var mentity = page.mentity
545 section.title = mentity.html_name
546 section.subtitle = mentity.html_declaration
547 # FIXME ugly hack to avoid diff
548 if mentity isa MGroup and mentity.is_root then
549 section.title = mentity.mproject.html_name
550 section.subtitle = mentity.mproject.html_declaration
551 else if mentity isa MProperty then
552 section.title = "{mentity.html_name}{mentity.intro.html_signature.write_to_string}"
553 section.subtitle = mentity.html_namespace
554 section.summary_title = mentity.html_name
555 end
556 render(v, doc, page, section)
557 return section
558 end
559
560 redef fun render(v, doc, page, parent) do
561 for child in children do
562 child.render(v, doc, page, parent)
563 end
564 end
565 end
566
567 redef class ConcernSection
568 redef fun render(v, doc, page, parent) do
569 var section = new TplSection(mentity.nitdoc_id)
570 var mentity = self.mentity
571 # FIXME hideous hacks to avoid diff
572 if page.mentity isa MModule and mentity isa MModule then
573 render_concern_mmodule(page, section, mentity)
574 else if page.mentity isa MClass and mentity isa MModule then
575 render_concern_other(page, section, mentity)
576 else if page.mentity isa MProperty and mentity isa MModule then
577 render_concern_other(page, section, mentity)
578 end
579 for child in children do
580 child.render(v, doc, page, section)
581 end
582 parent.add_child section
583 end
584
585 private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
586 var title = new Template
587 if mmodule == page.mentity then
588 title.add "in "
589 section.summary_title = "in {mmodule.html_name}"
590 else
591 title.add "from "
592 section.summary_title = "from {mmodule.html_name}"
593 end
594 title.add mmodule.html_namespace
595 section.title = title
596 end
597
598 private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
599 var title = new Template
600 title.add "in "
601 title.add mmodule.html_namespace
602 section.title = title
603 section.summary_title = "in {mmodule.html_name}"
604 end
605 end
606
607 redef class MEntitySection
608 redef fun render(v, doc, page, parent) do
609 for child in children do child.render(v, doc, page, parent)
610 end
611 end
612
613 redef class IntroArticle
614 redef fun render(v, doc, page, parent) do
615 var article = new TplArticle("intro")
616 var mentity = self.mentity
617 if mentity isa MModule then
618 article.source_link = v.tpl_showsource(mentity.location)
619 else if mentity isa MClassDef then
620 article.source_link = v.tpl_showsource(mentity.location)
621 else if mentity isa MPropDef then
622 article.source_link = v.tpl_showsource(mentity.location)
623 end
624 # article.subtitle = mentity.html_declaration
625 article.content = write_to_string
626 parent.add_child article
627 end
628 end
629
630 redef class ConcernsArticle
631 redef fun render(v, doc, page, parent) do
632 parent.add_child new TplArticle.
633 with_content("concerns", "Concerns", write_to_string)
634 end
635 end
636
637 redef class DefinitionArticle
638 redef fun render(v, doc, page, parent) do
639 var title = new Template
640 title.add mentity.html_icon
641 title.add mentity.html_name
642
643 var article = new TplArticle(mentity.nitdoc_id)
644 article.title = title
645 article.title_classes.add "signature"
646 article.subtitle = mentity.html_declaration
647 article.summary_title = mentity.html_name
648 article.content = write_to_string
649
650 # FIXME less hideous hacks...
651 var mentity = self.mentity
652 if mentity isa MModule then
653 title = new Template
654 title.add mentity.html_icon
655 title.add mentity.html_namespace
656 article.title = title
657 else if mentity isa MClass then
658 title = new Template
659 title.add mentity.html_icon
660 title.add mentity.html_link
661 article.title = title
662 article.subtitle = mentity.html_namespace
663 article.content = null
664 else if mentity isa MClassDef then
665 title = new Template
666 title.add "in "
667 title.add mentity.mmodule.html_namespace
668 article.title = mentity.html_declaration
669 article.subtitle = title
670 article.source_link = v.tpl_showsource(mentity.location)
671 if mentity.is_intro and mentity.mmodule != page.mentity then
672 article.content = mentity.html_short_comment
673 end
674 if page isa MModulePage then is_toc_hidden = true
675 else if mentity isa MPropDef then
676 if page.mentity isa MClass then
677 title = new Template
678 title.add mentity.html_icon
679 title.add mentity.html_declaration
680 article.title = title
681 article.subtitle = mentity.html_namespace
682 # TODO move in its own phase? let's see after doc_template refactoring.
683 # Add linearization
684 var all_defs = new HashSet[MPropDef]
685 for local_def in local_defs(page.as(MClassPage), mentity.mproperty) do
686 all_defs.add local_def
687 var smpropdef = local_def
688 while not smpropdef.is_intro do
689 smpropdef = smpropdef.lookup_next_definition(
690 doc.mainmodule, smpropdef.mclassdef.bound_mtype)
691 all_defs.add smpropdef
692 end
693 end
694 var lin = all_defs.to_a
695 doc.mainmodule.linearize_mpropdefs(lin)
696 if lin.length > 1 then
697 var lin_article = new TplArticle("{mentity.nitdoc_id}.lin")
698 lin_article.title = "Inheritance"
699 var lst = new UnorderedList
700 lst.css_classes.add("list-unstyled list-labeled")
701 for smpropdef in lin do
702 lst.add_li tpl_inheritance_item(smpropdef)
703 end
704 lin_article.content = lst
705 article.add_child lin_article
706 end
707 else
708 title = new Template
709 title.add "in "
710 title.add mentity.mclassdef.html_link
711 article.title = title
712 toc_title = "in {mentity.mclassdef.html_name}"
713 end
714 article.source_link = v.tpl_showsource(mentity.location)
715 end
716 for child in children do
717 child.render(v, doc, page, article)
718 end
719 parent.add_child article
720 end
721
722 # Filter `page.mpropdefs` for this `mpropertie`.
723 #
724 # FIXME compatability with current templates.
725 private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
726 var mpropdefs = new HashSet[MPropDef]
727 for mpropdef in page.mpropdefs do
728 if mpropdef.mproperty == mproperty then
729 mpropdefs.add mpropdef
730 end
731 end
732 return mpropdefs
733 end
734
735 private fun tpl_inheritance_item(mpropdef: MPropDef): ListItem do
736 var lnk = new Template
737 lnk.add new TplLabel.with_classes(css_classes)
738 lnk.add mpropdef.mclassdef.mmodule.html_namespace
739 lnk.add "::"
740 var atext = mpropdef.mclassdef.html_link.text
741 var ahref = "{mpropdef.mclassdef.mclass.nitdoc_url}#{mpropdef.mproperty.nitdoc_id}"
742 var atitle = mpropdef.mclassdef.html_link.title
743 var anchor = new Link.with_title(ahref, atext, atitle)
744 lnk.add anchor
745 var comment = mpropdef.html_short_comment
746 if comment != null then
747 lnk.add ": "
748 lnk.add comment
749 end
750 var li = new ListItem(lnk)
751 li.css_classes.add "signature"
752 return li
753 end
754 end
755
756 redef class IntrosRedefsListArticle
757 redef fun render(v, doc, page, parent) do
758 if mentities.is_empty then return
759 var article = new TplArticle.with_title(list_title.to_lower, list_title)
760 article.content = write_to_string
761 parent.add_child article
762 end
763 end
764
765 # FIXME compatibility with doc_templates.
766 redef class ImportationListSection
767 redef fun render(v, doc, page, parent) do
768 var section = new TplSection.with_title("dependencies", "Dependencies")
769 for child in children do
770 child.render(v, doc, page, section)
771 end
772 parent.add_child section
773 end
774 end
775
776 # FIXME compatibility with doc_templates.
777 redef class InheritanceListSection
778 redef fun render(v, doc, page, parent) do
779 var section = new TplSection.with_title("inheritance", "Inheritance")
780 for child in children do
781 child.render(v, doc, page, section)
782 end
783 parent.add_child section
784 end
785 end
786
787 # FIXME compatibility with doc_templates.
788 redef class HierarchyListArticle
789 redef fun render(v, doc, page, parent) do
790 if mentities.is_empty then return
791 var article = new TplArticle.with_title(list_title.to_lower, list_title)
792 article.content = write_to_string
793 parent.add_child article
794 end
795 end
796
797 redef class GraphArticle
798 redef fun render(v, doc, page, parent) do
799 var output_dir = v.ctx.output_dir
800 var path = output_dir / id
801 var path_sh = path.escape_to_sh
802 var file = new FileWriter.open("{path}.dot")
803 file.write(dot)
804 file.close
805 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 ; \}")
806 var fmap = new FileReader.open("{path}.map")
807 map = fmap.read_all
808 fmap.close
809
810 var article = new TplArticle("graph")
811 article.css_classes.add "text-center"
812 article.content = write_to_string
813 parent.add_child article
814 end
815 end
816
817 redef class Location
818 # Github url based on this location
819 fun github(gitdir: String): String do
820 var base_dir = getcwd.join_path(gitdir).simplify_path
821 var file_loc = getcwd.join_path(file.filename).simplify_path
822 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
823 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
824 end
825 end