[Bio] / FortyEight / Table.pm Repository:
ViewVC logotype

Diff of /FortyEight/Table.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2, Fri Feb 23 19:44:21 2007 UTC revision 1.3, Fri Feb 23 20:01:26 2007 UTC
# Line 6  Line 6 
6    
7  1;  1;
8    
9    =over 3
10    
11    =head1 NAME
12    
13    Table
14    
15    =head1 DESCRIPTION
16    
17    The Table Component implements an HTML/javascript table for displaying, filtering and browsing data.
18    It supports onClick events and popup menus for each cell. Data can also be grouped by a single column.
19    Like all WebApplicationComponents, configuration of columns to display is also supported.
20    
21    =head1 ARGUMENTS
22    
23    Arguments are passed as a single hash. All data must be passed as references (i.e. reference to an array
24    instead of an array). A table is instanciated via the I<new> method.
25    
26    =head2 Mandatory Arguments
27    
28    =item B<data>
29    
30    This must be an array of rows, each containing an array of cells. The data type of the cell contents is
31    detected for sorting issues. The first cell in a column will determine the data type. Three types of data
32    are differentiated:
33    
34    Integers and Floats
35    Dates in the format mm/dd/yyyy
36    Strings
37    
38    The cell data must not include quotation marks or linebreaks of any kind.
39    
40    =item B<columns>
41    
42    The columns are passed as an array of column headers, also no quotation marks or linebreaks are allowed.
43    
44    =head2 Optional Arguments
45    
46    =item B<id>
47    
48    The identification of the table. Only neccessary if you have more than one table on a single page. Default is
49    'table'.
50    
51    =item B<image_base>
52    
53    The directory relative to the cgi directory where all images are stored. 'clear.gif' needs to be present in this
54    directory. Default is '../images'.
55    
56    =item B<offset>
57    
58    The array index of the first item in the list to be displayed. Default is 0.
59    
60    =item B<perpage>
61    
62    Number of items to be displayed on each page. Default is 20.
63    
64    =item B<show_perpage>
65    
66    Boolean to determine whether the user may change the number of items to be displayed on each
67    page. Default is false.
68    
69    =item B<show_topbrowse>
70    
71    Boolean to determine whether the browsing functions are displayed above the table. Default is
72    false.
73    
74    =item B<show_bottombrowse>
75    
76    Boolean to determine whether the browsing functions are displayed below the table. Default is
77    false.
78    
79    =item B<enable_grouping>
80    
81    Boolean to determine whether the grouping of a single column should be supported. Grouped
82    columns are collapsed if they contain consecutive identical values. They can be expanded
83    and collapsed by the user via a click on the symbol in the according cell. Default is false.
84    
85    =item B<group_col>
86    
87    Array index of the column to be the grouping column. Default is 0.
88    
89    =item B<sortable>
90    
91    Boolean to determine whether the user is allowed to sort the columns. Default is false.
92    
93    =item B<show_filter>
94    
95    Boolean to determine whether the user should be able to filter the columns. Default is false.
96    
97    =item B<available_operators>
98    
99    An array of operators available for filtering. Must be passed in the following format, which
100    is also the default:
101    
102     ( [ 'like', '&cong;' ],
103      [ 'unlike', '!&cong;' ],
104      [ 'equal', '=' ],
105      [ 'unequal', '!=' ],
106      [ 'less', '&lt;' ],
107      [ 'more', '&gt;' ] )
108    
109    Where the first entry is the operator and the second entry is the html to be displayed in the
110    select box.
111    
112    =item B<preselected_operators>
113    
114    A hash containing the column names as key and the operator to be pre-selected as a value. As
115    default, the first operator in the list is selected.
116    
117    =item B<operands>
118    
119    A hash containing the column names as key and the operand as values. If show_filter is true,
120    columns which are not a key of this hash will not receive a filter box.
121    
122    =item B<onclicks>
123    
124    If passed, this must be an array of rows, each containing an array of cells with the same
125    dimensions as the data array. The values should be urls that a click on the according cell
126    should link to.
127    
128    =item B<popup_menu>
129    
130    A hash containing the keys 'titles', 'infos' and 'menus'. Each of these have an array of arrays,
131    matching the dimensions of the data array, as a value. For usage of the popup menu, consult
132    the popup menu manual.
133    
134    =back
135    
136    =cut
137    
138  # initialize the table  # initialize the table
139  sub new {  sub new {
140    my ($params) = @_;    my ($params) = @_;
# Line 69  Line 198 
198    my $show_perpage      = $params->{show_perpage}      || 0;    my $show_perpage      = $params->{show_perpage}      || 0;
199    my $show_topbrowse    = $params->{show_topbrowse}    || 0;    my $show_topbrowse    = $params->{show_topbrowse}    || 0;
200    my $show_bottombrowse = $params->{show_bottombrowse} || 0;    my $show_bottombrowse = $params->{show_bottombrowse} || 0;
201    my $group_cols        = $params->{group_cols}        || {};    my $group_col         = $params->{group_col}         || 0;
202      my $enable_grouping   = $params->{enable_grouping}   || 0;
203    my $sortable          = $params->{sortable}          || 0;    my $sortable          = $params->{sortable}          || 0;
204    my $sortcols          = $params->{sortcols}          || { 'all' => 1 };    my $sortcols          = $params->{sortcols}          || { 'all' => 1 };
   my $control_menu      = $params->{control_menu};  
205    my $column_widths     = $params->{column_widths};    my $column_widths     = $params->{column_widths};
   my $collapsed_columns = $params->{collapsed_columns} || {};  
206    unless (defined($column_widths)) {    unless (defined($column_widths)) {
207      foreach (@columns) {      foreach (@columns) {
208        push(@$column_widths, -1);        push(@$column_widths, -1);
# Line 178  Line 306 
306    $data_source =~ s/'/\@1/g;    $data_source =~ s/'/\@1/g;
307    $data_source =~ s/"/\@2/g;    $data_source =~ s/"/\@2/g;
308    
   # get the groupcol information  
   my @group_cols_array;  
   my $num_groupcols = 0;  
   for (my $i=0; $i<scalar(@columns); $i++) {  
     if (exists($group_cols->{$i})) {  
       push(@group_cols_array, 1);  
       $num_groupcols++;  
     } else {  
       push(@group_cols_array, 0);  
     }  
   }  
   
309    # insert hidden fields    # insert hidden fields
310    $table .= "\n<input type='hidden' id='table_data_" . $id . "' value='" . $data_source . "'>\n";    $table .= "\n<input type='hidden' id='table_data_" . $id . "' value='" . $data_source . "'>\n";
311    $table .= "<input type='hidden' id='table_onclicks_" . $id . "' value='" . $onclicks . "'>\n";    $table .= "<input type='hidden' id='table_onclicks_" . $id . "' value='" . $onclicks . "'>\n";
# Line 201  Line 317 
317    $table .= "<input type='hidden' id='table_rows_" . $id . "' value='" .  $total . "'>\n";    $table .= "<input type='hidden' id='table_rows_" . $id . "' value='" .  $total . "'>\n";
318    $table .= "<input type='hidden' id='table_cols_" . $id . "' value='" . scalar(@columns) . "'>\n";    $table .= "<input type='hidden' id='table_cols_" . $id . "' value='" . scalar(@columns) . "'>\n";
319    $table .= "<input type='hidden' id='table_start_" . $id . "' value='0'>\n";    $table .= "<input type='hidden' id='table_start_" . $id . "' value='0'>\n";
   $table .= "<input type='hidden' id='table_numgroups_" . $id . "' value='" . $num_groupcols . "'>\n";  
   $table .= "<input type='hidden' id='table_groups_" . $id . "' value='" . join(';', @group_cols_array) . "'>\n";  
320    $table .= "<input type='hidden' id='table_sortdirection_" . $id . "' value='up'>\n";    $table .= "<input type='hidden' id='table_sortdirection_" . $id . "' value='up'>\n";
321    
322    # check for title    # check for title
# Line 216  Line 330 
330      $table_width = "width: " . $params->{table_width} . "px;";      $table_width = "width: " . $params->{table_width} . "px;";
331    }    }
332    
   # check for control menu  
   if ($control_menu) {  
   
     # surrounding table  
     $table .= "<table><tr><td>";  
   
     # control tree columns  
     $table .= "<table><tr><td>Visible Tree Columns</td></tr>";  
     my @sorted_keys = sort(keys(%$group_cols));  
     foreach my $key (@sorted_keys) {  
       my $colname = $columns[$key];  
       $table .= "<tr><td>$colname</td><td><input type='checkbox' name='" . $key  ."_vis' id='table_" . $id . "_" . $key  ."_vis' checked=checked></td></tr>";  
     }  
     $table .= "</table></td><td>";  
   
     # control data columns  
     $table .= "<div style='height: 250px; overflow: auto;'><table><tr><td>Visible Data Columns</td></tr>";  
     for (my $i=0; $i<scalar(@columns); $i++) {  
       unless ($group_cols->{$i}) {  
         $table .= "<tr><td>" . $columns[$i] . "</td><td><input type='checkbox' name='" . $i  ."_vis' id='table_" . $id . "_" . $i  ."_vis'></td></tr>";  
       }  
     }  
     $table .= "</table></div>";  
   
     $table .= "</td></tr></table><input type='button' value='Apply' onclick='reload_table(\"" . $id . "\");'><input type='button' value='Show Data' onclick='switch_data_tree(\"" . $id . "\");' id='table_" . $id . "_switch_button'>";  
   }  
   
333    # check for display options - select entries per page    # check for display options - select entries per page
334    if ($show_perpage) {    if ($show_perpage) {
335      $table .= "<table class='table_table' style='$table_width'>\n<tr><td align=center><span class='table_perpage'>display&nbsp;<input type='text' id='table_perpage_" . $id . "' name='table_perpage_" . $id . "' size='3' value='" . $perpage . "' onkeypress='check_submit_filter(event, \"" . $id . "\")'>&nbsp;items per page</span></td></tr>\n";      $table .= "<table class='table_table' style='$table_width'>\n<tr><td align=center><span class='table_perpage'>display&nbsp;<input type='text' id='table_perpage_" . $id . "' name='table_perpage_" . $id . "' size='3' value='" . $perpage . "' onkeypress='check_submit_filter(event, \"" . $id . "\")'>&nbsp;items per page</span></td></tr>\n";
# Line 260  Line 347 
347    # start data table    # start data table
348    $table .= "<tr><td><table id='table_" . $id . "' class='table_table' style='$table_width'>";    $table .= "<tr><td><table id='table_" . $id . "' class='table_table' style='$table_width'>";
349    
350    # write table header    # check for display options - display column filters
351      if ($complex_filter) {
352        if (scalar(keys(%operands)) > 0) {
353    $table .= "<tr>";    $table .= "<tr>";
   my $i = 1;  
   
   # check column widths  
   my $colwidths;  
354    
355    # iterate through columns        # check each value for an existing filter field
356          my $i = 0;
357    foreach my $col (@columns) {    foreach my $col (@columns) {
358      if ($column_widths->[$i - 1] ne -1) {          if (exists($operands{$col})) {
       push(@$colwidths, "width: " . $column_widths->[$i - 1] . "px;");  
     } else {  
       push(@$colwidths, "");  
     }  
   
     # count up column name  
     my $name = $id . "_col_" . $i;  
   
     # prepare html for sorting according to column  
     my $order_img = "<a href='javascript: table_sort(\"" . $id . "\", \"" . $i . "\", \"ASC\");' class='table_first_row' title='Click to sort'>";  
   
     # create row collapse/expand button  
     my $collapse_button = "";  
     if ($group_cols->{$i - 1}) {  
       if ($collapsed_columns->{$col}) {  
         $collapse_button = "<img src='./Html/plus.gif' id='table_collapse_" . $id . "_" . ($i - 1) . "' onclick='expand_column(\"" . $id . "\", \"" . ($i - 1) . "\");'>";  
       } else {  
         $collapse_button = "<img src='./Html/minus.gif' id='table_collapse_" . $id . "_" . ($i - 1) . "' onclick='expand_column(\"" . $id . "\", \"" . ($i - 1) . "\");'>";  
       }  
     }  
   
     # check for simple filter  
     my $filter = "";  
     if (defined($operands{$col})) {  
       if ($complex_filter) {  
359    
360          # check if there is a preselected value for this filter field          # check if there is a preselected value for this filter field
361          my $preselected_operand = "";          my $preselected_operand = "";
# Line 303  Line 364 
364          }          }
365    
366          # check for filter comparison operator          # check for filter comparison operator
367          $filter = "<br/><select name='" . $id . "_" . $col . "_operator' id='table_" . $id . "_operator_" . $i . "' style='width: 40px;'>";            $table .= "<td><select name='" . $id . "_" . $col . "_operator' id='table_" . $id . "_operator_" . $i . "'>";
368    
369          foreach my $operator (@available_operators) {          foreach my $operator (@available_operators) {
370            my $preselected_operator = "";            my $preselected_operator = "";
# Line 314  Line 375 
375              }              }
376            }            }
377    
378            $filter .= "<option value='" . $operator->[0] . "'" . $preselected_operator . ">" . $operator->[1] . "</option>";              $table .= "<option value='" . $operator->[0] . "'" . $preselected_operator . ">" . $operator->[1] . "</option>";
379          }          }
380          $filter .= "</select><input type='text' name='" . $id . $col . "' class='filter_item' value='" . $preselected_operand . "'  id='table_" . $id . "_operand_" . $i . "' onkeypress='check_submit_filter(event, \"" . $id . "\")' style='width: 70%;'>";            $table .= "</select><input type='text' name='" . $id . $col . "' class='filter_item' value='" . $preselected_operand . "'  id='table_" . $id . "_operand_" . $i . "' onkeypress='check_submit_filter(event, \"" . $id . "\")'></td>";
381        } else {        } else {
382          my $operator = 'like';            $table .= "<td></td>";
         if (defined($preselected_operators{$col})) {  
           $operator = $preselected_operators{$col};  
383          }          }
384          $filter = "<br/><input type=hidden name='" . $id . "_" . $col . "_operator' value='" . $operator . "' id='table_" . $id . "_operator_" . $i . "'><input type='text' name='" . $id . $col . "' class='filter_item' value='' size=5 id='table_" . $id . "_operand_" . $i . "' onkeypress='check_submit_filter(event, \"" . $id . "\")' style='width: 100%;' title='Enter Search Text'>";          $i++;
385          }
386    
387          $table .= "</tr>";
388        }        }
389      }      }
390    
391      # check if colum header click should sort    # write table header
392      if ($sortable) {    $table .= "<tr>";
393        if ($sortcols->{$i} || $sortcols->{'all'}) {    my $i = 1;
394          $table .= "<td name='" . $name . "' class='table_first_row' style='" . $colwidths->[$i - 1] . "'>" . $collapse_button . $order_img . $col . "&nbsp;<img src='./Html/up-arrow.gif'><img src='./Html/down-arrow.gif'></a>" . $filter . "</td>";  
395      # check column widths
396      my $colwidths;
397    
398      # iterate through columns
399      foreach my $col (@columns) {
400        if ($column_widths->[$i - 1] ne -1) {
401          push(@$colwidths, "width: " . $column_widths->[$i - 1] . "px;");
402        } else {
403          push(@$colwidths, "");
404        }        }
405    
406        # count up column name
407        my $name = $id . "_col_" . $i;
408    
409        # prepare html for sorting according to column
410        my $order_img = "<a href='javascript: table_sort(\"" . $id . "\", \"" . $i . "\", \"ASC\");' class='table_first_row' title='Click to sort'>";
411    
412        # create config button
413        my $conf_button = qq~<span style="background-color: white; border: 1px solid black; font-size: 7pt; padding: 1px; cursor: pointer; width: 13px; vertical-align: top; text-align: left;" class="hideme" onclick="change_group('$id\_col_$i');" id="$id\_col_$i" name="conf">+/-</span>~;
414    
415        # check for simple filter
416        my $filter = "";
417        if (defined($operands{$col})) {
418          $filter = "<br/><input type=hidden name='" . $id . "_" . $col . "_operator' value='like' id='table_" . $id . "_operator_" . $i . "'><input type='text' name='" . $id . $col . "' class='filter_item' value='' size=5 id='table_" . $id . "_operand_" . $i . "' onkeypress='check_submit_filter(event, \"" . $id . "\")' style='width: 100%;' title='Enter Search Text'>";
419        }
420    
421        # check if colum header click should sort
422        if (($sortable) && ($sortcols->{$i} || $sortcols->{'all'})) {
423          $table .= "<td name='" . $name . "' class='table_first_row' style='" . $colwidths->[$i - 1] . "'>" . $conf_button . $order_img . $col . "&nbsp;<img src='./Html/up-arrow.gif'><img src='./Html/down-arrow.gif'></a>" . $filter . "</td>";
424      } else {      } else {
425        $table .= "<td name='" . $name . "' class='table_first_row' style='" . $colwidths->[$i - 1] . "'>" . $collapse_button . $col . $filter . "</td>";        $table .= "<td name='" . $name . "' class='table_first_row' style='" . $colwidths->[$i - 1] . "'>" . $conf_button . $col . $filter . "</td>";
426      }      }
427    
428      # increase column counter      # increase column counter
# Line 382  Line 472 
472      $to = $total;      $to = $total;
473    }    }
474    
475    $browse .= "<tr><td><table class='table_browse'><tr><td align='left' width='20%'>" . $left . "</td><td align='center' width='60%'>displaying <span name='table_start_" . $id . "'>" . ($offset + 1) . "</span> - <span name='table_stop_" . $id . "'>" . $to . "</span> of <span name='table_total_" . $id . "'>" . $total . "</span></td><td align='right' width='20%'>" . $right . "</td></tr></table></td></tr>";    $browse .= "<tr><td><table class='table_browse'><tr><td align='left' width='20%'>" . $left . "</td><td align='center' width='60%'>displaying <input type='text' name='table_start_" . $id . "' class='disp' readonly=1 value='" . ($offset + 1) . "'> - <input type='text' name='table_stop_" . $id . "' class='disp' readonly=1 value='" . $to . "'> of <input type='text' name='table_total_" . $id . "' class='disp' readonly=1 value='" . $total . "'></td><td align='right' width='20%'>" . $right . "</td></tr></table></td></tr>";
476    
477    return $browse;    return $browse;
478  }  }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3