src/doc: IntroArticle use new templates
[nit.git] / src / doc / doc_phases / doc_html.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Render the DocModel pages as HTML pages.
16 #
17 # FIXME this module is all f*cked up to maintain compatibility with
18 # the original `doc_templates` and `doc_model` modules.
19 # This will change in further refactorings.
20 module doc_html
21
22 import doc_structure
23 import doc_hierarchies
24 import doc_intros_redefs
25 import doc_graphs
26 import html_templates
27
28 redef class ToolContext
29
30 # File pattern used to link documentation to source code.
31 var opt_source = new OptionString("link for source (%f for filename, " +
32 "%l for first line, %L for last line)", "--source")
33
34 # Directory where the CSS and JS is stored.
35 var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
36
37 # Use a shareurl instead of copy shared files.
38 #
39 # This is usefull if you don't want to store the Nitdoc templates with your
40 # documentation.
41 var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
42
43 # Use a custom title for the homepage.
44 var opt_custom_title = new OptionString("custom title for homepage", "--custom-title")
45
46 # Display a custom brand or logo in the documentation top menu.
47 var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
48
49 # Display a custom introduction text before the projects overview.
50 var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
51 # Display a custom footer on each documentation page.
52 #
53 # Generally used to display the documentation or product version.
54 var opt_custom_footer = new OptionString("custom footer text", "--custom-footer-text")
55
56 # Piwik tracker URL.
57 #
58 # If you want to monitor your visitors.
59 var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
60
61 # Piwik tracker site id.
62 var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
63
64 # These options are not currently used in Nitdoc.
65
66 # FIXME redo the plugin
67 var opt_github_upstream = new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
68 # FIXME redo the plugin
69 var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
70 # FIXME redo the plugin
71 var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
72
73 redef init do
74 super
75
76 option_context.add_option(
77 opt_source, opt_sharedir, opt_shareurl, opt_custom_title,
78 opt_custom_footer, opt_custom_intro, opt_custom_brand,
79 opt_github_upstream, opt_github_base_sha1, opt_github_gitdir,
80 opt_piwik_tracker, opt_piwik_site_id)
81 end
82
83 redef fun process_options(args) do
84 super
85 var upstream = opt_github_upstream
86 var base_sha = opt_github_base_sha1
87 var git_dir = opt_github_gitdir
88 var opts = [upstream.value, base_sha.value, git_dir.value]
89 if not opts.has_only(null) and opts.has(null) then
90 print "Option Error: options {upstream.names.first}, " +
91 "{base_sha.names.first} and {git_dir.names.first} " +
92 "are required to enable the GitHub plugin"
93 exit 1
94 end
95 end
96 end
97
98 # Render the Nitdoc as a HTML website.
99 class RenderHTMLPhase
100 super DocPhase
101
102 # Used to sort sidebar elements by name.
103 var name_sorter = new MEntityNameSorter
104
105 redef fun apply do
106 init_output_dir
107 for page in doc.pages do
108 page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}")
109 end
110 end
111
112 # Creates the output directory and imports assets files form `resources/`.
113 fun init_output_dir do
114 # create destination dir if it's necessary
115 var output_dir = ctx.output_dir
116 if not output_dir.file_exists then output_dir.mkdir
117 # locate share dir
118 var sharedir = ctx.opt_sharedir.value
119 if sharedir == null then
120 var dir = ctx.nit_dir
121 sharedir = dir/"share/nitdoc"
122 if not sharedir.file_exists then
123 print "Error: cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
124 abort
125 end
126 end
127 # copy shared files
128 if ctx.opt_shareurl.value == null then
129 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
130 else
131 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
132 end
133
134 end
135
136 # A source link template for a given location
137 fun tpl_showsource(location: nullable Location): nullable String
138 do
139 if location == null then return null
140 var source = ctx.opt_source.value
141 if source == null then
142 var url = location.file.filename.simplify_path
143 return "<a target='_blank' title='Show source' href=\"{url.html_escape}\">View Source</a>"
144 end
145 # THIS IS JUST UGLY ! (but there is no replace yet)
146 var x = source.split_with("%f")
147 source = x.join(location.file.filename.simplify_path)
148 x = source.split_with("%l")
149 source = x.join(location.line_start.to_s)
150 x = source.split_with("%L")
151 source = x.join(location.line_end.to_s)
152 source = source.simplify_path
153 return "<a target='_blank' title='Show source' href=\"{source.to_s.html_escape}\">View Source</a>"
154 end
155 end
156
157 redef class DocPage
158
159 # Render the page as a html template.
160 private fun render(v: RenderHTMLPhase, doc: DocModel): Writable do
161 var shareurl = "."
162 if v.ctx.opt_shareurl.value != null then
163 shareurl = v.ctx.opt_shareurl.value.as(not null)
164 end
165
166 # init page options
167 self.shareurl = shareurl
168 self.footer = v.ctx.opt_custom_footer.value
169 self.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
170
171 # build page
172 init_title(v, doc)
173 init_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 comment = mproject.html_short_comment
250 if comment != null then
251 sarticle.content = 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 article.content = write_to_string
610 parent.add_child article
611 end
612 end
613
614 redef class ConcernsArticle
615 redef fun render(v, doc, page, parent) do
616 # FIXME diff hack
617 var title = "concerns"
618 if page.mentity isa MProperty then title = "Concerns"
619 parent.add_child new TplArticle.
620 with_content(title, "Concerns", concerns.to_tpl)
621 end
622 end
623
624 redef class DefinitionArticle
625 redef fun render(v, doc, page, parent) do
626 var article: TplArticle
627 var mentity = self.mentity
628 # FIXME hideous hacks...
629 if mentity isa MModule then
630 article = mentity.tpl_article
631 article.subtitle = mentity.html_declaration
632 article.content = mentity.tpl_definition
633 else if mentity isa MClass then
634 article = make_mclass_article(v, page)
635 else if mentity isa MClassDef then
636 article = make_mclassdef_article(v, page)
637 article.source_link = v.tpl_showsource(mentity.location)
638 else if mentity isa MPropDef and page.mentity isa MClass then
639 article = make_mpropdef_article(v, doc, page)
640 else
641 article = mentity.tpl_article
642 article.subtitle = mentity.html_declaration
643 if mentity isa MPropDef then
644 article.source_link = v.tpl_showsource(mentity.location)
645 end
646 end
647 for child in children do
648 child.render(v, doc, page, article)
649 end
650 parent.add_child article
651 end
652
653 # FIXME avoid diff while preserving TplArticle compatibility.
654
655 private fun make_mclass_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
656 var article = mentity.tpl_article
657 article.subtitle = mentity.html_namespace
658 article.content = null
659 return article
660 end
661
662 private fun make_mclassdef_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
663 var mclassdef = mentity.as(MClassDef)
664 var article = mentity.tpl_article
665 if mclassdef.is_intro and mclassdef.mmodule != page.mentity then
666 article = mentity.tpl_short_article
667 end
668 var title = new Template
669 title.add "in "
670 title.add mclassdef.mmodule.html_namespace
671 article.subtitle = title
672 return article
673 end
674
675 private fun make_mpropdef_article(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplArticle
676 do
677 var mpropdef = mentity.as(MPropDef)
678 var mprop = mpropdef.mproperty
679 var article = new TplArticle(mprop.nitdoc_id)
680 var title = new Template
681 title.add mprop.tpl_icon
682 title.add "<span id='{mpropdef.nitdoc_id}'></span>"
683 if mpropdef.is_intro then
684 title.add mprop.html_link
685 title.add mprop.intro.html_signature
686 else
687 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
688 var def_url = "{cls_url}#{mprop.nitdoc_id}"
689 var lnk = new TplLink.with_title(def_url, mprop.html_name,
690 "Go to introduction")
691 title.add "redef "
692 title.add lnk
693 end
694 article.title = title
695 article.title_classes.add "signature"
696 article.summary_title = "{mprop.html_name}"
697 article.subtitle = mpropdef.html_namespace
698 var comment = mpropdef.html_comment
699 if comment != null then
700 article.content = comment
701 end
702 # TODO move in its own phase? let's see after doc_template refactoring.
703 # Add linearization
704 var all_defs = new HashSet[MPropDef]
705 for local_def in local_defs(page.as(MClassPage), mprop) do
706 all_defs.add local_def
707 var smpropdef = local_def
708 while not smpropdef.is_intro do
709 smpropdef = smpropdef.lookup_next_definition(
710 doc.mainmodule, smpropdef.mclassdef.bound_mtype)
711 all_defs.add smpropdef
712 end
713 end
714 var lin = all_defs.to_a
715 doc.mainmodule.linearize_mpropdefs(lin)
716 if lin.length > 1 then
717 var lin_article = new TplArticle("{mpropdef.nitdoc_id}.lin")
718 lin_article.title = "Inheritance"
719 var lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
720 for smpropdef in lin do
721 lst.add_li smpropdef.tpl_inheritance_item
722 end
723 lin_article.content = lst
724 article.add_child lin_article
725 end
726 return article
727 end
728
729 # Filter `page.mpropdefs` for this `mpropertie`.
730 #
731 # FIXME compatability with current templates.
732 private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
733 var mpropdefs = new HashSet[MPropDef]
734 for mpropdef in page.mpropdefs do
735 if mpropdef.mproperty == mproperty then
736 mpropdefs.add mpropdef
737 end
738 end
739 return mpropdefs
740 end
741 end
742
743 redef class IntrosRedefsListArticle
744 redef fun render(v, doc, page, parent) do
745 if mentities.is_empty then return
746 var title = list_title
747 # FIXME diff hack
748 var id = "intros"
749 if title == "Redefines" then id = "redefs"
750 var article = new TplArticle.with_title("{mentity.nitdoc_id}.{id}", title)
751 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
752 for mentity in mentities do
753 list.add_li mentity.tpl_list_item
754 end
755 article.content = list
756 parent.add_child article
757 end
758 end
759
760 # FIXME compatibility with doc_templates.
761 redef class ImportationListSection
762 redef fun render(v, doc, page, parent) do
763 var section = new TplSection.with_title("dependencies", "Dependencies")
764 for child in children do
765 child.render(v, doc, page, section)
766 end
767 parent.add_child section
768 end
769 end
770
771 # FIXME compatibility with doc_templates.
772 redef class InheritanceListSection
773 redef fun render(v, doc, page, parent) do
774 var section = new TplSection.with_title("inheritance", "Inheritance")
775 for child in children do
776 child.render(v, doc, page, section)
777 end
778 parent.add_child section
779 end
780 end
781
782 # FIXME compatibility with doc_templates.
783 redef class HierarchyListArticle
784 redef fun render(v, doc, page, parent) do
785 if mentities.is_empty then return
786 var title = list_title
787 var id = list_title.to_lower
788 var article = new TplArticle.with_title(id, title)
789 var list = new TplList.with_classes(["list-unstyled", "list-definition"])
790 for mentity in mentities do
791 list.elts.add mentity.tpl_list_item
792 end
793 article.content = list
794 parent.add_child article
795 end
796 end
797
798 redef class GraphArticle
799 redef fun render(v, doc, page, parent) do
800 var output_dir = v.ctx.output_dir
801 var path = output_dir / id
802 var path_sh = path.escape_to_sh
803 var file = new FileWriter.open("{path}.dot")
804 file.write(dot)
805 file.close
806 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 ; \}")
807 var fmap = new FileReader.open("{path}.map")
808 var map = fmap.read_all
809 fmap.close
810
811 var article = new TplArticle("graph")
812 var alt = ""
813 # FIXME diff hack
814 # if title != null then
815 # article.title = title
816 # alt = "alt='{title.html_escape}'"
817 # end
818 article.css_classes.add "text-center"
819 var content = new Template
820 var name_html = id.html_escape
821 content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
822 content.add map
823 article.content = content
824 parent.add_child article
825 end
826 end
827
828 redef class Location
829 # Github url based on this location
830 fun github(gitdir: String): String do
831 var base_dir = getcwd.join_path(gitdir).simplify_path
832 var file_loc = getcwd.join_path(file.filename).simplify_path
833 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
834 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
835 end
836 end
837
838 redef class MEntity
839 # A template article that briefly describe the entity
840 fun tpl_short_article: TplArticle do
841 var tpl = tpl_article
842 var comment = html_short_comment
843 if comment != null then
844 tpl.content = comment
845 end
846 return tpl
847 end
848
849 # A template article that describe the entity
850 fun tpl_article: TplArticle do
851 var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
852 tpl.title_classes.add "signature"
853 tpl.subtitle = html_namespace
854 tpl.summary_title = html_name
855 return tpl
856 end
857
858 # A template definition of the mentity
859 # include name, sysnopsys, comment and namespace
860 fun tpl_definition: TplDefinition is abstract
861
862 # A li element that can go in a list
863 fun tpl_list_item: TplListItem do
864 var lnk = new Template
865 lnk.add new TplLabel.with_classes(tpl_css_classes)
866 lnk.add html_link
867 var comment = html_short_comment
868 if comment != null then
869 lnk.add ": "
870 lnk.add comment
871 end
872 return new TplListItem.with_content(lnk)
873 end
874
875 var tpl_css_classes = new Array[String]
876
877 # Box title for this mentity
878 fun tpl_title: Template do
879 var title = new Template
880 title.add tpl_icon
881 title.add html_namespace
882 return title
883 end
884
885 # Icon that will be displayed before the title
886 fun tpl_icon: TplIcon do
887 var icon = new TplIcon.with_icon("tag")
888 icon.css_classes.add_all(tpl_css_classes)
889 return icon
890 end
891 end
892
893 redef class MConcern
894 # Return a li element for `self` that can be displayed in a concern list
895 private fun tpl_concern_item: TplListItem do
896 var lnk = new Template
897 lnk.add html_link_to_anchor
898 var comment = html_short_comment
899 if comment != null then
900 lnk.add ": "
901 lnk.add comment
902 end
903 return new TplListItem.with_content(lnk)
904 end
905 end
906
907 redef class MProject
908 redef fun tpl_definition do
909 var tpl = new TplDefinition
910 var comment = html_comment
911 if comment != null then
912 tpl.comment = comment
913 end
914 return tpl
915 end
916
917 redef fun tpl_css_classes do return ["public"]
918 end
919
920 redef class MGroup
921 redef fun tpl_definition do
922 var tpl = new TplDefinition
923 var comment = html_comment
924 if comment != null then
925 tpl.comment = comment
926 end
927 return tpl
928 end
929 end
930
931 redef class MModule
932 redef fun tpl_definition do
933 var tpl = new TplClassDefinition
934 var comment = html_comment
935 if comment != null then
936 tpl.comment = comment
937 end
938 return tpl
939 end
940
941 redef fun tpl_css_classes do return ["public"]
942 end
943
944 redef class MClass
945 redef fun tpl_definition do return intro.tpl_definition
946
947 redef fun tpl_title do
948 var title = new Template
949 title.add tpl_icon
950 title.add html_link
951 return title
952 end
953
954 redef fun tpl_icon do return intro.tpl_icon
955 redef fun tpl_css_classes do return intro.tpl_css_classes
956 end
957
958 redef class MClassDef
959 redef fun tpl_article do
960 var tpl = new TplArticle(nitdoc_id)
961 tpl.summary_title = "in {mmodule.html_name}"
962 tpl.title = html_declaration
963 tpl.title_classes.add "signature"
964 var title = new Template
965 title.add "in "
966 title.add mmodule.html_namespace
967 tpl.subtitle = title
968 var comment = html_comment
969 if comment != null then
970 tpl.content = comment
971 end
972 return tpl
973 end
974
975 redef fun tpl_title do
976 var title = new Template
977 title.add tpl_icon
978 title.add html_link
979 return title
980 end
981
982 redef fun tpl_definition do
983 var tpl = new TplClassDefinition
984 var comment = html_comment
985 if comment != null then
986 tpl.comment = comment
987 end
988 return tpl
989 end
990
991 redef fun tpl_css_classes do
992 var set = new HashSet[String]
993 if is_intro then set.add "intro"
994 for m in mclass.intro.modifiers do set.add m.to_cmangle
995 for m in modifiers do set.add m.to_cmangle
996 return set.to_a
997 end
998
999 fun tpl_modifiers: Template do
1000 var tpl = new Template
1001 for modifier in modifiers do
1002 if modifier == "public" then continue
1003 tpl.add "{modifier.html_escape} "
1004 end
1005 return tpl
1006 end
1007 end
1008
1009 redef class MProperty
1010 redef fun tpl_title do return intro.tpl_title
1011 redef fun tpl_icon do return intro.tpl_icon
1012 redef fun tpl_css_classes do return intro.tpl_css_classes
1013 end
1014
1015 redef class MPropDef
1016 redef fun tpl_article do
1017 var tpl = new TplArticle(nitdoc_id)
1018 tpl.summary_title = "in {mclassdef.html_name}"
1019 var title = new Template
1020 title.add "in "
1021 title.add mclassdef.html_link
1022 tpl.title = title
1023 tpl.subtitle = html_declaration
1024 var comment = html_comment
1025 if comment != null then
1026 tpl.content = comment
1027 end
1028 return tpl
1029 end
1030
1031 redef fun tpl_definition do
1032 var tpl = new TplDefinition
1033 var comment = html_comment
1034 if comment != null then
1035 tpl.comment = comment
1036 end
1037 return tpl
1038 end
1039
1040 redef fun tpl_css_classes do
1041 var set = new HashSet[String]
1042 if is_intro then set.add "intro"
1043 for m in mproperty.intro.modifiers do set.add m.to_cmangle
1044 for m in modifiers do set.add m.to_cmangle
1045 return set.to_a
1046 end
1047
1048 fun tpl_modifiers: Template do
1049 var tpl = new Template
1050 for modifier in modifiers do
1051 if modifier == "public" then continue
1052 tpl.add "{modifier.html_escape} "
1053 end
1054 return tpl
1055 end
1056
1057 redef fun tpl_list_item do
1058 var lnk = new Template
1059 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1060 var atext = html_link.text
1061 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1062 var atitle = html_link.title
1063 var anchor = new Link.with_title(ahref, atext, atitle)
1064 lnk.add anchor
1065 var comment = html_short_comment
1066 if comment != null then
1067 lnk.add ": "
1068 lnk.add comment
1069 end
1070 return new TplListItem.with_content(lnk)
1071 end
1072
1073 fun tpl_inheritance_item: TplListItem do
1074 var lnk = new Template
1075 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1076 lnk.add mclassdef.mmodule.html_namespace
1077 lnk.add "::"
1078 var atext = mclassdef.html_link.text
1079 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1080 var atitle = mclassdef.html_link.title
1081 var anchor = new Link.with_title(ahref, atext, atitle)
1082 lnk.add anchor
1083 var comment = html_short_comment
1084 if comment != null then
1085 lnk.add ": "
1086 lnk.add comment
1087 end
1088 var li = new TplListItem.with_content(lnk)
1089 li.css_classes.add "signature"
1090 return li
1091 end
1092 end
1093
1094 redef class ConcernsTree
1095
1096 private var seen = new HashSet[MConcern]
1097
1098 redef fun add(p, e) do
1099 if seen.has(e) then return
1100 seen.add e
1101 super(p, e)
1102 end
1103
1104 fun to_tpl: TplList do
1105 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1106 for r in roots do
1107 var li = r.tpl_concern_item
1108 lst.add_li li
1109 build_list(r, li)
1110 end
1111 return lst
1112 end
1113
1114 private fun build_list(e: MConcern, li: TplListItem) do
1115 if not sub.has_key(e) then return
1116 var subs = sub[e]
1117 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1118 for e2 in subs do
1119 if e2 isa MGroup and e2.is_root then
1120 build_list(e2, li)
1121 else
1122 var sli = e2.tpl_concern_item
1123 lst.add_li sli
1124 build_list(e2, sli)
1125 end
1126 end
1127 li.append lst
1128 end
1129 end
1130
1131 redef class MInnerClassDef
1132 redef fun tpl_definition do
1133 var tpl = new TplClassDefinition
1134 var comment = html_comment
1135 if comment != null then
1136 tpl.comment = comment
1137 end
1138 return tpl
1139 end
1140 end