3 * Copyright (C) 2008-20014 Florian Brosch, Didier Villevalois
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
24 using Valadoc
.Content
;
26 public class Valadoc
.Html
.HtmlRenderer
: ContentRenderer
{
28 protected Documentation? _container
;
29 protected Documentation? _owner
;
30 protected unowned MarkupWriter writer
;
31 protected Html
.CssClassResolver cssresolver
;
32 protected LinkHelper linker
;
33 protected Settings settings
;
35 public HtmlRenderer (Settings settings
, LinkHelper linker
, CssClassResolver cssresolver
) {
36 this
.cssresolver
= cssresolver
;
37 this
.settings
= settings
;
41 public void set_container (Documentation? container
) {
42 _container
= container
;
45 public void set_owner (Documentation? owner
) {
49 public void set_writer (MarkupWriter writer
) {
53 public override void render (ContentElement element
) {
54 element
.accept (this
);
57 public override void render_children (ContentElement element
) {
58 element
.accept_children (this
);
61 private string get_url (Documentation symbol
) {
62 return linker
.get_relative_link (_container
, symbol
, settings
);
65 private void write_unresolved_symbol_link (string given_symbol_name
, InlineContent? label_owner
= null) {
66 if (label_owner
== null || label_owner
.content
.size
== 0) {
67 writer
.start_tag ("code");
68 writer
.text (given_symbol_name
);
69 writer
.end_tag ("code");
71 writer
.start_tag ("i");
72 label_owner
.accept_children (this
);
77 private void write_resolved_symbol_link (Api
.Node symbol
, string? given_symbol_name
, InlineContent? label_owner
= null) {
78 var symbol_name
= (given_symbol_name
== null || given_symbol_name
== "") ? symbol
.get_full_name () : given_symbol_name
;
79 string href
= (symbol
== _container
|| symbol
== _owner
)?
null : get_url (symbol
);
80 string css_class
= cssresolver
.resolve (symbol
);
86 writer
.start_tag ("a", {"href", href
, "class", css_class
});
89 writer
.start_tag ("span", {"class", css_class
});
90 end_tag_name
= "span";
95 if (label_owner
!= null && label_owner
.content
.size
> 0) {
96 label_owner
.accept_children (this
);
98 writer
.text (symbol_name
);
103 writer
.end_tag (end_tag_name
);
106 private delegate
void Write ();
107 private delegate
void TagletWrite (Taglet taglet
);
109 private void write_taglets (Write header
, Write footer
, Write separator
,
110 Vala
.List
<Taglet
> taglets
, TagletWrite write
) {
111 if (taglets
.size
> 0) {
114 foreach (var taglet
in taglets
) {
125 public override void visit_comment (Comment element
) {
126 Vala
.List
<Taglet
> taglets
;
128 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.Deprecated
));
131 writer
.start_tag ("p", {"class", "main_title"});
132 writer
.start_tag ("b")
133 .text ("Deprecated: ")
137 writer
.end_tag ("p");
142 var deprecated
= taglet as Taglets
.Deprecated
;
143 deprecated
.accept_children (this
);
147 element
.accept_children (this
);
149 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.Param
));
150 taglets
.sort ((_a
, _b
) => {
151 Taglets
.Param a
= _a as Taglets
.Param
;
152 Taglets
.Param b
= _b as Taglets
.Param
;
154 if (a
.position
< 0 && b
.position
< 0) {
155 int cmp
= a
.parameter_name
.ascii_casecmp (b
.parameter_name
);
160 if (a
.parameter_name
== "...") {
164 if (b
.parameter_name
== "...") {
171 if (a
.position
< 0) {
175 if (b
.position
< 0) {
179 return a
.position
- b
.position
;
184 writer
.start_tag ("h2", {"class", "main_title"})
185 .text ("Parameters:")
187 writer
.start_tag ("table", {"class", "main_parameter_table"});
190 writer
.end_tag ("table");
195 var param
= taglet as Taglets
.Param
;
196 string[]? unknown_parameter_css
= null;
197 if (param
.parameter
== null && !param
.is_this
) {
198 unknown_parameter_css
= {"class", "main_parameter_table_unknown_parameter"};
201 writer
.start_tag ("tr", unknown_parameter_css
);
202 writer
.start_tag ("td", {"class", "main_parameter_table_name"})
203 .text (param
.parameter_name
)
205 writer
.start_tag ("td");
206 param
.accept_children (this
);
207 writer
.end_tag ("td");
208 writer
.end_tag ("tr");
211 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.Return
));
214 writer
.start_tag ("h2", {"class", "main_title"})
217 writer
.start_tag ("table", {"class", "main_parameter_table"});
220 writer
.end_tag ("table");
225 var param
= taglet as Taglets
.Return
;
226 writer
.start_tag ("tr");
227 writer
.start_tag ("td");
228 param
.accept_children (this
);
229 writer
.end_tag ("td");
230 writer
.end_tag ("tr");
233 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.Throws
));
236 writer
.start_tag ("h2", {"class", "main_title"})
237 .text ("Exceptions:")
239 writer
.start_tag ("table", {"class", "main_parameter_table"});
242 writer
.end_tag ("table");
247 var exception
= taglet as Taglets
.Throws
;
248 writer
.start_tag ("tr");
249 writer
.start_tag ("td", {"class", "main_parameter_table_name"})
250 .text (exception
.error_domain_name
)
252 writer
.start_tag ("td");
253 exception
.accept_children (this
);
254 writer
.end_tag ("td");
255 writer
.end_tag ("tr");
258 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.Since
));
261 writer
.start_tag ("h2", {"class", "main_title"})
264 writer
.start_tag ("p");
267 writer
.end_tag ("p");
272 var since
= taglet as Taglets
.Since
;
273 writer
.text (since
.version
);
276 taglets
= element
.find_taglets ((Api
.Node
) _container
, typeof (Taglets
.See
));
279 writer
.start_tag ("h2", {"class", "main_title"})
282 writer
.start_tag ("p");
285 writer
.end_tag ("p");
292 var see
= taglet as Taglets
.See
;
293 if (see
.symbol
== null) {
294 write_unresolved_symbol_link (see
.symbol_name
);
296 write_resolved_symbol_link (see
.symbol
, see
.symbol_name
);
301 public override void visit_embedded (Embedded element
) {
302 var caption
= element
.caption
;
304 var absolute_path
= Path
.build_filename (settings
.path
, element
.package
.name
, "img",
305 Path
.get_basename (element
.url
));
306 var relative_path
= Path
.build_filename ("img", Path
.get_basename (element
.url
));
308 copy_file (element
.url
, absolute_path
);
310 writer
.image (relative_path
, (caption
== null || caption
== "") ?
"" : caption
);
313 public override void visit_headline (Headline element
) {
314 writer
.start_tag ("h%d".printf (element
.level
));
315 element
.accept_children (this
);
316 writer
.end_tag ("h%d".printf (element
.level
));
319 public override void visit_wiki_link (WikiLink element
) {
320 if (element
.page
!= null) {
321 writer
.start_tag ("a", {"href", get_url (element
.page
)});
324 if (element
.content
.size
> 0) {
325 element
.accept_children (this
);
327 writer
.text (element
.name
.substring (0, element
.name
.last_index_of_char ('.')));
330 if (element
.page
!= null) {
331 writer
.end_tag ("a");
335 public override void visit_link (Link element
) {
336 if (Uri
.parse_scheme (element
.url
) != null) {
337 writer
.start_tag ("a", {"href", element
.url
, "target", "_blank"});
339 writer
.start_tag ("a", {"href", element
.url
});
342 if (element
.content
.size
> 0) {
343 element
.accept_children (this
);
345 writer
.text (element
.url
);
348 writer
.end_tag ("a");
351 public override void visit_symbol_link (SymbolLink element
) {
352 if (element
.symbol
== null) {
353 write_unresolved_symbol_link (element
.given_symbol_name
, element
);
355 write_resolved_symbol_link (element
.symbol
, element
.given_symbol_name
, element
);
359 public override void visit_list (Content
.List element
) {
360 string list_type
= null;
361 string bullet_type
= null;
362 string css_class
= null;
363 switch (element
.bullet
) {
364 case Content
.List
.Bullet
.NONE
:
366 css_class
= "no_bullet";
368 case Content
.List
.Bullet
.UNORDERED
:
371 case Content
.List
.Bullet
.ORDERED
:
374 case Content
.List
.Bullet
.ORDERED_NUMBER
:
378 case Content
.List
.Bullet
.ORDERED_LOWER_CASE_ALPHA
:
382 case Content
.List
.Bullet
.ORDERED_UPPER_CASE_ALPHA
:
386 case Content
.List
.Bullet
.ORDERED_LOWER_CASE_ROMAN
:
390 case Content
.List
.Bullet
.ORDERED_UPPER_CASE_ROMAN
:
395 writer
.start_tag (list_type
, {"class", css_class
, "type", bullet_type
});
396 element
.accept_children (this
);
397 writer
.end_tag (list_type
);
400 public override void visit_list_item (ListItem element
) {
401 writer
.start_tag ("li");
402 Paragraph? first_para
= (element
.content
.size
> 0)? element
.content
[0] as Paragraph
: null;
403 if (first_para
!= null) {
404 // We do not pick up alignments in gir-files.
405 first_para
.accept_children (this
);
406 bool first_entry
= true;
407 foreach (var item
in element
.content
) {
414 element
.accept_children (this
);
416 writer
.end_tag ("li");
419 public override void visit_page (Page element
) {
420 element
.accept_children (this
);
423 public override void visit_paragraph (Paragraph element
) {
424 //FIXME: the extra-field is just a workarround for the current codegen ...
425 switch (element
.horizontal_align
) {
426 case HorizontalAlign
.CENTER
:
427 writer
.start_tag ("p", {"style", "text-align: center;"});
429 case HorizontalAlign
.RIGHT
:
430 writer
.start_tag ("p", {"style", "text-align: right;"});
433 writer
.start_tag ("p");
436 element
.accept_children (this
);
437 writer
.end_tag ("p");
440 private void visit_notification_block (BlockContent element
, string headline
) {
441 writer
.start_tag ("div", {"class", "main_notification_block"});
442 writer
.start_tag ("span", {"class", "main_block_headline"})
446 writer
.start_tag ("div", {"class", "main_block_content"});
447 element
.accept_children (this
);
448 writer
.end_tag ("div");
449 writer
.end_tag ("div");
452 public override void visit_warning (Warning element
) {
453 visit_notification_block (element
, "Warning:");
456 public override void visit_note (Note element
) {
457 visit_notification_block (element
, "Note:");
460 public override void visit_run (Run element
) {
462 string css_type
= null;
463 switch (element
.style
) {
467 case Run
.Style
.ITALIC
:
470 case Run
.Style
.UNDERLINED
:
473 case Run
.Style
.MONOSPACED
:
476 case Run
.Style
.STROKE
:
479 case Run
.Style
.LANG_KEYWORD
:
481 css_type
= "main_keyword";
483 case Run
.Style
.LANG_ESCAPE
:
485 css_type
= "main_escape";
487 case Run
.Style
.LANG_LITERAL
:
489 css_type
= "main_literal";
491 case Run
.Style
.LANG_BASIC_TYPE
:
493 css_type
= "main_basic_type";
495 case Run
.Style
.LANG_TYPE
:
497 css_type
= "main_type";
499 case Run
.Style
.LANG_COMMENT
:
501 css_type
= "main_comment";
503 case Run
.Style
.LANG_PREPROCESSOR
:
505 css_type
= "main_preprocessor";
508 case Run
.Style
.XML_ESCAPE
:
510 css_type
= "xml_escape";
513 case Run
.Style
.XML_ELEMENT
:
515 css_type
= "xml_element";
518 case Run
.Style
.XML_ATTRIBUTE
:
520 css_type
= "xml_attribute";
523 case Run
.Style
.XML_ATTRIBUTE_VALUE
:
525 css_type
= "xml_attribute_value";
528 case Run
.Style
.XML_COMMENT
:
530 css_type
= "xml_comment";
533 case Run
.Style
.XML_CDATA
:
535 css_type
= "xml_cdata";
539 writer
.start_tag (tag
, {"class", css_type
});
541 element
.accept_children (this
);
543 writer
.end_tag (tag
);
547 public override void visit_source_code (SourceCode element
) {
548 writer
.set_wrap (false);
549 writer
.start_tag ("pre", {"class", "main_source"});
550 element
.accept_children (this
);
551 writer
.end_tag ("pre");
552 writer
.set_wrap (true);
555 public override void visit_table (Table element
) {
556 writer
.start_tag ("table", {"class", "main_table"});
557 element
.accept_children (this
);
558 writer
.end_tag ("table");
561 public override void visit_table_cell (TableCell element
) {
564 if (element
.horizontal_align
!= HorizontalAlign
.NONE
) {
565 style
+= "text-align: "+element
.horizontal_align
.to_string ()+"; ";
568 if (element
.vertical_align
!= VerticalAlign
.NONE
) {
569 style
+= "vertical-align: "+element
.vertical_align
.to_string ()+"; ";
572 writer
.start_tag ("td", {"class", "main_table",
573 "colspan", element
.colspan
.to_string (),
574 "rowspan", element
.rowspan
.to_string (),
576 element
.accept_children (this
);
577 writer
.end_tag ("td");
580 public override void visit_table_row (TableRow element
) {
581 writer
.start_tag ("tr");
582 element
.accept_children (this
);
583 writer
.end_tag ("tr");
586 public override void visit_taglet (Taglet element
) {
589 public override void visit_text (Text element
) {
590 write_string (element
.content
);
593 private void write_string (string content
) {
594 unichar chr
= content
[0];
598 for (i
= 0; chr
!= '\0' ; i
++, chr
= content
[i
]) {
601 writer
.text (content
.substring (lpos
, i
-lpos
));
602 writer
.simple_tag ("br");
606 writer
.text (content
.substring (lpos
, i
-lpos
));
607 writer
.text ("<");
611 writer
.text (content
.substring (lpos
, i
-lpos
));
612 writer
.text (">");
616 writer
.text (content
.substring (lpos
, i
-lpos
));
617 writer
.text ("&");
622 writer
.text (content
.substring (lpos
, i
-lpos
));