2 # -*- coding: utf-8; -*-
4 ### WTF, perl cannot read a file?
5 ###use File::Slurp qw( read_file );
7 ### texi2html customization script for LilyPond
8 ### Author: Reinhold Kainhofer <reinhold@kainhofer.com>, 2008.
9 ### Some code parts copied from texi2html and adapted. These functions
10 ### were written mainly by Patrice Dumas
14 ### Features implemented here:
15 ### -) For split manuals, the main page is index.html.
16 ### -) All @unnumbered* sections are placed into the same file
17 ### (implemented by split_at_numbered_sections)
18 ### -) Use our custom CSS file, with IE-specific fixes in another CSS file,
19 ### impelmented by lilypond_css_lines
20 ### -) TOC (folded, with the current page highlighted) in an overflown <div>
21 ### is added to every page; implemented by:
22 ### lilypond_print_element_header -- building of the TOC
23 ### lilypond_toc_body -- generation of customized TOC output
24 ### lilypond_print_page_head -- start <div id="main">
25 ### print_lilypond_page_foot -- closing id=main, output of footer & TOC
26 ### -) External refs are formatted only as "Text of the node" (not as >>see
27 ### "NODE" section "SECTION" in "BOOK"<< like with default texi2html). Also,
28 ### the leading "(book-name)" is removed.
29 ### Implemented by overriding lilypond_external_ref
30 ### -) Navigation bars on top/bottom of the page and between sections are not
31 ### left-aligned, but use a combination of left/center/right aligned table
32 ### cells; For this, I heavily extend the texi2html code to allow for
33 ### differently aligned cells and for multi-line tables);
34 ### Implemented in lilypond_print_navigation
35 ### -) Different formatting than the default: example uses the same formatting
37 ### -) Allow translated section titles: All section titles can be translated,
38 ### the original (English) title is associated with @translationof. This is
39 ### needed, because the file name / anchor is generated from the original
40 ### English title, since otherwise language-autoselection would break with
42 ### Since it is then no longer possible to obtain the file name from the
43 ### section title, I keep a sectionname<=>filename/anchor around. This way,
44 ### xrefs from other manuals can simply load that map and retrieve the
45 ### correct file name for the link. Implemented in:
46 ### lilypond_unknown (handling of @translationof, in case
47 ### extract_texi_filenames.py messes up...)
48 ### lilypond_element_file_name (correct file name: use the map)
49 ### lilypond_element_target_name (correct anchor: use the map)
50 ### lilypond_init_map (read in the externally created map from disk)
51 ### lilypond_external_href (load the map for xrefs, use the correct
53 ### -) The HTML anchors for all sections are derived from the node name /
54 ### section title (pre-generated in the .xref-map file). Implemented by:
55 ### lilypond_element_target_name (adjust section anchors)
56 ### -) Use the standard footnote format "<sup>nr</sup> text" instead of the
57 ### ugly format of texi2html (<h3>(nr)</h3><p>text</p>). Implemented in
58 ### makeinfo_like_foot_line_and_ref
59 ### makeinfo_like_foot_lines
60 ### makeinfo_like_paragraph
63 ### Useful helper functions:
64 ### -) texinfo_file_name($node_name): returns a texinfo-compatible file name
65 ### for the given string $node_name (whitespace trimmed/replaced by -,
66 ### non-standard chars replaced by _xxxx (ascii char code) and forced to
67 ### start with a letter by prepending t_g if necessary)
70 package Texi2HTML::Config;
72 #############################################################################
74 #############################################################################
77 my $LY_LANGUAGES = {};
78 $LY_LANGUAGES->{'fr'} = {
79 'Back to Documentation Index' => 'Retour à l\'accueil de la documentation',
81 $LY_LANGUAGES->{'es'} = {
82 'Back to Documentation Index' => 'Volver al índice de la documentación',
84 $LY_LANGUAGES->{'de'} = {
85 'Back to Documentation Index' => 'Zur Dokumentationsübersicht',
87 $LY_LANGUAGES->{'ja'} = {
88 'Back to Documentation Index' => 'ドキュメント インデックスに戻る',
92 sub ly_get_string () {
93 my $lang = $Texi2HTML::THISDOC{current_lang};
95 if ($lang and $lang ne "en" and $LY_LANGUAGES->{$lang}->{$string}) {
96 return $LY_LANGUAGES->{$lang}->{$string};
103 #############################################################################
104 ### SETTINGS FOR TEXI2HTML
105 #############################################################################
107 # Validation fix for texi2html<=1.82
108 $Texi2HTML::Config::DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
110 @Texi2HTML::Config::CSS_REFS = (
111 {FILENAME => "lilypond-web.css", TITLE => "Default style"},
114 @Texi2HTML::Config::ALT_CSS_REFS = (
115 {FILENAME => "lilypond-web-alt1.css", TITLE => "Alternate style 1"},
116 {FILENAME => "lilypond-web-alt2.css", TITLE => "Alternate style 2"},
119 $Texi2HTML::Config::USE_ACCESSKEY = 1;
120 $Texi2HTML::Config::USE_LINKS = 1;
121 $Texi2HTML::Config::USE_REL_REV = 1;
122 $Texi2HTML::Config::SPLIT_INDEX = 0;
123 $Texi2HTML::Config::SEPARATED_FOOTNOTES = 0; # Print footnotes on same page, not separated
124 # FIXME: remove for GOP
125 #if ($Texi2HTML::Config::SPLIT eq 'section') {
126 # $Texi2HTML::Config::element_file_name = \&lilypond_element_file_name;
130 # FIXME: creates duplicate anchors, which causes Opera to barf;
131 # should be fixed in lilypond-texi2html.init too
132 # $Texi2HTML::Config::element_target_name = \&lilypond_element_target_name;
133 $default_print_element_header = $Texi2HTML::Config::print_element_header;
134 $Texi2HTML::Config::print_element_header = \&lilypond_print_element_header;
135 $Texi2HTML::Config::print_page_foot = \&print_lilypond_page_foot;
136 $Texi2HTML::Config::print_navigation = \&lilypond_print_navigation;
137 $Texi2HTML::Config::external_ref = \&lilypond_external_ref;
138 $default_external_href = $Texi2HTML::Config::external_href;
139 $Texi2HTML::Config::external_href = \&lilypond_external_href;
140 $default_toc_body = $Texi2HTML::Config::toc_body;
141 $Texi2HTML::Config::toc_body = \&lilypond_toc_body;
142 $Texi2HTML::Config::css_lines = \&lilypond_css_lines;
143 $default_unknown = $Texi2HTML::Config::unknown;
144 $Texi2HTML::Config::unknown = \&lilypond_unknown;
145 $default_print_page_head = $Texi2HTML::Config::print_page_head;
146 $Texi2HTML::Config::print_page_head = \&lilypond_print_page_head;
147 # $Texi2HTML::Config::foot_line_and_ref = \&lilypond_foot_line_and_ref;
148 $Texi2HTML::Config::foot_line_and_ref = \&makeinfo_like_foot_line_and_ref;
149 $Texi2HTML::Config::foot_lines = \&makeinfo_like_foot_lines;
150 $Texi2HTML::Config::paragraph = \&makeinfo_like_paragraph;
154 # Examples should be formatted similar to quotes:
155 $Texi2HTML::Config::complex_format_map->{'example'} = {
156 'begin' => q{"<blockquote>"},
157 'end' => q{"</blockquote>\n"},
161 %Texi2HTML::config::misc_pages_targets = (
162 'Overview' => 'Overview',
163 'Contents' => 'Contents',
168 my @section_to_filename;
173 #############################################################################
175 #############################################################################
178 $Data::Dumper::Maxdepth = 2;
180 sub print_element_info($)
183 print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
184 print "Element: $element\n";
185 print Dumper($element);
192 #############################################################################
194 #############################################################################
196 # Convert a given node name to its proper file name (normalization as explained
197 # in the texinfo manual:
198 # http://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html
199 sub texinfo_file_name($)
203 # File name normalization by texinfo:
204 # 1/2: letters and numbers are left unchanged
205 # 3/4: multiple, leading and trailing whitespace is removed
206 $text = main::normalise_space($text);
207 # 5/6: all remaining spaces are converted to '-', all other 7- or 8-bit
208 # chars are replaced by _xxxx (xxxx=ascii character code)
209 while ($text ne '') {
210 if ($text =~ s/^([A-Za-z0-9]+)//o) { # number or letter stay unchanged
212 } elsif ($text =~ s/^ //o) { # space -> '-'
214 } elsif ($text =~ s/^(.)//o) { # Otherwise use _xxxx (ascii char code)
216 if ( $ccode <= 0xFFFF ) {
217 $result .= sprintf("_%04x", $ccode);
219 $result .= sprintf("__%06x", $ccode);
223 # 7: if name does not begin with a letter, prepend 't_g' (so it starts with a letter)
224 if ($result !~ /^[a-zA-Z]/) {
225 $result = 't_g' . $result;
232 # Load a file containing a nodename<=>filename map (tab-sepatared, i.e.
233 # NODENAME\tFILENAME\tANCHOR
234 # Returns a ref to a hash "Node title" => ["FilenameWithoutExt", "Anchor"]
235 sub load_map_file ($)
240 if (open(XREFFILE, $mapfile)) {
241 print STDERR "Reading map file: $mapfile\n";
243 while ( $line = <XREFFILE> ) {
244 # parse the tab-separated entries and insert them into the map:
246 my @entries = split(/\t/, $line);
247 if (scalar (@entries) == 3) {
248 $node_map->{$entries[0]} = [$entries[1], $entries[2]];
250 print STDERR "Invalid entry in the node file $mapfile: $line\n";
255 print STDERR "warning: cannot load map file: no such file: $mapfile\n";
261 # Split the given path into dir and basename (with .texi removed). Used mainly
262 # to get the path/basename of the original texi input file
263 sub split_texi_filename ($)
266 my ($docu_dir, $docu_name);
267 if ($docu =~ /(.*\/)/) {
268 chop($docu_dir = $1);
270 $docu_name =~ s/.*\///;
275 $docu_name =~ s/\.te?x(i|info)?$//;
276 return ($docu_dir, $docu_name);
283 #############################################################################
285 #############################################################################
287 # Include our standard CSS file, not hard-coded CSS code directly in the HTML!
288 # For IE, conditionally include the lilypond-ie-fixes.css style sheet
289 sub lilypond_css_lines ($$)
291 my $import_lines = shift;
292 my $rule_lines = shift;
293 return if (defined($Texi2HTML::THISDOC{'CSS_LINES'}));
294 if (@$rule_lines or @$import_lines)
296 $Texi2HTML::THISDOC{'CSS_LINES'} = "<style type=\"text/css\">\n<!--\n";
297 $Texi2HTML::THISDOC{'CSS_LINES'} .= join('',@$import_lines) . "\n" if (@$import_lines);
298 $Texi2HTML::THISDOC{'CSS_LINES'} .= join('',@$rule_lines) . "\n" if (@$rule_lines);
299 $Texi2HTML::THISDOC{'CSS_LINES'} .= "-->\n</style>\n";
301 foreach my $ref (@CSS_REFS)
303 $Texi2HTML::THISDOC{'CSS_LINES'} .= "<link rel=\"stylesheet\" type=\"text/css\" title=\"$ref->{TITLE}\" href=\"$ref->{FILENAME}\">\n";
306 foreach my $ref (@Texi2HTML::Config::ALT_CSS_REFS)
308 $Texi2HTML::THISDOC{'CSS_LINES'} .= "<link rel=\"alternate stylesheet\" type=\"text/css\" href=\"$ref->{FILENAME}\" title=\"$ref->{TITLE}\">\n";
311 # GOP tweak: We aren't using an IE-specific stylesheet
312 #$Texi2HTML::THISDOC{'CSS_LINES'} .= "<!--[if lte IE 7]>\n<link href=\"lilypond-ie-fixes.css\" rel=\"stylesheet\" type=\"text/css\">\n<![endif]-->\n";
319 #############################################################################
320 ### SPLITTING BASED ON NUMBERED SECTIONS
321 #############################################################################
323 # FIXME: removed for GOP.
326 #############################################################################
327 ### CLEANER LINK TITLE FOR EXTERNAL REFS
328 #############################################################################
330 # The default formatting of external refs returns e.g.
331 # "(lilypond-internals)Timing_translator", so we remove all (...) from the
332 # file_and_node argument. Also, we want only a very simple format, so we don't
333 # even call the default handler!
334 sub lilypond_external_ref($$$$$$)
339 my $file_node = shift;
341 my $cross_ref = shift;
343 my $displaytext = '';
345 # 1) if we have a cross ref name, that's the text to be displayed:
346 # 2) For the top node, use the (printable) name of the manual, unless we
347 # have an explicit cross ref name
348 # 3) In all other cases use the section name
349 if ($cross_ref ne '') {
350 $displaytext = $cross_ref;
351 } elsif (($section eq '') or ($section eq 'Top')) {
352 $displaytext = $book;
354 $displaytext = $section;
357 $displaytext = &$anchor('', $href, $displaytext) if ($displaytext ne '');
358 return &$I('%{node_file_href}', { 'node_file_href' => $displaytext });
365 #############################################################################
366 ### HANDLING TRANSLATED SECTIONS: handle @translationof, secname<->filename
367 ### map stored on disk, xrefs in other manuals load that map
368 #############################################################################
371 # Try to make use of @translationof to generate files according to the original
372 # English section title...
373 sub lilypond_unknown($$$$$)
381 # the @translationof macro provides the original English section title,
382 # which should be used for file/anchor naming, while the title will be
383 # translated to each language
384 # It is already used by extract_texi_filenames.py, so this should not be
385 # necessary here at all. Still, I'll leave the code in just in case the
386 # python script messed up ;-)
387 if ($pass == 1 and $macro eq "translationof") {
388 if (ref($state->{'element'}) eq 'HASH') {
389 $state->{'element'}->{'translationof'} = main::normalise_space($line);
391 return ('', 1, undef, undef);
393 return &$default_unknown($macro, $line, $pass, $stack, $state);
400 my %translated_books = ();
401 # Construct a href to an external source of information.
402 # node is the node with texinfo @-commands
403 # node_id is the node transliterated and transformed as explained in the
405 # node_xhtml_id is the node transformed such that it is unique and can
406 # be used to make an html cross ref as explained in the texinfo manual
407 # file is the file in '(file)node'
408 sub lilypond_external_href($$$)
412 my $node_hxmlt_id = shift;
415 # 1) Keep a hash of book->section_map
416 # 2) if not file in keys hash => try to load the map (assign empty map if
417 # non-existent => will load only once!)
418 # 3) if node in the section=>(file, anchor) map, replace node_id and
419 # node_xhtml_id by the map's values
420 # 4) call the default_external_href with these values (or the old ones if not found)
422 if (($node_id ne '') and defined($file) and ($node_id ne 'Top')) {
423 my $map_name = $file;
424 $map_name =~ s/-big-page//;
426 # Load the map if we haven't done so already
427 if (!exists($translated_books{$map_name})) {
428 my ($docu_dir, $docu_name) = split_texi_filename ($Texi2HTML::THISDOC{'input_file_name'});
429 my $map_filename = main::locate_include_file ("${map_name}.$Texi2HTML::THISDOC{current_lang}.xref-map")
430 || main::locate_include_file ("${map_name}.xref-map");
431 $translated_books{$map_name} = load_map_file ($map_filename);
434 # look up translation. use these values instead of the old filename/anchor
435 my $section_name_map = $translated_books{$map_name};
436 my $node_text = main::remove_texi($node);
437 if (defined($section_name_map->{$node_text})) {
438 ($node_id, $node_hxmlt_id) = @{$section_name_map->{$node_text}};
440 print STDERR "WARNING: Unable to find node '$node_text' in book $map_name.\n";
445 return &$default_external_href($node, $node_id, $node_hxmlt_id, $file);
447 return &$default_external_href($node, $node_id, $node_hxmlt_id);
455 #############################################################################
456 ### CUSTOM TOC FOR EACH PAGE (in a frame on the left)
457 #############################################################################
459 my $page_toc_depth = 2;
460 my @default_toc = [];
462 # Initialize the toc_depth to 1 if the command-line option -D=short_toc is given
463 sub lilypond_init_toc_depth ()
465 if (exists($main::value{'short_toc'}) and not exists($main::value{'bigpage'})) {
469 # Set the TOC-depth (depending on a texinfo variable short_toc) in a
470 # command-handler, so we have them available when creating the pages
471 push @Texi2HTML::Config::command_handler_process, \&lilypond_init_toc_depth;
474 # recursively generate the TOC entries for the element and its children (which
475 # are only shown up to maxlevel. All ancestors of the current element are also
476 # shown with their immediate children, irrespective of their level.
477 # Unnumbered entries are only printed out if they are at top-level or 2nd level
478 # or their parent element is an ancestor of the currently viewed node.
479 # The conditions to call this method to print the entry for a child node is:
480 # -) the parent is an ancestor of the current page node
481 # -) the parent is a numbered element at top-level toplevel (i.e. show numbered
482 # and unnumbered 2nd-level children of numbered nodes)
483 # -) the child element is a numbered node below level maxlevel
484 sub generate_ly_toc_entries($$$)
487 my $element_path = shift;
489 #my $maxlevel = shift;
491 # Skip undefined sections, plus all sections generated by index splitting
492 return() if (not defined($element) or exists($element->{'index_page'}));
494 my $level = $element->{'toc_level'};
495 my $is_parent_of_current = $element->{'id'} && $element_path->{$element->{'id'}};
496 my $ind = ' ' x $level;
497 # GDP hack: leave this open for color
498 my $this_css_class = " class=\"";
499 $this_css_class .= $is_parent_of_current ? " toc_current" : "";
501 # GDP tweak: if the node name is in the color_X list
502 # TODO: use a hash, load from file?
503 # FIXME: load from file, to allow for translations!
507 "Learning", "Glossary", "Essay",
508 "Contact", "Tiny examples", "Bug reports"
511 "Features", "Examples", "Freedom",
512 "Unix", "MacOS X", "Windows",
513 "Notation", "Usage", "Snippets",
514 "Help us", "Development", "Authors"
517 "Productions", "Testimonials",
518 "Source", "Old downloads",
519 "FAQ", "Changes", "Internals",
520 "Publications", "Old news"
525 "Translated", "Old", "FDL"
528 my $addColor = " colorDefault";
529 foreach $color (@color_1) {
530 if ($element->{'text'} eq $color) {
531 $addColor = " color1";
534 foreach $color (@color_2) {
535 if ($element->{'text'} eq $color) {
536 $addColor = " color2";
539 foreach $color (@color_3) {
540 if ($element->{'text'} eq $color) {
541 $addColor = " color3";
544 foreach $color (@color_4) {
545 if ($element->{'text'} eq $color) {
546 $addColor = " color4";
550 $this_css_class .= $addColor . "\"";
555 my $entry = "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}",$element->{'text'});
557 push (@result, $entry);
558 my $children = $element->{'section_childs'};
559 if (defined($children) and (ref($children) eq "ARRAY")) {
560 my $force_children = $is_parent_of_current or ($level == 1 and $element->{'number'});
561 my @child_result = ();
562 foreach my $c (@$children) {
563 my $is_numbered_child = defined ($c->{'number'});
564 my $below_maxlevel = $c->{'toc_level'} le $maxlevel;
565 if ($force_children or ($is_numbered_child and $below_maxlevel)) {
566 my @child_res = generate_ly_toc_entries($c, $element_path, $maxlevel);
567 push (@child_result, @child_res);
570 # if no child nodes were generated, e.g. for the index, where expanded pages
571 # are ignored, don't generate a list at all...
573 push (@result, "\n$ind<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
575 # GOP tweak: (next 2 lines; alternates)
576 push (@result, "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}","(main)"));
577 #push (@result, "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}","(".$element->{'text'}." main)"));
578 push (@result, @child_result);
579 push (@result, "$ind</ul>\n");
582 push (@result, "$ind</li>\n");
587 # Print a customized TOC, containing only the first two levels plus the whole
588 # path to the current page
589 sub lilypond_generate_page_toc_body($)
592 my $current_element = $element;
594 $parentelements{$element->{'id'}} = 1;
595 # Find the path to the current element
596 while ( defined($current_element->{'sectionup'}) and
597 ($current_element->{'sectionup'} ne $current_element) )
599 $parentelements{$current_element->{'sectionup'}->{'id'}} = 1
600 if ($current_element->{'sectionup'}->{'id'} ne '');
601 $current_element = $current_element->{'sectionup'};
602 if (exists($main::value{'shallow_toc'})) {
606 return () if not defined($current_element);
607 # Create the toc entries recursively
609 my @toc_entries = ("<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
610 # my @toc_entries = ("<div class=\"contents\">\n", "<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
612 # FIXME: add link to main page, really hackily.
613 if ($element->{'sectionup'}) {
614 # it's not the top element
615 push (@toc_entries, "<li><a href=\"index.html\">Main</a></li>\n");
617 push (@toc_entries, "<li class=\"toc_current\"><a href=\"index.html\">Main</a></li>\n");
619 my $children = $current_element->{'section_childs'};
620 # FIXME: generate toc
621 foreach ( @$children ) {
622 push (@toc_entries, generate_ly_toc_entries($_, \%parentelements, $page_toc_depth));
624 if (!exists($main::value{'shallow_toc'})) {
625 # WTF, perl needs 6 lines of magic to do: ' ' + open ('file-name').read ()?
627 my $name = 'search-box.html';
628 open FILE, $name or open FILE, "../$name" or die die "no such file: $name: $!";
630 # All these also seems to work, but fail silently. Great, it runs!
631 # It's late already, let's this broken site.
633 # push (@toc_entries, '<li>\n' + <FILE> + '</li>\n');
634 # push (@toc_entries, '<li>\n' . <FILE> . '</li>\n');
635 # my $string = '<li>\n' + <FILE> + '</li>\n';
636 # my $string = '<li>\n' + <FILE> + '</li>\n';
637 # my $string = '<li>\n' . <FILE> . '</li>\n';
639 # $string = '<li>\n' + $string + '</li>\n';
640 $string = "<li>\n" . $string . "</li>\n";
641 push (@toc_entries, $string);
644 push (@toc_entries, "</ul>\n");
646 # push (@toc_entries, "</div>\n");
647 push (@toc_entries, "\n");
651 sub lilypond_print_toc_div ($$)
655 my @lines = @$tocref;
656 # use default TOC if no custom lines have been generated
657 @lines = @default_toc if (not @lines);
660 print $fh "\n\n<div id=\"tocframe\">\n";
661 #print $fh "<div class=\"contents\">\n";
663 # Remove the leading "GNU LilyPond --- " from the manual title
664 my $topname = $Texi2HTML::NAME{'Top'};
665 $topname =~ s/^GNU LilyPond(:| &[mn]dash;) //;
667 # construct the top-level Docs index (relative path and including language!)
668 my $lang = $Texi2HTML::THISDOC{current_lang};
669 if ($lang and $lang ne "en") {
675 $reldir = "../" if ($Texi2HTML::Config::SPLIT eq 'section');
676 my $uplink = $reldir."index.${lang}html";
678 # print $fh "<p class=\"toc_uplink\"><a href=\"$uplink\"
679 # title=\"Documentation Index\"><< " .
680 # &ly_get_string ('Back to Documentation Index') .
683 # print $fh '<h4 class="toc_header"> ' . &$anchor('',
684 # $Texi2HTML::HREF{'Top'},
686 # 'title="Start of the manual"'
690 foreach my $line (@lines) {
694 print $fh "</div>\n\n";
698 # Create the custom TOC for this page (partially folded, current page is
699 # highlighted) and store it in a global variable. The TOC is written out after
700 # the html contents (but positioned correctly using CSS), so that browsers with
701 # css turned off still show the contents first.
702 our @this_page_toc = ();
703 sub lilypond_print_element_header
705 my $first_in_page = shift;
706 my $previous_is_top = shift;
707 if ($first_in_page and not @this_page_toc) {
708 if (defined($Texi2HTML::THIS_ELEMENT)) {
709 # Create the TOC for this page
710 @this_page_toc = lilypond_generate_page_toc_body($Texi2HTML::THIS_ELEMENT);
713 return &$default_print_element_header( $first_in_page, $previous_is_top);
716 # Generate the HTML output for the TOC
717 sub lilypond_toc_body($)
719 my $elements_list = shift;
720 # Generate a default TOC for pages without THIS_ELEMENT
721 @default_toc = lilypond_generate_page_toc_body(@$elements_list[0]);
722 return &$default_toc_body($elements_list);
725 # Print out the TOC in a <div> at the beginning of the page
726 sub lilypond_print_page_head($)
729 &$default_print_page_head($fh);
730 print $fh "<div id=\"main\">\n";
733 # Print out the TOC in a <div>, which will be formatted as a
734 # sidebar mimicking a TOC frame
735 sub print_lilypond_page_foot($)
738 my $program_string = &$program_string();
739 # print $fh "<p><font size='-1'>$program_string</font><br>$PRE_BODY_CLOSE</p>\n";
741 # Do not include language selection in div#main
742 print $fh "<!-- end div#main here -->\n</div>\n\n";
745 print $fh "<!-- FOOTER -->\n\n";
746 print $fh "<div id=\"footer\">\n";
747 print $fh "<div id=\"language\">\n";
748 print $fh "<h3>Other languages</h3>\n";
749 print $fh "<p><a href=\"\">Deutsch</a>, Español, Français, Magyar.</p>\n";
750 print $fh "<p>About automatic language selection.</p>\n";
751 print $fh "</div>\n";
754 print $fh "<div id=\"verifier_texinfo\">\n";
755 print $fh "<h3>Validation</h3>\n";
756 print $fh "<p>Thanks to <a href=\"http://www.webdev.nl/\">webdev.nl</a>";
757 print $fh " for hosting <code>lilypond.org</code>.\n";
758 print $fh "<a href=\"http://validator.w3.org/check?uri=referer\">\n";
759 print $fh "<img src=\"http://www.w3.org/Icons/valid-html401\"\n";
760 print $fh " alt=\"Valid HTML 4.01 Transitional\"\n";
761 print $fh " height=\"31\" width=\"88\"></a></p>\n";
765 # Print the TOC frame and reset the TOC:
766 lilypond_print_toc_div ($fh, \@this_page_toc);
770 print $fh "</body>\n</html>\n";
777 #############################################################################
778 ### NICER / MORE FLEXIBLE NAVIGATION PANELS
779 #############################################################################
781 sub get_navigation_text
784 my $text = $NAVIGATION_TEXT{$button};
785 if ( ($button eq 'Back') or ($button eq 'FastBack') ) {
786 $text = $text . $Texi2HTML::NODE{$button} . " ";
787 } elsif ( ($button eq 'Forward') or ($button eq 'FastForward') ) {
788 $text = " " . $Texi2HTML::NODE{$button} . $text;
789 } elsif ( $button eq 'Up' ) {
790 $text = " ".$text.": " . $Texi2HTML::NODE{$button} . " ";
796 # Don't automatically create left-aligned table cells for every link, but
797 # instead create a <td> only on an appropriate '(left|right|center)-aligned-cell-n'
798 # button text. It's alignment as well as the colspan will be taken from the
799 # name of the button. Also, add 'newline' button text to create a new table
800 # row. The texts of the buttons are generated by get_navigation_text and
801 # will contain the name of the next/previous section/chapter.
802 sub lilypond_print_navigation
805 my $vertical = shift;
807 my $result = "<table class=\"nav_table\">\n";
809 $result .= "<tr>" unless $vertical;
811 foreach my $button (@$buttons)
813 $result .= qq{<tr valign="top" align="left">\n} if $vertical;
814 # Allow (left|right|center)-aligned-cell and newline as buttons!
815 if ( $button =~ /^(.*)-aligned-cell-(.*)$/ )
817 $result .= qq{</td>} unless $beginofline;
818 $result .= qq{<td valign="middle" align="$1" colspan="$2">};
821 elsif ( $button eq 'newline' )
823 $result .= qq{</td>} unless $beginofline;
824 $result .= qq{</tr>};
829 elsif (ref($button) eq 'CODE')
831 $result .= &$button($vertical);
833 elsif (ref($button) eq 'SCALAR')
835 $result .= "$$button" if defined($$button);
837 elsif (ref($button) eq 'ARRAY')
839 my $text = $button->[1];
840 my $button_href = $button->[0];
841 # verify that $button_href is simple text and text is a reference
842 if (defined($button_href) and !ref($button_href)
843 and defined($text) and (ref($text) eq 'SCALAR') and defined($$text))
845 if ($Texi2HTML::HREF{$button_href})
847 my $anchor_attributes = '';
848 if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button_href})) and ($BUTTONS_ACCESSKEY{$button_href} ne ''))
850 $anchor_attributes = "accesskey=\"$BUTTONS_ACCESSKEY{$button_href}\"";
852 if ($USE_REL_REV and (defined($BUTTONS_REL{$button_href})) and ($BUTTONS_REL{$button_href} ne ''))
854 $anchor_attributes .= " rel=\"$BUTTONS_REL{$button_href}\"";
858 $Texi2HTML::HREF{$button_href},
859 get_navigation_text($$text),
865 $result .= get_navigation_text($$text);
869 elsif ($button eq ' ')
870 { # handle space button
872 ($ICONS && $ACTIVE_ICONS{' '}) ?
873 &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{' '}) :
874 $NAVIGATION_TEXT{' '};
877 elsif ($Texi2HTML::HREF{$button})
879 my $btitle = $BUTTONS_GOTO{$button} ?
880 'title="' . $BUTTONS_GOTO{$button} . '"' : '';
881 if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button})) and ($BUTTONS_ACCESSKEY{$button} ne ''))
883 $btitle .= " accesskey=\"$BUTTONS_ACCESSKEY{$button}\"";
885 if ($USE_REL_REV and (defined($BUTTONS_REL{$button})) and ($BUTTONS_REL{$button} ne ''))
887 $btitle .= " rel=\"$BUTTONS_REL{$button}\"";
889 if ($ICONS && $ACTIVE_ICONS{$button})
893 $Texi2HTML::HREF{$button},
894 &$button_icon_img($BUTTONS_NAME{$button},
895 $ACTIVE_ICONS{$button},
896 $Texi2HTML::SIMPLE_TEXT{$button}),
905 $Texi2HTML::HREF{$button},
906 get_navigation_text($button),
913 { # button is passive
915 $ICONS && $PASSIVE_ICONS{$button} ?
916 &$button_icon_img($BUTTONS_NAME{$button},
917 $PASSIVE_ICONS{$button},
918 $Texi2HTML::SIMPLE_TEXT{$button}) :
920 "[" . get_navigation_text($button) . "]";
922 $result .= "</td>\n" if $vertical;
923 $result .= "</tr>\n" if $vertical;
925 $result .= "</td>" unless $beginofline;
926 $result .= "</tr>" unless $vertical;
927 $result .= "</table>\n";
933 @Texi2HTML::Config::SECTION_BUTTONS =
934 ('left-aligned-cell-1', 'FastBack',
935 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
936 'right-aligned-cell-1', 'FastForward',
938 'left-aligned-cell-2', 'Back',
939 'center-aligned-cell-1', 'Up',
940 'right-aligned-cell-2', 'Forward'
943 # buttons for misc stuff
944 @Texi2HTML::Config::MISC_BUTTONS = ('center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About');
946 # buttons for chapter file footers
947 # (and headers but only if SECTION_NAVIGATION is false)
948 @Texi2HTML::Config::CHAPTER_BUTTONS =
949 ('left-aligned-cell-1', 'FastBack',
950 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
951 'right-aligned-cell-1', 'FastForward',
954 # buttons for section file footers
955 @Texi2HTML::Config::SECTION_FOOTER_BUTTONS =
956 ('left-aligned-cell-1', 'FastBack',
957 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
958 'right-aligned-cell-1', 'FastForward',
960 'left-aligned-cell-2', 'Back',
961 'center-aligned-cell-1', 'Up',
962 'right-aligned-cell-2', 'Forward'
965 @Texi2HTML::Config::NODE_FOOTER_BUTTONS =
966 ('left-aligned-cell-1', 'FastBack',
967 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
968 'right-aligned-cell-1', 'FastForward',
970 'left-aligned-cell-2', 'Back',
971 'center-aligned-cell-1', 'Up',
972 'right-aligned-cell-2', 'Forward'
979 #############################################################################
980 ### FOOTNOTE FORMATTING
981 #############################################################################
983 # Format footnotes in a nicer way: Instead of printing the number in a separate
984 # (nr) heading line, use the standard way of prepending <sup>nr</sup> immediately
985 # before the fn text.
988 # The following code is copied from texi2html's examples/makeinfo.init and
989 # should be updated when texi2html makes some changes there!
991 my $makekinfo_like_footnote_absolute_number = 0;
993 sub makeinfo_like_foot_line_and_ref($$$$$$$$)
995 my $foot_num = shift;
996 my $relative_num = shift;
999 my $from_file = shift;
1000 my $footnote_file = shift;
1004 $makekinfo_like_footnote_absolute_number++;
1006 # this is a bit obscure, this allows to add an anchor only if formatted
1007 # as part of the document.
1008 $docid = '' if ($state->{'outside_document'} or $state->{'multiple_pass'});
1010 if ($from_file eq $footnote_file)
1012 $from_file = $footnote_file = '';
1015 my $foot_anchor = "<sup>" . &$anchor($docid, "$footnote_file#$footid", $relative_num) . "</sup>";
1016 $foot_anchor = &$anchor($docid, "$footnote_file#$footid", "($relative_num)") if ($state->{'preformatted'});
1018 # unshift @$lines, "<li>";
1019 # push @$lines, "</li>\n";
1020 return ($lines, $foot_anchor);
1023 sub makeinfo_like_foot_lines($)
1026 unshift @$lines, "<hr>\n<h4>$Texi2HTML::I18n::WORDS->{'Footnotes_Title'}</h4>\n";
1027 #<ol type=\"1\">\n";
1028 # push @$lines, "</ol>";
1032 my %makekinfo_like_paragraph_in_footnote_nr;
1034 sub makeinfo_like_paragraph ($$$$$$$$$$$$$)
1039 my $paragraph_command = shift;
1040 my $paragraph_command_formatted = shift;
1041 my $paragraph_number = shift;
1043 my $item_nr = shift;
1044 my $enumerate_style = shift;
1046 my $command_stack_at_end = shift;
1047 my $command_stack_at_begin = shift;
1049 #print STDERR "format: $format\n" if (defined($format));
1050 #print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n";
1051 $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or
1052 exists($special_list_commands{$format}->{$paragraph_command}));
1053 return '' if ($text =~ /^\s*$/);
1054 foreach my $style(t2h_collect_styles($command_stack_at_begin))
1056 $text = t2h_begin_style($style, $text);
1058 foreach my $style(t2h_collect_styles($command_stack_at_end))
1060 $text = t2h_end_style($style, $text);
1062 if (defined($paragraph_number) and defined($$paragraph_number))
1064 $$paragraph_number++;
1065 return $text if (($format eq 'itemize' or $format eq 'enumerate') and
1066 ($$paragraph_number == 1));
1071 $open .= " align=\"$paragraph_style{$align}\"";
1073 my $footnote_text = '';
1074 if (defined($command_stack_at_begin->[0]) and $command_stack_at_begin->[0] eq 'footnote')
1076 my $state = $Texi2HTML::THISDOC{'state'};
1077 $makekinfo_like_paragraph_in_footnote_nr{$makekinfo_like_footnote_absolute_number}++;
1078 if ($makekinfo_like_paragraph_in_footnote_nr{$makekinfo_like_footnote_absolute_number} <= 1)
1080 $open.=' class="footnote"';
1081 my $document_file = $state->{'footnote_document_file'};
1082 if ($document_file eq $state->{'footnote_footnote_file'})
1084 $document_file = '';
1086 my $docid = $state->{'footnote_place_id'};
1087 my $doc_state = $state->{'footnote_document_state'};
1088 $docid = '' if ($doc_state->{'outside_document'} or $doc_state->{'multiple_pass'});
1089 my $foot_label = &$anchor($state->{'footnote_footnote_id'},
1090 $document_file . "#$state->{'footnote_place_id'}",
1091 "$state->{'footnote_number_in_page'}");
1092 $footnote_text = "<small>[${foot_label}]</small> ";
1095 return $open.'>'.$footnote_text.$text.'</p>';
1099 #############################################################################
1101 #############################################################################
1103 # For split pages, use index.html as start page!
1104 if ($Texi2HTML::Config::SPLIT eq 'section') {
1105 $Texi2HTML::Config::TOP_FILE = 'index.html';