src/doc: move components generation from `doc_model` to `doc_html` phase
[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 end
219 end
220
221 redef class OverviewPage
222 redef var html_url = "index.html"
223
224 redef fun init_title(v, doc) do
225 title = "Overview"
226 if v.ctx.opt_custom_title.value != null then
227 title = v.ctx.opt_custom_title.value.to_s
228 end
229 end
230
231 # TODO this should be done in StructurePhase.
232 redef fun init_content(v, doc) do
233 # intro text
234 var section = new TplSection.with_title("overview", title)
235 var article = new TplArticle("intro")
236 if v.ctx.opt_custom_intro.value != null then
237 article.content = v.ctx.opt_custom_intro.value.to_s
238 end
239 section.add_child article
240 # Projects list
241 var mprojects = doc.model.mprojects.to_a
242 var sorter = new MConcernRankSorter
243 sorter.sort mprojects
244 var ssection = new TplSection.with_title("projects", "Projects")
245 for mproject in mprojects do
246 var sarticle = mproject.tpl_article
247 sarticle.subtitle = mproject.html_declaration
248 sarticle.content = mproject.tpl_definition
249 var mdoc = mproject.mdoc_or_fallback
250 if mdoc != null then
251 sarticle.content = mdoc.tpl_short_comment
252 end
253 ssection.add_child sarticle
254 end
255 section.add_child ssection
256 self.add_section section
257 end
258
259 redef fun init_sidebar(v, doc) do sidebar = new TplSidebar
260 end
261
262 redef class SearchPage
263 redef var html_url = "search.html"
264 redef fun init_title(v, doc) do title = "Index"
265
266 redef fun init_topmenu(v, doc) do
267 super
268 topmenu.active_item = topmenu.items.last
269 end
270
271 redef fun init_sidebar(v, doc) do end
272
273 # TODO this should be done in StructurePhase.
274 redef fun init_content(v, doc) do
275 var tpl = new TplSearchPage("search_all")
276 var section = new TplSection("search")
277 # title
278 tpl.title = "Index"
279 # modules list
280 for mmodule in modules_list(v, doc) do
281 tpl.modules.add mmodule.html_link
282 end
283 # classes list
284 for mclass in classes_list(v, doc) do
285 tpl.classes.add mclass.html_link
286 end
287 # properties list
288 for mproperty in mprops_list(v, doc) do
289 var m = new Template
290 m.add mproperty.intro.html_link
291 m.add " ("
292 m.add mproperty.intro.mclassdef.mclass.html_link
293 m.add ")"
294 tpl.props.add m
295 end
296 section.add_child tpl
297 self.add_section section
298 end
299
300 # Extract mmodule list to display (sorted by name)
301 private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
302 var sorted = new Array[MModule]
303 for mmodule in doc.model.mmodule_importation_hierarchy do
304 if mmodule.is_fictive or mmodule.is_test_suite then continue
305 sorted.add mmodule
306 end
307 v.name_sorter.sort(sorted)
308 return sorted
309 end
310
311 # Extract mclass list to display (sorted by name)
312 private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
313 var sorted = doc.mclasses.to_a
314 v.name_sorter.sort(sorted)
315 return sorted
316 end
317
318 # Extract mproperty list to display (sorted by name)
319 private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
320 var sorted = doc.mproperties.to_a
321 v.name_sorter.sort(sorted)
322 return sorted
323 end
324 end
325
326 redef class MEntityPage
327 redef var html_url is lazy do return mentity.nitdoc_url
328 redef fun init_title(v, doc) do title = mentity.html_name
329 redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
330 end
331
332 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
333 # doc phases. This is to preserve the compatibility with the current
334 # `doc_templates` module.
335
336 redef class MGroupPage
337 redef fun init_topmenu(v, doc) do
338 super
339 var mproject = mentity.mproject
340 if not mentity.is_root then
341 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
342 end
343 topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
344 topmenu.active_item = topmenu.items.last
345 end
346
347 redef fun init_sidebar(v, doc) do
348 super
349 var mclasses = new HashSet[MClass]
350 mclasses.add_all intros
351 mclasses.add_all redefs
352 if mclasses.is_empty then return
353 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
354
355 var sorted = mclasses.to_a
356 v.name_sorter.sort(sorted)
357 for mclass in sorted do
358 list.add_li tpl_sidebar_item(mclass)
359 end
360 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
361 end
362
363 private fun tpl_sidebar_item(def: MClass): TplListItem do
364 var classes = def.intro.tpl_css_classes.to_a
365 if intros.has(def) then
366 classes.add "intro"
367 else
368 classes.add "redef"
369 end
370 var lnk = new Template
371 lnk.add new TplLabel.with_classes(classes)
372 lnk.add def.html_link
373 return new TplListItem.with_content(lnk)
374 end
375 end
376
377 redef class MModulePage
378 redef fun init_topmenu(v, doc) do
379 super
380 var mproject = mentity.mproject
381 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
382 topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
383 topmenu.active_item = topmenu.items.last
384 end
385
386 # Class list to display in sidebar
387 redef fun init_sidebar(v, doc) do
388 # TODO filter here?
389 super
390 var mclasses = new HashSet[MClass]
391 mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
392 mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
393 if mclasses.is_empty then return
394 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
395
396 var sorted = mclasses.to_a
397 v.name_sorter.sort(sorted)
398 for mclass in sorted do
399 list.add_li tpl_sidebar_item(mclass)
400 end
401 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
402 end
403
404 private fun tpl_sidebar_item(def: MClass): TplListItem do
405 var classes = def.intro.tpl_css_classes.to_a
406 if def.intro_mmodule == self.mentity then
407 classes.add "intro"
408 else
409 classes.add "redef"
410 end
411 var lnk = new Template
412 lnk.add new TplLabel.with_classes(classes)
413 lnk.add def.html_link
414 return new TplListItem.with_content(lnk)
415 end
416 end
417
418 redef class MClassPage
419
420 redef fun init_topmenu(v, doc) do
421 super
422 var mproject = mentity.intro_mmodule.mgroup.mproject
423 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
424 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
425 topmenu.active_item = topmenu.items.last
426 end
427
428 redef fun init_sidebar(v, doc) do
429 super
430 var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
431 var summary = new TplList.with_classes(["list-unstyled"])
432
433 by_kind.sort_groups(v.name_sorter)
434 for g in by_kind.groups do tpl_sidebar_list(g, summary)
435 sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
436 end
437
438 private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
439 if mprops.is_empty then return
440 var entry = new TplListItem.with_content(mprops.title)
441 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
442 for mprop in mprops do
443 list.add_li tpl_sidebar_item(mprop)
444 end
445 entry.append list
446 summary.elts.add entry
447 end
448
449 private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
450 var classes = mprop.intro.tpl_css_classes.to_a
451 if not mprop_is_local(mprop) then
452 classes.add "inherit"
453 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
454 var def_url = "{cls_url}#{mprop.nitdoc_id}"
455 var lnk = new TplLink(def_url, mprop.html_name)
456 var mdoc = mprop.intro.mdoc_or_fallback
457 if mdoc != null then lnk.title = mdoc.short_comment
458 var item = new Template
459 item.add new TplLabel.with_classes(classes)
460 item.add lnk
461 return new TplListItem.with_content(item)
462 end
463 if mpropdefs.has(mprop.intro) then
464 classes.add "intro"
465 else
466 classes.add "redef"
467 end
468 var lnk = new Template
469 lnk.add new TplLabel.with_classes(classes)
470 lnk.add mprop.html_link_to_anchor
471 return new TplListItem.with_content(lnk)
472 end
473
474 private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
475 var res = new HashSet[MProperty]
476 var local = mentity.local_mproperties(v.ctx.min_visibility)
477 for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
478 if local.has(mprop) then continue
479 #if mprop isa MMethod and mprop.is_init then continue
480 if mprop.intro.mclassdef.mclass.name == "Object" and
481 (mprop.visibility == protected_visibility or
482 mprop.intro.mclassdef.mmodule.name != "kernel") then continue
483 res.add mprop
484 end
485 res.add_all local
486 return res
487 end
488
489 private fun mprop_is_local(mprop: MProperty): Bool do
490 for mpropdef in mprop.mpropdefs do
491 if self.mpropdefs.has(mpropdef) then return true
492 end
493 return false
494 end
495 end
496
497 redef class MPropertyPage
498 redef fun init_title(v, doc) do
499 title = "{mentity.html_name}{mentity.html_short_signature.write_to_string}"
500 end
501
502 redef fun init_topmenu(v, doc) do
503 super
504 var mmodule = mentity.intro_mclassdef.mmodule
505 var mproject = mmodule.mgroup.mproject
506 var mclass = mentity.intro_mclassdef.mclass
507 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
508 topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
509 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
510 topmenu.active_item = topmenu.items.last
511 end
512 end
513
514 redef class DocComposite
515 # Render this DocComposite as HTML.
516 #
517 # FIXME needed to maintain TplSection compatibility.
518 fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
519 end
520
521 redef class DocRoot
522
523 # Start the rendering from root.
524 #
525 # FIXME needed to maintain TplSection compatibility.
526 fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
527 var section = new TplSection("top")
528 var mentity = page.mentity
529 section.title = mentity.html_name
530 section.subtitle = mentity.html_declaration
531 # FIXME ugly hack to avoid diff
532 if mentity isa MGroup and mentity.is_root then
533 section.title = mentity.mproject.html_name
534 section.subtitle = mentity.mproject.html_declaration
535 else if mentity isa MProperty then
536 section.title = "{mentity.html_name}{mentity.intro.html_signature.write_to_string}"
537 section.subtitle = mentity.html_namespace
538 section.summary_title = mentity.html_name
539 end
540 render(v, doc, page, section)
541 return section
542 end
543
544 redef fun render(v, doc, page, parent) do
545 for child in children do
546 child.render(v, doc, page, parent)
547 end
548 end
549 end
550
551 redef class ConcernSection
552 redef fun render(v, doc, page, parent) do
553 var section = new TplSection(mentity.nitdoc_id)
554 var mentity = self.mentity
555 # FIXME hideous hacks to avoid diff
556 if page.mentity isa MModule and mentity isa MModule then
557 render_concern_mmodule(page, section, mentity)
558 else if page.mentity isa MClass and mentity isa MModule then
559 render_concern_other(page, section, mentity)
560 else if page.mentity isa MProperty and mentity isa MModule then
561 render_concern_other(page, section, mentity)
562 end
563 for child in children do
564 child.render(v, doc, page, section)
565 end
566 parent.add_child section
567 end
568
569 private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
570 var title = new Template
571 if mmodule == page.mentity then
572 title.add "in "
573 section.summary_title = "in {mmodule.html_name}"
574 else
575 title.add "from "
576 section.summary_title = "from {mmodule.html_name}"
577 end
578 title.add mmodule.html_namespace
579 section.title = title
580 end
581
582 private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
583 var title = new Template
584 title.add "in "
585 title.add mmodule.html_namespace
586 section.title = title
587 section.summary_title = "in {mmodule.html_name}"
588 end
589 end
590
591 redef class MEntitySection
592 redef fun render(v, doc, page, parent) do
593 for child in children do child.render(v, doc, page, parent)
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.html_declaration
609 # FIXME diff hack
610 if mentity isa MProperty then
611 # intro title
612 var ns = mentity.intro.mclassdef.mmodule.html_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.html_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.html_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.html_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.html_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.html_link
704 title.add mprop.intro.html_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.html_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.html_name}"
716 article.subtitle = mpropdef.html_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 FileWriter.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 FileReader.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
845
846 redef class Location
847 # Github url based on this location
848 fun github(gitdir: String): String do
849 var base_dir = getcwd.join_path(gitdir).simplify_path
850 var file_loc = getcwd.join_path(file.filename).simplify_path
851 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
852 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
853 end
854 end
855
856 redef class MEntity
857 # A template article that briefly describe the entity
858 fun tpl_short_article: TplArticle do
859 var tpl = tpl_article
860 var mdoc = mdoc_or_fallback
861 if mdoc != null then
862 tpl.content = mdoc.tpl_short_comment
863 end
864 return tpl
865 end
866
867 # A template article that describe the entity
868 fun tpl_article: TplArticle do
869 var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
870 tpl.title_classes.add "signature"
871 tpl.subtitle = html_namespace
872 tpl.summary_title = html_name
873 return tpl
874 end
875
876 # A template definition of the mentity
877 # include name, sysnopsys, comment and namespace
878 fun tpl_definition: TplDefinition is abstract
879
880 # A li element that can go in a list
881 fun tpl_list_item: TplListItem do
882 var lnk = new Template
883 lnk.add new TplLabel.with_classes(tpl_css_classes)
884 lnk.add html_link
885 var mdoc = mdoc_or_fallback
886 if mdoc != null then
887 lnk.add ": "
888 lnk.add mdoc.tpl_short_comment
889 end
890 return new TplListItem.with_content(lnk)
891 end
892
893 var tpl_css_classes = new Array[String]
894
895 # Box title for this mentity
896 fun tpl_title: Template do
897 var title = new Template
898 title.add tpl_icon
899 title.add html_namespace
900 return title
901 end
902
903 # Icon that will be displayed before the title
904 fun tpl_icon: TplIcon do
905 var icon = new TplIcon.with_icon("tag")
906 icon.css_classes.add_all(tpl_css_classes)
907 return icon
908 end
909 end
910
911 redef class MConcern
912 # Return a li element for `self` that can be displayed in a concern list
913 private fun tpl_concern_item: TplListItem do
914 var lnk = new Template
915 lnk.add html_link_to_anchor
916 var mdoc = mdoc_or_fallback
917 if mdoc != null then
918 lnk.add ": "
919 lnk.add mdoc.tpl_short_comment
920 end
921 return new TplListItem.with_content(lnk)
922 end
923 end
924
925 redef class MProject
926 redef fun tpl_definition do
927 var tpl = new TplDefinition
928 var mdoc = mdoc_or_fallback
929 if mdoc != null then
930 tpl.comment = mdoc.tpl_comment
931 end
932 return tpl
933 end
934
935 redef fun tpl_css_classes do return ["public"]
936 end
937
938 redef class MGroup
939 redef fun tpl_definition do
940 var tpl = new TplDefinition
941 var mdoc = mdoc_or_fallback
942 if mdoc != null then
943 tpl.comment = mdoc.tpl_comment
944 end
945 return tpl
946 end
947 end
948
949 redef class MModule
950 redef fun tpl_definition do
951 var tpl = new TplClassDefinition
952 var mdoc = mdoc_or_fallback
953 if mdoc != null then
954 tpl.comment = mdoc.tpl_comment
955 end
956 return tpl
957 end
958
959 redef fun tpl_css_classes do return ["public"]
960 end
961
962 redef class MClass
963 redef fun tpl_definition do return intro.tpl_definition
964
965 redef fun tpl_title do
966 var title = new Template
967 title.add tpl_icon
968 title.add html_link
969 return title
970 end
971
972 redef fun tpl_icon do return intro.tpl_icon
973 redef fun tpl_css_classes do return intro.tpl_css_classes
974 end
975
976 redef class MClassDef
977 redef fun tpl_article do
978 var tpl = new TplArticle(nitdoc_id)
979 tpl.summary_title = "in {mmodule.html_name}"
980 tpl.title = html_declaration
981 tpl.title_classes.add "signature"
982 var title = new Template
983 title.add "in "
984 title.add mmodule.html_namespace
985 tpl.subtitle = title
986 var mdoc = mdoc_or_fallback
987 if mdoc != null then
988 tpl.content = mdoc.tpl_comment
989 end
990 return tpl
991 end
992
993 redef fun tpl_title do
994 var title = new Template
995 title.add tpl_icon
996 title.add html_link
997 return title
998 end
999
1000 redef fun tpl_definition do
1001 var tpl = new TplClassDefinition
1002 var mdoc = mdoc_or_fallback
1003 if mdoc != null then
1004 tpl.comment = mdoc.tpl_comment
1005 end
1006 return tpl
1007 end
1008
1009 redef fun tpl_css_classes do
1010 var set = new HashSet[String]
1011 if is_intro then set.add "intro"
1012 for m in mclass.intro.modifiers do set.add m.to_cmangle
1013 for m in modifiers do set.add m.to_cmangle
1014 return set.to_a
1015 end
1016
1017 fun tpl_modifiers: Template do
1018 var tpl = new Template
1019 for modifier in modifiers do
1020 if modifier == "public" then continue
1021 tpl.add "{modifier.html_escape} "
1022 end
1023 return tpl
1024 end
1025 end
1026
1027 redef class MProperty
1028 redef fun tpl_title do return intro.tpl_title
1029 redef fun tpl_icon do return intro.tpl_icon
1030 redef fun tpl_css_classes do return intro.tpl_css_classes
1031 end
1032
1033 redef class MPropDef
1034 redef fun tpl_article do
1035 var tpl = new TplArticle(nitdoc_id)
1036 tpl.summary_title = "in {mclassdef.html_name}"
1037 var title = new Template
1038 title.add "in "
1039 title.add mclassdef.html_link
1040 tpl.title = title
1041 tpl.subtitle = html_declaration
1042 var mdoc = mdoc_or_fallback
1043 if mdoc != null then
1044 tpl.content = mdoc.tpl_comment
1045 end
1046 return tpl
1047 end
1048
1049 redef fun tpl_definition do
1050 var tpl = new TplDefinition
1051 var mdoc = mdoc_or_fallback
1052 if mdoc != null then
1053 tpl.comment = mdoc.tpl_comment
1054 end
1055 return tpl
1056 end
1057
1058 redef fun tpl_css_classes do
1059 var set = new HashSet[String]
1060 if is_intro then set.add "intro"
1061 for m in mproperty.intro.modifiers do set.add m.to_cmangle
1062 for m in modifiers do set.add m.to_cmangle
1063 return set.to_a
1064 end
1065
1066 fun tpl_modifiers: Template do
1067 var tpl = new Template
1068 for modifier in modifiers do
1069 if modifier == "public" then continue
1070 tpl.add "{modifier.html_escape} "
1071 end
1072 return tpl
1073 end
1074
1075 redef fun tpl_list_item do
1076 var lnk = new Template
1077 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1078 var atext = html_link.text
1079 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1080 var atitle = html_link.title
1081 var anchor = new Link.with_title(ahref, atext, atitle)
1082 lnk.add anchor
1083 var mdoc = mdoc_or_fallback
1084 if mdoc != null then
1085 lnk.add ": "
1086 lnk.add mdoc.tpl_short_comment
1087 end
1088 return new TplListItem.with_content(lnk)
1089 end
1090
1091 fun tpl_inheritance_item: TplListItem do
1092 var lnk = new Template
1093 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1094 lnk.add mclassdef.mmodule.html_namespace
1095 lnk.add "::"
1096 var atext = mclassdef.html_link.text
1097 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1098 var atitle = mclassdef.html_link.title
1099 var anchor = new Link.with_title(ahref, atext, atitle)
1100 lnk.add anchor
1101 var mdoc = mdoc_or_fallback
1102 if mdoc != null then
1103 lnk.add ": "
1104 lnk.add mdoc.tpl_short_comment
1105 end
1106 var li = new TplListItem.with_content(lnk)
1107 li.css_classes.add "signature"
1108 return li
1109 end
1110 end
1111
1112 redef class ConcernsTree
1113
1114 private var seen = new HashSet[MConcern]
1115
1116 redef fun add(p, e) do
1117 if seen.has(e) then return
1118 seen.add e
1119 super(p, e)
1120 end
1121
1122 fun to_tpl: TplList do
1123 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1124 for r in roots do
1125 var li = r.tpl_concern_item
1126 lst.add_li li
1127 build_list(r, li)
1128 end
1129 return lst
1130 end
1131
1132 private fun build_list(e: MConcern, li: TplListItem) do
1133 if not sub.has_key(e) then return
1134 var subs = sub[e]
1135 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1136 for e2 in subs do
1137 if e2 isa MGroup and e2.is_root then
1138 build_list(e2, li)
1139 else
1140 var sli = e2.tpl_concern_item
1141 lst.add_li sli
1142 build_list(e2, sli)
1143 end
1144 end
1145 li.append lst
1146 end
1147 end
1148
1149 redef class MInnerClassDef
1150 redef fun tpl_definition do
1151 var tpl = new TplClassDefinition
1152 var mdoc = mdoc_or_fallback
1153 if mdoc != null then
1154 tpl.comment = mdoc.tpl_comment
1155 end
1156 return tpl
1157 end
1158 end