src/doc: move HTML output related services from `doc_model` to `html_model`
[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 "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.page_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): TplPage 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 # build page
167 var tpl = new TplPage
168 tpl.title = tpl_title(v, doc)
169 tpl.url = page_url
170 tpl.shareurl = shareurl
171 tpl.topmenu = tpl_topmenu(v, doc)
172 tpl.add_section tpl_content(v, doc)
173 tpl.footer = v.ctx.opt_custom_footer.value
174 tpl.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
175 tpl.sidebar = tpl_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 tpl.scripts.add new TplPiwikScript(tracker_url, site_id)
182 end
183 return tpl
184 end
185
186 # FIXME diff hack
187 # all properties below are roughly copied from `doc_pages`
188
189 # URL to this page.
190 fun page_url: String is abstract
191
192 # Build page sidebar if any
193 fun tpl_sidebar(v: RenderHTMLPhase, doc: DocModel): nullable TplSidebar do return null
194
195 # Build page title string
196 fun tpl_title(v: RenderHTMLPhase, doc: DocModel): String do
197 if v.ctx.opt_custom_title.value != null then
198 return v.ctx.opt_custom_title.value.to_s
199 end
200 return "Nitdoc"
201 end
202
203 # Build top menu template
204 fun tpl_topmenu(v: RenderHTMLPhase, doc: DocModel): TplTopMenu do
205 var topmenu = new TplTopMenu(page_url)
206 var brand = v.ctx.opt_custom_brand.value
207 if brand != null then
208 var tpl = new Template
209 tpl.add "<span class='navbar-brand'>"
210 tpl.add brand
211 tpl.add "</span>"
212 topmenu.brand = tpl
213 end
214 topmenu.add_link new TplLink("index.html", "Overview")
215 topmenu.add_link new TplLink("search.html", "Index")
216 return topmenu
217 end
218
219 # Build page content template
220 fun tpl_content(v: RenderHTMLPhase, doc: DocModel): TplSection is abstract
221 end
222
223 redef class OverviewPage
224 redef fun page_url do return "index.html"
225
226 redef fun tpl_title(v, doc) do
227 if v.ctx.opt_custom_title.value != null then
228 return v.ctx.opt_custom_title.value.to_s
229 else
230 return "Overview"
231 end
232 end
233
234 # TODO this should be done in StructurePhase.
235 redef fun tpl_content(v, doc) do
236 # intro text
237 var section = new TplSection.with_title("overview", tpl_title(v, doc))
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 = mproject.tpl_article
250 sarticle.subtitle = mproject.tpl_declaration
251 sarticle.content = mproject.tpl_definition
252 var mdoc = mproject.mdoc_or_fallback
253 if mdoc != null then
254 sarticle.content = mdoc.tpl_short_comment
255 end
256 ssection.add_child sarticle
257 end
258 section.add_child ssection
259 return section
260 end
261
262 redef fun tpl_sidebar(v, doc) do return new TplSidebar
263 end
264
265 redef class SearchPage
266 redef fun page_url do return "search.html"
267 redef fun tpl_title(v, doc) do return "Index"
268
269 # TODO this should be done in StructurePhase.
270 redef fun tpl_content(v, doc) do
271 var tpl = new TplSearchPage("search_all")
272 var section = new TplSection("search")
273 # title
274 tpl.title = "Index"
275 # modules list
276 for mmodule in modules_list(v, doc) do
277 tpl.modules.add mmodule.tpl_link
278 end
279 # classes list
280 for mclass in classes_list(v, doc) do
281 tpl.classes.add mclass.tpl_link
282 end
283 # properties list
284 for mproperty in mprops_list(v, doc) do
285 var m = new Template
286 m.add mproperty.intro.tpl_link
287 m.add " ("
288 m.add mproperty.intro.mclassdef.mclass.tpl_link
289 m.add ")"
290 tpl.props.add m
291 end
292 section.add_child tpl
293 return section
294 end
295
296 # Extract mmodule list to display (sorted by name)
297 private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
298 var sorted = new Array[MModule]
299 for mmodule in doc.model.mmodule_importation_hierarchy do
300 if mmodule.is_fictive or mmodule.is_test_suite then continue
301 sorted.add mmodule
302 end
303 v.name_sorter.sort(sorted)
304 return sorted
305 end
306
307 # Extract mclass list to display (sorted by name)
308 private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
309 var sorted = doc.mclasses.to_a
310 v.name_sorter.sort(sorted)
311 return sorted
312 end
313
314 # Extract mproperty list to display (sorted by name)
315 private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
316 var sorted = doc.mproperties.to_a
317 v.name_sorter.sort(sorted)
318 return sorted
319 end
320 end
321
322 redef class MEntityPage
323 redef fun page_url do return mentity.nitdoc_url
324 redef fun tpl_title(v, doc) do return mentity.nitdoc_name
325 redef fun tpl_content(v, doc) do return root.start_rendering(v, doc, self)
326 end
327
328 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
329 # doc phases. This is to preserve the compatibility with the current
330 # `doc_templates` module.
331
332 redef class MGroupPage
333 redef fun tpl_topmenu(v, doc) do
334 var topmenu = super
335 var mproject = mentity.mproject
336 if not mentity.is_root then
337 topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
338 end
339 topmenu.add_link new TplLink(page_url, mproject.nitdoc_name)
340 return topmenu
341 end
342
343 redef fun tpl_sidebar(v, doc) do
344 var sidebar = new TplSidebar
345 var mclasses = new HashSet[MClass]
346 mclasses.add_all intros
347 mclasses.add_all redefs
348 if mclasses.is_empty then return sidebar
349 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
350
351 var sorted = mclasses.to_a
352 v.name_sorter.sort(sorted)
353 for mclass in sorted do
354 list.add_li tpl_sidebar_item(mclass)
355 end
356 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
357 return sidebar
358 end
359
360 private fun tpl_sidebar_item(def: MClass): TplListItem do
361 var classes = def.intro.tpl_css_classes.to_a
362 if intros.has(def) then
363 classes.add "intro"
364 else
365 classes.add "redef"
366 end
367 var lnk = new Template
368 lnk.add new TplLabel.with_classes(classes)
369 lnk.add def.tpl_link
370 return new TplListItem.with_content(lnk)
371 end
372 end
373
374 redef class MModulePage
375 redef fun tpl_topmenu(v, doc) do
376 var topmenu = super
377 var mproject = mentity.mproject
378 topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
379 topmenu.add_link new TplLink(mentity.nitdoc_url, mentity.nitdoc_name)
380 return topmenu
381 end
382
383 # Class list to display in sidebar
384 redef fun tpl_sidebar(v, doc) do
385 # TODO filter here?
386 var sidebar = new TplSidebar
387 var mclasses = new HashSet[MClass]
388 mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
389 mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
390 if mclasses.is_empty then return sidebar
391 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
392
393 var sorted = mclasses.to_a
394 v.name_sorter.sort(sorted)
395 for mclass in sorted do
396 list.add_li tpl_sidebar_item(mclass)
397 end
398 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
399 return sidebar
400 end
401
402 private fun tpl_sidebar_item(def: MClass): TplListItem do
403 var classes = def.intro.tpl_css_classes.to_a
404 if def.intro_mmodule == self.mentity then
405 classes.add "intro"
406 else
407 classes.add "redef"
408 end
409 var lnk = new Template
410 lnk.add new TplLabel.with_classes(classes)
411 lnk.add def.tpl_link
412 return new TplListItem.with_content(lnk)
413 end
414 end
415
416 redef class MClassPage
417
418 redef fun tpl_title(v, doc) do
419 return "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
420 end
421
422 redef fun tpl_topmenu(v, doc) do
423 var topmenu = super
424 var mproject = mentity.intro_mmodule.mgroup.mproject
425 topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
426 topmenu.add_link new TplLink(page_url, mentity.nitdoc_name)
427 return topmenu
428 end
429
430 redef fun tpl_sidebar(v, doc) do
431 var sidebar = new TplSidebar
432 var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
433 var summary = new TplList.with_classes(["list-unstyled"])
434
435 by_kind.sort_groups(v.name_sorter)
436 for g in by_kind.groups do tpl_sidebar_list(g, summary)
437 sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
438 return sidebar
439 end
440
441 private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
442 if mprops.is_empty then return
443 var entry = new TplListItem.with_content(mprops.title)
444 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
445 for mprop in mprops do
446 list.add_li tpl_sidebar_item(mprop)
447 end
448 entry.append list
449 summary.elts.add entry
450 end
451
452 private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
453 var classes = mprop.intro.tpl_css_classes.to_a
454 if not mprop_is_local(mprop) then
455 classes.add "inherit"
456 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
457 var def_url = "{cls_url}#{mprop.nitdoc_id}"
458 var lnk = new TplLink(def_url, mprop.nitdoc_name)
459 var mdoc = mprop.intro.mdoc_or_fallback
460 if mdoc != null then lnk.title = mdoc.short_comment
461 var item = new Template
462 item.add new TplLabel.with_classes(classes)
463 item.add lnk
464 return new TplListItem.with_content(item)
465 end
466 if mpropdefs.has(mprop.intro) then
467 classes.add "intro"
468 else
469 classes.add "redef"
470 end
471 var lnk = new Template
472 lnk.add new TplLabel.with_classes(classes)
473 lnk.add mprop.tpl_anchor
474 return new TplListItem.with_content(lnk)
475 end
476
477 private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
478 var res = new HashSet[MProperty]
479 var local = mentity.local_mproperties(v.ctx.min_visibility)
480 for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
481 if local.has(mprop) then continue
482 #if mprop isa MMethod and mprop.is_init then continue
483 if mprop.intro.mclassdef.mclass.name == "Object" and
484 (mprop.visibility == protected_visibility or
485 mprop.intro.mclassdef.mmodule.name != "kernel") then continue
486 res.add mprop
487 end
488 res.add_all local
489 return res
490 end
491
492 private fun mprop_is_local(mprop: MProperty): Bool do
493 for mpropdef in mprop.mpropdefs do
494 if self.mpropdefs.has(mpropdef) then return true
495 end
496 return false
497 end
498 end
499
500 redef class MPropertyPage
501 redef fun tpl_topmenu(v, doc) do
502 var topmenu = super
503 var mmodule = mentity.intro_mclassdef.mmodule
504 var mproject = mmodule.mgroup.mproject
505 var mclass = mentity.intro_mclassdef.mclass
506 topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
507 topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
508 topmenu.add_link new TplLink(page_url, mentity.nitdoc_name)
509 return topmenu
510 end
511
512 redef fun tpl_title(v, doc) do
513 return "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
514 end
515
516 redef fun tpl_sidebar(v, doc) do return new TplSidebar
517 end
518
519 redef class DocComposite
520 # Render this DocComposite as HTML.
521 #
522 # FIXME needed to maintain TplSection compatibility.
523 fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
524 end
525
526 redef class DocRoot
527
528 # Start the rendering from root.
529 #
530 # FIXME needed to maintain TplSection compatibility.
531 fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
532 var section = new TplSection("top")
533 var mentity = page.mentity
534 section.title = mentity.nitdoc_name
535 section.subtitle = mentity.tpl_declaration
536 # FIXME ugly hack to avoid diff
537 if mentity isa MGroup and mentity.is_root then
538 section.title = mentity.mproject.nitdoc_name
539 section.subtitle = mentity.mproject.tpl_declaration
540 else if mentity isa MClass then
541 section.title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
542 else if mentity isa MProperty then
543 section.title = "{mentity.nitdoc_name}{mentity.intro.tpl_signature.write_to_string}"
544 section.subtitle = mentity.tpl_namespace
545 section.summary_title = mentity.nitdoc_name
546 end
547 render(v, doc, page, section)
548 return section
549 end
550
551 redef fun render(v, doc, page, parent) do
552 for child in children do
553 child.render(v, doc, page, parent)
554 end
555 end
556 end
557
558 redef class ConcernSection
559 redef fun render(v, doc, page, parent) do
560 var section = new TplSection(mentity.nitdoc_id)
561 var mentity = self.mentity
562 # FIXME hideous hacks to avoid diff
563 if page.mentity isa MModule and mentity isa MModule then
564 render_concern_mmodule(page, section, mentity)
565 else if page.mentity isa MClass and mentity isa MModule then
566 render_concern_other(page, section, mentity)
567 else if page.mentity isa MProperty and mentity isa MModule then
568 render_concern_other(page, section, mentity)
569 end
570 for child in children do
571 child.render(v, doc, page, section)
572 end
573 parent.add_child section
574 end
575
576 private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
577 var title = new Template
578 if mmodule == page.mentity then
579 title.add "in "
580 section.summary_title = "in {mmodule.nitdoc_name}"
581 else
582 title.add "from "
583 section.summary_title = "from {mmodule.nitdoc_name}"
584 end
585 title.add mmodule.tpl_namespace
586 section.title = title
587 end
588
589 private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
590 var title = new Template
591 title.add "in "
592 title.add mmodule.tpl_namespace
593 section.title = title
594 section.summary_title = "in {mmodule.nitdoc_name}"
595 end
596 end
597
598 redef class IntroArticle
599 redef fun render(v, doc, page, parent) do
600 var article = new TplArticle("intro")
601 var mentity = self.mentity
602 if mentity isa MModule then
603 article.source_link = v.tpl_showsource(mentity.location)
604 else if mentity isa MClassDef then
605 article.source_link = v.tpl_showsource(mentity.location)
606 else if mentity isa MPropDef then
607 article.source_link = v.tpl_showsource(mentity.location)
608 end
609 # article.subtitle = mentity.tpl_declaration
610 # FIXME diff hack
611 if mentity isa MProperty then
612 # intro title
613 var ns = mentity.intro.mclassdef.mmodule.tpl_namespace
614 var section = new TplSection("intro")
615 var title = new Template
616 title.add "Introduction in "
617 title.add ns
618 section.title = title
619 section.summary_title = "Introduction"
620 var intro = mentity.intro.tpl_article
621 intro.source_link = v.tpl_showsource(mentity.intro.location)
622 section.add_child intro
623 parent.add_child section
624 else
625 article.content = mentity.tpl_definition
626 parent.add_child article
627 end
628 end
629 end
630
631 redef class ConcernsArticle
632 redef fun render(v, doc, page, parent) do
633 # FIXME diff hack
634 var title = "concerns"
635 if page.mentity isa MProperty then title = "Concerns"
636 parent.add_child new TplArticle.
637 with_content(title, "Concerns", concerns.to_tpl)
638 end
639 end
640
641 redef class DefinitionArticle
642 redef fun render(v, doc, page, parent) do
643 var article: TplArticle
644 var mentity = self.mentity
645 # FIXME hideous hacks...
646 if mentity isa MModule then
647 article = mentity.tpl_article
648 article.subtitle = mentity.tpl_declaration
649 article.content = mentity.tpl_definition
650 else if mentity isa MClass then
651 article = make_mclass_article(v, page)
652 else if mentity isa MClassDef then
653 article = make_mclassdef_article(v, page)
654 article.source_link = v.tpl_showsource(mentity.location)
655 else if mentity isa MPropDef and page.mentity isa MClass then
656 article = make_mpropdef_article(v, doc, page)
657 else
658 article = mentity.tpl_article
659 article.subtitle = mentity.tpl_declaration
660 if mentity isa MPropDef then
661 article.source_link = v.tpl_showsource(mentity.location)
662 end
663 if not mentity isa MVirtualTypeProp then
664 # article.content = mentity.tpl_comment
665 end
666 end
667 for child in children do
668 child.render(v, doc, page, article)
669 end
670 parent.add_child article
671 end
672
673 # FIXME avoid diff while preserving TplArticle compatibility.
674
675 private fun make_mclass_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
676 var article = mentity.tpl_article
677 article.subtitle = mentity.tpl_namespace
678 article.content = null
679 return article
680 end
681
682 private fun make_mclassdef_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
683 var mclassdef = mentity.as(MClassDef)
684 var article = mentity.tpl_article
685 if mclassdef.is_intro and mclassdef.mmodule != page.mentity then
686 article = mentity.tpl_short_article
687 end
688 var title = new Template
689 title.add "in "
690 title.add mclassdef.mmodule.tpl_namespace
691 article.subtitle = title
692 return article
693 end
694
695 private fun make_mpropdef_article(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplArticle
696 do
697 var mpropdef = mentity.as(MPropDef)
698 var mprop = mpropdef.mproperty
699 var article = new TplArticle(mprop.nitdoc_id)
700 var title = new Template
701 title.add mprop.tpl_icon
702 title.add "<span id='{mpropdef.nitdoc_id}'></span>"
703 if mpropdef.is_intro then
704 title.add mprop.tpl_link
705 title.add mprop.intro.tpl_signature
706 else
707 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
708 var def_url = "{cls_url}#{mprop.nitdoc_id}"
709 var lnk = new TplLink.with_title(def_url, mprop.nitdoc_name,
710 "Go to introduction")
711 title.add "redef "
712 title.add lnk
713 end
714 article.title = title
715 article.title_classes.add "signature"
716 article.summary_title = "{mprop.nitdoc_name}"
717 article.subtitle = mpropdef.tpl_namespace
718 if mpropdef.mdoc_or_fallback != null then
719 article.content = mpropdef.mdoc_or_fallback.tpl_comment
720 end
721 # TODO move in its own phase? let's see after doc_template refactoring.
722 # Add linearization
723 var all_defs = new HashSet[MPropDef]
724 for local_def in local_defs(page.as(MClassPage), mprop) do
725 all_defs.add local_def
726 var smpropdef = local_def
727 while not smpropdef.is_intro do
728 smpropdef = smpropdef.lookup_next_definition(
729 doc.mainmodule, smpropdef.mclassdef.bound_mtype)
730 all_defs.add smpropdef
731 end
732 end
733 var lin = all_defs.to_a
734 doc.mainmodule.linearize_mpropdefs(lin)
735 if lin.length > 1 then
736 var lin_article = new TplArticle("{mpropdef.nitdoc_id}.lin")
737 lin_article.title = "Inheritance"
738 var lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
739 for smpropdef in lin do
740 lst.add_li smpropdef.tpl_inheritance_item
741 end
742 lin_article.content = lst
743 article.add_child lin_article
744 end
745 return article
746 end
747
748 # Filter `page.mpropdefs` for this `mpropertie`.
749 #
750 # FIXME compatability with current templates.
751 private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
752 var mpropdefs = new HashSet[MPropDef]
753 for mpropdef in page.mpropdefs do
754 if mpropdef.mproperty == mproperty then
755 mpropdefs.add mpropdef
756 end
757 end
758 return mpropdefs
759 end
760 end
761
762 redef class IntrosRedefsListArticle
763 redef fun render(v, doc, page, parent) do
764 if mentities.is_empty then return
765 var title = list_title
766 # FIXME diff hack
767 var id = "intros"
768 if title == "Redefines" then id = "redefs"
769 var article = new TplArticle.with_title("{mentity.nitdoc_id}.{id}", title)
770 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
771 for mentity in mentities do
772 list.add_li mentity.tpl_list_item
773 end
774 article.content = list
775 parent.add_child article
776 end
777 end
778
779 # FIXME compatibility with doc_templates.
780 redef class ImportationListSection
781 redef fun render(v, doc, page, parent) do
782 var section = new TplSection.with_title("dependencies", "Dependencies")
783 for child in children do
784 child.render(v, doc, page, section)
785 end
786 parent.add_child section
787 end
788 end
789
790 # FIXME compatibility with doc_templates.
791 redef class InheritanceListSection
792 redef fun render(v, doc, page, parent) do
793 var section = new TplSection.with_title("inheritance", "Inheritance")
794 for child in children do
795 child.render(v, doc, page, section)
796 end
797 parent.add_child section
798 end
799 end
800
801 # FIXME compatibility with doc_templates.
802 redef class HierarchyListArticle
803 redef fun render(v, doc, page, parent) do
804 if mentities.is_empty then return
805 var title = list_title
806 var id = list_title.to_lower
807 var article = new TplArticle.with_title(id, title)
808 var list = new TplList.with_classes(["list-unstyled", "list-definition"])
809 for mentity in mentities do
810 list.elts.add mentity.tpl_list_item
811 end
812 article.content = list
813 parent.add_child article
814 end
815 end
816
817 redef class GraphArticle
818 redef fun render(v, doc, page, parent) do
819 var output_dir = v.ctx.output_dir
820 var path = output_dir / id
821 var path_sh = path.escape_to_sh
822 var file = new FileWriter.open("{path}.dot")
823 file.write(dot)
824 file.close
825 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 ; \}")
826 var fmap = new FileReader.open("{path}.map")
827 var map = fmap.read_all
828 fmap.close
829
830 var article = new TplArticle("graph")
831 var alt = ""
832 # FIXME diff hack
833 # if title != null then
834 # article.title = title
835 # alt = "alt='{title.html_escape}'"
836 # end
837 article.css_classes.add "text-center"
838 var content = new Template
839 var name_html = id.html_escape
840 content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
841 content.add map
842 article.content = content
843 parent.add_child article
844 end
845 end