File Coverage

blib/lib/FAQ/OMatic/Appearance.pm
Criterion Covered Total %
statement 12 366 3.2
branch 0 104 0.0
condition 0 52 0.0
subroutine 4 17 23.5
pod 0 13 0.0
total 16 552 2.9


\n"; \n";
line stmt bran cond sub pod time code
1             ##############################################################################
2             # The Faq-O-Matic is Copyright 1997 by Jon Howell, all rights reserved. #
3             # #
4             # This program is free software; you can redistribute it and/or #
5             # modify it under the terms of the GNU General Public License #
6             # as published by the Free Software Foundation; either version 2 #
7             # of the License, or (at your option) any later version. #
8             # #
9             # This program is distributed in the hope that it will be useful, #
10             # but WITHOUT ANY WARRANTY; without even the implied warranty of #
11             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
12             # GNU General Public License for more details. #
13             # #
14             # You should have received a copy of the GNU General Public License #
15             # along with this program; if not, write to the Free Software #
16             # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.#
17             # #
18             # Jon Howell can be contacted at: #
19             # 6211 Sudikoff Lab, Dartmouth College #
20             # Hanover, NH 03755-3510 #
21             # jonh@cs.dartmouth.edu #
22             # #
23             # An electronic copy of the GPL is available at: #
24             # http://www.gnu.org/copyleft/gpl.html #
25             # #
26             ##############################################################################
27              
28 1     1   6 use strict;
  1         2  
  1         49  
29              
30             ###
31             ### Appearance.pm
32             ###
33             ### These and variables functions supply some of the appearance
34             ### of Faq-O-Matic pages.
35             ###
36              
37             package FAQ::OMatic::Appearance;
38 1     1   669 use FAQ::OMatic::ImageRef;
  1         2  
  1         37  
39 1     1   691 use FAQ::OMatic::I18N;
  1         3  
  1         185  
40              
41 1         5638 use vars qw($highlightColor $highlightStart $highlightEnd
42 1     1   7 $graphHistory $graphHeight $graphWidth);
  1         1  
