2b49b9e5c4bb081a7618a0516989b46f407c3a32
[nit.git] / src / web / model_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 # Translate mentities to html blocks.
16 module model_html
17
18 import model
19 import doc::doc_down
20 import html::bootstrap
21
22 redef class MEntity
23
24 # Returns the MEntity name escaped for html.
25 #
26 # * MPackage: `foo`
27 # * MGroup: `foo`
28 # * MModule: `foo`
29 # * MClass: `Foo[E]`
30 # * MClassDef: `Foo[E]`
31 # * MProperty: `foo(e)`
32 # * MPropdef: `foo(e)`
33 var html_name: String is lazy do return name.html_escape
34
35 # MEntity namespace escaped for html.
36 fun html_raw_namespace: String is abstract
37
38 # Link to MEntity in the web server.
39 # TODO this should be parameterizable... but how?
40 fun html_link: Link do return new Link("/doc/{html_raw_namespace}", html_name)
41
42 # Returns the list of keyword used in `self` declaration.
43 fun html_modifiers: Array[String] is abstract
44
45 # Returns the complete MEntity declaration decorated with HTML.
46 #
47 # * MPackage: `package foo`
48 # * MGroup: `group foo`
49 # * MModule: `module foo`
50 # * MClass: `private abstract class Foo[E: Object]`
51 # * MClassDef: `redef class Foo[E]`
52 # * MProperty: `private fun foo(e: Object): Int`
53 # * MPropdef: `redef fun foo(e)`
54 fun html_declaration: Template do
55 var tpl = new Template
56 tpl.add "<span>"
57 tpl.add html_modifiers.join(" ")
58 tpl.add " "
59 tpl.add html_link
60 tpl.add "</span>"
61 return tpl
62 end
63
64 # Returns `self` namespace decorated with HTML links.
65 #
66 # * MPackage: `mpackage`
67 # * MGroup: `mpackage(::group)`
68 # * MModule: `mgroup::mmodule`
69 # * MClass: `mpackage::mclass`
70 # * MClassDef: `mmodule::mclassdef`
71 # * MProperty: `mclass::mprop`
72 # * MPropdef: `mclassdef:mpropdef`
73 fun html_namespace: Template is abstract
74
75 # Returns the synopsis and the comment of this MEntity formatted as HTML.
76 var html_documentation: nullable Writable is lazy do
77 var mdoc = mdoc_or_fallback
78 if mdoc == null then return null
79 return mdoc.html_documentation
80 end
81
82 # Returns the synopsis of this MEntity formatted as HTML.
83 var html_synopsis: nullable Writable is lazy do
84 var mdoc = mdoc_or_fallback
85 if mdoc == null then return null
86 return mdoc.html_synopsis
87 end
88
89 # Returns the the comment without the synopsis formatted as HTML.
90 var html_comment: nullable Writable is lazy do
91 var mdoc = mdoc_or_fallback
92 if mdoc == null then return null
93 return mdoc.html_comment
94 end
95
96 # Icon that will be displayed before the title
97 fun html_icon: BSIcon do
98 var icon = new BSIcon("tag")
99 icon.css_classes.add_all(css_classes)
100 return icon
101 end
102
103 # CSS classes used to decorate `self`.
104 #
105 # Mainly used for icons.
106 var css_classes = new Array[String]
107 end
108
109 redef class MPackage
110 redef fun html_raw_namespace do return html_name
111
112 redef var html_modifiers = ["package"]
113 redef fun html_namespace do return html_link
114 redef var css_classes = ["public"]
115 end
116
117 redef class MGroup
118 redef fun html_raw_namespace do
119 var parent = self.parent
120 if parent != null then
121 return "{parent.html_raw_namespace}::{html_name}"
122 end
123 return "{mpackage.html_raw_namespace}::{html_name}"
124 end
125
126 redef var html_modifiers = ["group"]
127
128 # Depends if `self` is root or not.
129 #
130 # * If root `mpackage`.
131 # * Else `mpackage::self`.
132 redef fun html_namespace do
133 var tpl = new Template
134 tpl.add mpackage.html_namespace
135 if mpackage.root != self then
136 tpl.add "::"
137 tpl.add html_link
138 end
139 return tpl
140 end
141
142 redef var css_classes = ["public"]
143 end
144
145 redef class MModule
146
147 redef var html_modifiers = ["module"]
148
149 # Depends if `self` belongs to a MGroup.
150 #
151 # * If mgroup `mgroup::self`.
152 # * Else `self`.
153 redef fun html_namespace do
154 var mgroup = self.mgroup
155 var tpl = new Template
156 if mgroup != null then
157 tpl.add mgroup.html_namespace
158 tpl.add "::"
159 end
160 tpl.add html_link
161 return tpl
162 end
163
164 redef fun html_raw_namespace do
165 var mpackage = self.mpackage
166 var mgroup = self.mgroup
167 if mgroup != null then
168 return "{mgroup.html_raw_namespace}::{html_name}"
169 else if mpackage != null then
170 return "{mpackage.html_raw_namespace}::{html_name}"
171 end
172 return html_name
173 end
174
175 redef var css_classes = ["public"]
176 end
177
178 redef class MClass
179 redef fun mdoc_or_fallback do return intro.mdoc
180
181 # Format: `Foo[E]`
182 redef var html_name is lazy do
183 var tpl = new Template
184 tpl.add name.html_escape
185 if arity > 0 then
186 tpl.add "["
187 var parameter_names = new Array[String]
188 for p in mparameters do
189 parameter_names.add(p.html_name)
190 end
191 tpl.add parameter_names.join(", ")
192 tpl.add "]"
193 end
194 return tpl.write_to_string
195 end
196
197 redef fun html_modifiers do return intro.html_modifiers
198 redef fun html_declaration do return intro.html_declaration
199
200 # Returns `mpackage::self`.
201 redef fun html_namespace do
202 var mgroup = intro_mmodule.mgroup
203 var tpl = new Template
204 if mgroup != null then
205 tpl.add mgroup.mpackage.html_namespace
206 tpl.add "::"
207 end
208 tpl.add "<span>"
209 tpl.add html_link
210 tpl.add "</span>"
211 return tpl
212 end
213
214 redef fun html_raw_namespace do return intro.html_raw_namespace
215
216 # Returns `intro.html_short_signature`.
217 fun html_short_signature: Template do return intro.html_short_signature
218
219 # Returns `intro.html_signature`.
220 fun html_signature: Template do return intro.html_signature
221
222 redef fun html_icon do return intro.html_icon
223 redef fun css_classes do return intro.css_classes
224 end
225
226 redef class MClassDef
227 redef fun html_raw_namespace do return "{mmodule.html_raw_namespace}::{html_name}"
228
229 redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback
230
231 # Depends if `self` is an intro or not.
232 #
233 # * If intro contains the visibility and kind.
234 # * If redef contains the `redef` keyword and kind.
235 redef fun html_modifiers do
236 var res = new Array[String]
237 if not is_intro then
238 res.add "redef"
239 else
240 if mclass.visibility != public_visibility then
241 res.add mclass.visibility.to_s
242 end
243 end
244 res.add mclass.kind.to_s
245 return res
246 end
247
248 # Depends if `self` is an intro or not.
249 #
250 # For intro: `private abstract class Foo[E: Object]`
251 # For redef: `redef class Foo[E]`
252 redef fun html_declaration do
253 var tpl = new Template
254 tpl.add "<span>"
255 tpl.add html_modifiers.join(" ")
256 tpl.add " "
257 tpl.add html_link
258 if is_intro then
259 tpl.add html_signature
260 else
261 tpl.add html_short_signature
262 end
263 tpl.add "</span>"
264 return tpl
265 end
266
267 # Returns `mmodule::self`
268 redef fun html_namespace do
269 var tpl = new Template
270 tpl.add mmodule.html_namespace
271 tpl.add "::<span>"
272 tpl.add mclass.html_link
273 tpl.add "</span>"
274 return tpl
275 end
276
277 # Returns the MClassDef generic signature without static bounds.
278 fun html_short_signature: Template do
279 var tpl = new Template
280 var mparameters = mclass.mparameters
281 if not mparameters.is_empty then
282 tpl.add "["
283 for i in [0..mparameters.length[ do
284 tpl.add mparameters[i].html_name
285 if i < mparameters.length - 1 then tpl.add ", "
286 end
287 tpl.add "]"
288 end
289 return tpl
290 end
291
292 # Returns the MClassDef generic signature with static bounds.
293 fun html_signature: Template do
294 var tpl = new Template
295 var mparameters = mclass.mparameters
296 if not mparameters.is_empty then
297 tpl.add "["
298 for i in [0..mparameters.length[ do
299 tpl.add "{mparameters[i].html_name}: "
300 tpl.add bound_mtype.arguments[i].html_signature
301 if i < mparameters.length - 1 then tpl.add ", "
302 end
303 tpl.add "]"
304 end
305 return tpl
306 end
307
308 redef fun css_classes do
309 var set = new HashSet[String]
310 if is_intro then set.add "intro"
311 for m in mclass.intro.modifiers do set.add m.to_cmangle
312 for m in modifiers do set.add m.to_cmangle
313 return set.to_a
314 end
315
316
317 # List of all modifiers like redef, private etc.
318 var modifiers: Array[String] is lazy do
319 var res = new Array[String]
320 if not is_intro then
321 res.add "redef"
322 else
323 res.add mclass.visibility.to_s
324 end
325 res.add mclass.kind.to_s
326 return res
327 end
328 end
329
330 redef class MProperty
331 redef fun mdoc_or_fallback do return intro.mdoc
332 redef fun html_modifiers do return intro.html_modifiers
333 redef fun html_declaration do return intro.html_declaration
334
335 # Returns `mclass::self`.
336 redef fun html_namespace do
337 var tpl = new Template
338 tpl.add intro_mclassdef.mclass.html_namespace
339 tpl.add "::<span>"
340 tpl.add intro.html_link
341 tpl.add "</span>"
342 return tpl
343 end
344
345 redef fun html_raw_namespace do return intro.html_raw_namespace
346
347 # Returns `intro.html_short_signature`.
348 fun html_short_signature: Template do return intro.html_short_signature
349
350 # Returns `intro.html_signature`.
351 fun html_signature: Template do return intro.html_signature
352
353 redef fun css_classes do return intro.css_classes
354 end
355
356 redef class MPropDef
357 redef fun html_raw_namespace do return "{mclassdef.html_raw_namespace}::{html_name}"
358 redef fun mdoc_or_fallback do return mdoc or else mproperty.mdoc_or_fallback
359
360 # Depends if `self` is an intro or not.
361 #
362 # * If intro contains the visibility and kind.
363 # * If redef contains the `redef` keyword and kind.
364 redef fun html_modifiers do
365 var res = new Array[String]
366 if not is_intro then
367 res.add "redef"
368 else
369 if mproperty.visibility != public_visibility then
370 res.add mproperty.visibility.to_s
371 end
372 end
373 return res
374 end
375
376 # Depends if `self` is an intro or not.
377 #
378 # For intro: `private fun foo(e: Object): Bar is abstract`
379 # For redef: `redef fun foo(e) is cached`
380 redef fun html_declaration do
381 var tpl = new Template
382 tpl.add "<span>"
383 tpl.add html_modifiers.join(" ")
384 tpl.add " "
385 if is_intro then
386 tpl.add html_link
387 tpl.add html_signature
388 else
389 tpl.add mproperty.intro.html_link
390 tpl.add html_short_signature
391 end
392 tpl.add "</span>"
393 return tpl
394 end
395
396 # Returns `mclassdef::self`
397 redef fun html_namespace do
398 var tpl = new Template
399 tpl.add mclassdef.html_namespace
400 tpl.add "::"
401 tpl.add html_link
402 return tpl
403 end
404
405 # Returns the MPropdDef signature without static types.
406 fun html_short_signature: Template is abstract
407
408 # Returns the MPropDef signature with static types.
409 fun html_signature: Template is abstract
410
411 redef fun css_classes do
412 var set = new HashSet[String]
413 if is_intro then set.add "intro"
414 for m in mproperty.intro.modifiers do set.add m.to_cmangle
415 for m in modifiers do set.add m.to_cmangle
416 return set.to_a
417 end
418
419 # List of all modifiers like redef, private, abstract, intern, fun etc.
420 var modifiers: Array[String] is lazy do
421 var res = new Array[String]
422 if not is_intro then
423 res.add "redef"
424 else
425 res.add mproperty.visibility.to_s
426 end
427 var mprop = self
428 if mprop isa MVirtualTypeDef then
429 res.add "type"
430 else if mprop isa MMethodDef then
431 if mprop.is_abstract then
432 res.add "abstract"
433 else if mprop.is_intern then
434 res.add "intern"
435 end
436 if mprop.mproperty.is_init then
437 res.add "init"
438 else
439 res.add "fun"
440 end
441 end
442 return res
443 end
444 end
445
446 redef class MAttributeDef
447
448 redef fun html_modifiers do
449 var res = super
450 res.add "var"
451 return res
452 end
453
454 redef fun html_short_signature do return new Template
455
456 redef fun html_signature do
457 var static_mtype = self.static_mtype
458 var tpl = new Template
459 if static_mtype != null then
460 tpl.add ": "
461 tpl.add static_mtype.html_signature
462 end
463 return tpl
464 end
465 end
466
467 redef class MMethodDef
468
469 # FIXME annotation should be handled in their own way
470 redef fun html_modifiers do
471 if mproperty.is_init then
472 var res = new Array[String]
473 if mproperty.visibility != public_visibility then
474 res.add mproperty.visibility.to_s
475 end
476 return res
477 end
478 var res = super
479 if is_abstract then
480 res.add "abstract"
481 else if is_intern then
482 res.add "intern"
483 end
484 res.add "fun"
485 return res
486 end
487
488 redef fun html_declaration do
489 if mproperty.is_init then
490 var tpl = new Template
491 tpl.add "<span>"
492 tpl.add html_modifiers.join(" ")
493 tpl.add " "
494 tpl.add html_link
495 tpl.add html_signature
496 tpl.add "</span>"
497 return tpl
498 end
499 return super
500 end
501
502 redef fun html_short_signature do
503 var new_msignature = self.new_msignature
504 if mproperty.is_root_init and new_msignature != null then
505 return new_msignature.html_short_signature
506 end
507 return msignature.as(not null).html_short_signature
508 end
509
510 redef fun html_signature do
511 var new_msignature = self.new_msignature
512 if mproperty.is_root_init and new_msignature != null then
513 return new_msignature.html_signature
514 end
515 return msignature.as(not null).html_signature
516 end
517 end
518
519 redef class MVirtualTypeProp
520 redef fun html_link do return mvirtualtype.html_link
521 end
522
523 redef class MVirtualTypeDef
524
525 redef fun html_modifiers do
526 var res = super
527 res.add "type"
528 return res
529 end
530
531 redef fun html_short_signature do return new Template
532
533 redef fun html_signature do
534 var bound = self.bound
535 var tpl = new Template
536 if bound == null then return tpl
537 tpl.add ": "
538 tpl.add bound.html_signature
539 return tpl
540 end
541 end
542
543 redef class MType
544 # Returns the signature of this type whithout bounds.
545 fun html_short_signature: Template is abstract
546
547 # Returns the signature of this type.
548 fun html_signature: Template is abstract
549 end
550
551 redef class MClassType
552 redef fun html_link do return mclass.html_link
553 redef fun html_short_signature do return html_link
554 redef fun html_signature do return html_link
555 end
556
557 redef class MNullableType
558 redef fun html_short_signature do
559 var tpl = new Template
560 tpl.add "nullable "
561 tpl.add mtype.html_short_signature
562 return tpl
563 end
564
565 redef fun html_signature do
566 var tpl = new Template
567 tpl.add "nullable "
568 tpl.add mtype.html_signature
569 return tpl
570 end
571 end
572
573 redef class MGenericType
574 redef fun html_short_signature do
575 var lnk = html_link
576 var tpl = new Template
577 tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
578 tpl.add "["
579 for i in [0..arguments.length[ do
580 tpl.add arguments[i].html_short_signature
581 if i < arguments.length - 1 then tpl.add ", "
582 end
583 tpl.add "]"
584 return tpl
585 end
586
587 redef fun html_signature do
588 var lnk = html_link
589 var tpl = new Template
590 tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
591 tpl.add "["
592 for i in [0..arguments.length[ do
593 tpl.add arguments[i].html_signature
594 if i < arguments.length - 1 then tpl.add ", "
595 end
596 tpl.add "]"
597 return tpl
598 end
599 end
600
601 redef class MParameterType
602 redef fun html_short_signature do return html_link
603 redef fun html_signature do return html_link
604 redef fun html_raw_namespace do return html_name
605 end
606
607 redef class MVirtualType
608 redef fun html_signature do return html_link
609 redef fun html_raw_namespace do return html_name
610 end
611
612 redef class MSignature
613 redef fun html_short_signature do
614 var tpl = new Template
615 if not mparameters.is_empty then
616 tpl.add "("
617 for i in [0..mparameters.length[ do
618 tpl.add mparameters[i].html_short_signature
619 if i < mparameters.length - 1 then tpl.add ", "
620 end
621 tpl.add ")"
622 end
623 return tpl
624 end
625
626 redef fun html_signature do
627 var tpl = new Template
628 if not mparameters.is_empty then
629 tpl.add "("
630 for i in [0..mparameters.length[ do
631 tpl.add mparameters[i].html_signature
632 if i < mparameters.length - 1 then tpl.add ", "
633 end
634 tpl.add ")"
635 end
636 var return_mtype = self.return_mtype
637 if return_mtype != null then
638 tpl.add ": "
639 tpl.add return_mtype.html_signature
640 end
641 return tpl
642 end
643 end
644
645 redef class MParameter
646
647 # Returns `self` name and ellipsys if any.
648 fun html_short_signature: Template do
649 var tpl = new Template
650 tpl.add name
651 if is_vararg then tpl.add "..."
652 return tpl
653 end
654
655 # Returns `self` name with it's static type and ellipsys if any.
656 fun html_signature: Template do
657 var tpl = new Template
658 tpl.add "{name}: "
659 tpl.add mtype.html_signature
660 if is_vararg then tpl.add "..."
661 return tpl
662 end
663 end
664
665 redef class MEntityTree
666 # Render `self` as a hierarchical UnorderedList.
667 fun html_list: UnorderedList do
668 var lst = new_unordered_list
669 for r in roots do
670 var li = new_mentity_item(r)
671 lst.add_li li
672 build_html_list(r, li)
673 end
674 return lst
675 end
676
677 # Build the html list recursively.
678 private fun build_html_list(e: MEntity, li: ListItem) do
679 if not sub.has_key(e) then return
680 var subs = sub[e]
681 var lst = new_unordered_list
682 for e2 in subs do
683 if e2 isa MGroup and e2.is_root then
684 build_html_list(e2, li)
685 else
686 var sli = new_mentity_item(e2)
687 lst.add_li sli
688 build_html_list(e2, sli)
689 end
690 end
691 var text = new Template
692 text.add li.text
693 if not lst.is_empty then text.add lst
694 li.text = text
695 end
696
697 # HTML unordered List used to compose the tree.
698 #
699 # Redefine this method to add custom CSS classes or other html attributes.
700 protected fun new_unordered_list: UnorderedList do return new UnorderedList
701
702 # Return a li element for `mconcern` that can be displayed in a concern list
703 protected fun new_mentity_item(mentity: MEntity): ListItem do
704 var tpl = new Template
705 tpl.add mentity.html_link
706 var comment = mentity.html_synopsis
707 if comment != null then
708 tpl.add ": "
709 tpl.add comment
710 end
711 return new ListItem(tpl)
712 end
713 end