--- loncom/interface/loncommon.pm 2004/11/02 20:48:02 1.226 +++ loncom/interface/loncommon.pm 2005/03/22 15:32:07 1.257 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.226 2004/11/02 20:48:02 albertel Exp $ +# $Id: loncommon.pm,v 1.257 2005/03/22 15:32:07 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -379,7 +379,7 @@ sub coursebrowser_javascript { return (<<ENDSTDBRW); <script type="text/javascript" language="Javascript" > var stdeditbrowser; - function opencrsbrowser(formname,uname,udom,desc) { + function opencrsbrowser(formname,uname,udom,desc,extra_element) { var url = '/adm/pickcourse?'; var filter; if (filter != null) { @@ -396,6 +396,12 @@ sub coursebrowser_javascript { url += 'form=' + formname + '&cnumelement='+uname+ '&cdomelement='+udom+ '&cnameelement='+desc; + if (extra_element !=null && extra_element != '' && formname == 'rolechoice') { + url += '&roleelement='+extra_element; + if (domainfilter == null || domainfilter == '') { + url += '&domainfilter='+extra_element; + } + } var title = 'Course_Browser'; var options = 'scrollbars=1,resizable=1,menubar=0'; options += ',width=700,height=600'; @@ -407,9 +413,9 @@ ENDSTDBRW } sub selectcourse_link { - my ($form,$unameele,$udomele,$desc)=@_; + my ($form,$unameele,$udomele,$desc,$extra_element)=@_; return "<a href='".'javascript:opencrsbrowser("'.$form.'","'.$unameele. - '","'.$udomele.'","'.$desc.'");'."'>".&mt('Select Course')."</a>"; + '","'.$udomele.'","'.$desc.'","'.$extra_element.'");'."'>".&mt('Select Course')."</a>"; } =pod @@ -541,7 +547,7 @@ END $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n"; foreach my $value (sort(keys(%$hashref))) { $result.=" <option value=\"$value\" "; - $result.=" selected=\"true\" " if ($value eq $firstdefault); + $result.=" selected=\"selected\" " if ($value eq $firstdefault); $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n"; } $result .= "</select>\n"; @@ -551,7 +557,7 @@ END my $seconddefault = $hashref->{$firstdefault}->{'default'}; foreach my $value (sort(keys(%select2))) { $result.=" <option value=\"$value\" "; - $result.=" selected=\"true\" " if ($value eq $seconddefault); + $result.=" selected=\"selected\" " if ($value eq $seconddefault); $result.=">".&mt($select2{$value})."</option>\n"; } $result .= "</select>\n"; @@ -662,6 +668,7 @@ sub help_open_menu { my $link=''; my $title = &mt('Get help'); my $origurl = $ENV{'REQUEST_URI'}; + $origurl=~s|^/~|/priv/|; my $timestamp = time; foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) { $$_ = &Apache::lonnet::escape($$_); @@ -680,25 +687,38 @@ sub help_open_menu { "<table bgcolor='#773311' cellspacing='1' cellpadding='1' border='0'><tr>". "<td bgcolor='#886622'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; } + my $html=&Apache::lonxml::xmlbegin(); my $helpicon=&lonhttpdurl("/adm/lonIcons/helpgateway.gif"); $template .= <<"ENDTEMPLATE"; <script type="text/javascript"> -//<!-- BEGIN LON-CAPA Internal -function helpMenu(caller) { - if (caller == 'open') { - newWindow = window.open("","helpmenu","HEIGHT=$height,WIDTH=$width,resize=yes,scrollbars=yes" ) - caller = newWindow.document - } else { - caller = this.document - } - caller.write("<html><head><title>LON-CAPA Help Menu</title><meta http-equiv='pragma' content='no-cache'></head>") - caller.write("<frameset rows='105,*' border='0'><frame name='bannerframe' src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>") - caller.write("</html>") - caller.close() - if (caller == newWindow.document) { - caller.focus() +// <!-- BEGIN LON-CAPA Internal +// <![CDATA[ +function helpMenu(target) { + var caller = this; + if (target == 'open') { + var newWindow = null; + try { + newWindow = window.open("/adm/rat/empty.html","helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" ) + } + catch(error) { + writeHelp(caller); + return; + } + if (newWindow) { + caller = newWindow; + } } + writeHelp(caller); + return; } +function writeHelp(caller) { + caller.document.write('$html<head><title>LON-CAPA Help Menu</title><meta http-equiv="pragma" content="no-cache"></head>') + caller.document.write("<frameset rows='105,*' border='0'><frame name='bannerframe' src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>") + caller.document.write("</html>") + caller.document.close() + caller.focus() +} +// ]]> // END LON-CAPA Internal --> </script> <a href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help Menu)" /></a> @@ -815,6 +835,98 @@ ENDTEMPLATE =pod +=item * change_content_javascript(): + +This and the next function allow you to create small sections of an +otherwise static HTML page that you can update on the fly with +Javascript, even in Netscape 4. + +The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag) +must be written to the HTML page once. It will prove the Javascript +function "change(name, content)". Calling the change function with the +name of the section +you want to update, matching the name passed to C<changable_area>, and +the new content you want to put in there, will put the content into +that area. + +B<Note>: Netscape 4 only reserves enough space for the changable area +to contain room for the original contents. You need to "make space" +for whatever changes you wish to make, and be B<sure> to check your +code in Netscape 4. This feature in Netscape 4 is B<not> powerful; +it's adequate for updating a one-line status display, but little more. +This script will set the space to 100% width, so you only need to +worry about height in Netscape 4. + +Modern browsers are much less limiting, and if you can commit to the +user not using Netscape 4, this feature may be used freely with +pretty much any HTML. + +=cut + +sub change_content_javascript { + # If we're on Netscape 4, we need to use Layer-based code + if ($ENV{'browser.type'} eq 'netscape' && + $ENV{'browser.version'} =~ /^4\./) { + return (<<NETSCAPE4); + function change(name, content) { + doc = document.layers[name+"___escape"].layers[0].document; + doc.open(); + doc.write(content); + doc.close(); + } +NETSCAPE4 + } else { + # Otherwise, we need to use semi-standards-compliant code + # (technically, "innerHTML" isn't standard but the equivalent + # is really scary, and every useful browser supports it + return (<<DOMBASED); + function change(name, content) { + element = document.getElementById(name); + element.innerHTML = content; + } +DOMBASED + } +} + +=pod + +=item * changable_area($name, $origContent): + +This provides a "changable area" that can be modified on the fly via +the Javascript code provided in C<change_content_javascript>. $name is +the name you will use to reference the area later; do not repeat the +same name on a given HTML page more then once. $origContent is what +the area will originally contain, which can be left blank. + +=cut + +sub changable_area { + my ($name, $origContent) = @_; + + if ($ENV{'browser.type'} eq 'netscape' && + $ENV{'browser.version'} =~ /^4\./) { + # If this is netscape 4, we need to use the Layer tag + return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>"; + } else { + return "<span id='$name'>$origContent</span>"; + } +} + +=pod + +=back + +=head1 Excel and CSV file utility routines + +=over 4 + +=cut + +############################################################### +############################################################### + +=pod + =item * csv_translate($text) Translate $text to allow it to be output as a 'comma separated values' @@ -831,7 +943,6 @@ sub csv_translate { return $text; } - ############################################################### ############################################################### @@ -855,6 +966,10 @@ Currently supported formats: =item h3 +=item h4 + +=item i + =item date =back @@ -877,6 +992,8 @@ sub define_excel_formats { $format->{'h1'} = $workbook->add_format(bold=>1, size=>18); $format->{'h2'} = $workbook->add_format(bold=>1, size=>16); $format->{'h3'} = $workbook->add_format(bold=>1, size=>14); + $format->{'h4'} = $workbook->add_format(bold=>1, size=>12); + $format->{'i'} = $workbook->add_format(italic=>1); $format->{'date'} = $workbook->add_format(num_format=> 'mm/dd/yyyy hh:mm:ss'); return $format; @@ -887,84 +1004,83 @@ sub define_excel_formats { =pod -=item * change_content_javascript(): +=item * create_workbook -This and the next function allow you to create small sections of an -otherwise static HTML page that you can update on the fly with -Javascript, even in Netscape 4. +Create an Excel worksheet. If it fails, output message on the +request object and return undefs. -The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag) -must be written to the HTML page once. It will prove the Javascript -function "change(name, content)". Calling the change function with the -name of the section -you want to update, matching the name passed to C<changable_area>, and -the new content you want to put in there, will put the content into -that area. +Inputs: Apache request object -B<Note>: Netscape 4 only reserves enough space for the changable area -to contain room for the original contents. You need to "make space" -for whatever changes you wish to make, and be B<sure> to check your -code in Netscape 4. This feature in Netscape 4 is B<not> powerful; -it's adequate for updating a one-line status display, but little more. -This script will set the space to 100% width, so you only need to -worry about height in Netscape 4. - -Modern browsers are much less limiting, and if you can commit to the -user not using Netscape 4, this feature may be used freely with -pretty much any HTML. +Returns (undef) on failure, + Excel worksheet object, scalar with filename, and formats + from &Apache::loncommon::define_excel_formats on success =cut -sub change_content_javascript { - # If we're on Netscape 4, we need to use Layer-based code - if ($ENV{'browser.type'} eq 'netscape' && - $ENV{'browser.version'} =~ /^4\./) { - return (<<NETSCAPE4); - function change(name, content) { - doc = document.layers[name+"___escape"].layers[0].document; - doc.open(); - doc.write(content); - doc.close(); - } -NETSCAPE4 - } else { - # Otherwise, we need to use semi-standards-compliant code - # (technically, "innerHTML" isn't standard but the equivalent - # is really scary, and every useful browser supports it - return (<<DOMBASED); - function change(name, content) { - element = document.getElementById(name); - element.innerHTML = content; - } -DOMBASED +############################################################### +############################################################### +sub create_workbook { + my ($r) = @_; + # + # Create the excel spreadsheet + my $filename = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.xls'; + my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); + if (! defined($workbook)) { + $r->log_error("Error creating excel spreadsheet $filename: $!"); + $r->print('<p>'.&mt("Unable to create new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"). + '</p>'); + return (undef); } + # + $workbook->set_tempdir('/home/httpd/perl/tmp'); + # + my $format = &Apache::loncommon::define_excel_formats($workbook); + return ($workbook,$filename,$format); } +############################################################### +############################################################### + =pod -=item * changable_area($name, $origContent): +=item * create_text_file -This provides a "changable area" that can be modified on the fly via -the Javascript code provided in C<change_content_javascript>. $name is -the name you will use to reference the area later; do not repeat the -same name on a given HTML page more then once. $origContent is what -the area will originally contain, which can be left blank. +Create a file to write to and eventually make available to the usre. +If file creation fails, outputs an error message on the request object and +return undefs. -=cut +Inputs: Apache request object, and file suffix -sub changable_area { - my ($name, $origContent) = @_; +Returns (undef) on failure, + Filehandle and filename on success. - if ($ENV{'browser.type'} eq 'netscape' && - $ENV{'browser.version'} =~ /^4\./) { - # If this is netscape 4, we need to use the Layer tag - return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>"; - } else { - return "<span id='$name'>$origContent</span>"; +=cut + +############################################################### +############################################################### +sub create_text_file { + my ($r,$suffix) = @_; + if (! defined($suffix)) { $suffix = 'txt'; }; + my $fh; + my $filename = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.'.$suffix; + $fh = Apache::File->new('>/home/httpd'.$filename); + if (! defined($fh)) { + $r->log_error("Couldn't open $filename for output $!"); + $r->print("Problems occured in creating the output file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator."); } + return ($fh,$filename) } -=pod + +=pod =back @@ -1026,7 +1142,7 @@ sub multiple_select_form { $output.="\n<select name='$name' size='$size' multiple='1'>"; foreach (sort(keys(%hash))) { $output.='<option value="'.$_.'" '; - $output.='selected ' if ($selected{$_}); + $output.='selected="selected" ' if ($selected{$_}); $output.='>'.$hash{$_}."</option>\n"; } $output.="</select>\n"; @@ -1057,7 +1173,7 @@ sub select_form { } foreach (@keys) { $selectform.="<option value=\"$_\" ". - ($_ eq $def ? 'selected' : ''). + ($_ eq $def ? 'selected="selected" ' : ''). ">".&mt($hash{$_})."</option>\n"; } $selectform.="</select>"; @@ -1094,7 +1210,7 @@ sub select_level_form { my $selectform = "<select name=\"$name\" size=\"1\">\n"; for (my $i=0; $i<=18; $i++) { $selectform.="<option value=\"$i\" ". - ($i==$deflevel ? 'selected' : ''). + ($i==$deflevel ? 'selected="selected" ' : ''). ">".&gradeleveldescription($i)."</option>\n"; } $selectform.="</select>"; @@ -1124,7 +1240,7 @@ sub select_dom_form { my $selectdomain = "<select name=\"$name\" size=\"1\">\n"; foreach (@domains) { $selectdomain.="<option value=\"$_\" ". - ($_ eq $defdom ? 'selected' : ''). + ($_ eq $defdom ? 'selected="selected" ' : ''). ">$_</option>\n"; } $selectdomain.="</select>"; @@ -1223,9 +1339,11 @@ Outputs: ############################################################### ############################################################### sub decode_user_agent { + my ($r)=@_; my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"}); my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"}); my $httpbrowser=$ENV{"HTTP_USER_AGENT"}; + if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); } my $clientbrowser='unknown'; my $clientversion='0'; my $clientmathml=''; @@ -2278,7 +2396,7 @@ sub get_student_view { if (defined($moreenv)) { %form=(%form,%{$moreenv}); } - if ($target eq 'tex') {$form{'grade_target'} = 'tex';} + if (defined($target)) { $form{'grade_target'} = $target; } $feedurl=&Apache::lonnet::clutter($feedurl); my $userview=&Apache::lonnet::ssi_body($feedurl,%form); $userview=~s/\<body[^\>]*\>//gi; @@ -2318,7 +2436,7 @@ sub get_student_answers { =item * &submlink() -Inputs: $text $uname $udom $symb +Inputs: $text $uname $udom $symb $target Returns: A link to grades.pm such as to see the SUBM view of a student @@ -2326,15 +2444,64 @@ Returns: A link to grades.pm such as to ############################################### sub submlink { - my ($text,$uname,$udom,$symb)=@_; + my ($text,$uname,$udom,$symb,$target)=@_; if (!($uname && $udom)) { (my $cursymb, my $courseid,$udom,$uname)= &Apache::lonxml::whichuser($symb); if (!$symb) { $symb=$cursymb; } } - if (!$symb) { $symb=&symbread(); } - return '<a href="/adm/grades?symb='.$symb.'&student='.$uname. - '&userdom='.$udom.'&command=submission">'.$text.'</a>'; + if (!$symb) { $symb=&Apache::lonnet::symbread(); } + $symb=&Apache::lonnet::escape($symb); + if ($target) { $target="target=\"$target\""; } + return '<a href="/adm/grades?&command=submission&'. + 'symb='.$symb.'&student='.$uname. + '&userdom='.$udom.'" '.$target.'>'.$text.'</a>'; +} +############################################## + +=pod + +=item * &pgrdlink() + +Inputs: $text $uname $udom $symb $target + +Returns: A link to grades.pm such as to see the PGRD view of a student + +=cut + +############################################### +sub pgrdlink { + my $link=&submlink(@_); + $link=~s/(&command=submission)/$1&showgrading=yes/; + return $link; +} +############################################## + +=pod + +=item * &pprmlink() + +Inputs: $text $uname $udom $symb $target + +Returns: A link to parmset.pm such as to see the PPRM view of a +student andn resource + +=cut + +############################################### +sub pprmlink { + my ($text,$uname,$udom,$symb,$target)=@_; + if (!($uname && $udom)) { + (my $cursymb, my $courseid,$udom,$uname)= + &Apache::lonxml::whichuser($symb); + if (!$symb) { $symb=$cursymb; } + } + if (!$symb) { $symb=&Apache::lonnet::symbread(); } + $symb=&Apache::lonnet::escape($symb); + if ($target) { $target="target=\"$target\""; } + return '<a href="/adm/parmset?&command=set&'. + 'symb='.$symb.'&uname='.$uname. + '&udom='.$udom.'" '.$target.'>'.$text.'</a>'; } ############################################## @@ -2555,13 +2722,20 @@ sub bodytag { if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; } # construct main body tag my $bodytag = <<END; -<style> +<style type="text/css"> h1, h2, h3, th { font-family: Arial, Helvetica, sans-serif } a:focus { color: red; background: yellow } </style> <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link" style="margin-top: 0px;$addstyle" $addentries> END + if ($ENV{'environment.texengine'} eq 'jsMath') { + $bodytag.='<script type="text/javascript"> + function NoFontMessage () {} + </script>'."\n". + '<script src="/adm/jsMath/jsMath.js"></script>'."\n"; + } + my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'. $lonhttpdPort.$img.'" alt="'.$function.'" />'; if ($bodyonly) { @@ -2576,7 +2750,6 @@ END # No Remote my $roleinfo=(<<ENDROLE); <td bgcolor="$tabbg" align="right"> -<p> <font size="2" face="Arial, Helvetica, sans-serif"> $ENV{'environment.firstname'} $ENV{'environment.middlename'} @@ -2587,17 +2760,51 @@ END <font size="2" face="Arial, Helvetica, sans-serif">$role</font> <br /> <font size="2" face="Arial, Helvetica, sans-serif">$realm</font> -</p> </td> ENDROLE my $titleinfo = '<font face="Arial, Helvetica, sans-serif" size="+3" color="'. - $font.'"><b>'.$title.'</b></font>'; + $font.'"><b>'.$title.'</b></font>'; if ($customtitle) { $titleinfo = $customtitle; - } - return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web', - $forcereg). - '<table bgcolor="'.$pgbg.'" width="100%" border="0" cellspacing="3" cellpadding="3"><tr><td rowspan="3" bgcolor="'.$tabbg.'">'.$titleinfo.'</td>'.$roleinfo.'</tr></table>'; + } + + if ($ENV{'request.state'} eq 'construct') { + my ($uname,$thisdisfn)= + ($ENV{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|); + my $formaction='/priv/'.$uname.'/'.$thisdisfn; + $formaction=~s/\/+/\//g; + unless ($customtitle) { #this is for resources; directories have customtitle, and crumbs and select recent are created in lonpubdir.pm + my $parentpath = ''; + my $lastitem = ''; + if ($thisdisfn =~ m-(.+/)([^/]*)$-) { + $parentpath = $1; + $lastitem = $2; + } else { + $lastitem = $thisdisfn; + } + $titleinfo = &Apache::loncommon::help_open_menu('','','','',3,'Authoring'). + '<font face="Arial, Helvetica, sans-serif"><b>Construction Space</b>:</font> '. + '<form name="dirs" method="post" action="'.$formaction + .'" target="_top"><tt><b>' + .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."<font size=\"+1\">$lastitem</font></b></tt><br />" + .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()') + .'</form>' + .&Apache::lonmenu::constspaceform(); + + } + $forcereg=1; + } + my $titletable = '<table bgcolor="'.$pgbg.'" width="100%" border="0" '. + 'cellspacing="3" cellpadding="3">'. + '<tr><td rowspan="3" bgcolor="'.$tabbg.'">'. + $titleinfo.'</td>'.$roleinfo.'</tr></table>'; + if ($ENV{'request.state'} eq 'construct') { + $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable); + } else { + $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg). + $titletable; + } + return $bodytag; } # @@ -2607,6 +2814,17 @@ ENDROLE if ($customtitle) { $titleinfo = $customtitle; } + # + # Extra info if you are the DC + my $dc_info = ''; + if ($ENV{'user.adv'} && exists($ENV{'user.role.dc./'. + $ENV{'course.'.$ENV{'request.course.id'}. + '.domain'}.'/'})) { + my $cid = $ENV{'request.course.id'}; + $dc_info.= $cid.' '.$ENV{'course.'.$cid.'.internal.coursecode'}; + $dc_info = '('.$dc_info.')'; + } + # return(<<ENDBODY); $bodytag <table width="100%" cellspacing="0" border="0" cellpadding="0"> @@ -2616,8 +2834,8 @@ $upperleft</td> </tr> <tr> <td rowspan="3" bgcolor="$tabbg"> -$titleinfo -<td bgcolor="$tabbg" align="right"> +$titleinfo $dc_info +</td><td bgcolor="$tabbg" align="right"> <font size="2" face="Arial, Helvetica, sans-serif"> $ENV{'environment.firstname'} $ENV{'environment.middlename'} @@ -2636,6 +2854,40 @@ ENDBODY } ############################################### +############################################### + +=pod + +=back + +=head1 HTTP Helpers + +=over 4 + +=item * &endbodytag() + +Returns a uniform footer for LON-CAPA web pages. + +Inputs: + +=over 4 + +=back + +Returns: A uniform footer for LON-CAPA web pages. + +=cut + +sub endbodytag { + my $endbodytag='</body>'; + if ($ENV{'environment.texengine'} eq 'jsMath') { + $endbodytag='<script type="text/javascript">jsMath.Process()</script>'. + "\n".$endbodytag; + } + return $endbodytag; +} + +############################################### =pod @@ -2664,6 +2916,61 @@ sub get_users_function { ############################################### +=pod + +=item get_sections + +Determines all the sections for a course including +sections with students and sections containing other roles. +Incoming parameters: domain, course number, reference to +section hash (keys to be section/group IDs), reference to +array containing roles for which sections should be gathered +(optional). If the fourth argument is undefined, sections +are gathered for any role. + +Returns number of sections. + +=cut + +############################################### +sub get_sections { + my ($cdom,$cnum,$sectioncount,$possible_roles) = @_; + if (!($cdom && $cnum)) { return 0; } + my $cid = $cdom.'_'.$cnum; + my $numsections = 0; + + if (!defined($possible_roles) || (grep/^st$/,@$possible_roles)) { + my ($classlist) = &Apache::loncoursedata::get_classlist($cid,$cdom,$cnum); + my $sec_index = &Apache::loncoursedata::CL_SECTION(); + my $status_index = &Apache::loncoursedata::CL_STATUS(); + while (my ($student,$data) = each %$classlist) { + my ($section,$status) = ($data->[$sec_index], + $data->[$status_index]); + unless ($section eq '-1' || $section =~ /^\s*$/) { + if (!defined($$sectioncount{$section})) { $numsections++; } + $$sectioncount{$section}++; + } + } + } + my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); + foreach my $user (sort(keys(%courseroles))) { + if ($user !~ /^(\w{2})/) { next; } + my ($role) = ($user =~ /^(\w{2})/); + if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; } + my $section; + if ($role eq 'cr' && + $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) { + $section=$1; + } + if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; } + if (!defined($section) || $section eq '-1') { next; } + if (!defined($$sectioncount{$section})) { $numsections++; } + $$sectioncount{$section}++; + } + return $numsections; +} + + sub get_posted_cgi { my $r=shift; @@ -2800,6 +3107,7 @@ sub no_cache { sub content_type { my ($r,$type,$charset) = @_; + if ($ENV{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; } unless ($charset) { $charset=&Apache::lonlocal::current_encoding; } @@ -2937,7 +3245,12 @@ needs $ENV{'form.upfile'} and $ENV{'form sub upfile_record_sep { if ($ENV{'form.upfiletype'} eq 'xml') { } else { - return split(/\n/,$ENV{'form.upfile'}); + my @records; + foreach my $line (split(/\n/,$ENV{'form.upfile'})) { + if ($line=~/^\s*$/) { next; } + push(@records,$line); + } + return @records; } } @@ -3095,7 +3408,7 @@ sub csv_print_select_table { $r->print('<option value="none"></option>'); foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<option value="'.$_.'"'. - ($_ eq $defaultcol ? ' selected ' : ''). + ($_ eq $defaultcol ? ' selected="selected" ' : ''). '>Column '.($_+1).'</option>'); } $r->print('</select></td></tr>'."\n"); @@ -3139,7 +3452,7 @@ sub csv_samples_select_table { foreach (@$d) { my ($value,$display,$defaultcol)=@{ $_ }; $r->print('<option value="'.$value.'"'. - ($i eq $defaultcol ? ' selected ':'').'>'. + ($i eq $defaultcol ? ' selected="selected" ':'').'>'. $display.'</option>'); } $r->print('</select></td><td>'); @@ -3270,6 +3583,9 @@ they are plotted. If undefined, default =item @Values: An array of array references. Each array reference holds data to be plotted in a stacked bar chart. +=item If the final element of @Values is a hash reference the key/value +pairs will be added to the graph definition. + =back Returns: @@ -3290,6 +3606,10 @@ sub DrawBarGraph { '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66', ]; } + my $extra_settings = {}; + if (ref($Values[-1]) eq 'HASH') { + $extra_settings = pop(@Values); + } # my $identifier = &get_cgi_id(); my $id = 'cgi.'.$identifier; @@ -3365,6 +3685,11 @@ sub DrawBarGraph { $ValuesHash{$id.'.bar_width'} = $bar_width; $ValuesHash{$id.'.labels'} = join(',',@Labels); # + # Deal with other parameters + while (my ($key,$value) = each(%$extra_settings)) { + $ValuesHash{$id.'.'.$key} = $value; + } + # &Apache::lonnet::appenv(%ValuesHash); return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; } @@ -3734,7 +4059,7 @@ sub icon { $curfext.".gif"; } } - return $iconname; + return &lonhttpdurl($iconname); } sub lonhttpdurl { @@ -3772,7 +4097,7 @@ sub escape_double { # Escapes the last element of a full URL. sub escape_url { my ($url) = @_; - my @urlslices = split(/\//, $url); + my @urlslices = split(/\//, $url,-1); my $lastitem = &Apache::lonnet::escape(pop(@urlslices)); return join('/',@urlslices).'/'.$lastitem; }