43             # basically constants. TODO mod_perl -- they're configs, so when admin
44             # changes config, it won't show up immediately in mod_perl children.
45              
46             my @allLinks; # constants. no mod_perl cache badness
47             my $indentTypes;
48              
49             # These surround words in the document that were in a search query.
50             $highlightColor = $FAQ::OMatic::Config::highlightColor || "#a01010";
51             $highlightStart = "";
52             $highlightEnd = "";
53              
54             $graphHistory = 60; # default graphs show data going back two months
55             $graphWidth = 250; # image size of stats graphs
56             $graphHeight = 180;
57              
58             # These control the overall appearance of the page (background color/gif,
59             # title string). Please leave the string in the footer that identifies
60             # the homepage of Faq-O-Matic so others can see where to get the
61             # software for their own site.
62             sub cPageHeader {
63 0   0 0 0   my $params = shift || {};
64 0   0       my $showLinks = shift || [];
65 0   0       my $suppressType = shift || '';
66              
67             # this is a func because FAQ::OMatic::fomTitle() isn't well-defined at
68             # global initialization time.
69 0 0         my $type = ($suppressType) ? '' : "Content-type: text/html\n\n";
70              
71             # THANKS: to Billy Naylor for requesting the ability to insert
72             # THANKS: a corporate logo into every page's HTML.
73 0 0         if (FAQ::OMatic::getParam($params, 'render') ne 'text') {
74 0   0       my $pageHeader = $FAQ::OMatic::Config::pageHeader || '';
75 0           my $page = '';
76 0           $page .= $type;
77 0           $page .= "
78             ."\"-//W3C//DTD HTML 4.0 Transitional//EN\">";
79 0           $page .= "".FAQ::OMatic::fomTitle() </td> </tr> <tr> <td class="h" > <a name="80">80</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> .FAQ::OMatic::pageDesc($params)."\n"
81             ."
82             ."text=\"$FAQ::OMatic::Config::textColor\" "
83             ."link=\"$FAQ::OMatic::Config::linkColor\" "
84             ."vlink=\"$FAQ::OMatic::Config::vlinkColor\">\n";
85              
86             # THANKS: to Steve Taylor for sending a
87             # patch to allow file inclusion in page headers/footers. Some
88             # people want to put a lot of HTML in there...
89 0 0         if ($pageHeader =~ m#^file=(.*)$#) {
90             # this file= stuff isn't working right yet. Not sure why patterns
91             # aren't doing what I expect.
92 0           $page .= FAQ::OMatic::cat($1);
93             } else {
94 0           $page .= "$pageHeader\n";
95             }
96              
97 0 0 0       if ($FAQ::OMatic::Config::navigationBlockAtTop || '') {
98             # THANKS to Jim Adler for suggesting
99             # a copy of the nav block at the top of each page.
100 0           $page .= navigationBlock($params, $showLinks);
101             }
102 0           return $page;
103             } else {
104 0           my $title = FAQ::OMatic::fomTitle().FAQ::OMatic::pageDesc($params);
105 0           my $space = " "x(int((75-length($title))/2));
106 0           return $space.$title."\n\n";
107             }
108             }
109              
110             sub cPageFooter {
111 0   0 0 0   my $params = shift || {};
112 0   0       my $showLinks = shift || [];
113              
114 0 0         if (FAQ::OMatic::getParam($params, 'render') eq 'text') {
115 0           return "Generated by FAQ-O-Matic $FAQ::OMatic::VERSION,\n"
116             ."available at "
117             ."http://faqomatic.sourceforge.net/\n"
118             } else {
119 0           my $page = '';
120 0           $page .= navigationBlock($params, $showLinks);
121              
122 0   0       my $pageFooter = $FAQ::OMatic::Config::pageFooter || '';
123 0 0         if ($pageFooter =~ m#^file=(.*)$#) {
124             # this file= stuff isn't working right yet. Not sure why patterns
125             # aren't doing what I expect.
126 0           $page .= FAQ::OMatic::cat($1);
127             } else {
128 0           $page .= "$pageFooter\n";
129             }
130 0           $page .= "\n";
131 0           return $page;
132             }
133             }
134              
135             @allLinks =
136             ( 'help', 'search', 'appearance', 'entire', 'edit', 'renderText' );
137              
138             sub allLinks {
139 0     0 0   my @a2 = @allLinks; # make a copy of the array so it doesn't get modified
140 0           return \@a2;
141             }
142              
143             sub navigationBlock {
144 0     0 0   my $params = shift;
145 0   0       my $showLinks = shift || []; # ref to array of links to show
146              
147 0   0       my $filename = $params->{'file'} || '1';
148 0   0       my $recurse = $params->{'_recurse'} || '';
149 0           my $item = new FAQ::OMatic::Item($filename);
150              
151 0           my %sl = map {$_=>$_} @{$showLinks};
  0            
  0            
152 0           $showLinks = \%sl;
153              
154 0 0         delete $showLinks->{'renderText'}
155             if (FAQ::OMatic::getParam($params, 'textCmds') eq 'hide');
156              
157 0           my @cells = ();
158 0 0         if ($showLinks->{'help'}) {
159 0           push @cells, helpButton($params);
160             }
161              
162 0 0         if ($showLinks->{'search'}) {
163             # Search Form
164 0           push @cells,
165             FAQ::OMatic::button(
166             FAQ::OMatic::makeAref('-command'=>'searchForm',
167             '-params'=>$params),
168             gettext("Search"));
169             }
170              
171 0 0         if ($showLinks->{'appearance'}) {
172             # Appearance Options
173 0           push @cells,
174             FAQ::OMatic::button(
175             FAQ::OMatic::makeAref('-command'=>'appearanceForm',
176             '-params'=>$params),
177             gettext("Appearance"));
178             }
179              
180 0 0         if ($showLinks->{'entire'}) {
181             # Show This Entire Category
182 0 0         if ($item->isCategory()) {
183 0 0         if ($recurse) {
184             # provide a way to get rid of the recursive display
185             # THANKS: Jim Adler
186 0           push @cells,
187             FAQ::OMatic::button(
188             FAQ::OMatic::makeAref('-command'=>'faq',
189             '-params'=>$params,
190             '-changedParams'=>{'_recurse'=>''}),
191             gettext("Show Top Category Only") . "");
192             } else {
193 0           push @cells,
194             FAQ::OMatic::button(
195             FAQ::OMatic::makeAref('-command'=>'faq',
196             '-params'=>$params,
197             '-changedParams'=>{'_recurse'=>1}),
198             gettext("Show This Entire Category") . "");
199             }
200             } else {
201 0           push @cells, "";
202             }
203             }
204              
205 0 0         if ($showLinks->{'renderText'}) {
206 0           my $text;
207 0 0         if ($item->isCategory())
    0          
208             {
209 0           $text = gettext("Show This Category As Text");
210             }
211             elsif ($item->isAnswer())
212             {
213 0           $text = gettext("Show This Answer As Text");
214             }
215             else # fixup for unexpected cases
216             {
217 0           my $whatAmI = gettext($item->whatAmI());
218 0           gettexta("Show This %0 As Text", $whatAmI)
219             }
220 0           push @cells,
221             FAQ::OMatic::button(
222             FAQ::OMatic::makeAref('-command'=>'faq',
223             '-params'=>$params,
224             '-changedParams'=>{'render'=>'text'}),
225             $text);
226 0 0 0       if ($item->isCategory() and $showLinks->{'entire'}) {
227 0           push @cells,
228             FAQ::OMatic::button(
229             FAQ::OMatic::makeAref('-command'=>'faq',
230             '-params'=>$params,
231             '-changedParams'=>{'render'=>'text', '_recurse'=>1}),
232             gettext("Show This Entire Category As Text"));
233             }
234             }
235              
236 0 0 0       if ($showLinks->{'edit'}
237             and $FAQ::OMatic::Config::showEditOnFaq) {
238             # Show Edit Commands
239 0 0         if (FAQ::OMatic::getParam($params, 'editCmds') ne 'hide') {
240 0           push @cells, FAQ::OMatic::button(
241             FAQ::OMatic::makeAref('-command'=>'faq',
242             '-params'=>$params,
243             '-changedParams'=>{'editCmds'=>'hide'}),
244             gettext("Hide Expert Edit Commands"));
245             } else {
246 0   0       my $showStyle = $FAQ::OMatic::Config::showEditOnFaq || 'show';
247 0 0         $showStyle = 'show' if ($showStyle ne 'compact');
248              
249 0           push @cells, FAQ::OMatic::button(
250             FAQ::OMatic::makeAref('-command'=>'faq',
251             '-params'=>$params,
252             '-changedParams'=>{'editCmds'=>$showStyle}),
253             gettext("Show Expert Edit Commands"));
254             }
255             }
256              
257 0 0         if ($showLinks->{'faq'}) {
258             # return to faq
259 0   0       my $cmd = $params->{'cmd'} || '';
260 0 0 0       if ($cmd ne '' and $cmd ne 'faq') {
261 0           push @cells,
262             FAQ::OMatic::button(
263             FAQ::OMatic::makeAref('-command'=>'faq',
264             '-params'=>$params,
265             # kill unneeded params from 'authenticate':
266             '-changedParams'=>{'partnum'=>'',
267             'checkSequenceNumber'=>''},
268             ),
269             gettext("Return to the FAQ"));
270             }
271             }
272              
273 0           my $useTable = FAQ::OMatic::getParam($params, 'render') eq 'tables';
274              
275 0           my $page = "\n\n";
276 0           my $software = gettext("This is a") . "
277             ."http://faqomatic.sourceforge.net/"
278             ."\">Faq-O-Matic $FAQ::OMatic::VERSION.\n";
279 0 0         if ($useTable) {
280 0   0       my $tw = $FAQ::OMatic::Config::tableWidth || '';
281 0   0       my $bgc = $FAQ::OMatic::Config::regularPartColor || '#ffffff';
282 0           $page .="
283             ."bgcolor=\"$bgc\">\n"
284             ."
\n"; \n" } @cells; \n".join('', @cells)."\n"; ";
285 0           @cells = map { "$_
  0            
286 0           $page .= "
287 0   0       my $numCells = scalar(@cells) || 0;
288 0 0         if ($showLinks->{'faqomatic-home'}) {
289 0           $page.= "
\n"
290             .$software
291             ."
292             }
293 0           $page .= "
\n"
294             ."
\n";
295             } else {
296             # @cells = map { "
$_\n" } @cells; /jes
297 0           @cells = map { "$_\n" } @cells;
  0            
298 0           $page .= "\n".join('', @cells)."\n";
299 0 0         if ($showLinks->{'faqomatic-home'}) {
300             # $page .= "
".$software; /jes
301 0           $page .= $software."
";
302             }
303             }
304              
305 0           return $page;
306             }
307              
308             sub helpButton {
309 0     0 0   my $params = shift;
310 0           my $page = '';
311 0   0       my $cmd = $params->{'cmd'} || '';
312              
313             # Help
314             # -- disabled for this version, since it's not completely implemented
315             # or very tested. all the other code is here, there's just no
316             # "front door" to get into the help system through.
317             # if ($params->{'help'}) {
318             # $page.=""
319             # .FAQ::OMatic::button(
320             # FAQ::OMatic::makeAref('-command'=>$cmd,
321             # '-params'=>$params,
322             # '-changedParams'=>{'help'=>''},
323             # '-saveTransients'=>1,
324             # '-target'=>'_top'),
325             # "Hide Help")
326             # ."
327             # } else {
328             # $page.=""
329             # .FAQ::OMatic::button(
330             # FAQ::OMatic::makeAref('-command'=>'help',
331             # '-params'=>$params,
332             # '-changedParams'=>{'_onCmd'=>$cmd},
333             # '-saveTransients'=>1,
334             # '-target'=>'_top'),
335             # "Help")
336             # ."
337             # }
338              
339 0           return $page;
340             }
341              
342             sub max {
343 0     0 0   my $champ = shift;
344 0           while (defined(my $contender = shift)) {
345 0 0         $champ = ($champ > $contender) ? $champ : $contender;
346             }
347 0           return $champ;
348             }
349              
350             sub itemRender {
351 0     0 0   my $params = shift;
352 0           my $itemboxes = shift;
353              
354             # Here is how the itemRender data structure is arranged:
355             # $itemboxes is a ref to an array, each element contains the data to
356             # draw a single item. (There are multiple entries when
357             # [Show All Items Below Here] is in effect.)
358             # $itemboxes->[i] is a ref to a hash.
359             # $itemboxes->[i]->{'item'} is the FAQ::OMatic::Item object that this
360             # itembox represents.
361             # $itemboxes->[i]->{'rows'} is a ref to an array, each element of which
362             # is a row, structured as described below. Each row corresponds
363             # to a part in the item, plus a few extra rows for other parts of
364             # the page.
365             # $itemboxes->[i]->{'rows'}->[p] is a ref to a hash, describing that part.
366             # $itemboxes->[i]->{'rows'}->[p]->{'type'} is one of
367             # 'three', 'multirow', 'wide'.
368             # $itemboxes->[i]->{'rows'}->[p]->{'id'} is a debugging string that
369             # indicates the source of the row data
370             # type 'three' parts have ->{'body'}, ->{'editbody'}, ->{'afterbody'}
371             # refs. 'body' is a hash ref to 'text' and 'color'.
372             # 'editbody' is an array ref to edit cmds that apply to this part body.
373             # each element of the array is a hash of 'text' and 'color'.
374             # 'afterbody' is an array ref to edit cmds that apply after this
375             # part body.
376             # type 'multirow' fields have ->{'cells'}, a ref to an array of cells
377             # that should be laid out horizontally.
378             # type 'wide' fields have ->{'text'} and ->{'color'} parts that should
379             # fill the width of the display.
380              
381 0           my $render = FAQ::OMatic::getParam($params, 'render');
382 0 0         if ($render eq 'simple') {
    0          
383 0           return itemRenderSimple($params, $itemboxes);
384             } elsif ($render eq 'text') {
385 0           return itemRenderText($params, $itemboxes);
386             } else {
387             # tables
388 0           my $editDisplay = FAQ::OMatic::getParam($params, 'editCmds');
389 0 0         if ($editDisplay eq 'compact') {
390 0           return itemRenderCompactEdits($params, $itemboxes);
391             } else {
392 0           return itemRenderNormalEdits($params, $itemboxes);
393             }
394             }
395             }
396              
397             sub itemRenderNormalEdits {
398 0     0 0   my $params = shift;
399 0           my $itemboxes = shift;
400              
401             # first, compute the widest row of cells in the table, so that
402             # 'wide' and 'three'->'body' parts fit the width of the table.
403 0           my $maxwidth = 0;
404 0           my $tablerows = 0;
405 0           my $tablerowcounts = {};
406 0           foreach my $itembox (@{$itemboxes}) {
  0            
407 0           my $item = $itembox->{'item'};
408 0           my $rows = $itembox->{'rows'};
409 0           foreach my $row (@{$rows}) {
  0            
410 0 0         if ($row->{'type'} eq 'three') {
    0          
    0          
411 0           $maxwidth = max($maxwidth, 3, scalar(@{$row->{'afterbody'}}));
  0            
412 0           $tablerows += max(2, scalar(@{$row->{'editbody'}})+1);
  0            
413             } elsif ($row->{'type'} eq 'multirow') {
414 0           $maxwidth = max($maxwidth, scalar(@{$row->{'cells'}}));
  0            
415 0           $tablerows += 1;
416             } elsif ($row->{'type'} eq 'wide') {
417 0           $maxwidth = max($maxwidth, 1);
418 0           $tablerows += 1;
419             } else {
420 0           die "unknown row type ".$row->{'type'};
421             }
422             }
423 0           $tablerowcounts->{$rows} = $tablerows;
424 0           $tablerows = 0;
425             # rows are tallied per item ($rows is the set of rows in an item),
426             # so that we can compute the correct rowspan for the solid bar
427             # at the left of an item.
428             }
429              
430 0           my $rt = '';
431              
432 0           $rt.= "\n" \n"; on first table row, since we already did "; \n\n"; \n"; \n\n"; \n"; \n"; \n"; \n"; \n"; \n";
433             ."cellpadding=5 cellspacing=2>\n";
434 0           foreach my $itembox (@{$itemboxes}) {
  0            
435 0           my $item = $itembox->{'item'};
436 0           my $rows = $itembox->{'rows'};
437 0           $tablerows = $tablerowcounts->{$rows};
438              
439 0           my ($spacer,$sw) = FAQ::OMatic::ImageRef::getImageRefCA('', '',
440             $item->isCategory(), $params);
441            
442 0           my $itemFile = $item->{'filename'};
443 0           my $itemName = $item->getTitle();
444 0           $rt.="\n
445             ."
446             ."valign=top align=center rowspan=$tablerows width=$sw>\n"
447             ."$spacer\n
448 0           my $first = 1;
449             # don't send
450              
451 0           foreach my $row (@{$rows}) {
  0            
452 0 0         if ($first) {
453 0           $first = 0;
454             } else {
455 0           $rt .= "\n
456             }
457 0 0         if ($row->{'type'} eq 'three') {
    0          
458 0           my ($bodycolor,$bodytext) = getColorText($row->{'body'});
459 0           my @editbody = @{$row->{'editbody'}}; # array ref
  0            
460 0           my $rowspan = scalar @editbody;
461 0           my $colspan = $maxwidth - 1;
462 0           my @afterbody = @{$row->{'afterbody'}}; # array ref
  0            
463              
464 0           $rt.="";
465             # append a row (spanned by part box) for each editbody cell
466             # first cell shares a row with part body
467 0           my $cell = shift @editbody;
468 0           my ($color,$text) = getColorText($cell);
469 0           $rt .= "\n$text
470            
471             # a row from Part.pm with edit commands
472 0           $rt .= "\n
473             ."rowspan=$rowspan"
474             ." $bodycolor>$bodytext
475             # remaining cells get own rows
476 0           foreach $cell (@editbody) {
477 0           ($color,$text) = getColorText($cell);
478 0           $rt .= "\n
"
479             ."$text
480             }
481              
482             # append a row containing the below cells
483 0           $rt .= "
484 0           foreach $cell (@afterbody) {
485 0           ($color,$text) = getColorText($cell);
486 0           $rt .= "\n$text
487             }
488 0           $rt .= "
489             } elsif ($row->{'type'} eq 'multirow') {
490             # row is specified as a series of cells to be crammed
491             # together horizontally.
492 0           $rt.="";
493 0           foreach my $cell (@{$row->{'cells'}}) {
  0            
494 0           my ($color,$text) = getColorText($cell);
495 0           $rt .= "\n$text
496             }
497 0           $rt .= "
498             } else {
499             # row is specified as a single cell that should fill the
500             # width of the table.
501 0           my ($color,$text) = getColorText($row);
502 0           $rt .= ""
503             ."$text
504             }
505             }
506             }
507 0           $rt.="\n
\n";
508              
509 0           return $rt;
510             }
511              
512             sub getColorText {
513 0     0 0   my $hashref = shift;
514 0   0       my $color = $hashref->{'color'} || '';
515 0   0       my $size = $hashref->{'size'} || '';
516 0 0         $color = "bgcolor=$color" if ($color);
517 0   0       my $text = $hashref->{'text'} || '';
518 0 0         if ($size eq 'edit') {
519             # The editing buttons are smaller so that they'll not look as much like
520             # part of the item being displayed, but more like little intruders.
521 0           $text = "${text}";
522             }
523 0           return ($color,$text);
524             }
525              
526             sub itemRenderCompactEdits {
527 0     0 0   my $params = shift;
528 0           my $itemboxes = shift;
529              
530             # first, compute the widest row of cells in the table, so that
531             # 'wide' and 'three'->'body' parts fit the width of the table.
532 0           my $maxwidth = 0;
533 0           my $tablerows = 0;
534 0           my $tablerowcounts = {};
535 0           foreach my $itembox (@{$itemboxes}) {
  0            
536 0           my $item = $itembox->{'item'};
537 0           my $rows = $itembox->{'rows'};
538 0           foreach my $row (@{$rows}) {
  0            
539 0 0         if ($row->{'type'} eq 'three') {
    0          
    0          
540             # both editbody and afterbody are laid out horizontally.
541 0           $maxwidth = max($maxwidth, 3, scalar(@{$row->{'editbody'}}));
  0            
542 0           $maxwidth = max($maxwidth, 3, scalar(@{$row->{'afterbody'}}));
  0            
543             # the 'body' gets one row, the 'editbody' and 'afterbody'
544             # share a second row.
545 0           $tablerows += 2;
546             } elsif ($row->{'type'} eq 'multirow') {
547 0           $maxwidth = max($maxwidth, scalar(@{$row->{'cells'}}));
  0            
548 0           $tablerows += 1;
549             } elsif ($row->{'type'} eq 'wide') {
550 0           $maxwidth = max($maxwidth, 1);
551 0           $tablerows += 1;
552             } else {
553 0           die "unknown row type ".$row->{'type'};
554             }
555             }
556 0           $tablerowcounts->{$rows} = $tablerows;
557 0           $tablerows = 0;
558             # rows are tallied per item ($rows is the set of rows in an item),
559             # so that we can compute the correct rowspan for the solid bar
560             # at the left of an item.
561             }
562              
563 0           my $rt = '';
564              
565 0           $rt.= "\n" \n"; on first table row, since we already did "; \n"; \n"; \n"; \n";
566             ."cellpadding=5 cellspacing=2>\n";
567 0           foreach my $itembox (@{$itemboxes}) {
  0            
568 0           my $item = $itembox->{'item'};
569 0           my $rows = $itembox->{'rows'};
570 0           $tablerows = $tablerowcounts->{$rows};
571              
572 0           my ($spacer,$sw) = FAQ::OMatic::ImageRef::getImageRefCA('', '',
573             $item->isCategory(), $params);
574            
575 0           my $itemFile = $item->{'filename'};
576 0           my $itemName = $item->getTitle();
577             # THANKS to charlie buckheit for suggesting
578             # the width tag, which helps keep the item-tall bar skinny
579             # in Internet Exploder. (Nothing seems to help in Netscape.)
580 0           $rt.="\n
581             ."
582             ."valign=top align=center rowspan=$tablerows width=$sw>\n"
583             ."$spacer\n
584 0           my $first = 1;
585             # don't send
586              
587 0           foreach my $row (@{$rows}) {
  0            
588 0 0         if ($first) {
589 0           $first = 0;
590             } else {
591 0           $rt .= "\n
592             }
593 0 0         if ($row->{'type'} eq 'three') {
    0          
594 0           my ($bodycolor,$bodytext) = getColorText($row->{'body'});
595 0           my @editbody = @{$row->{'editbody'}}; # array ref
  0            
596 0           my @afterbody = @{$row->{'afterbody'}}; # array ref
  0            
597              
598 0           $rt.="";
599             # in compact mode, the 'body' gets a row to itself
600             # a row from Part.pm with edit commands
601 0           $rt .= "\n
602             ."$bodycolor>$bodytext
603              
604             # 'editbody' and 'afterbody' cells crammed into a single
605             # cell (hence the "compact" :v)
606             # everybody in the cell gets the color of the first guy.
607 0           my ($color,$text) = getColorText($editbody[0]);
608 0           $rt .= "
";
609 0           my $cell;
610 0           foreach $cell (@editbody) {
611 0           ($color,$text) = getColorText($cell);
612 0           $rt.="".$text;
613             }
614 0           $rt .= "\n
";
615 0           foreach $cell (@afterbody) {
616 0           ($color,$text) = getColorText($cell);
617 0           $rt.="".$text;
618             }
619 0           $rt .= "
620             } elsif ($row->{'type'} eq 'multirow') {
621             # row is specified as a series of cells to be crammed
622             # together horizontally.
623 0           my @cells = @{$row->{'cells'}};
  0            
624              
625             # everybody in the cell gets the color of the first guy.
626 0           my ($color,$text) = getColorText($cells[0]);
627 0           $rt.="";
628              
629 0           foreach my $cell (@cells) {
630 0           my ($color,$text) = getColorText($cell);
631 0           $rt .= "".$text;
632             }
633 0           $rt .= "
634             } else {
635             # row is specified as a single cell that should fill the
636             # width of the table.
637 0           my ($color,$text) = getColorText($row);
638 0           $rt .= ""
639             ."$text
640             }
641             }
642             }
643 0           $rt.="\n
\n";
644              
645 0           return $rt;
646             }
647              
648             sub itemRenderSimple {
649             # an HTML rendering mode that uses no tables; a goal is for it to
650             # look acceptable in lynx.
651 0     0 0   my $params = shift;
652 0           my $itemboxes = shift;
653              
654 0           my $rt = "
\n";
655              
656 0           foreach my $itembox (@{$itemboxes}) {
  0            
657 0           my $item = $itembox->{'item'};
658 0           my $rows = $itembox->{'rows'};
659              
660 0           my $itemFile = $item->{'filename'};
661 0           my $itemName = $item->getTitle();
662              
663             # this rendering method assumes (hopes!) that the first
664             # row of an item is a 'wide' row, something that looks like
665             # a title.
666 0           my $row = shift @$rows;
667 0 0         if ($row->{'type'} ne 'wide') {
668 0           FAQ::OMatic::gripe('problem', "assertion failed. ".caller(0));
669             }
670 0           my $text = $row->{'text'};
671 0           $rt.="\n\n"
672             ."
$text\n"
673             ."
    \n";
674              
675 0           foreach $row (@{$rows}) {
  0            
676 0           $rt .= "\n";
677 0 0         if ($row->{'type'} eq 'three') {
    0          
678 0           my ($bodycolor,$bodytext) = getColorText($row->{'body'});
679 0           my @editbody = @{$row->{'editbody'}}; # array ref
  0            
680 0           my @afterbody = @{$row->{'afterbody'}}; # array ref
  0            
681              
682 0           $rt.="";
683 0           $rt.="
  • $bodytext
    \n";
  • 684 0           my $cell;
    685 0           foreach $cell (@editbody) {
    686 0           my ($color,$text) = getColorText($cell);
    687 0           $rt.="".$text;
    688             }
    689 0           $rt .= "\n
    ";
    690 0           foreach $cell (@afterbody) {
    691 0           my ($color,$text) = getColorText($cell);
    692 0           $rt.="".$text;
    693             }
    694             } elsif ($row->{'type'} eq 'multirow') {
    695             # row is specified as a series of cells to be crammed
    696             # together horizontally.
    697 0           $rt.="";
    698 0           $rt.="
  • ";
  • 699 0           foreach my $cell (@{$row->{'cells'}}) {
      0            
    700 0           my ($color,$text) = getColorText($cell);
    701 0           $rt .= "$text\n";
    702             }
    703             } else {
    704             # row is specified as a single cell that should fill the
    705             # width of the table.
    706 0           my ($color,$text) = getColorText($row);
    707 0           $rt .= ""
    708             ."
  • $text\n";
  • 709             }
    710             }
    711 0           $rt.="\n\n";
    712             }
    713 0           $rt.="\n\n";
    714              
    715 0           return $rt;
    716             }
    717              
    718             sub itemRenderText {
    719             # a text-only rendering mode
    720 0     0 0   my $params = shift;
    721 0           my $itemboxes = shift;
    722              
    723 0           my $rt = '';
    724              
    725 0           foreach my $itembox (@{$itemboxes}) {
      0            
    726 0           my $item = $itembox->{'item'};
    727 0           my $rows = $itembox->{'rows'};
    728              
    729 0           my $itemFile = $item->{'filename'};
    730 0           my $itemName = $item->getTitle();
    731              
    732             # this rendering method assumes (hopes!) that the first
    733             # row of an item is a 'wide' row, something that looks like
    734             # a title.
    735 0           my $row = shift @$rows;
    736 0 0         if ($row->{'type'} ne 'wide') {
    737 0           FAQ::OMatic::gripe('problem', "assertion failed. ".caller(0));
    738             }
    739 0           my $text = $row->{'text'};
    740 0           $rt.="$text\n";
    741              
    742 0           foreach $row (@{$rows}) {
      0            
    743 0           my $part = $row->{'part'};
    744 0           my $indentType = 'regular';
    745 0 0 0       if (defined $part and ($part->{'Type'} eq 'directory')) {
    746 0           $indentType = 'directory';
    747             }
    748            
    749 0 0         if ($row->{'type'} eq 'three') {
        0          
    750 0           my ($bodycolor,$bodytext) = getColorText($row->{'body'});
    751 0           my @editbody = @{$row->{'editbody'}}; # array ref
      0            
    752 0           my @afterbody = @{$row->{'afterbody'}}; # array ref
      0            
    753              
    754 0           $rt.=indent($indentType, $bodytext);
    755             # edit text not shown (supported) in render=text mode
    756             # (that's the editbody and afterbody data)
    757 0           $rt .= "\n";
    758             } elsif ($row->{'type'} eq 'multirow') {
    759             # row is specified as a series of cells to be crammed
    760             # together horizontally.
    761 0 0         if (not $row->{'isEdit'}) {
    762             # supress data that's just editing links
    763 0           foreach my $cell (@{$row->{'cells'}}) {
      0            
    764 0           my ($color,$text) = getColorText($cell);
    765 0           $rt .= indent($indentType,$text);
    766             }
    767             }
    768             } else {
    769             # row is specified as a single cell that should fill the
    770             # width of the table.
    771 0           my ($color,$text) = getColorText($row);
    772 0           $rt .= indent($indentType,$text);
    773             }
    774             }
    775 0           $rt.="\n";
    776             }
    777 0           $rt.="\n";
    778              
    779 0           return $rt;
    780             }
    781              
    782             $indentTypes = {
    783             'regular' => ' ',
    784             'directory' => ' + ',
    785             };
    786              
    787             sub indent {
    788 0     0 0   my $type = shift;
    789 0           my $text = shift;
    790              
    791 0 0         my $indent = defined($indentTypes->{$type})
    792             ? $indentTypes->{$type}
    793             : $type;
    794              
    795 0           $text =~ s#^#$indent#gm;
    796 0           return $text;
    797             }
    798              
    799             1;