[Bio] / Sprout / ResultHelper.pm Repository:
ViewVC logotype

Annotation of /Sprout/ResultHelper.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (view) (download) (as text)

1 : parrello 1.1 #!/usr/bin/perl -w
2 :    
3 :     package ResultHelper;
4 :    
5 :     use strict;
6 :     use Tracer;
7 :     use FIG;
8 :     use URI::Escape;
9 :    
10 :     =head1 Search Result Display Helper
11 :    
12 :     =head2 Introduction
13 :    
14 :     This is the base class for search output. It provides common methods for formatting the
15 :     output and providing options to the caller. This class is never used by itself.
16 :     Instead, a subclass (whose name begins with C<RH> is constructed.
17 :    
18 :     The following fields are maintained by this object.
19 :    
20 :     =over 4
21 :    
22 :     =item parent
23 :    
24 :     The parent search helper.
25 :    
26 :     =item record
27 :    
28 :     An B<ERDBObject> representing the current data.
29 :    
30 :     =item columns
31 :    
32 :     Reference to a hash specifying the different possible columns that can be
33 :     included in the result.
34 :    
35 :     =back
36 :    
37 :     Additional fields may be appended by the subclasses.
38 :    
39 :     =head2 Column Processing
40 :    
41 :     The subclass will generally have multiple column names defined. For each column,
42 :     several bits of information are needed-- how to format the column, how to compute
43 :     the column value at search time, how to compute it at run time (which is optional),
44 :     the column title to be used, and whether or not the column should be included in
45 :     a download. The orthodox object-oriented method for doing this would be to define
46 :     a B<Column> class and define each possible column using a subclass. To make things
47 :     a little less cumbersome, we instead define each column using a static method in
48 :     the subclass. The method gets as its parameters the result helper object and
49 :     the type of information required. For example, the following call would ask for
50 :     the title of a column called C<orgName>.
51 :    
52 :     my $title = RHFeatures::orgName(title => $rhelp);
53 :    
54 :     The B<orgName> method itself would look like this.
55 :    
56 :     sub orgName {
57 :     # Get the parameters.
58 :     my ($type, $rhelp, $key) = @_;
59 :     # Declare the return variable.
60 :     my $retVal;
61 :     # Process according to the information requested.
62 :     if ($type eq 'title' {
63 :     # Return the title for this column.
64 :     $retVal = 'Organism and Gene ID';
65 :     } elsif ($type eq 'download') {
66 :     # This field should be included in a download.
67 :     $retVal = 'text'; # or 'num', or 'list', or ''
68 :     } elsif ($type eq 'style') {
69 :     # This is a text field, so it's left-aligned.
70 :     $retVal = "leftAlign";
71 :     } elsif ($type eq 'value') {
72 :     # Get the organism and feature name.
73 :     $rhelp->FeatureName();
74 :     } elsif ($type eq 'runTimeValue') {
75 :     # This field does not require a runtime value.
76 :     };
77 :     return $retVal;
78 :     }
79 :    
80 :     The method is essentially a giant case statement based on the type of data desired. The
81 :     types are
82 :    
83 :     =over 4
84 :    
85 :     =item title
86 :    
87 :     Return the title of the column to be used when it is displayed.
88 :    
89 :     =item download
90 :    
91 :     Identifies how the column should be downloaded. An empty string means it should not
92 :     be downloaded at all. The other values are C<num>, indicating that the column contains
93 :     numeric data, C<text>, indicating that the column contains an html-escaped string,
94 : parrello 1.2 C<link>, indicating that the column contains a L</Formlet> or L</FakeButton>,
95 :     C<list>, indicating that the column contains a comma-separated list with optional
96 :     hyperlinks, or C<align>,indicating that the column contains multi-line
97 :     aligned text with individual lines separated by a C<br> tag.
98 : parrello 1.1
99 :     =item style
100 :    
101 :     Return the style to be used to display each table cell in the column. The return
102 :     value is a valid C<TD> class name from the style sheet. The style sheet should
103 :     contain styles for C<leftAlign>, C<rightAlign>, and C<center> to accomodate the
104 :     most common requirements.
105 :    
106 :     =item value
107 :    
108 :     Return the value to be stored in the result cache. In most cases, this should be an
109 :     html string. If the value is to be computed when the data is displayed (which is
110 :     sometimes necessary for performance reasons), then the return value should be of
111 :     the form C<%%>I<colName>C<=>I<key>, where I<colName> is the column name and
112 :     I<key> is a value used to compute the result at display time. The key value will
113 :     be passed as a third parameter to the column method.
114 :    
115 :     =item runTimeValue
116 :    
117 :     Return the value to be displayed. This method is only used when the information
118 :     is not easily available at the time the result cache is built.
119 :    
120 :     =back
121 :    
122 :     The idea behind this somewhat cumbersome design is that new columns can be added
123 :     very easily by simply adding a new method to the result helper.
124 :    
125 :     Note that a column name must be a valid PERL method name! This means no spaces
126 :     or other fancy stuff.
127 :    
128 :     Run-time values are a bit tricky, and require some explanation. The normal procedure
129 :     during a search is to compute the values to be displayed as soon as an item is found
130 :     and store them directly in the result cache. Run-time values are those that are too
131 :     expensive to compute during the search, so they are not computed until the result
132 :     cache is displayed. Because a search can return thousands of results, but only 50 or
133 :     so are displayed at a time, this makes a big difference.
134 :    
135 :     =head2 Extra Columns
136 :    
137 :     It is necessary for individual searches to be able to create output columns specific
138 :     to the type of search. These are called extra columns.
139 :    
140 :     To create extra columns, you use the L</AddExtraColumn> method. This method
141 :     specifies the location of an extra column in the column list, its name, and its format.
142 :    
143 :     The extra columns are put in whatever positions the user specifies, although if
144 :     you try to put two columns in the same place or add a column before another added
145 :     column, this could cause the position to shift.
146 :    
147 :     Unlike regular columns, there is no need to compute a value or run-time value. The
148 :     other column properties (title, style, etc.) are stored in the extra column's
149 :     definition in this object. When the column headers are written, the header for an
150 :     extra column is in the form C<X=>I<something>. The I<something> is a frozen copy
151 :     of the extra column's hash. When the headers are read back in, the extra column data
152 :     is thawed into the hash so that the various options are identical to what they were
153 :     when the result cache was created.
154 :    
155 :     Extra columns are the most volatile requirement in the whole search system. I will
156 :     count myself happy if this implementation of them lasts more than a week.
157 :    
158 :     =cut
159 :    
160 :     # This value is used to do a single indent level in the XML output.
161 :     use constant XML_INDENT => " ";
162 :    
163 :     =head2 Public Methods
164 :    
165 :     =head3 new
166 :    
167 :     C<< my $rhelp = ResultHelper->new($shelp); >>
168 :    
169 :     Construct a new ResultHelper object to serve the specified search helper.
170 :    
171 :     =over 4
172 :    
173 :     =item shelp
174 :    
175 :     Parent search helper that is generating the output.
176 :    
177 :     =item type
178 :    
179 :     Classname used to format requests for columns.
180 :    
181 :     =item extras
182 :    
183 :     Reference to a hash of extra column data keyed on extra column name. For each extra column,
184 :     it contains the column's current value.
185 :    
186 :     =item cache
187 :    
188 :     A hash for use by the run-time value methods, to save time when multiple run-time values
189 :     use the same base object.
190 :    
191 :     =item columns
192 :    
193 :     The list of the columns to displayed in the search results. Normal columns are stored as
194 :     strings. Extra columns are stored as hash references.
195 :    
196 :     =item record
197 :    
198 :     Data record for the current output row.
199 :    
200 :     =item id
201 :    
202 :     ID for the current output row.
203 :    
204 :     =item RETURN
205 :    
206 :     Returns a newly-constructed result helper.
207 :    
208 :     =back
209 :    
210 :     =cut
211 :    
212 :     sub new {
213 :     # Get the parameters.
214 :     my ($class, $shelp) = @_;
215 :     # Save the result type in the CGI parms.
216 :     my $cgi = $shelp->Q();
217 :     $cgi->param(-name => 'ResultType', -value => substr($class, 2));
218 :     Trace("Result helper created of type $class.") if T(3);
219 :     # Create the $rhelp object.
220 :     my $retVal = {
221 :     parent => $shelp,
222 :     record => undef,
223 :     id => undef,
224 :     type => $class,
225 :     extras => {},
226 :     cache => {},
227 :     columns => [],
228 :     };
229 :     # Return it.
230 :     return $retVal;
231 :     }
232 :    
233 :     =head3 DB
234 :    
235 :     C<< my $sprout = $rhelp->DB(); >>
236 :    
237 :     Return the Sprout object for accessing the database.
238 :    
239 :     =cut
240 :    
241 :     sub DB {
242 :     # Get the parameters.
243 :     my ($self) = @_;
244 :     # Return the parent helper's database object.
245 :     return $self->Parent()->DB();
246 :     }
247 :    
248 :     =head3 PutData
249 :    
250 :     C<< $rhelp->PutData($sortKey, $id, $record); >>
251 :    
252 :     Store a line of data in the result file.
253 :    
254 :     =over 4
255 :    
256 :     =item sortKey
257 :    
258 :     String to be used for sorting this line of data among the others.
259 :    
260 :     =item id
261 :    
262 :     ID string for the result line. This is not shown in the results, but
263 :     is used by some of the download methods.
264 :    
265 :     =item record
266 :    
267 :     An B<ERDBObject> containing data to be used by the column methods.
268 :    
269 :     =back
270 :    
271 :     =cut
272 :    
273 :     sub PutData {
274 :     # Get the parameters.
275 :     my ($self, $sortKey, $id, $record) = @_;
276 :     # Save the data record and ID so the column methods can get to it.
277 :     $self->{record} = $record;
278 :     $self->{id} = $id;
279 :     # Loop through the columns, producing output data.
280 :     my @outputCols = ();
281 :     for my $column (@{$self->{columns}}) {
282 :     push @outputCols, $self->ColumnValue($column);
283 :     }
284 :     # Get the parent search helper.
285 :     my $shelp = $self->{parent};
286 :     # Write the column data.
287 :     $shelp->WriteColumnData($sortKey, $id, @outputCols);
288 :     }
289 :    
290 :     =head3 GetColumnHeaders
291 :    
292 :     C<< my $colHdrs = $rhelp->GetColumnHeaders(); >>
293 :    
294 :     Return the list of column headers for this session. The return value is a
295 :     reference to the live column header list.
296 :    
297 :     =cut
298 :    
299 :     sub GetColumnHeaders {
300 :     # Get the parameters.
301 :     my ($self) = @_;
302 :     # Return the column headers.
303 :     return $self->{columns};
304 :     }
305 :    
306 :     =head3 DownloadFormatsAvailable
307 :    
308 :     C<< my %dlTypes = $rhelp->DownloadFormatsAvailable(); >>
309 :    
310 :     Return a hash mapping each download type to a download description. The default is
311 :     the C<tbl> format, which is a tab-delimited download, and the C<xml> format,
312 :     which is XML. If you want additional formats, override L</MoreDownloadFormats>.
313 :    
314 :     =cut
315 :    
316 :     sub DownloadFormatsAvailable {
317 :     # Get the parameters.
318 :     my ($self) = @_;
319 :     Trace("Creating download type hash.") if T(3);
320 :     # Declare the return variable.
321 :     my %retVal = ( tbl => 'Results table as a tab-delimited file',
322 :     xml => 'Results table in XML format');
323 :     Trace("Asking for download formats from the helper.") if T(3);
324 :     # Ask for more formats.
325 :     $self->MoreDownloadFormats(\%retVal);
326 :     # Return the resulting hash.
327 :     return %retVal;
328 :     }
329 :    
330 :     =head3 DownloadDataLine
331 :    
332 :     C<< $rhelp->DownloadDataLine($objectID, $dlType, \@cols, \@colHdrs); >>
333 :    
334 :     Return one or more lines of download data. The exact data returned depends on the
335 :     download type.
336 :    
337 :     =over 4
338 :    
339 :     =item objectID
340 :    
341 :     ID of the object whose data is in this line of results.
342 :    
343 :     =item dlType
344 :    
345 :     The type of download (e.g. C<tbl>, C<fasta>).
346 :    
347 :     =item eol
348 :    
349 :     The end-of-line character to use.
350 :    
351 :     =item cols
352 :    
353 :     A reference to a list of the data columns, or a string containing
354 :     C<header> or C<footer>. The strings will cause the header lines
355 :     or footer lines to be output rather than a data line.
356 :    
357 :     =item colHdrs
358 :    
359 :     A reference to a list of the column headers. Each header describes the data found
360 :     in the corresponding column of the I<cols> list.
361 :    
362 :     =item RETURN
363 :    
364 :     Returns a list of strings that can be written to the download output.
365 :    
366 :     =back
367 :    
368 :     =cut
369 :    
370 :     sub DownloadDataLine {
371 :     # Get the parameters.
372 :     my ($self, $objectID, $dlType, $cols, $colHdrs) = @_;
373 :     # Declare the return variable.
374 :     my @retVal = ();
375 :     # Check the download type.
376 :     if ($dlType eq 'tbl' || $dlType eq 'xml') {
377 :     # Check for headers or footers.
378 :     if ($cols eq 'header') {
379 :     # Here we want headers. Only the XML type has them.
380 :     if ($dlType eq 'xml') {
381 :     @retVal = ('<?xml version="1.0" encoding="utf-8" ?>',
382 :     '<Results>');
383 :     }
384 :     } elsif ($cols eq 'footer') {
385 :     # Here we want footers. Again, only the XML type requires them.
386 :     if ($dlType eq 'xml') {
387 :     @retVal = ('</Results>');
388 :     }
389 :     } else {
390 :     # Here we are downloading the displayed columns as a tab-delimited file or
391 :     # as XML and we are tasked with producing the output lines for the current
392 :     # row of data. The first thing is to get the download format information
393 :     # about the columns.
394 :     my @keepCols = map { $self->ColumnDownload($_) } @{$colHdrs};
395 :     # Remove the columns that are not being kept. The list we create here
396 :     # will contain the name of each column, its value, and its download format.
397 :     my @actualCols = ();
398 :     for (my $i = 0; $i <= $#keepCols; $i++) {
399 :     if ($keepCols[$i]) {
400 :     push @actualCols, [$colHdrs->[$i], $self->GetRunTimeValues($cols->[$i]), $keepCols[$i]];
401 :     }
402 :     }
403 :     # Now it's time to do the actual writing, so we need to know if this
404 :     # is XML or tab-delimited.
405 :     if ($dlType eq 'tbl') {
406 :     # Clean up the HTML.
407 :     my @actual = map { HtmlCleanup($_->[1], $_->[2]) } @actualCols;
408 :     # Return the line of data.
409 :     push @retVal, join("\t", @actual);
410 :     } elsif ($dlType eq 'xml') {
411 :     # Convert to XML. Since a single XML tag can contain multiple lines, we re-split them.
412 :     # This is important, because when the lines are output we need to insure the correct
413 :     # EOL character is used.
414 :     my @actual = map { split /\n/, "<$_->[0]>" . XmlCleanup($_->[1], $_->[2]) . "</$_->[0]>" } @actualCols;
415 :     # Return the XML object.
416 :     push @retVal, XML_INDENT x 1 . "<Item id=\"$objectID\">";
417 :     push @retVal, map { XML_INDENT x 2 . $_ } @actual;
418 :     push @retVal, XML_INDENT x 1 . "</Item>";
419 :     }
420 :     }
421 :     } else {
422 :     # Now we have a special-purpose download format, so we let the subclass deal
423 :     # with it.
424 :     @retVal = $self->MoreDownloadDataMethods($objectID, $dlType, $cols, $colHdrs);
425 :     }
426 :     # Return the result.
427 :     return @retVal;
428 :     }
429 :    
430 :     =head3 Formlet
431 :    
432 :     C<< my $html = $rhelp->Formlet($caption, $url, $target, %parms); >>
433 :    
434 :     Create a mini-form that posts to the specified URL with the specified parameters. The
435 :     parameters will be stored in hidden fields, and the form's only visible control will
436 :     be a submit button with the specified caption.
437 :    
438 :     Note that we don't use B<CGI.pm> services here because they generate forms with extra characters
439 :     and tags that we don't want to deal with.
440 :    
441 :     This method is tightly bound to L</FormletToLink>, which converts a formlet to a URL. A
442 :     change here will require a change to the other method.
443 :    
444 :     =over 4
445 :    
446 :     =item caption
447 :    
448 :     Caption to be put on the form button.
449 :    
450 :     =item url
451 :    
452 :     URL to be put in the form's action parameter.
453 :    
454 :     =item target
455 :    
456 :     Frame or target in which the form results should appear. If C<undef> is specified,
457 :     the default target will be used.
458 :    
459 :     =item parms
460 :    
461 :     Hash containing the parameter names as keys and the parameter values as values.
462 :    
463 :     =back
464 :    
465 :     =cut
466 :    
467 :     sub Formlet {
468 :     # Get the parameters.
469 :     my ($self, $caption, $url, $target, %parms) = @_;
470 :     # Compute the target HTML.
471 :     my $targetHtml = ($target ? " target=\"$target\"" : "");
472 :     # Start the form.
473 :     my $retVal = "<form method=\"POST\" action=\"$url\"$target>";
474 :     # Add the parameters.
475 :     for my $parm (keys %parms) {
476 :     $retVal .= "<input type=\"hidden\" name=\"$parm\" value=\"$parms{$parm}\" />";
477 :     }
478 :     # Put in the button.
479 :     $retVal .= "<input type=\"submit\" name=\"submit\" value=\"$caption\" class=\"button\" />";
480 :     # Close the form.
481 :     $retVal .= "</form>";
482 :     # Return the result.
483 :     return $retVal;
484 :     }
485 :    
486 :     =head3 HtmlCleanup
487 :    
488 :     C<< my $text = ResultHelper::HtmlCleanup($htmlText, $type); >>
489 :    
490 :     Take a string of Html text and clean it up so it appears as real text.
491 :     Note that this method is not yet sophisticated enough to detect right-angle brackets
492 :     inside tag parameters, nor can it handle style or script tags. Its only sophistication
493 : parrello 1.2 is that it knows how to convert formlets or fake buttons URLs. Otherwise, it is a dirt simple
494 : parrello 1.1 method that suffices for search result processing.
495 :    
496 :     =over 4
497 :    
498 :     =item htmlText
499 :    
500 :     Html text to clean up.
501 :    
502 :     =item type
503 :    
504 :     Type of column: C<num> for a number, C<text> for a string, C<list> for a
505 :     comma-separated list, and C<link> for a formlet link.
506 :    
507 :     =item RETURN
508 :    
509 :     Returns the downloadable form of the Html string.
510 :    
511 :     =back
512 :    
513 :     =cut
514 :    
515 :     sub HtmlCleanup {
516 :     # Get the parameters.
517 :     my ($htmlText, $type) = @_;
518 :     # Declare the return variable.
519 :     my $retVal;
520 :     # Check for a formlet.
521 :     if ($type eq 'link') {
522 : parrello 1.2 # Here we have a formlet or fake button and we want to convert it to a URL.
523 :     $retVal = ButtonToLink($htmlText);
524 : parrello 1.1 } elsif ($type eq 'align') {
525 :     # Here we have multiple lines. Convert the new-lines to serial commas.
526 :     $retVal =~ s/<br\s*\/?>/, /g;
527 :     } else {
528 :     # Here we have normal HTML. Start by taking the raw text.
529 :     $retVal = $htmlText;
530 :     # Delete any tags. This is a very simplistic algorithm that will fail if there
531 :     # is a right angle bracket inside a parameter string.
532 :     $retVal =~ s/<[^>]+>//g;
533 :     # Unescape the & tags.
534 :     $retVal = CGI::unescapeHTML($retVal);
535 :     }
536 :     # Return the result.
537 :     return $retVal;
538 :     }
539 :    
540 :     =head3 XmlCleanup
541 :    
542 :     C<< my $text = ResultHelper::XmlCleanup($htmlText, $type); >>
543 :    
544 :     Take a string of Html text and clean it up so it appears as html.
545 :    
546 :     =over 4
547 :    
548 :     =item htmlText
549 :    
550 :     Html text to clean up.
551 :    
552 :     =item type
553 :    
554 :     Type of column: C<num> for a number, C<text> for a string, C<list> for a
555 : parrello 1.2 comma-separated list, and C<link> for a formlet or fake button.
556 : parrello 1.1
557 :     =item RETURN
558 :    
559 :     Returns the column data in XML format.
560 :    
561 :     =back
562 :    
563 :     =cut
564 :    
565 :     sub XmlCleanup {
566 :     # Get the parameters.
567 :     my ($htmlText, $type) = @_;
568 :     # Declare the return variable.
569 :     my $retVal;
570 :     # Check for a formlet.
571 :     if ($type eq 'link') {
572 : parrello 1.2 # Here we have a formlet or fake button and we want to convert it to a URL.
573 :     $retVal = ButtonToLink($htmlText);
574 : parrello 1.1 } elsif ($type eq 'num' || $type eq 'text') {
575 :     # Here we have a number or text. Return the raw value.
576 :     $retVal = $htmlText;
577 :     } elsif ($type eq 'align') {
578 :     # Here we have aligned text. This is converted into an XML array of lines.
579 :     # First, we find the break tags.
580 :     my @lines = split /<br[^>]+>/, $htmlText;
581 :     # Format the lines as an XML array. The extra new-line causes the first array
582 :     # element to be on a separate line from the first item tag.
583 :     $retVal = "\n" . map { XML_INDENT . "<line>$_</line>\n" } @lines;
584 :     } elsif ($type eq 'list') {
585 :     # Here we have a comma-delimited list of possibly-linked strings. We will convert it to
586 :     # an XML array. First, we get the pieces.
587 :     my @entries = split /\s*,\s*/, $htmlText;
588 :     # Each piece is processed individually, so we can check for hyperlinks.
589 :     # The return value starts with a new-line, so that the first list element
590 :     # is not on the same line as the open tag.
591 :     $retVal = "\n";
592 :     for my $entry (@entries) {
593 :     # Check for a hyperlink.
594 :     if ($entry =~ /<a[^>]+(href="[^"]+")[^>]*>(.+)<\/a>/) {
595 :     # Put the URL in the tag.
596 :     $retVal .= XML_INDENT . "<value $1>$2</value>\n";
597 :     } else {
598 :     # No URL, so the tag is unadorned.
599 :     $retVal .= XML_INDENT . "<value>$entry</value>\n";
600 :     }
601 :     }
602 :     }
603 :     # Return the result.
604 :     return $retVal;
605 :     }
606 :    
607 : parrello 1.2 =head3 ButtonToLink
608 : parrello 1.1
609 : parrello 1.2 C<< my $url = ResultHelper::ButtonToLink($htmlText); >>
610 : parrello 1.1
611 : parrello 1.2 Convert a formlet or fake button to a link. This process is bound very tightly with
612 :     the way L</Formlet> and L</FakeButton> generate Html. A change there requires a
613 :     change here.
614 : parrello 1.1
615 :     =over 4
616 :    
617 :     =item htmlText
618 :    
619 :     HTML text for the formlet.
620 :    
621 :     =item RETURN
622 :    
623 :     Returns a URL that will produce the same result as clicking the formlet button.
624 :    
625 :     =back
626 :    
627 :     =cut
628 :    
629 : parrello 1.2 sub ButtonToLink {
630 : parrello 1.1 # Get the parameters.
631 :     my ($htmlText) = @_;
632 :     # Declare the return variable.
633 :     my $retVal;
634 :     # We begin with the action.
635 : parrello 1.2 if ($htmlText =~ /action="([^"]+)"/i) {
636 :     # Action found, so this is a formlet. The action is the base of the URL.
637 :     $retVal = $1;
638 :     # Now, parse out the parameters, all of which are stored in the formlet as hidden
639 :     # input fields. This is the point where we assume that the formlet generates things
640 :     # in a well-defined format.
641 :     my @parms = ();
642 :     while ($htmlText =~ /<input\s+type="hidden"\s+name="([^"]+)"\s+value="([^"]+)"/ig) {
643 :     push @parms, "$1=" . uri_escape($2);
644 :     }
645 :     # If there were any parameters, assemble them into the URL.
646 :     if (scalar(@parms)) {
647 :     $retVal .= "?" . join(";", @parms);
648 :     }
649 :     } elsif ($htmlText =~ /<a\s+href="([^"]+)"/) {
650 :     # Here we have a fake button. The URL is the HREF.
651 :     $retVal = $1;
652 :     } else {
653 :     # Here the column is empty. We output an empty string.
654 :     $retVal = '';
655 : parrello 1.1 }
656 : parrello 1.2 # Now a final cleanup. If we have a URL and it's relative, we need to add our path to it.
657 :     if ($retVal && $retVal !~ m#http://#) {
658 :     # The link doesn't begin with http, so we must fix it. Get our URL.
659 :     my $cgi = CGI->new();
660 :     my $selfURL = $cgi->url(-full => 1);
661 :     # Strip off the page name.
662 :     $selfURL =~ m#^(.+)/[^/]+$#;
663 :     my $path = $1;
664 :     # Combine it with the relative URL.
665 :     $retVal = "$1/$retVal";
666 : parrello 1.1 }
667 :     # Return the result.
668 :     return $retVal;
669 :     }
670 :    
671 :     =head3 FakeButton
672 :    
673 :     C<< my $html = $rhelp->FakeButton($caption, $url, $target, %parms); >>
674 :    
675 :     Create a fake button that hyperlinks to the specified URL with the specified parameters.
676 :     Unlike a real button, this one won't visibly click, but it will take the user to the
677 :     correct place.
678 :    
679 :     The parameters of this method are deliberately identical to L</Formlet> so that we
680 :     can switch easily from real buttons to fake ones in the code.
681 :    
682 :     =over 4
683 :    
684 :     =item caption
685 :    
686 :     Caption to be put on the button.
687 :    
688 :     =item url
689 :    
690 :     URL for the target page or script.
691 :    
692 :     =item target
693 :    
694 :     Frame or target in which the new page should appear. If C<undef> is specified,
695 :     the default target will be used.
696 :    
697 :     =item parms
698 :    
699 :     Hash containing the parameter names as keys and the parameter values as values.
700 :     These will be appended to the URL.
701 :    
702 :     =back
703 :    
704 :     =cut
705 :    
706 :     sub FakeButton {
707 :     # Get the parameters.
708 :     my ($self, $caption, $url, $target, %parms) = @_;
709 :     # Declare the return variable.
710 :     my $retVal;
711 :     # Compute the target URL.
712 :     my $targetUrl = "$url?" . join(";", map { "$_=" . uri_escape($parms{$_}) } keys %parms);
713 :     # Compute the target-frame HTML.
714 :     my $targetHtml = ($target ? " target=\"$target\"" : "");
715 :     # Assemble the result.
716 :     return "<a href=\"$targetUrl\" $targetHtml><div class=\"button2 button\">$caption</div></a>";
717 :     }
718 :    
719 :     =head3 Parent
720 :    
721 :     C<< my $shelp = $rhelp->Parent(); >>
722 :    
723 :     Return this helper's parent search helper.
724 :    
725 :     =cut
726 :    
727 :     sub Parent {
728 :     # Get the parameters.
729 :     my ($self) = @_;
730 :     # Return the parent.
731 :     return $self->{parent};
732 :     }
733 :    
734 :     =head3 Record
735 :    
736 :     C<< my $erdbObject = $rhelp->Record(); >>
737 :    
738 :     Return the record currently stored in this object. The record contains the data for
739 :     the result output line being built, and is in the form of a B<ERDBObject>.
740 :    
741 :     =cut
742 :    
743 :     sub Record {
744 :     # Get the parameters.
745 :     my ($self) = @_;
746 :     # Get the record.
747 :     my $retVal = $self->{record};
748 :     # If it does not exist, trace a message.
749 :     Trace("No record found in result helper.") if T(3) && ! defined($retVal);
750 :     # Return the record.
751 :     return $retVal;
752 :     }
753 :    
754 :     =head3 ID
755 :    
756 :     C<< my $id = $rhelp->ID(); >>
757 :    
758 :     Return the ID for the record currently stored in this object (if any).
759 :    
760 :    
761 :     =cut
762 :    
763 :     sub ID {
764 :     # Get the parameters.
765 :     my ($self) = @_;
766 :     # Get the record.
767 :     my $retVal = $self->{id};
768 :     # If it does not exist, trace a message. We say "no record found" because a
769 :     # missing ID implies a missing record.
770 :     Trace("No record found in result helper.") if T(3) && ! defined($retVal);
771 :     # Return the ID.
772 :     return $retVal;
773 :     }
774 :    
775 :    
776 :    
777 :     =head3 Cache
778 :    
779 :     C<< my $cacheHash = $rhelp->Cache(); >>
780 :    
781 :     Return a reference to the internal cache. The internal cache is used by the
782 :     run-time value methods to keep stuff in memory between calls for the same
783 :     output line.
784 :    
785 :     =cut
786 :    
787 :     sub Cache {
788 :     # Get the parameters.
789 :     my ($self) = @_;
790 :     # Return the cache.
791 :     return $self->{cache};
792 :     }
793 :    
794 :     =head3 PreferredID
795 :    
796 :     C<< my $featureID = $rhelp->PreferredID($featureObject); >>
797 :    
798 :     Return the preferred ID for the specified feature. The feature passed in must be in the
799 :     form of an ERDB feature object. The preferred alias type will be determined using the
800 :     CGI C<AliasType> parameter, and then cached in the feature object using the name
801 :     C<Feature(alias)> so this method can find it easily if it is needed again.
802 :    
803 :     =over 4
804 :    
805 :     =item featureObject
806 :    
807 :     An B<ERDBObject> for the relevant feature.
808 :    
809 :     =item RETURN
810 :    
811 :     The preferred ID for the feature (Locus Tag, Uniprot ID, etc.) if one exists, otherwise
812 :     the FIG ID.
813 :    
814 :     =back
815 :    
816 :     =cut
817 :    
818 :     sub PreferredID {
819 :     # Get the parameters.
820 :     my ($self, $featureObject) = @_;
821 :     # Declare the return variable.
822 :     my $retVal;
823 :     # Check for a cached value.
824 :     if ($featureObject->HasField('Feature(alias)')) {
825 :     $retVal = $featureObject->PrimaryValue('Feature(alias)');
826 :     } else {
827 :     # Here we need to compute the alias. First, get the preferred type.
828 :     my $aliasType = $self->Parent()->GetPreferredAliasType();
829 :     # The fallback is to use the FIG ID.
830 :     my $fid = $featureObject->PrimaryValue('Feature(id)');
831 :     $retVal = $fid;
832 :     # We only need to proceed if the preferred type is NOT FIG.
833 :     if ($aliasType ne 'FIG') {
834 :     # Here we need to find a real alias of the specified type. To start,
835 :     # we need a Sprout object.
836 :     my $sprout = $self->DB();
837 :     # Ask for all the aliases connected to this feature ID.
838 :     my @aliases = $sprout->GetFlat(['IsAliasOf'], 'IsAliasOf(to-link) = ?',
839 :     [$fid], 'IsAliasOf(from-link)');
840 :     # Extract an alias of the preferred type.
841 :     my $foundAlias = AliasAnalysis::Find($aliasType, \@aliases);
842 :     # If an alias was found, use it. Otherwise, the FIG ID will stay in place.
843 :     if (defined($foundAlias)) {
844 :     $retVal = $foundAlias;
845 :     }
846 :     }
847 :     # Save the alias type for future calls.
848 :     $featureObject->AddValues('Feature(alias)', $retVal);
849 :     }
850 :     # Return the ID computed.
851 :     return $retVal;
852 :     }
853 :    
854 :    
855 :     =head2 Column-Related Methods
856 :    
857 :     =head3 Compute
858 :    
859 :     C<< my $retVal = $rhelp->Compute($type, $colName, $runTimeKey); >>
860 :    
861 :     Call a column method to return a result. This involves some fancy C<eval> stuff.
862 :     The column method is called as a static method of the relevant subclass.
863 :    
864 :     =over 4
865 :    
866 :     =item type
867 :    
868 :     The type of column data requested: C<title> for the column title, C<style> for the
869 :     column's display style, C<value> for the value to be put in the result cache,
870 :     C<download> for the indicator of how the column should be included in
871 :     downloads, and C<runTimeValue> for the value to be used when the result is
872 :     displayed. Note that if a run-time value is required, then the normal value
873 :     must be formatted in a special way (see L<Column Processing>).
874 :    
875 :     A little fancy dancing is required for extra columns. For extra columns, only
876 :     the title, style, and download status are ever requested.
877 :    
878 :     =item colName
879 :    
880 :     Name of the column of interest. The name may contain a colon, in which case
881 :     the column name is the part before the colon and the value after it is
882 :     passed to the column method as the run-time key.
883 :    
884 :     =item runTimeKey (optional)
885 :    
886 :     If a run-time value is desired, this should be the key taken from the value stored
887 :     in the result cache.
888 :    
889 :     =item RETURN
890 :    
891 :     Returns the desired result for the specified column.
892 :    
893 :     =back
894 :    
895 :     =cut
896 :    
897 :     sub Compute {
898 :     # Get the parameters.
899 :     my ($self, $type, $colName, $runTimeKey) = @_;
900 :     # Declare the return variable.
901 :     my $retVal;
902 :     # Check for an extra column.
903 :     if (ref $colName eq 'HASH') {
904 :     # Look for the appropriate data from the hash.
905 :     if ($type eq 'value') {
906 :     # The caller wants the column value, which is stored in the "extras"
907 :     # member keyed by column name.
908 :     my $realName = $colName->{name};
909 :     $retVal = $self->{extras}->{$realName};
910 :     Trace("Extra column $realName retrieved value is $retVal.") if T(4);
911 :     } else {
912 :     # The other data items are stored in the column name itself.
913 :     $retVal = $colName->{$type};
914 :     }
915 :     } else {
916 :     # Here we have a real built-in column. The search helper chooses which of
917 :     # these to use (usually by adding to a default list), and we use static
918 :     # methods in our subclass to process them. An eval call is used to
919 :     # accomplish the result. First, we do some goofiness so we can deal
920 :     # with the possible absence of a run-time key.
921 :     my $realRunTimeKey = (defined $runTimeKey ? ", '$runTimeKey'" : "");
922 :     # Check for a complex column name. Note that during run-time expansion, the
923 :     # column names will have been simplified (that is, the colon will have been
924 :     # removed and the parameter attached to the incoming run-time key.
925 :     if ($colName =~ /(\S+):(.+)/) {
926 :     $colName = $1;
927 :     $realRunTimeKey = $2;
928 :     }
929 :     # Get the result helper type.
930 :     my $rhType = $self->{type};
931 :     # Create the string for returning the desired results.
932 :     my $expression = "${rhType}::$colName($type => \$self$realRunTimeKey)";
933 :     # Evaluate to get the result. Note we automatically translate undefined results to
934 :     # an empty string.
935 :     Trace("Evaluating: $expression") if T(4);
936 :     $retVal = eval($expression) || "";
937 :     # Check for an error.
938 :     if ($@) {
939 :     Trace("Evaluation failed in Compute of $expression") if T(1);
940 :     Confess("$self->{type} column request failed: $@");
941 :     }
942 :     }
943 :     # Return the computed result.
944 :     return $retVal;
945 :     }
946 :    
947 :     =head3 ColumnDownload
948 :    
949 :     C<< my $flag = $rhelp->ColumnDownload($colName); >>
950 :    
951 :     Return the type of data in the column, or an empty string if it should
952 :     not be downloaded. In general, all columns are downloaded except those
953 :     that are graphic representations of something.
954 :    
955 :     =over 4
956 :    
957 :     =item colName
958 :    
959 :     Name of the column in question.
960 :    
961 :     =item RETURN
962 :    
963 :     Returns one of the download data types discussed in L</Column Processing>.
964 :    
965 :     =back
966 :    
967 :     =cut
968 :    
969 :     sub ColumnDownload {
970 :     # Get the parameters.
971 :     my ($self, $colName) = @_;
972 :     # Compute the result.
973 :     my $retVal = $self->Compute(download => $colName);
974 :     # Return it.
975 :     return $retVal;
976 :     }
977 :    
978 :     =head3 ColumnTitle
979 :    
980 :     C<< my $titleHtml = $rhelp->ColumnTitle($colName); >>
981 :    
982 :     Return the title to be used in the result table for the specified column.
983 :    
984 :     =over 4
985 :    
986 :     =item colName
987 :    
988 :     Name of the relevant column.
989 :    
990 :     =item RETURN
991 :    
992 :     Returns the html to be used for the column title.
993 :    
994 :     =back
995 :    
996 :     =cut
997 :    
998 :     sub ColumnTitle {
999 :     # Get the parameters.
1000 :     my ($self, $colName) = @_;
1001 :     # Compute the result.
1002 :     my $retVal = $self->Compute(title => $colName);
1003 :     # Return it.
1004 :     return $retVal;
1005 :     }
1006 :    
1007 :     =head3 ColumnValue
1008 :    
1009 :     C<< my $htmlValue = $rhelp->ColumnValue($colName); >>
1010 :    
1011 :     Return the display value for a column. This could be HTML text or it
1012 :     could be a run-time value specification. The column value is computed
1013 :     using the data record currently stored in the result helper.
1014 :    
1015 :     =over 4
1016 :    
1017 :     =item colName
1018 :    
1019 :     Name of the column whose value is desired.
1020 :    
1021 :     =item RETURN
1022 :    
1023 :     Returns the value to be stored in the result cache.
1024 :    
1025 :     =back
1026 :    
1027 :     =cut
1028 :    
1029 :     sub ColumnValue {
1030 :     # Get the parameters.
1031 :     my ($self, $colName) = @_;
1032 :     # Compute the return value.
1033 :     my $retVal = $self->Compute(value => $colName);
1034 :     # Return it.
1035 :     return $retVal;
1036 :     }
1037 :    
1038 :     =head3 ColumnStyle
1039 :    
1040 :     C<< my $className = $rhelp->ColumnStyle($colName); >>
1041 :    
1042 :     Return the display style for the specified column. This must be a classname
1043 :     defined for C<TD> tags in the active style sheet.
1044 :    
1045 :     =over 4
1046 :    
1047 :     =item colName
1048 :    
1049 :     Name of the relevant column.
1050 :    
1051 :     =item RETURN
1052 :    
1053 :     Returns the name of the style class to be used for this column's cells.
1054 :    
1055 :     =back
1056 :    
1057 :     =cut
1058 :    
1059 :     sub ColumnStyle {
1060 :     # Get the parameters.
1061 :     my ($self, $colName) = @_;
1062 :     # Compute the return value.
1063 :     my $retVal = $self->Compute(style => $colName);
1064 :     # Return it.
1065 :     return $retVal;
1066 :     }
1067 :    
1068 :     =head3 GetRunTimeValues
1069 :    
1070 :     C<< my @valueHtml = $rhelp->GetRunTimeValues(@cols); >>
1071 :    
1072 :     Return the run-time values of a row of columns. The incoming values contain
1073 :     the actual column contents. Run-time columns will be identified by the
1074 :     leading C<%%> marker. The run-time columns are converted in sequence
1075 :     using methods in the base class.
1076 :    
1077 :     =over 4
1078 :    
1079 :     =item cols
1080 :    
1081 :     A list of columns. Runtime columns will be of the format C<%%>I<colName>C<=>I<key>,
1082 :     where I<colName> is the actual column name and I<key> is the key to be passed to
1083 :     the evaluator. Columns that do not have this format are unchanged.
1084 :    
1085 :     =item RETURN
1086 :    
1087 :     Returns a list of the final values for all the run-time columns.
1088 :    
1089 :     =back
1090 :    
1091 :     =cut
1092 :    
1093 :     sub GetRunTimeValues {
1094 :     # Get the parameters.
1095 :     my ($self, @cols) = @_;
1096 :     # Declare the return value.
1097 :     my @retVal = ();
1098 :     # Clear the cache. The run-time value methods can store stuff
1099 :     # in here to save computation time.
1100 :     $self->{cache} = {};
1101 :     # Loop through the columns.
1102 :     for my $col (@cols) {
1103 :     # Declare a holding variable.
1104 :     my $retVal;
1105 :     # Parse the column data.
1106 :     if ($col =~ /^%%(\w+)=(.+)/) {
1107 :     # It parsed as a run-time value, so call the Compute method.
1108 :     $retVal = $self->Compute(runTimeValue => $1, $2);
1109 :     } else {
1110 :     # Here it's a search-time value, so we leave it unchanged.
1111 :     $retVal = $col;
1112 :     }
1113 :     # Add this column to the result list.
1114 :     push @retVal, $retVal;
1115 :     }
1116 :     # Return the result.
1117 :     return @retVal;
1118 :     }
1119 :    
1120 :     =head3 SetColumns
1121 :    
1122 :     C<< $rhelp->SetColumns(@cols); >>
1123 :    
1124 :     Store the specified object columns. These are the columns computed by the search
1125 :     framework, and should generally be specified first. If the search itself is
1126 :     going to generate additional data, the columns for displaying this additional
1127 :     data should be specified by a subsequent call to L</AddExtraColumn>.
1128 :    
1129 :     =over 4
1130 :    
1131 :     =item cols
1132 :    
1133 :     A list of column names. These must correspond to names defined in the result
1134 :     helper subclass (see L</Column Processing>).
1135 :    
1136 :     =back
1137 :    
1138 :     =cut
1139 :    
1140 :     sub SetColumns {
1141 :     # Get the parameters.
1142 :     my ($self, @cols) = @_;
1143 :     # Store the columns in the column list. Note that this erases any
1144 :     # previous column information.
1145 :     $self->{columns} = \@cols;
1146 :     }
1147 :    
1148 :     =head3 AddExtraColumn
1149 :    
1150 :     C<< $rhelp->AddExtraColumn($name => $loc, %data); >>
1151 :    
1152 :     Add an extra column to the column list at a specified location.
1153 :    
1154 :     =over 4
1155 :    
1156 :     =item name
1157 :    
1158 :     The name of the column to add.
1159 :    
1160 :     =item loc
1161 :    
1162 :     The location at which the column should be displayed. The column is added
1163 :     at the specified column location in the column list. It may be moved,
1164 :     however, if subsequent column additions are placed at or before its
1165 :     specified location. To put a column at the beginning, specify C<0>;
1166 :     to put it at the end specify C<undef>.
1167 :    
1168 :     =item data
1169 :    
1170 :     A hash specifying the title, style, and download flag for the extra
1171 :     column. The download flag (key C<download>) should specify the type
1172 :     of data in the column. The title (key C<title>) should be the name
1173 :     displayed for the column in the result display table. The style
1174 :     (key C<style>) should be the style class used for displaying the cells
1175 :     in the column.
1176 :    
1177 :     =back
1178 :    
1179 :     =cut
1180 :    
1181 :     sub AddExtraColumn {
1182 :     # Get the parameters.
1183 :     my ($self, $name, $loc, %data) = @_;
1184 :     # Add the name to the column hash.
1185 :     $data{name} = $name;
1186 :     # Store the result in the column list.
1187 :     $self->_StoreColumnSpec(\%data, $loc);
1188 :     }
1189 :    
1190 :     =head3 AddOptionalColumn
1191 :    
1192 :     C<< $rhelp->AddOptionalColumn($name => $loc); >>
1193 :    
1194 :     Store the specified column name in the column list at the
1195 :     specified location. The column name must be one that
1196 :     is known to the result helper subclass. This method
1197 :     allows ordinary columns (as opposed to extra columns)
1198 :     to be added after the initial L</SetColumns> call.
1199 :    
1200 :     =over 4
1201 :    
1202 :     =item name
1203 :    
1204 :     Name of the desired column.
1205 :    
1206 :     =item location
1207 :    
1208 :     Location at which the desired column should be stored.
1209 :    
1210 :     =back
1211 :    
1212 :     =cut
1213 :    
1214 :     sub AddOptionalColumn {
1215 :     # Get the parameters.
1216 :     my ($self, $name => $loc) = @_;
1217 :     # Currently, there is no extra work required here, but that
1218 :     # may change.
1219 :     $self->_StoreColumnSpec($name, $loc);
1220 :     }
1221 :    
1222 :     =head3 PutExtraColumns
1223 :    
1224 :     C<< $rhelp->PutExtraColumns(name1 => value1, name2 => value2, ...); >>
1225 :    
1226 :     Store the values of one or more extra columns. If a search produces extra columns (that is,
1227 :     columns whose data is determined by the search instead of queries against the database), then
1228 :     for each row of output, the search must call this method to specify the values of the various
1229 :     extra columns. Multiple calls to this method are allowed, in which case each call either
1230 :     overrides or adds to the values specified by the prior call.
1231 :    
1232 :     =over 4
1233 :    
1234 :     =item extraColumnMap
1235 :    
1236 :     A hash keyed on extra column name that maps the column names to the column's values for the current
1237 :     row of table data.
1238 :    
1239 :     =back
1240 :    
1241 :     =cut
1242 :    
1243 :     sub PutExtraColumns {
1244 :     # Get the parameters.
1245 :     my ($self, %extraColumnMap) = @_;
1246 :     # Copy the hash values into the extra column hash.
1247 :     my $counter = 0;
1248 :     for my $name (keys %extraColumnMap) {
1249 :     $self->{extras}->{$name} = $extraColumnMap{$name};
1250 :     Trace("Extra column $name has value $extraColumnMap{$name}.") if T(4);
1251 :     }
1252 :     }
1253 :    
1254 :     =head2 Internal Utilities
1255 :    
1256 :     =head3 StoreColumnSpec
1257 :    
1258 :     C<< $rhelp->_StoreColumnSpec($column, $location); >>
1259 :    
1260 :     Store the specified column information at the specified location in the column name list.
1261 :     The information is a string for an ordinary column and a hash for an extra column. The
1262 :     actual location at which the column is stored will be adjusted so that there are no
1263 :     gaps in the list. If the location is undefined, it defaults to the end. Thus, C<0>
1264 :     will always store at the beginning and C<undef> will always store at the end.
1265 :    
1266 :     =over 4
1267 :    
1268 :     =item column
1269 :    
1270 :     A column name or extra-column hash to be stored in the column list.
1271 :    
1272 :     =item location
1273 :    
1274 :     The index at which the column name should be stored, or C<undef> to store it
1275 :     at the end.
1276 :    
1277 :     =back
1278 :    
1279 :     =cut
1280 :    
1281 :     sub _StoreColumnSpec {
1282 :     # Get the parameters.
1283 :     my ($self, $column, $location) = @_;
1284 :     # Compute the current column count.
1285 :     my $columnCount = scalar @{$self->{columns}};
1286 :     # Adjust the location.
1287 :     if (! defined($location) || $location > $columnCount) {
1288 :     $location = $columnCount;
1289 :     }
1290 :     # Insert the column into the list.
1291 :     splice @{$self->{columns}}, $location, 0, $column;
1292 :     }
1293 :    
1294 :    
1295 :     =head2 Virtual Methods
1296 :    
1297 :     The following methods can be overridden by the subclass. In some cases, they
1298 :     must be overridden.
1299 :    
1300 :     =head3 DefaultResultColumns
1301 :    
1302 :     C<< my @colNames = $rhelp->DefaultResultColumns(); >>
1303 :    
1304 :     Return a list of the default columns to be used by searches with this
1305 :     type of result. Note that the actual default columns are computed by
1306 :     the search helper. This method is only needed if the search helper doesn't
1307 :     care.
1308 :    
1309 :     The columns returned should be in the form of column names, all of which
1310 :     must be defined by the result helper class.
1311 :    
1312 :     =cut
1313 :    
1314 :     sub DefaultResultColumns {
1315 :     # This method must be overridden.
1316 :     Confess("Pure virtual call to DefaultResultColumns.");
1317 :     }
1318 :    
1319 :     =head3 MoreDownloadFormats
1320 :    
1321 :     C<< $rhelp->MoreDownloadFormats(\%dlTypes); >>
1322 :    
1323 :     Add additional supported download formats to the type table. The table is a
1324 :     hash keyed on the download type code for which the values are the download
1325 :     descriptions. There is a special syntax that allows the placement of text
1326 :     fields inside the description. Use square brackets containing the name
1327 :     for the text field. The field will come in to the download request as
1328 :     a GET-type field.
1329 :    
1330 :     =over 4
1331 :    
1332 :     =item dlTypes
1333 :    
1334 :     Reference to a download-type hash. The purpose of this method is to add more
1335 :     download types relevant to the particular result type. Each type is described
1336 :     by a key (the download type itself) and a description. The description can
1337 :     contain a single text field that may be used to pass a parameter to the
1338 :     download. The text field is of the format C<[>I<fieldName>C<]>,
1339 :     where I<fieldName> is the name to give the text field's parameter in the
1340 :     generated download URL.
1341 :    
1342 :     =back
1343 :    
1344 :     =cut
1345 :    
1346 :     sub MoreDownloadFormats {
1347 :     Trace("Pure virtual call to MoreDownloadFormats.") if T(3);
1348 :     # Take no action.
1349 :     }
1350 :    
1351 :     =head3 MoreDownloadDataMethods
1352 :    
1353 :     C<< my @lines = $rhelp->MoreDownloadDataMethods($objectID, $dlType, \@cols, \@colHdrs); >>
1354 :    
1355 :     Create one or more lines of download data for a download of the specified type. Override
1356 :     this method if you need to process more download types than the default C<tbl> method.
1357 :    
1358 :     =over 4
1359 :    
1360 :     =item objectID
1361 :    
1362 :     ID of the object for this data row.
1363 :    
1364 :     =item dlType
1365 :    
1366 :     Download type (e.g. C<fasta>, etc.)
1367 :    
1368 :     =item cols
1369 :    
1370 :     Reference to a list of the data columns from the result cache, or alternatively
1371 :     the string C<header> (indicating that header lines are desired) or C<footer>
1372 :     (indicating that footer lines are desired).
1373 :    
1374 :     =item colHdrs
1375 :    
1376 :     The list of column headers from the result cache.
1377 :    
1378 :     =item RETURN
1379 :    
1380 :     Returns an array of data lines to output to the download file.
1381 :    
1382 :     =back
1383 :    
1384 :     =cut
1385 :    
1386 :     sub MoreDownloadDataMethods {
1387 :     # Get the parameters.
1388 :     my ($self, $objectID, $dlType, $cols, $colHdrs) = @_;
1389 :     # If we need to call this method, then the subclass should have overridden it.
1390 :     Confess("Invalid download type \"$dlType\" specified for result class $self->{type}.");
1391 :     }
1392 :    
1393 :     1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3