--- loncom/interface/loncommon.pm 2007/09/24 23:29:53 1.587 +++ loncom/interface/loncommon.pm 2007/11/06 02:23:49 1.608 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.587 2007/09/24 23:29:53 raeburn Exp $ +# $Id: loncommon.pm,v 1.608 2007/11/06 02:23:49 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -367,7 +367,7 @@ sub selectstudent_link { return ''; } return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. - '","'.$udomele.'","","1");'."'>".&mt('Select User')."</a>"; + '","'.$udomele.'");'."'>".&mt('Select User')."</a>"; } if ($env{'request.role'}=~/^(au|dc|su)/) { return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. @@ -407,7 +407,7 @@ sub coursebrowser_javascript { '&cdomelement='+udom+ '&cnameelement='+desc; if (extra_element !=null && extra_element != '') { - if (formname == 'rolechoice') { + if (formname == 'rolechoice' || formname == 'studentform') { url += '&roleelement='+extra_element; if (domainfilter == null || domainfilter == '') { url += '&domainfilter='+extra_element; @@ -1074,6 +1074,77 @@ sub changable_area { =pod +=item * viewport_geometry_js { + +Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser. + +=cut + + +sub viewport_geometry_js { + return <<"GEOMETRY"; +var Geometry = {}; +function init_geometry() { + if (Geometry.init) { return }; + Geometry.init=1; + if (window.innerHeight) { + Geometry.getViewportHeight = function() { return window.innerHeight; }; + Geometry.getViewportWidth = function() { return window.innerWidth; }; + Geometry.getHorizontalScroll = function() { return window.pageXOffset; }; + Geometry.getVerticalScroll = function() { return window.pageYOffset; }; + } + else if (document.documentElement && document.documentElement.clientHeight) { + Geometry.getViewportHeight = + function() { return document.documentElement.clientHeight; }; + Geometry.getViewportWidth = + function() { return document.documentElement.clientWidth; }; + + Geometry.getHorizontalScroll = + function() { return document.documentElement.scrollLeft; }; + Geometry.getVerticalScroll = + function() { return document.documentElement.scrollTop; }; + } + else if (document.body.clientHeight) { + Geometry.getViewportHeight = + function() { return document.body.clientHeight; }; + Geometry.getViewportWidth = + function() { return document.body.clientWidth; }; + Geometry.getHorizontalScroll = + function() { return document.body.scrollLeft; }; + Geometry.getVerticalScroll = + function() { return document.body.scrollTop; }; + } +} + +GEOMETRY +} + +=pod + +=item * viewport_size_js { + +Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window. + +=cut + +sub viewport_size_js { + my $geometry = &viewport_geometry_js(); + return <<"DIMS"; + +$geometry + +function getViewportDims(width,height) { + init_geometry(); + width.value = Geometry.getViewportWidth(); + height.value = Geometry.getViewportHeight(); + return; +} + +DIMS +} + +=pod + =item * resize_textarea_js emits the needed javascript to resize a textarea to be as big as possible @@ -1087,37 +1158,41 @@ to be attached to the <body> for the onl =cut sub resize_textarea_js { + my $geometry = &viewport_geometry_js(); return <<"RESIZE"; <script type="text/javascript"> -var Geometry = {}; -function init_geometry() { - if (Geometry.init) { return }; - Geometry.init=1; - if (window.innerHeight) { - Geometry.getViewportHeight = function() { return window.innerHeight; }; - } - else if (document.documentElement && document.documentElement.clientHeight) { - Geometry.getViewportHeight = - function() { return document.documentElement.clientHeight; }; - } - else if (document.body.clientHeight) { - Geometry.getViewportHeight = - function() { return document.body.clientHeight; }; +$geometry + +function getX(element) { + var x = 0; + while (element) { + x += element.offsetLeft; + element = element.offsetParent; + } + return x; +} +function getY(element) { + var y = 0; + while (element) { + y += element.offsetTop; + element = element.offsetParent; } + return y; } + function resize_textarea(textarea_id,bottom_id) { init_geometry(); var textarea = document.getElementById(textarea_id); //alert(textarea); - var textarea_top = textarea.offsetTop; + var textarea_top = getY(textarea); var textarea_height = textarea.offsetHeight; var bottom = document.getElementById(bottom_id); - var bottom_top = bottom.offsetTop; + var bottom_top = getY(bottom); var bottom_height = bottom.offsetHeight; var window_height = Geometry.getViewportHeight(); - var fudge = 23; + var fudge = 23; var new_height = window_height-fudge-textarea_top-bottom_height; if (new_height < 300) { new_height = 300; @@ -1332,8 +1407,6 @@ sub domain_select { =over 4 -=cut - =item * multiple_select_form($name,$value,$size,$hash,$order) Returns a string containing a <select> element int multiple mode @@ -1520,7 +1593,7 @@ input: 4 arguments (two required, two op option, and selected by default. $hide - Value of 'hide' causes hiding of the name of the server, if 1 server found, or default, if 0 found. -output: returns 1 items: +output: returns 2 items: (a) form element which contains either: (i) <select name="$name"> <option value="$hostid1">$hostid $servers{$hostid}</option> @@ -1725,19 +1798,16 @@ END } my $radioval = "'nochange'"; - if (exists($in{'curr_authtype'}) && - defined($in{'curr_authtype'}) && - $in{'curr_authtype'} ne '') { - $radioval = "'$in{'curr_authtype'}arg'"; + if (defined($in{'curr_authtype'})) { + if ($in{'curr_authtype'} ne '') { + $radioval = "'".$in{'curr_authtype'}."arg'"; + } } my $argfield = 'null'; - if ( grep/^mode$/,(keys %in) ) { + if (defined($in{'mode'})) { if ($in{'mode'} eq 'modifycourse') { - if ( grep/^curr_authtype$/,(keys %in) ) { - $radioval = "'$in{'curr_authtype'}'"; - } - if ( grep/^curr_autharg$/,(keys %in) ) { - unless ($in{'curr_autharg'} eq '') { + if (defined($in{'curr_autharg'})) { + if ($in{'curr_autharg'} ne '') { $argfield = "'$in{'curr_autharg'}'"; } } @@ -1834,7 +1904,7 @@ sub authform_nochange{ return $result; } -sub authform_kerberos{ +sub authform_kerberos { my %in = ( formname => 'document.cu', kerb_def_dom => 'MSU.EDU', @@ -1850,22 +1920,23 @@ sub authform_kerberos{ $check4 = ' checked="on"'; } $krbarg = $in{'kerb_def_dom'}; - if (grep(/^curr_authtype$/,(keys(%in)))) { - if ($in{'curr_authtype'} =~ m/^krb(\d+)$/) { - $krbver = $1; + if (defined($in{'curr_authtype'})) { + if ($in{'curr_authtype'} eq 'krb') { $krbcheck = ' checked="on"'; - if ($krbver eq '5') { - $check5 = ' checked="on"'; - $check4 = ''; - } else { - $check4 = ' checked="on"'; - $check5 = ''; + if (defined($in{'curr_kerb_ver'})) { + if ($in{'curr_krb_ver'} eq '5') { + $check5 = ' checked="on"'; + $check4 = ''; + } else { + $check4 = ' checked="on"'; + $check5 = ''; + } } - if (grep(/^curr_autharg$/,(keys(%in)))) { + if (defined($in{'curr_autharg'})) { $krbarg = $in{'curr_autharg'}; } if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { - if (grep(/^curr_autharg$/,(keys(%in)))) { + if (defined($in{'curr_autharg'})) { $result = &mt('Currently Kerberos authenticated with domain [_1] Version [_2].', $in{'curr_autharg'},$krbver); @@ -1884,7 +1955,7 @@ sub authform_kerberos{ if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { return; } elsif ($authtype eq '') { - if (grep(/^mode$/,(keys(%in)))) { + if (defined($in{'mode'})) { if ($in{'mode'} eq 'modifycourse') { if ($authnum == 1) { $authtype = '<input type="hidden" name="login" value="krb">'; @@ -1945,11 +2016,11 @@ sub authform_internal{ ); my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall); my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); - if (grep(/^curr_authtype$/,(keys(%in)))) { - if ($in{'curr_authtype'} eq 'internal:') { + if (defined($in{'curr_authtype'})) { + if ($in{'curr_authtype'} eq 'int') { if ($can_assign{'int'}) { $intcheck = 'checked="on" '; - if (grep(/^curr_autharg$/,(keys(%in)))) { + if (defined($in{'curr_autharg'})) { $intarg = $in{'curr_autharg'}; } } else { @@ -1965,7 +2036,7 @@ sub authform_internal{ if (!$can_assign{'int'}) { return; } elsif ($authtype eq '') { - if (grep(/^mode$/,(keys(%in)))) { + if (defined($in{'mode'})) { if ($in{'mode'} eq 'modifycourse') { if ($authnum == 1) { $authtype = '<input type="hidden" name="login" value="int">'; @@ -1978,7 +2049,7 @@ sub authform_internal{ $authtype = '<input type="radio" name="login" value="int" '.$intcheck. ' onchange="'.$jscall.'" onclick="'.$jscall.'" />'; } - $autharg = '<input type="text" size="10" name="intarg" value="'. + $autharg = '<input type="password" size="10" name="intarg" value="'. $intarg.'" onchange="'.$jscall.'" />'; $result = &mt ('[_1] Internally authenticated (with initial password [_2])', @@ -1994,11 +2065,11 @@ sub authform_local{ ); my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall); my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); - if (grep(/^curr_authtype$/,(keys(%in)))) { - if ($in{'curr_authtype'} eq 'localauth:') { + if (defined($in{'curr_authtype'})) { + if ($in{'curr_authtype'} eq 'loc') { if ($can_assign{'loc'}) { $loccheck = 'checked="on" '; - if (grep(/^curr_autharg$/,(keys(%in)))) { + if (defined($in{'curr_autharg'})) { $locarg = $in{'curr_autharg'}; } } else { @@ -2014,7 +2085,7 @@ sub authform_local{ if (!$can_assign{'loc'}) { return; } elsif ($authtype eq '') { - if (grep(/^mode$/,(keys(%in)))) { + if (defined($in{'mode'})) { if ($in{'mode'} eq 'modifycourse') { if ($authnum == 1) { $authtype = '<input type="hidden" name="login" value="loc">'; @@ -2043,8 +2114,8 @@ sub authform_filesystem{ ); my ($fsyscheck,$result,$authtype,$autharg,$jscall); my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); - if (grep(/^curr_authtype$/,(keys(%in)))) { - if ($in{'curr_authtype'} eq 'unix:') { + if (defined($in{'curr_authtype'})) { + if ($in{'curr_authtype'} eq 'fsys') { if ($can_assign{'fsys'}) { $fsyscheck = 'checked="on" '; } else { @@ -2060,7 +2131,7 @@ sub authform_filesystem{ if (!$can_assign{'fsys'}) { return; } elsif ($authtype eq '') { - if (grep(/^mode$/,(keys(%in)))) { + if (defined($in{'mode'})) { if ($in{'mode'} eq 'modifycourse') { if ($authnum == 1) { $authtype = '<input type="hidden" name="login" value="fsys">'; @@ -2080,7 +2151,7 @@ sub authform_filesystem{ ('[_1] Filesystem Authenticated (with initial password [_2])', '<label><input type="radio" name="login" value="fsys" '. $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />', - '</label><input type="text" size="10" name="fsysarg" value="" '. + '</label><input type="password" size="10" name="fsysarg" value="" '. 'onchange="'.$jscall.'" />'); return $result; } @@ -2877,14 +2948,14 @@ sub get_previous_attempt { $lasthash{$key}=$returnhash{$version.':'.$key}; } } - $prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">'; - $prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>'; + $prevattempts=&start_data_table().&start_data_table_header_row(); + $prevattempts.='<th>'.&mt('History').'</th>'; foreach my $key (sort(keys(%lasthash))) { my ($ign,@parts) = split(/\./,$key); if ($#parts > 0) { my $data=$parts[-1]; pop(@parts); - $prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.' </td>'; + $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>'; } else { if ($#parts == 0) { $prevattempts.='<th>'.$parts[0].'</th>'; @@ -2893,28 +2964,37 @@ sub get_previous_attempt { } } } + $prevattempts.=&end_data_table_header_row(); if ($getattempt eq '') { for ($version=1;$version<=$returnhash{'version'};$version++) { - $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>'; + $prevattempts.=&start_data_table_row(). + '<td>'.&mt('Transaction [_1]',$version).'</td>'; foreach my $key (sort(keys(%lasthash))) { my $value = &format_previous_attempt_value($key, $returnhash{$version.':'.$key}); $prevattempts.='<td>'.$value.' </td>'; } + $prevattempts.=&end_data_table_row(); } } - $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>'; + $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>'; foreach my $key (sort(keys(%lasthash))) { my $value = &format_previous_attempt_value($key,$lasthash{$key}); if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} $prevattempts.='<td>'.$value.' </td>'; } - $prevattempts.='</tr></table></td></tr></table>'; + $prevattempts.= &end_data_table_row().&end_data_table(); } else { - $prevattempts='Nothing submitted - no attempts.'; + $prevattempts= + &start_data_table().&start_data_table_row(). + '<td>'.&mt('Nothing submitted - no attempts.').'</td>'. + &end_data_table_row().&end_data_table(); } } else { - $prevattempts='No data.'; + $prevattempts= + &start_data_table().&start_data_table_row(). + '<td>'.&mt('No data.').'</td>'. + &end_data_table_row().&end_data_table(); } } @@ -3089,9 +3169,9 @@ sub pprmlink { if (!$symb) { $symb=&Apache::lonnet::symbread(); } $symb=&escape($symb); if ($target) { $target="target=\"$target\""; } - return '<a href="/adm/parmset?&command=set&'. - 'symb='.$symb.'&uname='.$uname. - '&udom='.$udom.'" '.$target.'>'.$text.'</a>'; + return '<a href="/adm/parmset?command=set&'. + 'symb='.$symb.'&uname='.$uname. + '&udom='.$udom.'" '.$target.'>'.$text.'</a>'; } ############################################## @@ -4019,7 +4099,7 @@ sub standard_css { my $vlink = &designparm($function.'.vlink', $domain); my $link = &designparm($function.'.link', $domain); - my $sans = 'Arial,Helvetica,sans-serif'; + my $sans = 'Verdana,Arial,Helvetica,sans-serif'; my $mono = 'monospace'; my $data_table_head = $tabbg; my $data_table_light = '#EEEEEE'; @@ -4037,8 +4117,9 @@ sub standard_css { my $table_header = '#DDDDDD'; my $feedback_link_bg = '#BBBBBB'; - my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px' - : '0px 3px 0px 4px'; + my $border = ($env{'browser.type'} eq 'explorer' || + $env{'browser.type'} eq 'safari' ) ? '0px 2px 0px 2px' + : '0px 3px 0px 4px'; return <<END; @@ -4058,7 +4139,7 @@ table.thinborder tr td { form, .inline { display: inline; } .center { text-align: center; } -.LC_filename {font-family: $mono;} +.LC_filename {font-family: $mono; white-space:pre;} .LC_error { color: red; font-size: larger; @@ -4099,7 +4180,7 @@ table.LC_pastsubmission { margin: 2px; } -table#LC_top_nav, table#LC_menubuttons { +table#LC_top_nav, table#LC_menubuttons,table#LC_nav_location { width: 100%; background: $pgbg; border: 2px; @@ -4107,7 +4188,7 @@ table#LC_top_nav, table#LC_menubuttons { padding: 0px; } -table#LC_title_bar, table.LC_breadcrumbs, table#LC_nav_location, +table#LC_title_bar, table.LC_breadcrumbs, table#LC_title_bar.LC_with_remote { width: 100%; border-color: $pgbg; @@ -4304,13 +4385,13 @@ table.LC_data_table, table.LC_mail_list } table.LC_nested_outer { border: 1px solid #000000; - border-collapse: separate; + border-collapse: collapse; border-spacing: 0px; width: 100%; } table.LC_nested { border: 0px; - border-collapse: separate; + border-collapse: collapse; border-spacing: 0px; width: 100%; } @@ -4362,7 +4443,8 @@ table.LC_nested tr.LC_info_row td { font-size: small; text-align: center; } -table.LC_nested tr.LC_info_row td.LC_left_item { +table.LC_nested tr.LC_info_row td.LC_left_item, +table.LC_nested_outer tr th.LC_left_item { text-align: left; } table.LC_nested td { @@ -4731,12 +4813,19 @@ table.LC_descriptive_input td.LC_descrip text-align: right; font-weight: bold; } -table.LC_feedback_link { - background: $feedback_link_bg; +div.LC_feedback_link { + background: white; + width: 100%; } span.LC_feedback_link { - background: $feedback_link_bg; - font-size: larger; + background: $feedback_link_bg; + font-size: larger; +} +span.LC_message_link { + background: $feedback_link_bg; + font-size: larger; + position: absolute; + right: 1em; } table.LC_prior_tries { @@ -4886,6 +4975,156 @@ table.LC_sty_end { background: #FFBBBB; } +table.LC_double_column { + border-width: 0px; + border-collapse: collapse; + width: 100%; + padding: 2px; +} + +table.LC_double_column tr td.LC_left_col { + top: 2px; + left: 2px; + width: 47%; + vertical-align: top; +} + +table.LC_double_column tr td.LC_right_col { + top: 2px; + right: 2px; + width: 47%; + vertical-align: top; +} + +span.LC_role_level { + font-weight: bold; +} + +div.LC_left_float { + float: left; + padding-right: 5%; + padding-bottom: 4px; +} + +div.LC_clear_float_header { + padding-bottom: 2px; +} + +div.LC_clear_float_footer { + padding-top: 10px; + clear: both; +} + + +div.LC_grade_select_mode { + float: left; + font-family: $sans; +} +div.LC_grade_select_mode div div { + margin: 5px; +} +div.LC_grade_select_mode_selector { + margin: 5px; + float: left; +} +div.LC_grade_select_mode_selector_header { + font: bold medium $sans; +} +div.LC_grade_select_mode_type { + clear: left; +} + +div.LC_grade_show_user { + margin-top: 20px; + border: 1px solid black; +} +div.LC_grade_user_name { + background: #DDDDEE; + border-bottom: 1px solid black; + font: bold large $sans; +} +div.LC_grade_show_user_odd_row div.LC_grade_user_name { + background: #DDEEDD; +} + +div.LC_grade_show_problem, +div.LC_grade_submissions, +div.LC_grade_message_center, +div.LC_grade_info_links, +div.LC_grade_assign { + margin: 5px; + width: 99%; + background: #FFFFFF; +} +div.LC_grade_show_problem_header, +div.LC_grade_submissions_header, +div.LC_grade_message_center_header, +div.LC_grade_assign_header { + font: bold large $sans; +} +div.LC_grade_show_problem_problem, +div.LC_grade_submissions_body, +div.LC_grade_message_center_body, +div.LC_grade_assign_body { + border: 1px solid black; + width: 99%; + background: #FFFFFF; +} +span.LC_grade_check_note { + font: normal medium $sans; + display: inline; + position: absolute; + right: 1em; +} + + +div.LC_edit_problem_header { + font: normal medium $sans; + margin: 2px; +} +div.LC_edit_problem_header, +div.LC_edit_problem_header div, +div.LC_edit_problem_editxml_header, +div.LC_edit_problem_editxml_header div { + margin-top: 5px; +} +div.LC_edit_problem_header_edit_row { + background: $tabbg; + padding: 3px; + margin-bottom: 5px; +} +div.LC_edit_problem_header_title { + font: larger bold $sans; + background: $tabbg; + padding: 3px; +} +table.LC_edit_problem_header_title { + font: larger bold $sans; + width: 100%; + border-color: $pgbg; + border-style: solid; + border-width: $border; + + background: $tabbg; + border-collapse: collapse; + padding: 0px +} + +div.LC_edit_problem_discards { + float: left; + padding-bottom: 5px; +} +div.LC_edit_problem_saves { + float: right; + padding-bottom: 5px; +} +hr.LC_edit_problem_divide { + clear: both; + color: $tabbg; + background-color: $tabbg; + height: 3px; + border: 0px; +} END } @@ -5002,7 +5241,9 @@ Inputs: none sub xml_begin { my $output=''; - &Apache::lonhtmlcommon::init_htmlareafields(); + if ($env{'internal.start_page'}==1) { + &Apache::lonhtmlcommon::init_htmlareafields(); + } if ($env{'browser.mathml'}) { $output='<?xml version="1.0"?>' @@ -6564,20 +6805,21 @@ sub csv_print_samples { my ($r,$records) = @_; my $samples = &get_samples($records,3); - $r->print(&mt('Samples').'<br /><table border="2"><tr>'); + $r->print(&mt('Samples').'<br />'.&start_data_table(). + &start_data_table_header_row()); foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); } - $r->print('</tr>'); + $r->print(&end_data_table_header_row()); foreach my $hash (@$samples) { - $r->print('<tr>'); + $r->print(&start_data_table_row()); foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { $r->print('<td>'); if (defined($$hash{$sample})) { $r->print($$hash{$sample}); } $r->print('</td>'); } - $r->print('</tr>'); + $r->print(&end_data_table_row()); } - $r->print('</tr></table><br />'."\n"); + $r->print(&end_data_table().'<br />'."\n"); } ###################################################### @@ -6602,12 +6844,13 @@ sub csv_print_select_table { my $i=0; my $samples = &get_samples($records,1); $r->print(&mt('Associate columns with student attributes.')."\n". - '<table border="2"><tr>'. + &start_data_table().&start_data_table_header_row(). '<th>'.&mt('Attribute').'</th>'. - '<th>'.&mt('Column').'</th></tr>'."\n"); + '<th>'.&mt('Column').'</th>'. + &end_data_table_header_row()."\n"); foreach my $array_ref (@$d) { my ($value,$display,$defaultcol)=@{ $array_ref }; - $r->print('<tr><td>'.$display.'</td>'); + $r->print(&start_data_table_row().'<tr><td>'.$display.'</td>'); $r->print('<td><select name=f'.$i. ' onchange="javascript:flip(this.form,'.$i.');">'); @@ -6617,9 +6860,10 @@ sub csv_print_select_table { ($sample eq $defaultcol ? ' selected="selected" ' : ''). '>Column '.($sample+1).'</option>'); } - $r->print('</select></td></tr>'."\n"); + $r->print('</select></td>'.&end_data_table_row()."\n"); $i++; } + $r->print(&end_data_table()); $i--; return $i; } @@ -6646,11 +6890,13 @@ sub csv_samples_select_table { my $i=0; # my $samples = &get_samples($records,3); - $r->print('<table border=2><tr><th>'. - &mt('Field').'</th><th>'.&mt('Samples').'</th></tr>'); + $r->print(&start_data_table(). + &start_data_table_header_row().'<th>'. + &mt('Field').'</th><th>'.&mt('Samples').'</th>'. + &end_data_table_header_row()); foreach my $key (sort(keys(%{ $samples->[0] }))) { - $r->print('<tr><td><select name="f'.$i.'"'. + $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'. ' onchange="javascript:flip(this.form,'.$i.');">'); foreach my $option (@$d) { my ($value,$display,$defaultcol)=@{ $option }; @@ -6664,9 +6910,10 @@ sub csv_samples_select_table { $r->print($samples->[$line]{$key}."<br />\n"); } } - $r->print('</td></tr>'); + $r->print('</td>'.&end_data_table_row()); $i++; } + $r->print(&end_data_table()); $i--; return($i); }