2 # -*- coding: utf-8; -*-
4 ### texi2html customization script for LilyPond
5 ### Author: Reinhold Kainhofer <reinhold@kainhofer.com>, 2008.
6 ### Some code parts copied from texi2html and adapted. These functions
7 ### were written mainly by Patrice Dumas
11 ### Features implemented here:
12 ### -) For split manuals, the main page is index.html.
13 ### -) All @unnumbered* sections are placed into the same file
14 ### (implemented by split_at_numbered_sections)
15 ### -) Use our custom CSS file, with IE-specific fixes in another CSS file,
16 ### impelmented by lilypond_css_lines
17 ### -) TOC (folded, with the current page highlighted) in an overflown <div>
18 ### is added to every page; implemented by:
19 ### lilypond_print_element_header -- building of the TOC
20 ### lilypond_toc_body -- generation of customized TOC output
21 ### lilypond_print_page_head -- start <div id="main">
22 ### print_lilypond_page_foot -- closing id=main, output of footer & TOC
23 ### -) External refs are formatted only as "Text of the node" (not as >>see
24 ### "NODE" section "SECTION" in "BOOK"<< like with default texi2html). Also,
25 ### the leading "(book-name)" is removed.
26 ### Implemented by overriding lilypond_external_ref
27 ### -) Navigation bars on top/bottom of the page and between sections are not
28 ### left-aligned, but use a combination of left/center/right aligned table
29 ### cells; For this, I heavily extend the texi2html code to allow for
30 ### differently aligned cells and for multi-line tables);
31 ### Implemented in lilypond_print_navigation
32 ### -) Different formatting than the default: example uses the same formatting
34 ### -) Allow translated section titles: All section titles can be translated,
35 ### the original (English) title is associated with @translationof. This is
36 ### needed, because the file name / anchor is generated from the original
37 ### English title, since otherwise language-autoselection would break with
39 ### Since it is then no longer possible to obtain the file name from the
40 ### section title, I keep a sectionname<=>filename/anchor around. This way,
41 ### xrefs from other manuals can simply load that map and retrieve the
42 ### correct file name for the link. Implemented in:
43 ### lilypond_unknown (handling of @translationof, in case
44 ### extract_texi_filenames.py messes up...)
45 ### lilypond_element_file_name (correct file name: use the map)
46 ### lilypond_element_target_name (correct anchor: use the map)
47 ### lilypond_init_map (read in the externally created map from disk)
48 ### lilypond_external_href (load the map for xrefs, use the correct
50 ### -) The HTML anchors for all sections are derived from the node name /
51 ### section title (pre-generated in the .xref-map file). Implemented by:
52 ### lilypond_element_target_name (adjust section anchors)
53 ### -) Use the standard footnote format "<sup>nr</sup> text" instead of the
54 ### ugly format of texi2html (<h3>(nr)</h3><p>text</p>). Implemented in
55 ### makeinfo_like_foot_line_and_ref
56 ### makeinfo_like_foot_lines
57 ### makeinfo_like_paragraph
60 ### Useful helper functions:
61 ### -) texinfo_file_name($node_name): returns a texinfo-compatible file name
62 ### for the given string $node_name (whitespace trimmed/replaced by -,
63 ### non-standard chars replaced by _xxxx (ascii char code) and forced to
64 ### start with a letter by prepending t_g if necessary)
67 package Texi2HTML
::Config
;
69 #############################################################################
71 #############################################################################
74 my $LY_LANGUAGES = {};
75 $LY_LANGUAGES->{'fr'} = {
76 'Back to Documentation Index' => 'Retour à l\'accueil de la documentation',
78 $LY_LANGUAGES->{'es'} = {
79 'Back to Documentation Index' => 'Volver al índice de la documentación',
81 $LY_LANGUAGES->{'de'} = {
82 'Back to Documentation Index' => 'Zur Dokumentationsübersicht',
84 $LY_LANGUAGES->{'ja'} = {
85 'Back to Documentation Index' => 'ドキュメント インデックスに戻る',
89 sub ly_get_string
() {
90 my $lang = $Texi2HTML::THISDOC
{current_lang
};
92 if ($lang and $lang ne "en" and $LY_LANGUAGES->{$lang}->{$string}) {
93 return $LY_LANGUAGES->{$lang}->{$string};
100 #############################################################################
101 ### SETTINGS FOR TEXI2HTML
102 #############################################################################
104 # Validation fix for texi2html<=1.82
105 $Texi2HTML::Config
::DOCTYPE
= '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
107 @Texi2HTML::Config
::CSS_REFS
= (
108 {FILENAME
=> "lilypond-web.css", TITLE
=> "Default style"},
111 @Texi2HTML::Config
::ALT_CSS_REFS
= (
112 {FILENAME
=> "lilypond-web-alt1.css", TITLE
=> "Alternate style 1"},
113 {FILENAME
=> "lilypond-web-alt2.css", TITLE
=> "Alternate style 2"},
116 $Texi2HTML::Config
::USE_ACCESSKEY
= 1;
117 $Texi2HTML::Config
::USE_LINKS
= 1;
118 $Texi2HTML::Config
::USE_REL_REV
= 1;
119 $Texi2HTML::Config
::SPLIT_INDEX
= 0;
120 $Texi2HTML::Config
::SEPARATED_FOOTNOTES
= 0; # Print footnotes on same page, not separated
121 # FIXME: remove for GOP
122 #if ($Texi2HTML::Config::SPLIT eq 'section') {
123 # $Texi2HTML::Config::element_file_name = \&lilypond_element_file_name;
127 # FIXME: creates duplicate anchors, which causes Opera to barf;
128 # should be fixed in lilypond-texi2html.init too
129 # $Texi2HTML::Config::element_target_name = \&lilypond_element_target_name;
130 $default_print_element_header = $Texi2HTML::Config
::print_element_header
;
131 $Texi2HTML::Config
::print_element_header
= \
&lilypond_print_element_header
;
132 $Texi2HTML::Config
::print_page_foot
= \
&print_lilypond_page_foot
;
133 $Texi2HTML::Config
::print_navigation
= \
&lilypond_print_navigation
;
134 $Texi2HTML::Config
::external_ref
= \
&lilypond_external_ref
;
135 $default_external_href = $Texi2HTML::Config
::external_href
;
136 $Texi2HTML::Config
::external_href
= \
&lilypond_external_href
;
137 $default_toc_body = $Texi2HTML::Config
::toc_body
;
138 $Texi2HTML::Config
::toc_body
= \
&lilypond_toc_body
;
139 $Texi2HTML::Config
::css_lines
= \
&lilypond_css_lines
;
140 $default_unknown = $Texi2HTML::Config
::unknown
;
141 $Texi2HTML::Config
::unknown
= \
&lilypond_unknown
;
142 $default_print_page_head = $Texi2HTML::Config
::print_page_head
;
143 $Texi2HTML::Config
::print_page_head
= \
&lilypond_print_page_head
;
144 # $Texi2HTML::Config::foot_line_and_ref = \&lilypond_foot_line_and_ref;
145 $Texi2HTML::Config
::foot_line_and_ref
= \
&makeinfo_like_foot_line_and_ref
;
146 $Texi2HTML::Config
::foot_lines
= \
&makeinfo_like_foot_lines
;
147 $Texi2HTML::Config
::paragraph
= \
&makeinfo_like_paragraph
;
151 # Examples should be formatted similar to quotes:
152 $Texi2HTML::Config
::complex_format_map
->{'example'} = {
153 'begin' => q{"<blockquote>"},
154 'end' => q{"</blockquote>\n"},
158 %Texi2HTML::config::misc_pages_targets = (
159 'Overview' => 'Overview',
160 'Contents' => 'Contents',
165 my @section_to_filename;
170 #############################################################################
172 #############################################################################
175 $Data::Dumper::Maxdepth = 2;
177 sub print_element_info($)
180 print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
181 print "Element: $element\n";
182 print Dumper($element);
189 #############################################################################
191 #############################################################################
193 # Convert a given node name to its proper file name (normalization as explained
194 # in the texinfo manual:
195 # http://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html
196 sub texinfo_file_name($)
200 # File name normalization by texinfo:
201 # 1/2: letters and numbers are left unchanged
202 # 3/4: multiple, leading and trailing whitespace is removed
203 $text = main::normalise_space($text);
204 # 5/6: all remaining spaces are converted to '-', all other 7- or 8-bit
205 # chars are replaced by _xxxx (xxxx=ascii character code)
206 while ($text ne '') {
207 if ($text =~ s/^([A-Za-z0-9]+)//o) { # number or letter stay unchanged
209 } elsif ($text =~ s/^ //o) { # space -> '-'
211 } elsif ($text =~ s/^(.)//o) { # Otherwise use _xxxx (ascii char code)
213 if ( $ccode <= 0xFFFF ) {
214 $result .= sprintf("_%04x", $ccode);
216 $result .= sprintf("__%06x", $ccode);
220 # 7: if name does not begin with a letter, prepend 't_g' (so it starts with a letter)
221 if ($result !~ /^[a-zA-Z]/) {
222 $result = 't_g' . $result;
229 # Load a file containing a nodename<=>filename map (tab-sepatared, i.e.
230 # NODENAME\tFILENAME\tANCHOR
231 # Returns a ref to a hash "Node title" => ["FilenameWithoutExt", "Anchor"]
232 sub load_map_file ($)
237 if (open(XREFFILE, $mapfile)) {
239 while ( $line = <XREFFILE> ) {
240 # parse the tab-separated entries and insert them into the map:
242 my @entries = split(/\t/, $line);
243 if (scalar (@entries) == 3) {
244 $node_map->{$entries[0]} = [$entries[1], $entries[2]];
246 print STDERR "Invalid entry in the node file $mapfile: $line\n";
251 print STDERR "WARNING: Unable to load the map file $mapfile\n";
257 # Split the given path into dir and basename (with .texi removed). Used mainly
258 # to get the path/basename of the original texi input file
259 sub split_texi_filename ($)
262 my ($docu_dir, $docu_name);
263 if ($docu =~ /(.*\/)/) {
264 chop($docu_dir = $1);
266 $docu_name =~ s/.*\///;
271 $docu_name =~ s/\.te?x(i|info)?$//;
272 return ($docu_dir, $docu_name);
279 #############################################################################
281 #############################################################################
283 # Include our standard CSS file, not hard-coded CSS code directly in the HTML!
284 # For IE, conditionally include the lilypond-ie-fixes.css style sheet
285 sub lilypond_css_lines ($$)
287 my $import_lines = shift;
288 my $rule_lines = shift;
289 return if (defined($Texi2HTML::THISDOC{'CSS_LINES'}));
290 if (@$rule_lines or @$import_lines)
292 $Texi2HTML::THISDOC{'CSS_LINES'} = "<style type=\"text/css\">\n<!--\n";
293 $Texi2HTML::THISDOC{'CSS_LINES'} .= join('',@$import_lines) . "\n" if (@$import_lines);
294 $Texi2HTML::THISDOC{'CSS_LINES'} .= join('',@$rule_lines) . "\n" if (@$rule_lines);
295 $Texi2HTML::THISDOC{'CSS_LINES'} .= "-->\n</style>\n";
297 foreach my $ref (@CSS_REFS)
299 $Texi2HTML::THISDOC{'CSS_LINES'} .= "<link rel=\"stylesheet\" type=\"text/css\" title=\"$ref->{TITLE}\" href=\"$ref->{FILENAME}\">\n";
302 foreach my $ref (@Texi2HTML::Config::ALT_CSS_REFS)
304 $Texi2HTML::THISDOC{'CSS_LINES'} .= "<link rel=\"alternate stylesheet\" type=\"text/css\" href=\"$ref->{FILENAME}\" title=\"$ref->{TITLE}\">\n";
307 # GOP tweak: We aren't using an IE-specific stylesheet
308 #$Texi2HTML::THISDOC{'CSS_LINES'} .= "<!--[if lte IE 7]>\n<link href=\"lilypond-ie-fixes.css\" rel=\"stylesheet\" type=\"text/css\">\n<![endif]-->\n";
315 #############################################################################
316 ### SPLITTING BASED ON NUMBERED SECTIONS
317 #############################################################################
319 # FIXME: removed for GOP.
322 #############################################################################
323 ### CLEANER LINK TITLE FOR EXTERNAL REFS
324 #############################################################################
326 # The default formatting of external refs returns e.g.
327 # "(lilypond-internals)Timing_translator", so we remove all (...) from the
328 # file_and_node argument. Also, we want only a very simple format, so we don't
329 # even call the default handler!
330 sub lilypond_external_ref($$$$$$)
335 my $file_node = shift;
337 my $cross_ref = shift;
339 my $displaytext = '';
341 # 1) if we have a cross ref name, that's the text to be displayed:
342 # 2) For the top node, use the (printable) name of the manual, unless we
343 # have an explicit cross ref name
344 # 3) In all other cases use the section name
345 if ($cross_ref ne '') {
346 $displaytext = $cross_ref;
347 } elsif (($section eq '') or ($section eq 'Top')) {
348 $displaytext = $book;
350 $displaytext = $section;
353 $displaytext = &$anchor('', $href, $displaytext) if ($displaytext ne '');
354 return &$I('%{node_file_href}', { 'node_file_href' => $displaytext });
361 #############################################################################
362 ### HANDLING TRANSLATED SECTIONS: handle @translationof, secname<->filename
363 ### map stored on disk, xrefs in other manuals load that map
364 #############################################################################
367 # Try to make use of @translationof to generate files according to the original
368 # English section title...
369 sub lilypond_unknown($$$$$)
377 # the @translationof macro provides the original English section title,
378 # which should be used for file/anchor naming, while the title will be
379 # translated to each language
380 # It is already used by extract_texi_filenames.py, so this should not be
381 # necessary here at all. Still, I'll leave the code in just in case the
382 # python script messed up ;-)
383 if ($pass == 1 and $macro eq "translationof") {
384 if (ref($state->{'element'}) eq 'HASH') {
385 $state->{'element'}->{'translationof'} = main::normalise_space($line);
387 return ('', 1, undef, undef);
389 return &$default_unknown($macro, $line, $pass, $stack, $state);
396 my %translated_books = ();
397 # Construct a href to an external source of information.
398 # node is the node with texinfo @-commands
399 # node_id is the node transliterated and transformed as explained in the
401 # node_xhtml_id is the node transformed such that it is unique and can
402 # be used to make an html cross ref as explained in the texinfo manual
403 # file is the file in '(file)node'
404 sub lilypond_external_href($$$)
408 my $node_hxmlt_id = shift;
411 # 1) Keep a hash of book->section_map
412 # 2) if not file in keys hash => try to load the map (assign empty map if
413 # non-existent => will load only once!)
414 # 3) if node in the section=>(file, anchor) map, replace node_id and
415 # node_xhtml_id by the map's values
416 # 4) call the default_external_href with these values (or the old ones if not found)
418 if (($node_id ne '') and defined($file) and ($node_id ne 'Top')) {
419 my $map_name = $file;
420 $map_name =~ s/-big-page//;
422 # Load the map if we haven't done so already
423 if (!exists($translated_books{$map_name})) {
424 my ($docu_dir, $docu_name) = split_texi_filename ($Texi2HTML::THISDOC{'input_file_name'});
425 my $map_filename = main::locate_include_file ("${map_name}.$Texi2HTML::THISDOC{current_lang}.xref-map")
426 || main::locate_include_file ("${map_name}.xref-map");
427 $translated_books{$map_name} = load_map_file ($map_filename);
430 # look up translation. use these values instead of the old filename/anchor
431 my $section_name_map = $translated_books{$map_name};
432 my $node_text = main::remove_texi($node);
433 if (defined($section_name_map->{$node_text})) {
434 ($node_id, $node_hxmlt_id) = @{$section_name_map->{$node_text}};
436 print STDERR "WARNING: Unable to find node '$node_text' in book $map_name.\n";
441 return &$default_external_href($node, $node_id, $node_hxmlt_id, $file);
443 return &$default_external_href($node, $node_id, $node_hxmlt_id);
451 #############################################################################
452 ### CUSTOM TOC FOR EACH PAGE (in a frame on the left)
453 #############################################################################
455 my $page_toc_depth = 2;
456 my @default_toc = [];
459 # Initialize the toc_depth to 1 if the command-line option -D=short_toc is given
460 sub lilypond_init_toc_depth ()
462 if (exists($main::value{'short_toc'}) and not exists($main::value{'bigpage'})) {
466 # Set the TOC-depth (depending on a texinfo variable short_toc) in a
467 # command-handler, so we have them available when creating the pages
468 push @Texi2HTML::Config::command_handler_process, \&lilypond_init_toc_depth;
471 # recursively generate the TOC entries for the element and its children (which
472 # are only shown up to maxlevel. All ancestors of the current element are also
473 # shown with their immediate children, irrespective of their level.
474 # Unnumbered entries are only printed out if they are at top-level or 2nd level
475 # or their parent element is an ancestor of the currently viewed node.
476 # The conditions to call this method to print the entry for a child node is:
477 # -) the parent is an ancestor of the current page node
478 # -) the parent is a numbered element at top-level toplevel (i.e. show numbered
479 # and unnumbered 2nd-level children of numbered nodes)
480 # -) the child element is a numbered node below level maxlevel
481 sub generate_ly_toc_entries($$$)
484 my $element_path = shift;
486 #my $maxlevel = shift;
488 # Skip undefined sections, plus all sections generated by index splitting
489 return() if (not defined($element) or exists($element->{'index_page'}));
491 my $level = $element->{'toc_level'};
492 my $is_parent_of_current = $element->{'id'} && $element_path->{$element->{'id'}};
493 my $ind = ' ' x $level;
494 # GDP hack: leave this open for color
495 my $this_css_class = " class=\"";
496 $this_css_class .= $is_parent_of_current ? " toc_current" : "";
498 # GDP tweak: if the node name is in the color_X list
499 # TODO: use a hash, load from file?
500 # FIXME: load from file, to allow for translations!
504 "Learning", "Glossary", "Essay",
505 "Contact", "Tiny examples", "Bug reports"
508 "Features", "Examples", "Freedom",
509 "Unix", "MacOS X", "Windows",
510 "Notation", "Usage", "Snippets",
511 "Help us", "Development", "Authors"
514 "Productions", "Testimonials",
515 "Source", "Old downloads",
516 "FAQ", "Changes", "Internals",
517 "Publications", "Old news"
522 "Translated", "Old", "FDL"
525 my $addColor = " colorDefault";
526 foreach $color (@color_1) {
527 if ($element->{'text'} eq $color) {
528 $addColor = " color1";
531 foreach $color (@color_2) {
532 if ($element->{'text'} eq $color) {
533 $addColor = " color2";
536 foreach $color (@color_3) {
537 if ($element->{'text'} eq $color) {
538 $addColor = " color3";
541 foreach $color (@color_4) {
542 if ($element->{'text'} eq $color) {
543 $addColor = " color4";
547 $this_css_class .= $addColor . "\"";
552 my $entry = "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}",$element->{'text'});
554 push (@result, $entry);
555 my $children = $element->{'section_childs'};
556 if (defined($children) and (ref($children) eq "ARRAY")) {
557 my $force_children = $is_parent_of_current or ($level == 1 and $element->{'number'});
558 my @child_result = ();
559 foreach my $c (@$children) {
560 my $is_numbered_child = defined ($c->{'number'});
561 my $below_maxlevel = $c->{'toc_level'} le $maxlevel;
562 if ($force_children or ($is_numbered_child and $below_maxlevel)) {
563 my @child_res = generate_ly_toc_entries($c, $element_path, $maxlevel);
564 push (@child_result, @child_res);
567 # if no child nodes were generated, e.g. for the index, where expanded pages
568 # are ignored, don't generate a list at all...
570 push (@result, "\n$ind<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
572 # GOP tweak: (next 2 lines; alternates)
573 push (@result, "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}","(main)"));
574 #push (@result, "$ind<li$this_css_class>" . &$anchor ($element->{'tocid'}, "$element->{'file'}#$element->{'target'}","(".$element->{'text'}." main)"));
575 push (@result, @child_result);
576 push (@result, "$ind</ul>\n");
579 push (@result, "$ind</li>\n");
584 # Print a customized TOC, containing only the first two levels plus the whole
585 # path to the current page
586 sub lilypond_generate_page_toc_body($)
589 my $current_element = $element;
591 $parentelements{$element->{'id'}} = 1;
592 # Find the path to the current element
593 while ( defined($current_element->{'sectionup'}) and
594 ($current_element->{'sectionup'} ne $current_element) )
596 $parentelements{$current_element->{'sectionup'}->{'id'}} = 1
597 if ($current_element->{'sectionup'}->{'id'} ne '');
598 $current_element = $current_element->{'sectionup'};
600 return () if not defined($current_element);
601 # Create the toc entries recursively
603 my @toc_entries = ("<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
604 # my @toc_entries = ("<div class=\"contents\">\n", "<ul$NO_BULLET_LIST_ATTRIBUTE>\n");
606 # FIXME: add link to main page, really hackily.
607 if ($element->{'sectionup'}) {
608 # it's not the top element
609 push (@toc_entries, "<li><a href=\"index.html\">Main</a></li>\n");
611 push (@toc_entries, "<li class=\"toc_current\"><a href=\"index.html\">Main</a></li>\n");
614 my $children = $current_element->{'section_childs'};
615 # FIXME: generate toc
616 foreach ( @$children ) {
617 push (@toc_entries, generate_ly_toc_entries($_, \%parentelements, $page_toc_depth));
619 # FIXME: add search entry box
620 push (@toc_entries, "<li><form action=\"#\" method=\"get\"><input onfocus=\"this.value=''\" type=\"text\" name=\"search\" id=\"search\" value=\"Search\"></form></li>\n");
622 push (@toc_entries, "</ul>\n");
624 # push (@toc_entries, "</div>\n");
625 push (@toc_entries, "\n");
629 sub lilypond_print_toc_div ($$)
633 my @lines = @$tocref;
634 # use default TOC if no custom lines have been generated
635 @lines = @default_toc if (not @lines);
638 print $fh "\n\n<div id=\"tocframe\">\n";
639 #print $fh "<div class=\"contents\">\n";
641 # Remove the leading "GNU LilyPond --- " from the manual title
642 my $topname = $Texi2HTML::NAME{'Top'};
643 $topname =~ s/^GNU LilyPond(:| &[mn]dash;) //;
645 # construct the top-level Docs index (relative path and including language!)
646 my $lang = $Texi2HTML::THISDOC{current_lang};
647 if ($lang and $lang ne "en") {
653 $reldir = "../" if ($Texi2HTML::Config::SPLIT eq 'section');
654 my $uplink = $reldir."index.${lang}html";
656 # print $fh "<p class=\"toc_uplink\"><a href=\"$uplink\"
657 # title=\"Documentation Index\"><< " .
658 # &ly_get_string ('Back to Documentation Index') .
661 # print $fh '<h4 class="toc_header"> ' . &$anchor('',
662 # $Texi2HTML::HREF{'Top'},
664 # 'title="Start of the manual"'
668 foreach my $line (@lines) {
672 print $fh "</div>\n\n";
676 # Create the custom TOC for this page (partially folded, current page is
677 # highlighted) and store it in a global variable. The TOC is written out after
678 # the html contents (but positioned correctly using CSS), so that browsers with
679 # css turned off still show the contents first.
680 our @this_page_toc = ();
681 sub lilypond_print_element_header
683 my $first_in_page = shift;
684 my $previous_is_top = shift;
685 if ($first_in_page and not @this_page_toc) {
686 if (defined($Texi2HTML::THIS_ELEMENT)) {
687 # Create the TOC for this page
688 @this_page_toc = lilypond_generate_page_toc_body($Texi2HTML::THIS_ELEMENT);
691 return &$default_print_element_header( $first_in_page, $previous_is_top);
694 # Generate the HTML output for the TOC
695 sub lilypond_toc_body($)
697 my $elements_list = shift;
698 # Generate a default TOC for pages without THIS_ELEMENT
699 @default_toc = lilypond_generate_page_toc_body(@$elements_list[0]);
700 return &$default_toc_body($elements_list);
703 # Print out the TOC in a <div> at the beginning of the page
704 sub lilypond_print_page_head($)
707 &$default_print_page_head($fh);
708 print $fh "<div id=\"main\">\n";
711 # Print out the TOC in a <div>, which will be formatted as a
712 # sidebar mimicking a TOC frame
713 sub print_lilypond_page_foot($)
716 my $program_string = &$program_string();
717 # print $fh "<p><font size='-1'>$program_string</font><br>$PRE_BODY_CLOSE</p>\n";
719 # Do not include language selection in div#main
720 print $fh "<!-- end div#main here -->\n</div>\n\n";
723 print $fh "<!-- FOOTER -->\n\n";
724 print $fh "<div id=\"footer\">\n";
725 print $fh "<div id=\"language\">\n";
726 print $fh "<h3>Other languages</h3>\n";
727 print $fh "<p><a href=\"\">Deutsch</a>, Español, Français, Magyar.</p>\n";
728 print $fh "<p>About automatic language selection.</p>\n";
729 print $fh "</div>\n";
732 print $fh "<div id=\"verifier_texinfo\">\n";
733 print $fh "<h3>Validation</h3>\n";
734 print $fh "<p>Thanks to <a href=\"http://www.webdev.nl/\">webdev.nl</a>";
735 print $fh " for hosting <code>lilypond.org</code>.\n";
736 print $fh "<a href=\"http://validator.w3.org/check?uri=referer\">\n";
737 print $fh "<img src=\"http://www.w3.org/Icons/valid-html401\"\n";
738 print $fh " alt=\"Valid HTML 4.01 Transitional\"\n";
739 print $fh " height=\"31\" width=\"88\"></a></p>\n";
740 print $fh "<p>Web pages created with";
741 print $fh " <a href=\"http://www.gnu.org/software/texinfo/\">";
742 print $fh " GNU Texinfo</a>\n";
743 print $fh " and <a href=\"http://www.nongnu.org/texi2html/\">";
744 print $fh " texi2html</a>.</p>\n";
748 # Print the TOC frame and reset the TOC:
749 lilypond_print_toc_div ($fh, \@this_page_toc);
753 print $fh "</body>\n</html>\n";
760 #############################################################################
761 ### NICER / MORE FLEXIBLE NAVIGATION PANELS
762 #############################################################################
764 sub get_navigation_text
767 my $text = $NAVIGATION_TEXT{$button};
768 if ( ($button eq 'Back') or ($button eq 'FastBack') ) {
769 $text = $text . $Texi2HTML::NODE{$button} . " ";
770 } elsif ( ($button eq 'Forward') or ($button eq 'FastForward') ) {
771 $text = " " . $Texi2HTML::NODE{$button} . $text;
772 } elsif ( $button eq 'Up' ) {
773 $text = " ".$text.": " . $Texi2HTML::NODE{$button} . " ";
779 # Don't automatically create left-aligned table cells for every link, but
780 # instead create a <td> only on an appropriate '(left|right|center)-aligned-cell-n'
781 # button text. It's alignment as well as the colspan will be taken from the
782 # name of the button. Also, add 'newline' button text to create a new table
783 # row. The texts of the buttons are generated by get_navigation_text and
784 # will contain the name of the next/previous section/chapter.
785 sub lilypond_print_navigation
788 my $vertical = shift;
790 my $result = "<table class=\"nav_table\">\n";
792 $result .= "<tr>" unless $vertical;
794 foreach my $button (@$buttons)
796 $result .= qq{<tr valign="top" align="left">\n} if $vertical;
797 # Allow (left|right|center)-aligned-cell and newline as buttons!
798 if ( $button =~ /^(.*)-aligned-cell-(.*)$/ )
800 $result .= qq{</td>} unless $beginofline;
801 $result .= qq{<td valign="middle" align="$1" colspan="$2">};
804 elsif ( $button eq 'newline' )
806 $result .= qq{</td>} unless $beginofline;
807 $result .= qq{</tr>};
812 elsif (ref($button) eq 'CODE')
814 $result .= &$button($vertical);
816 elsif (ref($button) eq 'SCALAR')
818 $result .= "$$button" if defined($$button);
820 elsif (ref($button) eq 'ARRAY')
822 my $text = $button->[1];
823 my $button_href = $button->[0];
824 # verify that $button_href is simple text and text is a reference
825 if (defined($button_href) and !ref($button_href)
826 and defined($text) and (ref($text) eq 'SCALAR') and defined($$text))
828 if ($Texi2HTML::HREF{$button_href})
830 my $anchor_attributes = '';
831 if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button_href})) and ($BUTTONS_ACCESSKEY{$button_href} ne ''))
833 $anchor_attributes = "accesskey=\"$BUTTONS_ACCESSKEY{$button_href}\"";
835 if ($USE_REL_REV and (defined($BUTTONS_REL{$button_href})) and ($BUTTONS_REL{$button_href} ne ''))
837 $anchor_attributes .= " rel=\"$BUTTONS_REL{$button_href}\"";
841 $Texi2HTML::HREF{$button_href},
842 get_navigation_text($$text),
848 $result .= get_navigation_text($$text);
852 elsif ($button eq ' ')
853 { # handle space button
855 ($ICONS && $ACTIVE_ICONS{' '}) ?
856 &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{' '}) :
857 $NAVIGATION_TEXT{' '};
860 elsif ($Texi2HTML::HREF{$button})
862 my $btitle = $BUTTONS_GOTO{$button} ?
863 'title="' . $BUTTONS_GOTO{$button} . '"' : '';
864 if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button})) and ($BUTTONS_ACCESSKEY{$button} ne ''))
866 $btitle .= " accesskey=\"$BUTTONS_ACCESSKEY{$button}\"";
868 if ($USE_REL_REV and (defined($BUTTONS_REL{$button})) and ($BUTTONS_REL{$button} ne ''))
870 $btitle .= " rel=\"$BUTTONS_REL{$button}\"";
872 if ($ICONS && $ACTIVE_ICONS{$button})
876 $Texi2HTML::HREF{$button},
877 &$button_icon_img($BUTTONS_NAME{$button},
878 $ACTIVE_ICONS{$button},
879 $Texi2HTML::SIMPLE_TEXT{$button}),
888 $Texi2HTML::HREF{$button},
889 get_navigation_text($button),
896 { # button is passive
898 $ICONS && $PASSIVE_ICONS{$button} ?
899 &$button_icon_img($BUTTONS_NAME{$button},
900 $PASSIVE_ICONS{$button},
901 $Texi2HTML::SIMPLE_TEXT{$button}) :
903 "[" . get_navigation_text($button) . "]";
905 $result .= "</td>\n" if $vertical;
906 $result .= "</tr>\n" if $vertical;
908 $result .= "</td>" unless $beginofline;
909 $result .= "</tr>" unless $vertical;
910 $result .= "</table>\n";
916 @Texi2HTML::Config::SECTION_BUTTONS =
917 ('left-aligned-cell-1', 'FastBack',
918 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
919 'right-aligned-cell-1', 'FastForward',
921 'left-aligned-cell-2', 'Back',
922 'center-aligned-cell-1', 'Up',
923 'right-aligned-cell-2', 'Forward'
926 # buttons for misc stuff
927 @Texi2HTML::Config::MISC_BUTTONS = ('center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About');
929 # buttons for chapter file footers
930 # (and headers but only if SECTION_NAVIGATION is false)
931 @Texi2HTML::Config::CHAPTER_BUTTONS =
932 ('left-aligned-cell-1', 'FastBack',
933 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
934 'right-aligned-cell-1', 'FastForward',
937 # buttons for section file footers
938 @Texi2HTML::Config::SECTION_FOOTER_BUTTONS =
939 ('left-aligned-cell-1', 'FastBack',
940 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
941 'right-aligned-cell-1', 'FastForward',
943 'left-aligned-cell-2', 'Back',
944 'center-aligned-cell-1', 'Up',
945 'right-aligned-cell-2', 'Forward'
948 @Texi2HTML::Config::NODE_FOOTER_BUTTONS =
949 ('left-aligned-cell-1', 'FastBack',
950 'center-aligned-cell-3', 'Top', 'Contents', 'Index', 'About',
951 'right-aligned-cell-1', 'FastForward',
953 'left-aligned-cell-2', 'Back',
954 'center-aligned-cell-1', 'Up',
955 'right-aligned-cell-2', 'Forward'
962 #############################################################################
963 ### FOOTNOTE FORMATTING
964 #############################################################################
966 # Format footnotes in a nicer way: Instead of printing the number in a separate
967 # (nr) heading line, use the standard way of prepending <sup>nr</sup> immediately
968 # before the fn text.
971 # The following code is copied from texi2html's examples/makeinfo.init and
972 # should be updated when texi2html makes some changes there!
974 my $makekinfo_like_footnote_absolute_number = 0;
976 sub makeinfo_like_foot_line_and_ref($$$$$$$$)
978 my $foot_num = shift;
979 my $relative_num = shift;
982 my $from_file = shift;
983 my $footnote_file = shift;
987 $makekinfo_like_footnote_absolute_number++;
989 # this is a bit obscure, this allows to add an anchor only if formatted
990 # as part of the document.
991 $docid = '' if ($state->{'outside_document'} or $state->{'multiple_pass'});
993 if ($from_file eq $footnote_file)
995 $from_file = $footnote_file = '';
998 my $foot_anchor = "<sup>" . &$anchor($docid, "$footnote_file#$footid", $relative_num) . "</sup>";
999 $foot_anchor = &$anchor($docid, "$footnote_file#$footid", "($relative_num)") if ($state->{'preformatted'});
1001 # unshift @$lines, "<li>";
1002 # push @$lines, "</li>\n";
1003 return ($lines, $foot_anchor);
1006 sub makeinfo_like_foot_lines($)
1009 unshift @$lines, "<hr>\n<h4>$Texi2HTML::I18n::WORDS->{'Footnotes_Title'}</h4>\n";
1010 #<ol type=\"1\">\n";
1011 # push @$lines, "</ol>";
1015 my %makekinfo_like_paragraph_in_footnote_nr;
1017 sub makeinfo_like_paragraph ($$$$$$$$$$$$$)
1022 my $paragraph_command = shift;
1023 my $paragraph_command_formatted = shift;
1024 my $paragraph_number = shift;
1026 my $item_nr = shift;
1027 my $enumerate_style = shift;
1029 my $command_stack_at_end = shift;
1030 my $command_stack_at_begin = shift;
1032 #print STDERR "format: $format\n" if (defined($format));
1033 #print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n";
1034 $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or
1035 exists($special_list_commands{$format}->{$paragraph_command}));
1036 return '' if ($text =~ /^\s*$/);
1037 foreach my $style(t2h_collect_styles($command_stack_at_begin))
1039 $text = t2h_begin_style($style, $text);
1041 foreach my $style(t2h_collect_styles($command_stack_at_end))
1043 $text = t2h_end_style($style, $text);
1045 if (defined($paragraph_number) and defined($$paragraph_number))
1047 $$paragraph_number++;
1048 return $text if (($format eq 'itemize' or $format eq 'enumerate') and
1049 ($$paragraph_number == 1));
1054 $open .= " align=\"$paragraph_style{$align}\"";
1056 my $footnote_text = '';
1057 if (defined($command_stack_at_begin->[0]) and $command_stack_at_begin->[0] eq 'footnote')
1059 my $state = $Texi2HTML::THISDOC{'state'};
1060 $makekinfo_like_paragraph_in_footnote_nr{$makekinfo_like_footnote_absolute_number}++;
1061 if ($makekinfo_like_paragraph_in_footnote_nr{$makekinfo_like_footnote_absolute_number} <= 1)
1063 $open.=' class="footnote"';
1064 my $document_file = $state->{'footnote_document_file'};
1065 if ($document_file eq $state->{'footnote_footnote_file'})
1067 $document_file = '';
1069 my $docid = $state->{'footnote_place_id'};
1070 my $doc_state = $state->{'footnote_document_state'};
1071 $docid = '' if ($doc_state->{'outside_document'} or $doc_state->{'multiple_pass'});
1072 my $foot_label = &$anchor($state->{'footnote_footnote_id'},
1073 $document_file . "#$state->{'footnote_place_id'}",
1074 "$state->{'footnote_number_in_page'}");
1075 $footnote_text = "<small>[${foot_label}]</small> ";
1078 return $open.'>'.$footnote_text.$text.'</p>';
1082 #############################################################################
1084 #############################################################################
1086 # For split pages, use index.html as start page!
1087 if ($Texi2HTML::Config::SPLIT eq 'section') {
1088 $Texi2HTML::Config::TOP_FILE = 'index.html';