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