initial commit
[emacs-init.git] / nxhtml / nxhtml / html-wtoc / html-wtoc.pl
1 #! perl
2
3 # Copyright 2006, 2007 Lennart Borgman, http://OurComments.org/. All
4 # rights reserved.
5 #
6 # This file is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10
11 # This file is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
15
16 use strict;
17 use File::Copy;
18 use File::Spec;
19 #use File::Path qw();
20 use File::Path;
21 use File::Find qw();
22 use FindBin;
23
24 use lib "$FindBin::Bin/PerlLib";
25 use PathSubs qw();
26 use html_tags qw(
27 *html header
28 div
29 table Tr td
30 p hr br
31 a span img b
32 );
33
34 ### Script start parameters
35 my $m_param_action;
36 my $m_param_files  = 1;
37 my $m_param_pnum   = 0;
38 my $m_param_single = 0;
39 my $m_param_Template;
40 my $m_param_InPages;
41 my $m_param_OutRoot;
42 my @m_param_InRoot;
43 my $m_param_Overwrite;
44
45 ### Globals
46 my $m_iAlwaysOpenedLevel = 0;
47 my $m_sCommonIn;
48 my $m_sInPagesFolder;
49 my $m_sTemplateFolder;
50 my $m_sStartTemplate;
51 my $m_sBodyTemplate;
52 #my $m_sEndTemplate;
53 my $m_bBorders = 0;
54 my @pages;
55 my %page_num;
56 my %js_show_page;
57 my $m_TemplateTime;
58 my $m_InPagesTime;
59 my %m_linked_files;
60
61 sub get_params();
62 sub get_template();
63 sub read_page_list($);
64 sub find_pages($$);
65 sub write_pages();
66 sub send_page();
67 sub find_template_files();
68 sub find_linked_from_pages();
69 sub copy_wtoc_files();
70 sub copy_linked_files();
71
72 #push @pages, [$ind, $tit, $full_fil, $anc, $hrf, $trg, $tip];
73 sub IND { 0 }
74 sub TIT { 1 }
75 sub FULL_FIL { 2 }
76 sub ANC { 3 }
77 sub HRF { 4 }
78 sub TRG { 5 }
79 sub TIP { 6 }
80
81 ##########################################################
82 ### Main
83 ##########################################################
84 print "\n";
85 get_params();
86 if ($m_param_action eq "FIND") {
87     find_pages(\@m_param_InRoot, $m_param_InPages);
88 } elsif($m_param_action eq "MERGE") {
89     get_template();
90     read_page_list($m_param_InPages);
91     find_template_files();
92     copy_wtoc_files();
93     if ($m_param_files) {
94         write_pages();
95     } else {
96         send_page();
97     }
98     find_linked_from_pages();
99     copy_linked_files();
100 } elsif($m_param_action eq "TOC") {
101 }
102 exit;
103
104 sub copy_if_newer_or_overwrite($$) {
105     my $in_file = shift;
106     my $out = shift;
107     my $out_file = $out;
108     if (-d $out) {
109         my ($in_v, $in_d, $in_f) = File::Spec->splitpath( $in_file );
110         my ($out_v,$out_d,$out_f) = File::Spec->splitpath( $out, 1 );
111         $out_file = File::Spec->catpath( $out_v, $out_d, $in_f );
112     }
113     my $should_write = 1;
114     if (-e $out_file) {
115         if ($m_param_Overwrite) {
116             my $in_mdt = (stat $in_file)[9];
117             my $outmdt = (stat $out_file)[9];
118             if (($outmdt > $in_mdt)) {
119                 $should_write = 0;
120             }
121         } else {
122             $should_write = 0;
123         }
124     }
125     if ($should_write) {
126         if (!File::Copy::syscopy($in_file, $out_file)) {
127             die "syscopy($in_file, $out_file): $!";
128         } else {
129             print "  $in_file => $out_file\n";
130         }
131     }
132 } # copy_if_newer_or_overwrite
133
134 sub copy_wtoc_files() {
135     print "\n**** Copy html-wtoc files\n";
136     mkdir $m_param_OutRoot, 0777;
137     my $css_file = $FindBin::Bin . "/html-wtoc.css";
138     copy_if_newer_or_overwrite($css_file, $m_param_OutRoot);
139     my $js_file = $FindBin::Bin . "/html-wtoc.js";
140     copy_if_newer_or_overwrite($js_file,  $m_param_OutRoot);
141     my $OutRootImg = $m_param_OutRoot . "img/";
142     mkpath($OutRootImg);
143     my $imgsrc = $FindBin::Bin . "/img/";
144     opendir(IMGDIR, $imgsrc) or die "Can't opendir $imgsrc: $!";
145     while (my $imgfile = readdir(IMGDIR)) {
146         my $outimg = $OutRootImg . $imgfile;
147         $imgfile = $imgsrc . $imgfile;
148         #print STDERR ">>>$imgfile\n";
149         if (-f $imgfile) {
150             copy_if_newer_or_overwrite($imgfile, $outimg);
151         }
152     }
153     closedir(IMGDIR);
154 } # copy_wtoc_files
155
156 sub add_to_linked_files($$) {
157     my $from_file = shift;
158     my $to_file   = shift;
159     if (exists $m_linked_files{$to_file}) {
160         my $old_from = $m_linked_files{$to_file};
161         unless ($old_from eq $from_file) {
162             die "Both $from_file and $old_from should be copied to $to_file";
163         }
164     }
165     $m_linked_files{$to_file} = $from_file;
166 } # add_to_linked_files
167
168 sub copy_linked_files() {
169     print "\n**** Copy linked files\n";
170     my %pages;
171     for my $pnum (0..$#pages) {
172         $pages{ full_in_name($pnum) } = 1;
173     }
174     for my $to_file (keys %m_linked_files) {
175         my $from_file = $m_linked_files{$to_file};
176         unless (exists $pages{$from_file}) {
177             if (-e $from_file) {
178                 mkpath4file($to_file);
179                 copy_if_newer_or_overwrite($from_file, $to_file);
180             }
181         }
182     }
183 } # copy_linked_files
184
185 sub find_linked_files($;$) {
186     my $in_file = shift;
187     my $out_file = shift;
188     $out_file = in2out($in_file) unless ($out_file);
189     my $whole = get_file($in_file);
190     while ($whole =~ m!(?:\s|^)(?:href|src)="(.*?)"!gis) {
191         my $l = $1;
192         next unless $l =~ m!\.(?:css|js|jpg|jpeg|gif|png)$!;
193         if (!File::Spec->file_name_is_absolute($l)) {
194             next if $l =~ m!^javascript:!;
195             next if $l =~ m!^http://!;
196             next if $l =~ m!^ftp://!;
197             next if $l =~ m!^mailto:!;
198         }
199         my $rel_l = $l;
200         my $full_in = $l;
201         if (File::Spec->file_name_is_absolute($l)) {
202             $rel_l = PathSubs::mk_relative_link($in_file, $l);
203         } else {
204             $full_in = PathSubs::mk_absolute_link($in_file, $l);
205         }
206         my $full_out = PathSubs::mk_absolute_link($out_file, $rel_l);
207         add_to_linked_files($full_in, $full_out);
208     }
209 } # find_linked_files
210
211 sub find_template_files() {
212     print "\n**** Find files referenced in template file\n";
213     my $in_file  = $m_param_Template;
214     my $out_file = $m_param_OutRoot . "dummy.htm";
215     find_linked_files($in_file, $out_file);
216 }
217 sub find_linked_from_pages() {
218     for my $pnum (0..$#pages) {
219         next unless defined $pages[$pnum][FULL_FIL];
220         next unless $pages[$pnum][FULL_FIL] ne "";
221         next if defined $pages[$pnum][TRG];
222         find_linked_files( full_in_name($pnum) );
223     }
224 }
225
226 sub should_write_merged($$) {
227     my $pnum = shift;
228     my $out_file = shift;
229     my $should_write = 1;
230     if (-e $out_file) {
231         if ($m_param_Overwrite) {
232             my $srcmdt = page_src_time($pnum);
233             my $outmdt = (stat $out_file)[9];
234             if (($outmdt > $srcmdt)
235                 && ($outmdt > $m_TemplateTime)
236                 && ($outmdt > $m_InPagesTime)) {
237                 $should_write = 0;
238             }
239         } else {
240             $should_write = 0;
241         }
242     }
243     return $should_write;
244 }
245 sub write_pages() {
246     #print STDERR "*** param_OutRoot=$m_param_OutRoot\n";
247     if ($m_param_single) {
248         my $out_file = $m_param_OutRoot . "single_$m_param_pnum.html";
249         if (should_write_merged($m_param_pnum, $out_file)) {
250             my $page = create_single_page($m_param_pnum);
251             $page = shrink($page);
252             create_file_and_path($out_file, $page);
253         }
254     } else {
255         my $iPages = 0;
256         print "\n*** Creating pages:\n";
257         for my $pnum (0..$#pages) {
258             next unless defined $pages[$pnum][FULL_FIL];
259             next unless $pages[$pnum][FULL_FIL] ne "";
260             next if defined $pages[$pnum][TRG];
261             $iPages++;
262             my $out_file = full_out_name($pnum);
263             if (should_write_merged($pnum, $out_file)) {
264                 my $page = create_page($pnum);
265                 next unless $page;
266                 print " Creating page $iPages:  " . full_in_name($pnum) . "\n";
267                 $page = shrink($page);
268                 print "\t=>  $out_file\n";
269                 create_file_and_path($out_file, $page);
270             }
271         }
272     }
273 } # write_pages
274
275 sub send_page() {
276     my $page = ($m_param_single ?
277                 create_single_page($m_param_pnum)
278                 :
279                 create_page($m_param_pnum) );
280     print $page;
281 } # send_page
282
283 ##########################################################
284 ### Params
285 ##########################################################
286 sub die_usage() {
287     my $sScript = $0;
288     $sScript =~ tr!\\!/!;
289     $sScript =~ s!.*/(.*)!$1!;
290     die qq(Usage:
291   Making preliminary file list:
292     $sScript find in="in-dir" pages="pages-file" [overwrite=1]
293
294   Merging pages and table of contents:
295     $sScript merge pages="pages-file" outroot="out-dir" template="template-file" [overwrite=1]
296
297         \n);
298 }
299 #use Getopt::Long;
300 sub get_params() {
301     $| = 1;
302     for my $arg (@ARGV) { print " "; print $arg; } print "\n\n";
303     die_usage() unless $#ARGV > 0;
304     $m_param_action   = $ARGV[0];
305     $m_param_action =~ tr/a-z/A-Z/;
306     #push @m_param_InRoot, $FindBin::Bin . "/doc/";
307     #$m_param_OutRoot = $FindBin::Bin . "/tmp/";
308     #$m_param_Template = $FindBin::Bin . "/doc/home_template.htm";
309     #$m_param_InPages = $FindBin::Bin . "/doc/toc_pages.txt";
310     for (my $i = 1; $i <= $#ARGV; $i++) {
311         my ($k, $v) = ($ARGV[$i] =~ m!(.*?)=(.*)!);
312         $v =~ tr!\\!/!;
313         if ($k eq "in") {
314             $v = PathSubs::uniq_file($v);
315             $v .= "/" unless substr($v, -1) eq "/";
316             push @m_param_InRoot, $v;
317         } elsif( $k eq "outroot") {
318             $v = PathSubs::uniq_dir($v);
319             $v .= "/" unless substr($v, -1) eq "/";
320             $m_param_OutRoot = $v;
321         } elsif( $k eq "pages") {
322             $v = PathSubs::uniq_file($v);
323             $m_param_InPages = $v;
324         } elsif( $k eq "template") {
325             $v = PathSubs::uniq_file($v);
326             $m_param_Template = $v;
327         } elsif( $k eq "overwrite" ) {
328             $m_param_Overwrite = $v;
329         } elsif( $k eq "openedlevel" ) {
330             $m_iAlwaysOpenedLevel = $v * 1;
331         } else {
332             die "Unknown parameter: $ARGV[$i]\n";
333         }
334     }
335     if($m_param_action eq "FIND") {
336         if ($#m_param_InRoot < 0) { die_usage(); }
337         if (! defined $m_param_InPages) { die_usage(); }
338     } elsif($m_param_action eq "MERGE") {
339         if (! defined $m_param_InPages) { die_usage(); }
340         if (! defined $m_param_OutRoot) { die_usage(); }
341         if (! defined $m_param_Template) { die_usage(); }
342         $m_sTemplateFolder = $m_param_Template;
343         $m_sTemplateFolder =~ s![^/]*$!!;
344     } else {
345         die_usage();
346     }
347
348     $m_sInPagesFolder = $m_param_InPages;
349     $m_sInPagesFolder =~ s![^/]*$!!;
350     print "Parameters:\n";
351     print "    "  .  $m_param_action . "\n";
352     print "    pages=" .  $m_param_InPages . "\n";
353     print "    outroot=" .  $m_param_OutRoot . "\n";
354     print "    template=" .  $m_param_Template . "\n";
355     if (defined $m_param_Overwrite) {
356         print "    overwrite="  .  $m_param_Overwrite . "\n";
357     }
358     #if ($#m_param_InRoot == -1) { push @m_param_InRoot,$m_sInPagesFolder; }
359 }
360
361 sub get_template() {
362     my $sTemplate = get_file($m_param_Template, 1);
363     $m_TemplateTime = (stat $m_param_Template)[9];
364     $m_InPagesTime  = (stat $m_param_InPages)[9];
365     $sTemplate =~ s/<!--.*?-->//gs;
366     if (  $sTemplate =~ m!(.*?<body.*?>)(.*)</body>!si  ) {
367         $m_sStartTemplate = $1;
368         $m_sBodyTemplate = $2;
369         #$m_sEndTemplate = $3;
370     } else {
371         die "Can't find body of template\n";
372     }
373 } # get_template
374
375 sub read_page_list($) {
376     my $sPagesFile = shift;
377     my @in_files;
378     open(P,$sPagesFile) or die "Can't open toc list file $sPagesFile: $!\n";
379     while (my $sLine = <P>) {
380         chomp $sLine;
381         $sLine =~ s/^\s+|\s+$//g;
382         next if $sLine eq "";
383         next if substr($sLine, 0, 1) eq ";";
384         #print STDERR "$sLine\n";
385         my ($ind, $tit, $ref, $tip, $trg, $ico)
386             = map { s/^\s+|\s+$//g; $_; } split("###", $sLine);
387         #warn "trg=$trg\n" if defined $trg;
388         my ($fil, $anc) = ("", "");
389         my $hrf = "";
390         my $full_fil = "";
391         #$ref = "" unless defined $ref;
392         #print STDERR "ref=$ref\n";
393         if (defined $ref) {
394             if (defined $trg) { undef $trg unless $trg ne ""; }
395             if ((defined $trg) || ($ref =~ m/https?:/i)) {
396                 $hrf = $ref;
397             } else {
398                 ($fil, $anc) = split('#', $ref);
399                 if ($ind >= 0) {
400                     if (File::Spec->file_name_is_absolute($fil)) {
401                         $full_fil = $fil;
402                     } else {
403                         $full_fil = PathSubs::uniq_file($m_sInPagesFolder . $fil);
404                     }
405                 }
406             }
407         }
408         if ((!$tip) && ($full_fil ne "")) {
409             $tip = get_title($full_fil);
410         }
411         push @pages, [$ind, $tit, $full_fil, $anc, $hrf, $trg, $tip];
412         push @in_files, $full_fil if !defined $trg;
413     }
414     close P;
415     $m_sCommonIn = get_common_root(\@in_files). "/";
416 } # read_page_list
417
418
419
420 sub get_common_root($) {
421     my $psRoots = shift;
422     my @sCommon;
423     for my $s (@$psRoots) {
424         my $full_s = PathSubs::uniq_file($s);
425         my @full_s = split("/", $full_s);
426         if ($#sCommon == -1) {
427             @sCommon = @full_s;
428         } else {
429             my $iMax = $#sCommon; if ($#full_s < $iMax) { $iMax = $#full_s; }
430             for (my $i = 0; $i <= $iMax; $i++) {
431                 if ($sCommon[$i] ne $full_s[$i]) {
432                     #print STDERR "$i:  $sCommon[$i] != $full_s[$i]\n";
433                     @sCommon = @sCommon[0..$i-1];
434                     last;
435                 }
436             }
437         }
438     }
439     my $sCommon = join("/", @sCommon);
440     return $sCommon;
441 } # get_common_root
442
443
444 sub find_pages($$) {
445     my $pasInRoot  = shift;
446     my $sOutFile   = shift;
447     if (!$m_param_Overwrite) {
448         die "Don't want to overwrite existing output file $sOutFile!\n" if -e $sOutFile;
449     }
450     my $root_level;
451     my $sList;
452     my $handle_file =
453         sub {
454             return unless m/.html?/i;
455             return if -d $_;
456             my $fname = PathSubs::uniq_file($_);
457             die "Can't read $fname\n" unless -r $_;
458             my $title = get_title($_);
459             my $level = $fname =~ tr!/!!;
460             $level -= $root_level;
461             my $rel_fname = PathSubs::mk_relative_link($sOutFile, $fname);
462             $sList .= "$level ### $title ### $rel_fname\n";
463     };
464     for my $sInRoot (@$pasInRoot) {
465         $sInRoot = PathSubs::uniq_file($sInRoot);
466         chop($sInRoot) if (substr($sInRoot, -1) eq "/");
467         $root_level = $sInRoot =~ tr!/!!;
468         File::Find::find($handle_file, $sInRoot);
469     }
470     create_file($sOutFile, $sList);
471 } # find_pages
472
473
474 ##########################################################
475 ### File - page helpers
476 ##########################################################
477
478 sub file_name($) {
479     my $num = shift;
480     return $pages[$num][FULL_FIL];
481 }
482 sub file_anchor($) {
483     my $num = shift;
484     return $pages[$num][ANC];
485 }
486 sub file_href($) {
487     my $num = shift;
488     #die $pages[$num][HRF] if defined $pages[$num][HRF];
489     return $pages[$num][HRF];
490 }
491 sub file_target($) {
492     my $num = shift;
493     return $pages[$num][TRG];
494 }
495 sub file_title($) {
496     my $num = shift;
497     return $pages[$num][TIT];
498 }
499 sub file_tip($) {
500     my $num = shift;
501     return $pages[$num][TIP];
502 }
503 sub full_in_name($) {
504     my $num = shift;
505     my $name = file_name($num);
506     return $name;
507 }
508 sub full_out_href($) {
509     my $num = shift;
510     my $anchor = file_anchor($num);
511     my $full_href = full_out_name($num);
512     warn "full_href is null" unless $full_href;
513     if ((defined $anchor) && ($anchor ne "")) { $full_href .= "#" . $anchor; }
514     return $full_href;
515 }
516 sub full_out_name($) {
517     my $num = shift;
518     my $in_name = file_name($num);
519     return unless $in_name;
520     my $anchor = file_anchor($num);
521     #$m_param_OutRoot . $name;
522     $anchor = "";
523     my $name = substr($in_name, length($m_sCommonIn));
524     if ($anchor) {
525         my $base;
526         my $ext;
527         for (my $i = length($name);$i>0;$i--) {
528             if (substr($name, $i, 1) eq ".") {
529                 $base = substr($name, 0, $i-1);
530                 $ext  = substr($name, $i);
531                 $name = $base . "_sharp_" . $anchor . $ext;
532                 last;
533             }
534         }
535     }
536     $m_param_OutRoot . $name;
537 }
538 sub replace_name_link($) {
539     my $page = shift;
540     for my $k (keys %page_num) {
541         my $num = $page_num{$k};
542         my $href = ($m_param_single ? "javascript:ShowPage($num)" : file_name($num));
543         $page =~ s!%%$k%%!$href!gs;
544     }
545     return $page;
546 }
547
548 ##########################################################
549 ### File name helpers
550 ##########################################################
551 sub in2out($) {
552     my $in_name = shift;
553     die "in2out: File name is not abs: $in_name" unless File::Spec->file_name_is_absolute($in_name);
554     my $name = substr($in_name, length($m_sCommonIn));
555     $m_param_OutRoot . $name;
556 }
557
558 ##########################################################
559 ### File reading/writing
560 ##########################################################
561
562 sub mkpath4file($) {
563     my $file = shift;
564     my $path = $file;
565     $path =~ s|[^/]*$||;
566     File::Path::mkpath($path);
567 }
568 sub create_file($$) {
569     my ($out_file, $page) = @_;
570     if (!$m_param_Overwrite) {
571         if (-e $out_file) { die "Will not overwrite $out_file\n"; }
572     }
573     open(OUT, ">$out_file") or die "Can't create $out_file: $!";
574     print OUT $page;
575     close OUT;
576     chmod 0111|((stat $out_file)[2]&07777), $out_file
577 }
578 sub create_file_and_path($$) {
579     my ($out_file, $page) = @_;
580     mkpath4file($out_file);
581     create_file($out_file, $page);
582 }
583
584
585 sub get_file($$) {
586     my ($file, $need) = @_;
587     if (open(FL, $file)) {
588         local $/;
589         my $whole = <FL>;
590         close FL;
591         return $whole;
592     } else {
593         my $err = $!;
594         die "Can't open $file: $err\n" if $need;
595         return "";
596     }
597 }
598
599 sub get_title($) {
600     my $file = shift;
601     open(H, $file) or die "Can't open and get title from $file: $!";
602     while (my $line = <H>) {
603         if ($line =~ m!<title>(.*?)</title>!i) { close H; return $1; }
604     }
605     close H;
606 }
607
608
609
610 ##########################################################
611 ### Html parsing etc
612 ##########################################################
613
614 sub get_head_from_file($) {
615     my $fname = shift;
616     my $err;
617     my $head = get_head(get_file($fname, 1), \$err);
618     die "\n\n$fname\n\t" . $err if defined $err;
619     return $head;
620 }
621 # BUG: These actually requires parsing of the file, but it does not
622 # seem very important:
623 sub get_head($$) {
624     my $html = shift;
625     my $perr  = shift;
626     return "" unless $html;
627     $html =~ s/<!--.*?-->//g;
628     if ($html =~ m!<head.*?>(.*)</head>!is) {
629         return $1;
630     }
631     $$perr = "Can't find <head>-tag in $html\n";
632 }
633 sub get_body($) {
634     my $html = shift;
635     return "" unless $html;
636     $html =~ s/<!--.*?-->//gs;
637     if ($html =~ m!<body[^>]*>(.*)</body>!is) {
638         return $1;
639     }
640     die "Can't find <body>-tag in $html\n";
641 }
642
643 sub shrink($) {
644     my $str = shift;
645     my $out_str = "";
646     my @str = split("\n", $str);
647     my $in_pre = 0;
648     for my $s (@str) {
649         if ($s =~ m!<pre>!i)  { $in_pre = 1; }
650         if ($s =~ m!</pre>!i) { $in_pre = 0; }
651         $s =~ s!^(\s*)!! unless $in_pre;
652         $out_str .= $s . "\n";
653     }
654     return $out_str;
655     $str =~ s!^(\s*)!!gm;
656     $str;
657 }
658
659
660 ##########################################################
661 ### Making what we see
662 ##########################################################
663
664 sub mk_search() {
665     return "" if ! $m_param_single;
666     return qq[
667             <a href="javascript:show_search()" xstyle="font-size: 8pt"
668             title="Show Search Form"
669             ><img src="img/search.gif" border="$m_bBorders" align="left"></a>
670             <a href="javascript:show_search()" xstyle="font-size: 8pt"
671             title="Show Search Form"
672             class="html-wtoc-search"
673             >Sök</a>
674             ];
675 }
676 sub mk_main_table($$$$$) {
677     my $left         = shift;
678     my $main         = shift;
679     my $srch_table   = shift;
680     my $sFile        = shift;
681     my $pNum         = shift;
682     my $search_tr = "";
683     if ($m_param_single) {
684         $search_tr =
685             Tr(
686                 td("&nbsp;&nbsp;")
687                 . td({-valign=>'bottom', }, mk_search(), ) )
688     }
689     my $cont_table =
690         table(
691             { -border=>"$m_bBorders", -cellpadding=>0, -cellspacing=>0,
692               -width=>"100%",
693               -id=>"html-wtoc-contents",
694               #-style=>"display:",
695               -summary=>"Table of contents",
696             },
697             Tr(
698                 #td("&nbsp;&nbsp;")
699                 td({-class=>"html-wtoc-margin"})
700                 . td({-valign=>'top'}, $left) )
701             . $search_tr
702         )
703         ;
704     my $page = $m_sBodyTemplate;
705     $page = replace_template_links($m_sBodyTemplate, $sFile);
706     $page    =~ s!%%TOC%%!$cont_table!;
707     $page    =~ s!%%PAGE%%!$main!;
708     return $page;
709 } # mk_main_table
710
711
712 sub find_ind_level_prev($) {
713     my $lThis = shift;
714     for (my $i = $lThis - 1; $i > 0; $i--) {
715         my $ind_lev = $pages[$i][IND];
716         if ($ind_lev < 50) { return $ind_lev; }
717     }
718     return undef;
719 }
720 sub find_ind_level_next($) {
721     my $lThis = shift;
722     #print "find_ind_level_next($lThis)";
723     #print ", ";
724     #print file_title($lThis);
725     #print "\n";
726     #for (my $i = $lThis; $i < $#pages; $i++) {
727     for (my $i = $lThis + 1; $i <= $#pages; $i++) {
728         my $ind_lev = $pages[$i][IND];
729         if ($ind_lev < 50) { return $ind_lev; }
730     }
731     return undef;
732 }
733
734
735
736
737
738
739
740
741 sub mk_opener_elem($$$) {
742     my $iPi = shift;
743     my $sHref = shift;
744     my $bOpened = shift;
745     my $Aattrib =
746     {
747         -id  =>"opener_$iPi",
748     };
749     if ($sHref) { $$Aattrib{href} = $sHref; }
750     my $sImg;
751     my $sAlt;
752     if ($bOpened) {
753         $sImg = "down";
754         $sAlt = "Close";
755     } else {
756         $sImg = "right";
757         $sAlt = "Open";
758     }
759     return
760         a(
761             $Aattrib,
762             img({
763                 -src=>"img/$sImg.gif",
764                 -alt=>$sAlt,
765                 -border=>0,
766                 -width=>12,
767                 -height=>12,
768                 },
769             ),
770         );
771 } # mk_opener_elem
772
773 sub mk_content($) {
774     my $pnum = shift;
775     if (!$pages[$pnum]) {
776         return br();
777     }
778     my $cont;
779     my @father;
780     my @child_trace;
781     my $this_indent = $pages[$pnum][IND];
782     my $this_file   = $pages[$pnum][FULL_FIL];
783     if ($this_indent == -2) {
784         return "";
785     }
786     my $this_href   = full_out_name($pnum);
787     #my $anchor = file_anchor($pnum);
788     #if (defined $anchor) { $this_href .= "#" . $anchor; }
789     my @size;
790     $size[0] = "1em";
791     $size[1] = "0.8em";
792     $size[2] = "0.8em";
793
794
795
796     ### Open all main level nodes
797     my @opened; # rename to visible!!!!!
798     for my $pi (0..$#pages) {
799         my $indent = $pages[$pi][IND];
800         if ($indent <= $m_iAlwaysOpenedLevel) {
801             $opened[$pi] = 1;
802         } else {
803             $opened[$pi] = 0;   # more simple to handle
804         }
805     }
806
807
808
809     ### Open ancestors and older sisters (if not a standalone node)
810     my $pnum_indent = $pages[$pnum][IND];
811     my $high_open = $pnum_indent;
812     my $standalone_open = 10;
813     if ($high_open < $standalone_open) { ### Not a standalone node
814         for (my $pi = $pnum; $pi >= 0; $pi--) {
815             my $pi_indent = $pages[$pi][IND];
816             if ($high_open >= $pi_indent) {
817                 $opened[$pi] = 1;
818                 $high_open = $pi_indent;
819                 for (my $ps = $pi+1; $ps <= $#pages; $ps++) {
820                     my $ps_indent = $pages[$ps][IND];
821                     last if $ps_indent < $pi_indent;
822                     $opened[$ps] = 1 if $ps_indent == $pi_indent;
823                 }
824             }
825             last if $pi_indent == 0;
826         }
827     }
828
829
830
831
832     ### Open direct childs and younger sisters
833     my $maybe_child  = 1;
834     my $more_sisters = 1;
835     my $max_open_indent = $pnum_indent;
836     for my $pi ($pnum+1..$#pages) {
837         my $pi_indent = $pages[$pi][IND];
838         if ($pi_indent <= $max_open_indent) { $maybe_child  = 0; }
839         if ($pi_indent < $pnum_indent)      { $more_sisters = 0; }
840         if ($pi_indent == $pnum_indent) {
841             if ($more_sisters) { $opened[$pi] = 1; }
842             $maybe_child = 0;
843         } elsif ($pi_indent == $pnum_indent+1) {
844             if ($maybe_child) { $opened[$pi] = 1; }
845         }
846     }
847     #exit if $pnum == 3;
848
849
850
851
852     ### Open all in the same file (necessary for non-JavaScript)
853     for my $pi (0..$#pages) {
854         my $file = $pages[$pi][FULL_FIL];
855         #printf STDERR "file - open=(%s)\n", $file;
856         #if ($file eq $this_file) {
857         if ($file eq $this_file) {
858             $opened[$pi] = 1;
859         }
860         if ($file eq "") {
861             if ($pi < $#pages) {
862                 if ($pages[$pi][IND] < $pages[$pi+1][IND]) {
863                     $opened[$pi+1] = 1;
864                 }
865             }
866         }
867         if ($pages[$pi][IND] > 10) {
868             $opened[$pi] = 0;
869             #print ">>>>>>>>\$opened[$pi] = 0;\n";
870         }
871         #print STDERR "+++++++++\$opened[$pi] = $opened[$pi]\n";
872     }
873
874
875
876
877     ### Make the actual contents
878     my $tooltip;
879     my $child_id;
880     for my $pi (0..$#pages) {
881 #         if (!$pages[$pi][FULL_FIL] && !$pages[$pi][HRF]) {
882 #             my $txt = file_title($pi); #$pages[$pi][TIT];
883 #             $txt = qq(</p><hr width="50%" align="left" /><p style='margin-top:0'>) if $txt eq "-";
884 #             $cont .= $txt;
885 #             $cont .= br();
886 #             next;
887 #         }
888         my $txt = file_title($pi); #$pages[$pi][TIT];
889         if ($txt eq "-") {
890             $txt = qq(</p><hr width="50%" align="left" /><p style='margin-top:0'>);
891             $cont .= $txt;
892             $cont .= br();
893             next;
894         }
895         #if ($pages[$pi][TRG]) {
896         #       next;
897         #}
898         #next if ! defined $opened[$pi];
899         #next if ! $opened[$pi];
900         my $ind_lev = $pages[$pi][IND];
901         next if $ind_lev > 50;
902         my $ind_lev_next = find_ind_level_next($pi);
903         #my $ind_lev_prev = find_ind_level_prev($pi);
904
905         my $this_entry = "";
906
907         ### Child id from previous row
908         if (defined $child_id) {
909             my $display = "";
910             if (!$opened[$pi]) {
911                 $display = qq(style="display:none");
912             } else {
913             }
914             $this_entry .= "\n<div id=\"$child_id\" $display>\n";
915             undef $child_id;
916         }
917         my $opener_elem = ""; #qq(<img src="img/blank12.gif" width=12 height=12 alt=" ">);
918         my $childs_are_visible = ($pi == $pnum);
919         if ($pi < $#pages) {
920             if ($pages[$pi][IND] < $pages[$pi+1][IND]) {
921                 if ($opened[$pi+1]) { $childs_are_visible = 1; }
922             }
923         }
924         #if ($pages[$pi][IND] < $m_iAlwaysOpenedLevel) { $childs_are_visible = 1; }
925
926         my $file_href;
927         my $target;
928         my $href;
929         my $href_self;
930         my $target_attrib;
931         my $title  = file_title($pi);
932         my $file_name = file_name($pi);
933         if ($title) {
934             $file_href = file_href($pi); # || "";
935             $target = file_target($pi);
936             $href =
937                 ($file_name ?
938                  ($m_param_files ?
939                   ($m_param_single ? "JavaScript:ShowPage($pi);"    :
940                    ($file_href ne ""? $file_href
941                     :
942                     PathSubs::mk_relative_link($this_href, full_out_href($pi))))
943                   :
944                   ($m_param_single ? "JavaScript:ShowPage($pi)" : "?pnum=$pi")
945                  )
946                  :
947                  (File::Spec->splitpath($this_href))[2]);
948             if ($pi == $pnum) {
949                 $href_self = $this_href;
950                 if ($href_self =~ m!([^/\\]*$)!) {
951                     $href_self = $1;
952                 }
953             }
954             $target_attrib = (defined $target? qq(target="$target"): "");
955         } else {
956             $href = "";
957             $target_attrib = "";
958         }
959
960         if (defined $ind_lev_next && $ind_lev_next > $ind_lev) {
961             $child_id = "toc_child_$pi";
962             #print "    child_id=$child_id\n";
963             push @child_trace, $child_id;
964             $opener_elem = mk_opener_elem($pi,
965                                           ($href? $href : $href_self),
966                                           $childs_are_visible);
967         }
968         $title =~ s/_/&nbsp;/go;
969         my $indent = ($ind_lev ? "&nbsp;" x (($ind_lev-1) * 4) : "");
970         my $size = $size[$ind_lev];
971         $title = b($title) if $ind_lev == 0;
972
973         my $Aattrib =
974         {
975             id=>"toc_link_$pi",
976             onclick=>"html_wtoc_nailing(this)",
977         };
978         if (!$file_name) {
979             $Aattrib =
980             {
981                 id=>"opener_text_$pi",
982             };
983         }
984         if ($pi == $pnum) {
985             ### Current page
986             $$Aattrib{class} = "html-wtoc-currcont";
987             $$Aattrib{title} = "You are here";
988             $$Aattrib{href}  = $href_self;
989             $this_entry .=
990                 table({
991                     -cellspacing=>0,
992                     -cellpadding=>0,
993                     -class=>"html-wtoc-contline",
994                     -border=>0,
995                     -summary=>"Formatter",
996                       },
997                       Tr({
998                          },
999                          td({
1000                             },
1001                             a(
1002                                 $Aattrib,
1003                                 $indent . $title . "&nbsp;"
1004                             )
1005                          )
1006                          . td({
1007                              -class=>"html-wtoc-mark",
1008                               },
1009                               $opener_elem
1010                          )
1011                       )
1012                 );
1013
1014
1015
1016
1017         } else {
1018             ### Link to other page
1019             if (file_title($pi)) {
1020                 $tooltip = $pages[$pi][TIP];
1021                 if (!defined $tooltip) { $tooltip = "Go to the page $title"; }
1022                 $$Aattrib{class} = "html-wtoc-contents-a";
1023                 my $a_or_span;
1024                 if (!defined $href) {
1025                     $a_or_span = span($Aattrib, $indent . $title);
1026                 } else {
1027                     $$Aattrib{title} = $tooltip;
1028                     $$Aattrib{href}  = $href;
1029                     if (defined $target) { $$Aattrib{target} = $target; }
1030                     $a_or_span = a($Aattrib, $indent . $title);
1031                 }
1032                 $this_entry .=
1033                     table({
1034                         -cellspacing=>0,
1035                         -cellpadding=>0,
1036                         -class=>"html-wtoc-contline",
1037                         -border=>0,
1038                         -summary=>"Formatter",
1039                           },
1040                           Tr({
1041                              },
1042                              td({
1043                                 },
1044                                 $a_or_span
1045                              )
1046                              . td({
1047                                  -class=>"html-wtoc-mark",
1048                                   },
1049                                   $opener_elem
1050                              )
1051                           )
1052                     );
1053             } else {
1054                 $this_entry .= $indent . " " . $title;
1055                 #die $this_entry;
1056             }
1057         }
1058         if ((!defined $ind_lev_next) || $ind_lev_next <= $ind_lev) {
1059             my $ind_end = $ind_lev;
1060             if (defined $ind_lev_next) { $ind_end = $ind_lev_next+1; }
1061             for (my $i = $ind_end; $i <= $ind_lev; $i++) {
1062                 my $end_id = pop @child_trace;
1063                 if (defined $end_id) {
1064                     $this_entry .= "</div><!-- end child $end_id -->";  # end childs' span
1065                     #print "   end $end_id\n";
1066                 }
1067             }
1068         }
1069         $cont .= $this_entry;
1070         $father[$ind_lev] = $pi;
1071     } #for my $pi (0..$#pages)
1072
1073     $cont = div({-class=>"html-wtoc-contents"}, $cont) . p("&nbsp;");
1074     #$cont =~ s|<|\n<|gms;
1075     #$cont =~ tr!\n\r! !;
1076     $cont =~ s{
1077             (\ssrc=)"(.*?)"
1078         }
1079     {
1080         my $s1 = $1;
1081         my $src = $2;
1082         if (!PathSubs::is_abs_path($src)) {
1083             my $srcabs = PathSubs::mk_absolute_link(full_out_name(0), $src);
1084             $src = PathSubs::mk_relative_link(full_out_name($pnum), $srcabs);
1085         };
1086         "${s1}\"$src\"";
1087     }egsmx;
1088     $cont;
1089 } # mk_content
1090
1091 sub mk_main_window($) {
1092     my $pnum = shift;
1093     my $full_name = full_in_name($pnum);
1094     return unless defined $full_name;
1095     return get_body(get_file($full_name, 1));
1096 }
1097
1098
1099
1100
1101
1102
1103
1104
1105 ##########################################################
1106 ### The JavaScripts and styles we need
1107 ##########################################################
1108
1109 sub mk_style($) {
1110     return "";
1111     my $pnum = shift;
1112     my $rel_link =
1113         PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "html-wtoc.css");
1114     return qq(<link rel="stylesheet" href="$rel_link" type="text/css">\n);
1115 }
1116 sub mk_js($) {
1117     my $pnum = shift;
1118     return <<__HTML_END_JS_PNUM__;
1119       <script type="text/JavaScript">
1120         var iCurrentChild = $pnum;
1121         var iMaxChildNum  = $#pages;
1122       </script>
1123 __HTML_END_JS_PNUM__
1124         return "";
1125     my $single_js = "";
1126     if ($m_param_single) {
1127         $single_js = qq[if (!document.all) { navigate("0.html"); }];
1128         my $page_info = "var page_name = new Array;\n";
1129         for my $i (0..$#pages) {
1130             my $page_name = file_title($i); #$pages[$i][TIT];
1131             $page_info .= qq[ page_name[$i] = "$page_name";\n];
1132         }
1133         $single_js .= $page_info;
1134     }
1135     my $sch_link =
1136         PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "search.js");
1137     my $top_link =
1138         PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "html-wtoc.js");
1139     return <<__HTML_END_JS__;
1140       <script type="text/JavaScript" src="$sch_link"></script>
1141       <script type="text/JavaScript" src="$top_link"></script>
1142       <script type="text/JavaScript">
1143         $single_js
1144       </script>
1145 __HTML_END_JS__
1146 }
1147
1148 ##########################################################
1149 ### Page creation
1150 ##########################################################
1151
1152 sub replace_template_links($$) {
1153     my $template   = shift;
1154     my $sFile = shift;
1155     $template =~ s{\ssrc="(.*?)"}
1156     {
1157         my $sSrc  = $m_param_OutRoot . $1;
1158         my $sRelSrc = PathSubs::mk_relative_link($sFile, $sSrc);
1159         qq( src="$sRelSrc");
1160     }exg;
1161     $template =~ s{\shref="(.*?)"}
1162     {
1163         my $sOld = $1;
1164         if ((lc substr($sOld, 0, 11)) eq "javascript:") {
1165             qq( href="$sOld");
1166         } elsif (PathSubs::is_abs_netpath($sOld)) {
1167             qq( href="$sOld");
1168         } else {
1169             my $sSrc  = $m_param_OutRoot . $sOld;
1170             my $sRelSrc = PathSubs::mk_relative_link($sFile, $sSrc);
1171             qq( href="$sRelSrc");
1172         }
1173     }exg;
1174     return $template;
1175 } # replace_template_links
1176
1177 sub mk_start_of_page($) {
1178     my $pnum = shift;
1179     my $page = "";
1180     my $page_style = mk_style($pnum);
1181     my $page_js    = mk_js($pnum);
1182     my $sFile = full_out_name($pnum);
1183     my $head       = "";
1184     $head .= $page_js;
1185     $head .= $page_style;
1186     $head .= get_head_from_file(full_in_name($pnum));
1187     $page .= header if !$m_param_files;
1188     $page .= replace_template_links($m_sStartTemplate, $sFile);
1189     $page =~ s!<title>HEAD</title>!$head!;
1190     my $focus_pnum = $pnum;
1191     my $ind_lev = $pages[$pnum][IND];
1192     if ($ind_lev > 50) { $focus_pnum = 0; }
1193     $page =~ s!%%PNUM%%!$focus_pnum!;
1194     return $page;
1195 } # mk_start_of_page
1196
1197 my %m_sCreatedPages;
1198 sub page_src_time($) {
1199     my $pnum = shift;
1200     my $src_file = $pages[$pnum][FULL_FIL];
1201     return (stat $src_file)[9];
1202 }
1203 sub create_page($) {
1204     my $pnum = shift;
1205     return unless $pages[$pnum][FULL_FIL];
1206
1207     my $out_name = full_out_name($pnum);
1208     return if exists $m_sCreatedPages{$out_name};
1209     $m_sCreatedPages{$out_name} = 1;
1210
1211     my $page = mk_start_of_page($pnum);
1212     my $cont_win = mk_content($pnum);
1213     my $main_win = mk_main_window($pnum);
1214     $page .= mk_main_table(
1215         $cont_win,
1216         $main_win,
1217         "",
1218         $out_name,
1219         $pnum,
1220         );
1221     $page .= end_html;
1222     $page = replace_name_link($page);
1223     return $page;
1224 } # create_page
1225
1226
1227 __END__
1228
1229
1230     ##########################################################
1231     ### Unused currently
1232     ##########################################################
1233
1234     sub build_ShowPage() {
1235         for my $num (0..$#pages) {
1236             $page_num{$pages[$num][FULL_FIL]} = $num;
1237             my $fon = full_out_name($num);
1238             if ($fon) { $js_show_page{$fon} = "ShowPage($num);"; }
1239         }
1240 }
1241 build_ShowPage();
1242
1243
1244 sub mk_meta_enter_exit() {
1245     return <<__HTML_EE__;
1246       <meta HTTP-EQUIV="Page-Enter" content="RevealTrans (Duration=0.1, Transition=31)">
1247       <meta HTTP-EQUIV="Page-Exit"  content="RevealTrans (Duration=1, Transition=23)">
1248 __HTML_EE__
1249 }
1250
1251 ##########################################################
1252 ### Single page
1253 ##########################################################
1254
1255 sub mk_noscript() {
1256     return <<__HTML_END_NOSCRIPT__;
1257       <noScript>
1258         Sorry, there is not yet any version for non-JavaScript browsers.
1259         You need to enable JavaScript to see the rest of the pages!
1260 __HTML_END_NOSCRIPT__
1261 }
1262
1263 sub create_single_page($) {
1264     my $pnum = shift;
1265
1266     my $page = mk_start_of_page($pnum);
1267     my $left_col = "";
1268     my $main     = "";
1269     for my $pi (0..$#pages) {
1270         next unless $pages[$pi][FULL_FIL];
1271         my $display = ($pi == $pnum ? 'style="display: block"' : 'Style="display: none"');
1272         my $pi_left_col = replace_rel_link(mk_content($pi),    full_out_name($pi));
1273         my $pi_main     = replace_rel_link(mk_main_window($pi), full_out_name($pi));
1274         my $pi_margin   = "";
1275         $left_col .= "\n<div id='left_col_$pi' $display>" .  $pi_left_col . "</div>\n";
1276         $main     .= "\n<div id='main_$pi'     $display>" .  $pi_main     . "</div>\n";
1277     }
1278     my $search_table = qq[
1279         <table border="0" width="100%" height="200"
1280         cellpadding="0" cellspacing="0"
1281         xbgcolor="yellow"
1282         class="html-wtoc-search"
1283         id="search" style="display:none">
1284                   <tr>
1285         <td>&nbsp;&nbsp;</td>
1286         <td align="left" valign="top" height="1">
1287         <form onsubmit="return do_search(input.value);"
1288         class="html-wtoc-search-form"
1289         >
1290         <input id="input" size="14"
1291         ><input type="image" name="Search" value="Search"
1292                                 title="Search"
1293                                 src="img/search.gif"
1294                                 align="top"
1295         >
1296         </td>
1297         </form>
1298                   </tr>
1299                   <tr valign="top">
1300         <td>&nbsp;&nbsp;</td>
1301         <td id="hits" valign="top">
1302         </td>
1303                   </tr>
1304                   <tr>
1305         <td>&nbsp;&nbsp;</td>
1306         <td valign="bottom">
1307
1308         <a href="javascript:hide_search()" xstyle="font-size: 8pt"
1309         title="Show Menu"
1310         ><img src="img/nosearch.gif" border=0 align="left"></a>
1311         <a href="javascript:hide_search()"
1312         title="Show Menu"
1313         >Göm sökning</a>
1314         </td>
1315                   </tr>
1316         </table>
1317         ];
1318     $page .= mk_main_table(
1319         $left_col,
1320         $main,
1321         $search_table,
1322         full_out_name($pnum),
1323         $pnum,
1324         );
1325     $page .= mk_noscript();
1326     $page .= end_html;
1327     $page =~ s/(\d+)\.html/javascript:ShowPage($1);/gs;
1328     #$page =~ s/<body(.*?)>/<body$1 onload="ShowPage(0)">/gis;
1329     $page =~ s/<body(.*?)>/<body$1 onload="HTML_WTOC_NS.onload_actions()">/gis;
1330     $page = replace_name_link($page);
1331     return $page;
1332 } # create_single_page
1333
1334 my $abs_pos_tbl =
1335     qq(
1336     <table border="$m_bBorders" cellpadding=0 cellspacing=0
1337     width="100%" height=70
1338     bgcolor="white"
1339     style="
1340     position: absolute;
1341     left: 0;
1342     top: 0;
1343     "
1344     >
1345     <tr>
1346     <td>
1347     </td>
1348     </tr>
1349     </table>
1350     );
1351
1352
1353 ##########################################################
1354 ### Index.htm
1355 ##########################################################
1356
1357 # sub mk_index_page($) {
1358 #     my $page = shift;
1359 #     my $check_browser = qq[ //if (document.all) { navigate("single_0.html"); }\n];
1360 #     #$page =~ s/(<script.*?>)/$1\n$check_browser/s;
1361 #     mkdir $m_param_OutRoot, 0777;
1362 #     my $out_file = $m_param_OutRoot . "index.htm";
1363 #     create_file_and_path($out_file, $page);
1364 # }
1365
1366
1367
1368
1369 ##########################################################
1370 ### Links handling
1371 ##########################################################
1372
1373
1374 sub replace_rel_link($$) {
1375     my ($page, $page_file) = @_;
1376     my $qr;
1377     $page =~
1378         s{
1379             (src|href)="(.*?)"
1380         }{
1381             my $src_href = $1;
1382             my $href = $2;
1383             if (!PathSubs::is_abs_path($href)) {
1384                 $href = PathSubs::mk_absolute_link($page_file, $href);
1385                 $href =~ tr|\\|/|;
1386                 if (exists $js_show_page{$href}) {
1387                     $href = "javascript:$js_show_page{$href}";
1388                 }
1389             }
1390             qq($src_href="$href");
1391     }xegsm;
1392
1393     $page;
1394 }
1395