version 1.78, 2002/01/14 16:32:38
|
version 1.102, 2002/08/28 19:50:29
|
Line 1
|
Line 1
|
|
# |
|
# $Id$ |
|
# |
|
# Copyright Michigan State University Board of Trustees |
|
# |
|
# This file is part of the LearningOnline Network with CAPA (LON-CAPA). |
|
# |
|
# LON-CAPA is free software; you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation; either version 2 of the License, or |
|
# (at your option) any later version. |
|
# |
|
# LON-CAPA is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
# GNU General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with LON-CAPA; if not, write to the Free Software |
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
# |
|
# /home/httpd/html/adm/gpl.txt |
|
# |
|
# http://www.lon-capa.org/ |
|
# |
# The LearningOnline Network with CAPA |
# The LearningOnline Network with CAPA |
# Spreadsheet/Grades Display Handler |
# Spreadsheet/Grades Display Handler |
# |
# |
Line 9
|
Line 34
|
# 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17, |
# 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17, |
# 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer |
# 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer |
# 01/14/02 Matthew |
# 01/14/02 Matthew |
|
# 02/04/02 Matthew |
|
|
|
# POD required stuff: |
|
|
|
=head1 NAME |
|
|
|
lonspreadsheet |
|
|
|
=head1 SYNOPSIS |
|
|
|
Spreadsheet interface to internal LON-CAPA data |
|
|
|
=head1 DESCRIPTION |
|
|
|
Lonspreadsheet provides course coordinators the ability to manage their |
|
students grades online. The students are able to view their own grades, but |
|
not the grades of their peers. The spreadsheet is highly customizable, |
|
offering the ability to use Perl code to manipulate data, as well as many |
|
built-in functions. |
|
|
|
|
|
=head2 Functions available to user of lonspreadsheet |
|
|
|
=over 4 |
|
|
|
=cut |
|
|
package Apache::lonspreadsheet; |
package Apache::lonspreadsheet; |
|
|
Line 20 use Apache::lonnet;
|
Line 71 use Apache::lonnet;
|
use Apache::Constants qw(:common :http); |
use Apache::Constants qw(:common :http); |
use GDBM_File; |
use GDBM_File; |
use HTML::TokeParser; |
use HTML::TokeParser; |
|
use Apache::lonhtmlcommon; |
# |
# |
# Caches for previously calculated spreadsheets |
# Caches for previously calculated spreadsheets |
# |
# |
Line 55 my %courseopt;
|
Line 106 my %courseopt;
|
my %useropt; |
my %useropt; |
my %parmhash; |
my %parmhash; |
|
|
|
# |
|
# Some hashes for stats on timing and performance |
|
# |
|
|
|
my %starttimes; |
|
my %usedtimes; |
|
my %numbertimes; |
|
|
# Stuff that only the screen handler can know |
# Stuff that only the screen handler can know |
|
|
my $includedir; |
my $includedir; |
Line 71 sub initsheet {
|
Line 130 sub initsheet {
|
$safeeval->permit("sort"); |
$safeeval->permit("sort"); |
$safeeval->deny(":base_io"); |
$safeeval->deny(":base_io"); |
$safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT'); |
$safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT'); |
|
$safeeval->share('$@'); |
my $code=<<'ENDDEFS'; |
my $code=<<'ENDDEFS'; |
# ---------------------------------------------------- Inside of the safe space |
# ---------------------------------------------------- Inside of the safe space |
|
|
Line 86 undef %v;
|
Line 146 undef %v;
|
undef %t; |
undef %t; |
undef %f; |
undef %f; |
undef %c; |
undef %c; |
undef %rl; |
undef %rowlabel; |
undef @os; |
undef @os; |
|
|
$maxrow=0; |
$maxrow=0; |
Line 114 $cfn='';
|
Line 174 $cfn='';
|
|
|
$usymb=''; |
$usymb=''; |
|
|
|
# error messages |
|
|
|
$errormsg=''; |
|
|
sub mask { |
sub mask { |
my ($lower,$upper)=@_; |
my ($lower,$upper)=@_; |
|
|
Line 190 sub mask {
|
Line 254 sub mask {
|
return '^'.$alpha.$num."\$"; |
return '^'.$alpha.$num."\$"; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item UWCALC(hashname,modules,units,date) |
|
|
|
returns the proportion of the module |
|
weights not previously completed by the student. |
|
|
|
=over 4 |
|
|
|
=item hashname |
|
|
|
name of the hash the module dates have been inserted into |
|
|
|
=item modules |
|
|
|
reference to a cell which contains a comma deliminated list of modules |
|
covered by the assignment. |
|
|
|
=item units |
|
|
|
reference to a cell which contains a comma deliminated list of module |
|
weights with respect to the assignment |
|
|
|
=item date |
|
|
|
reference to a cell which contains the date the assignment was completed. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub UWCALC { |
|
my ($hashname,$modules,$units,$date) = @_; |
|
my @Modules = split(/,/,$modules); |
|
my @Units = split(/,/,$units); |
|
my $total_weight; |
|
foreach (@Units) { |
|
$total_weight += $_; |
|
} |
|
my $usum=0; |
|
for (my $i=0; $i<=$#Modules; $i++) { |
|
if (&HASH($hashname,$Modules[$i]) eq $date) { |
|
$usum += $Units[$i]; |
|
} |
|
} |
|
return $usum/$total_weight; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item CDLSUM(list) |
|
|
|
returns the sum of the elements in a cell which contains |
|
a Comma Deliminate List of numerical values. |
|
'list' is a reference to a cell which contains a comma deliminated list. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub CDLSUM { |
|
my ($list)=@_; |
|
my $sum; |
|
foreach (split/,/,$list) { |
|
$sum += $_; |
|
} |
|
return $sum; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item CDLITEM(list,index) |
|
|
|
returns the item at 'index' in a Comma Deliminated List. |
|
|
|
=over 4 |
|
|
|
=item list |
|
|
|
reference to a cell which contains a comma deliminated list. |
|
|
|
=item index |
|
|
|
the Perl index of the item requested (first element in list has |
|
an index of 0) |
|
|
|
=back |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub CDLITEM { |
|
my ($list,$index)=@_; |
|
my @Temp = split/,/,$list; |
|
return $Temp[$index]; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item CDLHASH(name,key,value) |
|
|
|
loads a comma deliminated list of keys into |
|
the hash 'name', all with a value of 'value'. |
|
|
|
=over 4 |
|
|
|
=item name |
|
|
|
name of the hash. |
|
|
|
=item key |
|
|
|
(a pointer to) a comma deliminated list of keys. |
|
|
|
=item value |
|
|
|
a single value to be entered for each key. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub CDLHASH { |
|
my ($name,$key,$value)=@_; |
|
my @Keys; |
|
my @Values; |
|
# Check to see if we have multiple $key values |
|
if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) { |
|
my $keymask = &mask($key); |
|
# Assume the keys are addresses |
|
my @Temp = grep /$keymask/,keys(%v); |
|
@Keys = $v{@Temp}; |
|
} else { |
|
$Keys[0]= $key; |
|
} |
|
my @Temp; |
|
foreach $key (@Keys) { |
|
@Temp = (@Temp, split/,/,$key); |
|
} |
|
@Keys = @Temp; |
|
if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) { |
|
my $valmask = &mask($value); |
|
my @Temp = grep /$valmask/,keys(%v); |
|
@Values =$v{@Temp}; |
|
} else { |
|
$Values[0]= $value; |
|
} |
|
$value = $Values[0]; |
|
# Add values to hash |
|
for (my $i = 0; $i<=$#Keys; $i++) { |
|
my $key = $Keys[$i]; |
|
if (! exists ($hashes{$name}->{$key})) { |
|
$hashes{$name}->{$key}->[0]=$value; |
|
} else { |
|
my @Temp = sort(@{$hashes{$name}->{$key}},$value); |
|
$hashes{$name}->{$key} = \@Temp; |
|
} |
|
} |
|
return "hash '$name' updated"; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item GETHASH(name,key,index) |
|
|
|
returns the element in hash 'name' |
|
reference by the key 'key', at index 'index' in the values list. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub GETHASH { |
|
my ($name,$key,$index)=@_; |
|
if (! defined($index)) { |
|
$index = 0; |
|
} |
|
if ($key =~ /^[A-z]\d+$/) { |
|
$key = $v{$key}; |
|
} |
|
return $hashes{$name}->{$key}->[$index]; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item CLEARHASH(name) |
|
|
|
clears all the values from the hash 'name' |
|
|
|
=item CLEARHASH(name,key) |
|
|
|
clears all the values from the hash 'name' associated with the given key. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub CLEARHASH { |
|
my ($name,$key)=@_; |
|
if (defined($key)) { |
|
if (exists($hashes{$name}->{$key})) { |
|
$hashes{$name}->{$key}=undef; |
|
return "hash '$name' key '$key' cleared"; |
|
} |
|
} else { |
|
if (exists($hashes{$name})) { |
|
$hashes{$name}=undef; |
|
return "hash '$name' cleared"; |
|
} |
|
} |
|
return "Error in clearing hash"; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item HASH(name,key,value) |
|
|
|
loads values into an internal hash. If a key |
|
already has a value associated with it, the values are sorted numerically. |
|
|
|
=item HASH(name,key) |
|
|
|
returns the 0th value in the hash 'name' associated with 'key'. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
|
sub HASH { |
|
my ($name,$key,$value)=@_; |
|
my @Keys; |
|
undef @Keys; |
|
my @Values; |
|
# Check to see if we have multiple $key values |
|
if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) { |
|
my $keymask = &mask($key); |
|
# Assume the keys are addresses |
|
my @Temp = grep /$keymask/,keys(%v); |
|
@Keys = $v{@Temp}; |
|
} else { |
|
$Keys[0]= $key; |
|
} |
|
# If $value is empty, return the first value associated |
|
# with the first key. |
|
if (! $value) { |
|
return $hashes{$name}->{$Keys[0]}->[0]; |
|
} |
|
# Check to see if we have multiple $value(s) |
|
if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) { |
|
my $valmask = &mask($value); |
|
my @Temp = grep /$valmask/,keys(%v); |
|
@Values =$v{@Temp}; |
|
} else { |
|
$Values[0]= $value; |
|
} |
|
# Add values to hash |
|
for (my $i = 0; $i<=$#Keys; $i++) { |
|
my $key = $Keys[$i]; |
|
my $value = ($i<=$#Values ? $Values[$i] : $Values[0]); |
|
if (! exists ($hashes{$name}->{$key})) { |
|
$hashes{$name}->{$key}->[0]=$value; |
|
} else { |
|
my @Temp = sort(@{$hashes{$name}->{$key}},$value); |
|
$hashes{$name}->{$key} = \@Temp; |
|
} |
|
} |
|
return $Values[-1]; |
|
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item NUM(range) |
|
|
|
returns the number of items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub NUM { |
sub NUM { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $num= $#{@{grep(/$mask/,keys(%v))}}+1; |
my $num= $#{@{grep(/$mask/,keys(%v))}}+1; |
Line 209 sub BIN {
|
Line 549 sub BIN {
|
} |
} |
|
|
|
|
|
#------------------------------------------------------- |
|
|
|
=item SUM(range) |
|
|
|
returns the sum of items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub SUM { |
sub SUM { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $sum=0; |
my $sum=0; |
Line 218 sub SUM {
|
Line 567 sub SUM {
|
return $sum; |
return $sum; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item MEAN(range) |
|
|
|
compute the average of the items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub MEAN { |
sub MEAN { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $sum=0; my $num=0; |
my $sum=0; my $num=0; |
Line 232 sub MEAN {
|
Line 590 sub MEAN {
|
} |
} |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item STDDEV(range) |
|
|
|
compute the standard deviation of the items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub STDDEV { |
sub STDDEV { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $sum=0; my $num=0; |
my $sum=0; my $num=0; |
Line 248 sub STDDEV {
|
Line 615 sub STDDEV {
|
return sqrt($sum/($num-1)); |
return sqrt($sum/($num-1)); |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item PROD(range) |
|
|
|
compute the product of the items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub PROD { |
sub PROD { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $prod=1; |
my $prod=1; |
Line 257 sub PROD {
|
Line 633 sub PROD {
|
return $prod; |
return $prod; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item MAX(range) |
|
|
|
compute the maximum of the items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub MAX { |
sub MAX { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $max='-'; |
my $max='-'; |
Line 267 sub MAX {
|
Line 652 sub MAX {
|
return $max; |
return $max; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item MIN(range) |
|
|
|
compute the minimum of the items in the range. |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub MIN { |
sub MIN { |
my $mask=mask(@_); |
my $mask=mask(@_); |
my $min='-'; |
my $min='-'; |
Line 277 sub MIN {
|
Line 671 sub MIN {
|
return $min; |
return $min; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item SUMMAX(num,lower,upper) |
|
|
|
compute the sum of the largest 'num' items in the range from |
|
'lower' to 'upper' |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub SUMMAX { |
sub SUMMAX { |
my ($num,$lower,$upper)=@_; |
my ($num,$lower,$upper)=@_; |
my $mask=mask($lower,$upper); |
my $mask=mask($lower,$upper); |
my @inside=(); |
my @inside=(); |
foreach (grep /$mask/,keys(%v)) { |
foreach (grep /$mask/,keys(%v)) { |
$inside[$#inside+1]=$v{$_}; |
push (@inside,$v{$_}); |
} |
} |
@inside=sort(@inside); |
@inside=sort(@inside); |
my $sum=0; my $i; |
my $sum=0; my $i; |
Line 292 sub SUMMAX {
|
Line 696 sub SUMMAX {
|
return $sum; |
return $sum; |
} |
} |
|
|
|
#------------------------------------------------------- |
|
|
|
=item SUMMIN(num,lower,upper) |
|
|
|
compute the sum of the smallest 'num' items in the range from |
|
'lower' to 'upper' |
|
|
|
=cut |
|
|
|
#------------------------------------------------------- |
sub SUMMIN { |
sub SUMMIN { |
my ($num,$lower,$upper)=@_; |
my ($num,$lower,$upper)=@_; |
my $mask=mask($lower,$upper); |
my $mask=mask($lower,$upper); |
Line 339 sub expandnamed {
|
Line 753 sub expandnamed {
|
return 0; |
return 0; |
} |
} |
} else { |
} else { |
return '$c{\''.$expression.'\'}'; |
# it is not a function, so it is a parameter name |
|
# We should do the following: |
|
# 1. Take the list of parameter names |
|
# 2. look through the list for ones that match the parameter we want |
|
# 3. If there are no collisions, return the one that matches |
|
# 4. If there is a collision, return 'bad parameter name error' |
|
my $returnvalue = ''; |
|
my @matches = (); |
|
$#matches = -1; |
|
study $expression; |
|
foreach $parameter (keys(%c)) { |
|
push @matches,$parameter if ($parameter =~ /$expression/); |
|
} |
|
if ($#matches == 0) { |
|
$returnvalue = '$c{\''.$matches[0].'\'}'; |
|
} elsif ($#matches > 0) { |
|
# more than one match. Look for a concise one |
|
$returnvalue = "'non-unique parameter name : $expression'"; |
|
foreach (@matches) { |
|
if (/^$expression$/) { |
|
$returnvalue = '$c{\''.$_.'\'}'; |
|
} |
|
} |
|
} else { |
|
$returnvalue = "'bad parameter name : $expression'"; |
|
} |
|
return $returnvalue; |
} |
} |
} |
} |
|
|
Line 351 sub sett {
|
Line 791 sub sett {
|
} else { |
} else { |
$pattern='[A-Z]'; |
$pattern='[A-Z]'; |
} |
} |
|
|
|
# Deal with the template row |
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if ($_=~/template\_(\w)/) { |
if ($_=~/template\_(\w)/) { |
my $col=$1; |
my $col=$1; |
Line 359 sub sett {
|
Line 801 sub sett {
|
if ($_=~/A(\d+)/) { |
if ($_=~/A(\d+)/) { |
my $trow=$1; |
my $trow=$1; |
if ($trow) { |
if ($trow) { |
|
# Get the name of this cell |
my $lb=$col.$trow; |
my $lb=$col.$trow; |
|
# Grab the template declaration |
$t{$lb}=$f{'template_'.$col}; |
$t{$lb}=$f{'template_'.$col}; |
|
# Replace '#' with the row number |
$t{$lb}=~s/\#/$trow/g; |
$t{$lb}=~s/\#/$trow/g; |
|
# Replace '....' with ',' |
$t{$lb}=~s/\.\.+/\,/g; |
$t{$lb}=~s/\.\.+/\,/g; |
|
# Replace 'A0' with the value from 'A0' |
$t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; |
$t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; |
|
# Replace parameters |
$t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge; |
$t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge; |
} |
} |
} |
} |
Line 371 sub sett {
|
Line 819 sub sett {
|
} |
} |
} |
} |
} |
} |
|
|
|
# Deal with the normal cells |
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if (($f{$_}) && ($_!~/template\_/)) { |
if (($f{$_}) && ($_!~/template\_/)) { |
my $matches=($_=~/^$pattern(\d+)/); |
my $matches=($_=~/^$pattern(\d+)/); |
Line 386 sub sett {
|
Line 836 sub sett {
|
} |
} |
} |
} |
} |
} |
|
# For inserted lines, [B-Z] is also valid |
|
|
|
unless ($sheettype eq 'assesscalc') { |
|
foreach (keys(%f)) { |
|
if ($_=~/[B-Z](\d+)/) { |
|
if ($f{'A'.$1}=~/^[\~\-]/) { |
|
$t{$_}=$f{$_}; |
|
$t{$_}=~s/\.\.+/\,/g; |
|
$t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; |
|
$t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge; |
|
} |
|
} |
|
} |
|
} |
|
|
|
# For some reason 'A0' gets special treatment... This seems superfluous |
|
# but I imagine it is here for a reason. |
$t{'A0'}=$f{'A0'}; |
$t{'A0'}=$f{'A0'}; |
$t{'A0'}=~s/\.\.+/\,/g; |
$t{'A0'}=~s/\.\.+/\,/g; |
$t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; |
$t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; |
Line 393 sub sett {
|
Line 860 sub sett {
|
} |
} |
|
|
sub calc { |
sub calc { |
%v=(); |
undef %v; |
&sett(); |
&sett(); |
my $notfinished=1; |
my $notfinished=1; |
|
my $lastcalc=''; |
my $depth=0; |
my $depth=0; |
while ($notfinished) { |
while ($notfinished) { |
$notfinished=0; |
$notfinished=0; |
foreach (keys(%t)) { |
foreach (keys(%t)) { |
my $old=$v{$_}; |
my $old=$v{$_}; |
$v{$_}=eval($t{$_}); |
$v{$_}=eval $t{$_}; |
if ($@) { |
if ($@) { |
%v=(); |
undef %v; |
return $@; |
return $_.': '.$@; |
} |
} |
if ($v{$_} ne $old) { $notfinished=1; } |
if ($v{$_} ne $old) { $notfinished=1; $lastcalc=$_; } |
} |
} |
$depth++; |
$depth++; |
if ($depth>100) { |
if ($depth>100) { |
%v=(); |
undef %v; |
return 'Maximum calculation depth exceeded'; |
return $lastcalc.': Maximum calculation depth exceeded'; |
} |
} |
} |
} |
return ''; |
return ''; |
Line 436 sub outrowassess {
|
Line 904 sub outrowassess {
|
my @cols=(); |
my @cols=(); |
if ($n) { |
if ($n) { |
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n}); |
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n}); |
$cols[0]=$rl{$usy}.'<br>'. |
if ($rowlabel{$usy}) { |
|
$cols[0]=$rowlabel{$usy}.'<br>'. |
'<select name="sel_'.$n.'" onChange="changesheet('.$n. |
'<select name="sel_'.$n.'" onChange="changesheet('.$n. |
')"><option name="default">Default</option>'; |
')"><option name="default">Default</option>'; |
|
} else { $cols[0]=''; } |
foreach (@os) { |
foreach (@os) { |
$cols[0].='<option name="'.$_.'"'; |
$cols[0].='<option name="'.$_.'"'; |
if ($ufn eq $_) { |
if ($ufn eq $_) { |
Line 456 sub outrowassess {
|
Line 926 sub outrowassess {
|
'n','o','p','q','r','s','t','u','v','w','x','y','z') { |
'n','o','p','q','r','s','t','u','v','w','x','y','z') { |
my $fm=$f{$_.$n}; |
my $fm=$f{$_.$n}; |
$fm=~s/[\'\"]/\&\#34;/g; |
$fm=~s/[\'\"]/\&\#34;/g; |
$cols[$#cols+1]="'$_$n','$fm'".'___eq___'.$v{$_.$n}; |
push(@cols,"'$_$n','$fm'".'___eq___'.$v{$_.$n}); |
} |
} |
return @cols; |
return @cols; |
} |
} |
Line 465 sub outrow {
|
Line 935 sub outrow {
|
my $n=shift; |
my $n=shift; |
my @cols=(); |
my @cols=(); |
if ($n) { |
if ($n) { |
$cols[0]=$rl{$f{'A'.$n}}; |
$cols[0]=$rowlabel{$f{'A'.$n}}; |
} else { |
} else { |
$cols[0]='<b><font size=+1>Export</font></b>'; |
$cols[0]='<b><font size=+1>Export</font></b>'; |
} |
} |
Line 519 sub setothersheets {
|
Line 989 sub setothersheets {
|
# ------------------------------------------------ Add or change formula values |
# ------------------------------------------------ Add or change formula values |
|
|
sub setrowlabels { |
sub setrowlabels { |
my ($safeeval,%rl)=@_; |
my ($safeeval,%rowlabel)=@_; |
%{$safeeval->varglob('rl')}=%rl; |
%{$safeeval->varglob('rowlabel')}=%rowlabel; |
} |
} |
|
|
# ------------------------------------------------------- Calculate spreadsheet |
# ------------------------------------------------------- Calculate spreadsheet |
|
|
sub calcsheet { |
sub calcsheet { |
my $safeeval=shift; |
my $safeeval=shift; |
$safeeval->reval('&calc();'); |
return $safeeval->reval('&calc();'); |
} |
} |
|
|
# ------------------------------------------------------------------ Get values |
# ------------------------------------------------------------------ Get values |
Line 544 sub getformulas {
|
Line 1014 sub getformulas {
|
return %{$safeeval->varglob('f')}; |
return %{$safeeval->varglob('f')}; |
} |
} |
|
|
|
# ----------------------------------------------------- Get value of $f{'A'.$n} |
|
|
|
sub getfa { |
|
my ($safeeval,$n)=@_; |
|
return $safeeval->reval('$f{"A'.$n.'"}'); |
|
} |
|
|
# -------------------------------------------------------------------- Get type |
# -------------------------------------------------------------------- Get type |
|
|
sub gettype { |
sub gettype { |
Line 682 sub rown {
|
Line 1159 sub rown {
|
} |
} |
my $showf=0; |
my $showf=0; |
my $proc; |
my $proc; |
my $maxred; |
my $maxred=1; |
my $sheettype=&gettype($safeeval); |
my $sheettype=&gettype($safeeval); |
if ($sheettype eq 'studentcalc') { |
if ($sheettype eq 'studentcalc') { |
$proc='&outrowassess'; |
$proc='&outrowassess'; |
Line 695 sub rown {
|
Line 1172 sub rown {
|
} else { |
} else { |
$maxred=26; |
$maxred=26; |
} |
} |
|
if (&getfa($safeeval,$n)=~/^[\~\-]/) { $maxred=1; } |
if ($n eq '-') { $proc='&templaterow'; $n=-1; $dataflag=1; } |
if ($n eq '-') { $proc='&templaterow'; $n=-1; $dataflag=1; } |
foreach ($safeeval->reval($proc.'('.$n.')')) { |
foreach ($safeeval->reval($proc.'('.$n.')')) { |
my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD'); |
my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD'); |
Line 753 sub outsheet {
|
Line 1231 sub outsheet {
|
'><b><font size=+1>Import</font></b></td>'. |
'><b><font size=+1>Import</font></b></td>'. |
'<td colspan='.$maxyellow. |
'<td colspan='.$maxyellow. |
'><b><font size=+1>Calculations</font></b></td></tr><tr>'; |
'><b><font size=+1>Calculations</font></b></td></tr><tr>'; |
my $showf=0; |
my $showf=0; |
foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', |
foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', |
'a','b','c','d','e','f','g','h','i','j','k','l','m', |
'a','b','c','d','e','f','g','h','i','j','k','l','m', |
'n','o','p','q','r','s','t','u','v','w','x','y','z') { |
'n','o','p','q','r','s','t','u','v','w','x','y','z') { |
$showf++; |
$showf++; |
if ($showf<=$maxred) { |
if ($showf<=$maxred) { |
$tabledata.='<td bgcolor="#FFDDDD">'; |
$tabledata.='<td bgcolor="#FFDDDD">'; |
} else { |
} else { |
$tabledata.='<td>'; |
$tabledata.='<td>'; |
} |
} |
$tabledata.="<b><font size=+1>$_</font></b></td>"; |
$tabledata.="<b><font size=+1>$_</font></b></td>"; |
} |
} |
$tabledata.='</tr>'.&rown($safeeval,'-').&rown($safeeval,0); |
$tabledata.='</tr>'.&rown($safeeval,'-').&rown($safeeval,0); |
} else { $tabledata='<pre>'; } |
} else { $tabledata='<pre>'; } |
|
|
$r->print($tabledata); |
$r->print($tabledata); |
Line 781 sub outsheet {
|
Line 1259 sub outsheet {
|
$sortidx[$row-1]=$row-1; |
$sortidx[$row-1]=$row-1; |
} |
} |
@sortidx=sort { $sortby[$a] cmp $sortby[$b]; } @sortidx; |
@sortidx=sort { $sortby[$a] cmp $sortby[$b]; } @sortidx; |
|
|
my $what='Student'; |
my $what='Student'; |
if (&gettype($safeeval) eq 'assesscalc') { |
if (&gettype($safeeval) eq 'assesscalc') { |
$what='Item'; |
$what='Item'; |
Line 791 sub outsheet {
|
Line 1268 sub outsheet {
|
|
|
my $n=0; |
my $n=0; |
for ($row=0;$row<$maxrow;$row++) { |
for ($row=0;$row<$maxrow;$row++) { |
my $thisrow=&rown($safeeval,$sortidx[$row]+1); |
my $thisrow=&rown($safeeval,$sortidx[$row]+1); |
if ($thisrow) { |
if ($thisrow) { |
if (($n/25==int($n/25)) && (!$ENV{'form.showcsv'})) { |
if (($n/25==int($n/25)) && (!$ENV{'form.showcsv'})) { |
$r->print("</table>\n<br>\n"); |
$r->print("</table>\n<br>\n"); |
$r->rflush(); |
$r->rflush(); |
$r->print('<table border=2><tr><td> <td>'.$what.'</td>'); |
$r->print('<table border=2><tr><td> <td>'.$what.'</td>'); |
foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', |
$r->print('<td>'.join('</td><td>', |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', |
(split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. |
'a','b','c','d','e','f','g','h','i','j','k','l','m', |
'abcdefghijklmnopqrstuvwxyz'))). |
'n','o','p','q','r','s','t','u','v','w','x','y','z') { |
"</td></tr>\n"); |
$r->print('<td>'.$_.'</td>'); |
} |
|
$n++; |
|
$r->print($thisrow); |
} |
} |
$r->print('</tr>'); |
|
} |
|
$n++; |
|
$r->print($thisrow); |
|
} |
|
} |
} |
$r->print($ENV{'form.showcsv'}?'</pre>':'</table>'); |
$r->print($ENV{'form.showcsv'}?'</pre>':'</table>'); |
} |
} |
Line 815 sub outsheet {
|
Line 1289 sub outsheet {
|
# |
# |
# ----------------------------------------------- Read list of available sheets |
# ----------------------------------------------- Read list of available sheets |
# |
# |
|
|
sub othersheets { |
sub othersheets { |
my ($safeeval,$stype)=@_; |
my ($safeeval,$stype)=@_; |
|
# |
my $cnum=&getcnum($safeeval); |
my $cnum=&getcnum($safeeval); |
my $cdom=&getcdom($safeeval); |
my $cdom=&getcdom($safeeval); |
my $chome=&getchome($safeeval); |
my $chome=&getchome($safeeval); |
|
# |
my @alternatives=(); |
my @alternatives=(); |
my $result=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.':'. |
my %results=&Apache::lonnet::dump($stype.'_spreadsheets',$cdom,$cnum); |
$stype.'_spreadsheets',$chome); |
my ($tmp) = keys(%results); |
if ($result!~/^error\:/) { |
unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { |
foreach (split(/\&/,$result)) { |
@alternatives = sort (keys(%results)); |
$alternatives[$#alternatives+1]= |
} |
&Apache::lonnet::unescape((split(/\=/,$_))[0]); |
|
} |
|
} |
|
return @alternatives; |
return @alternatives; |
} |
} |
|
|
|
|
|
# |
|
# -------------------------------------- Parse a spreadsheet |
|
# |
|
sub parse_sheet { |
|
# $sheetxml is a scalar reference or a scalar |
|
my ($sheetxml) = @_; |
|
if (! ref($sheetxml)) { |
|
my $tmp = $sheetxml; |
|
$sheetxml = \$tmp; |
|
} |
|
my %f; |
|
my $parser=HTML::TokeParser->new($sheetxml); |
|
my $token; |
|
while ($token=$parser->get_token) { |
|
if ($token->[0] eq 'S') { |
|
if ($token->[1] eq 'field') { |
|
$f{$token->[2]->{'col'}.$token->[2]->{'row'}}= |
|
$parser->get_text('/field'); |
|
} |
|
if ($token->[1] eq 'template') { |
|
$f{'template_'.$token->[2]->{'col'}}= |
|
$parser->get_text('/template'); |
|
} |
|
} |
|
} |
|
return \%f; |
|
} |
|
|
# |
# |
# -------------------------------------- Read spreadsheet formulas for a course |
# -------------------------------------- Read spreadsheet formulas for a course |
# |
# |
Line 846 sub readsheet {
|
Line 1345 sub readsheet {
|
my $cdom=&getcdom($safeeval); |
my $cdom=&getcdom($safeeval); |
my $chome=&getchome($safeeval); |
my $chome=&getchome($safeeval); |
|
|
# --------- There is no filename. Look for defaults in course and global, cache |
if (! defined($fn)) { |
|
# There is no filename. Look for defaults in course and global, cache |
unless($fn) { |
|
unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) { |
unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) { |
$fn=&Apache::lonnet::reply('get:'.$cdom.':'.$cnum. |
my %tmphash = &Apache::lonnet::get('environment', |
':environment:spreadsheet_default_'.$stype, |
['spreadsheet_default_'.$stype], |
$chome); |
$cdom,$cnum); |
unless (($fn) && ($fn!~/^error\:/)) { |
my ($tmp) = keys(%tmphash); |
$fn='default_'.$stype; |
if ($tmp =~ /^(con_lost|error|no_such_host)/i) { |
} |
$fn = 'default_'.$stype; |
$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn; |
} else { |
|
$fn = $tmphash{'spreadsheet_default_'.$stype}; |
|
} |
|
unless (($fn) && ($fn!~/^error\:/)) { |
|
$fn='default_'.$stype; |
|
} |
|
$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn; |
} |
} |
} |
} |
|
|
Line 875 sub readsheet {
|
Line 1379 sub readsheet {
|
my %f=(); |
my %f=(); |
|
|
if ($fn=~/^default\_/) { |
if ($fn=~/^default\_/) { |
my $sheetxml=''; |
my $sheetxml=''; |
{ |
|
my $fh; |
my $fh; |
my $dfn=$fn; |
my $dfn=$fn; |
$dfn=~s/\_/\./g; |
$dfn=~s/\_/\./g; |
if ($fh=Apache::File->new($includedir.'/'.$dfn)) { |
if ($fh=Apache::File->new($includedir.'/'.$dfn)) { |
$sheetxml=join('',<$fh>); |
$sheetxml=join('',<$fh>); |
} else { |
} else { |
$sheetxml='<field row="0" col="A">"Error"</field>'; |
$sheetxml='<field row="0" col="A">"Error"</field>'; |
} |
} |
} |
%f=%{&parse_sheet(\$sheetxml)}; |
my $parser=HTML::TokeParser->new(\$sheetxml); |
} elsif($fn=~/\/*\.spreadsheet$/) { |
my $token; |
my $sheetxml=&Apache::lonnet::getfile |
while ($token=$parser->get_token) { |
(&Apache::lonnet::filelocation('',$fn)); |
if ($token->[0] eq 'S') { |
if ($sheetxml == -1) { |
if ($token->[1] eq 'field') { |
$sheetxml='<field row="0" col="A">"Error loading spreadsheet ' |
$f{$token->[2]->{'col'}.$token->[2]->{'row'}}= |
.$fn.'"</field>'; |
$parser->get_text('/field'); |
} |
} |
%f=%{&parse_sheet(\$sheetxml)}; |
if ($token->[1] eq 'template') { |
} else { |
$f{'template_'.$token->[2]->{'col'}}= |
my $sheet=''; |
$parser->get_text('/template'); |
my %tmphash = &Apache::lonnet::dump($fn,$cdom,$cnum); |
|
my ($tmp) = keys(%tmphash); |
|
unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { |
|
foreach (keys(%tmphash)) { |
|
$f{$_}=$tmphash{$_}; |
} |
} |
} |
} |
} |
} |
} else { |
|
my $sheet=''; |
|
my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.':'.$fn, |
|
$chome); |
|
unless ($reply=~/^error\:/) { |
|
$sheet=$reply; |
|
} |
|
foreach (split(/\&/,$sheet)) { |
|
my ($name,$value)=split(/\=/,$_); |
|
$f{&Apache::lonnet::unescape($name)}= |
|
&Apache::lonnet::unescape($value); |
|
} |
|
} |
|
# --------------------------------------------------------------- Cache and set |
# --------------------------------------------------------------- Cache and set |
$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f); |
$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f); |
&setformulas($safeeval,%f); |
&setformulas($safeeval,%f); |
Line 1019 sub tmpread {
|
Line 1513 sub tmpread {
|
$fn=$tmpdir.$fn.'.tmp'; |
$fn=$tmpdir.$fn.'.tmp'; |
my $fh; |
my $fh; |
my %fo=(); |
my %fo=(); |
|
my $countrows=0; |
if ($fh=Apache::File->new($fn)) { |
if ($fh=Apache::File->new($fn)) { |
my $name; |
my $name; |
while ($name=<$fh>) { |
while ($name=<$fh>) { |
Line 1026 sub tmpread {
|
Line 1521 sub tmpread {
|
my $value=<$fh>; |
my $value=<$fh>; |
chomp($value); |
chomp($value); |
$fo{$name}=$value; |
$fo{$name}=$value; |
|
if ($name=~/^A(\d+)$/) { |
|
if ($1>$countrows) { |
|
$countrows=$1; |
|
} |
|
} |
} |
} |
} |
} |
if ($nform eq 'changesheet') { |
if ($nform eq 'changesheet') { |
Line 1033 sub tmpread {
|
Line 1533 sub tmpread {
|
unless ($ENV{'form.sel_'.$nfield} eq 'Default') { |
unless ($ENV{'form.sel_'.$nfield} eq 'Default') { |
$fo{'A'.$nfield}.='__&&&__'.$ENV{'form.sel_'.$nfield}; |
$fo{'A'.$nfield}.='__&&&__'.$ENV{'form.sel_'.$nfield}; |
} |
} |
|
} elsif ($nfield eq 'insertrow') { |
|
$countrows++; |
|
my $newrow=substr('000000'.$countrows,-7); |
|
if ($nform eq 'top') { |
|
$fo{'A'.$countrows}='--- '.$newrow; |
|
} else { |
|
$fo{'A'.$countrows}='~~~ '.$newrow; |
|
} |
} else { |
} else { |
if ($nfield) { $fo{$nfield}=$nform; } |
if ($nfield) { $fo{$nfield}=$nform; } |
} |
} |
Line 1135 sub updateclasssheet {
|
Line 1643 sub updateclasssheet {
|
my $cdom=&getcdom($safeeval); |
my $cdom=&getcdom($safeeval); |
my $cid=&getcid($safeeval); |
my $cid=&getcid($safeeval); |
my $chome=&getchome($safeeval); |
my $chome=&getchome($safeeval); |
|
# |
# ---------------------------------------------- Read class list and row labels |
# Read class list and row labels |
|
my %classlist; |
my $classlst=&Apache::lonnet::reply |
my @tmp = &Apache::lonnet::dump('classlist',$cdom,$cnum); |
('dump:'.$cdom.':'.$cnum.':classlist',$chome); |
if ($tmp[0] !~ /^error/) { |
|
%classlist = @tmp; |
|
} else { |
|
return 'Could not access course data'; |
|
} |
|
undef @tmp; |
|
# |
my %currentlist=(); |
my %currentlist=(); |
my $now=time; |
my $now=time; |
unless ($classlst=~/^error\:/) { |
foreach my $student (keys(%classlist)) { |
foreach (split(/\&/,$classlst)) { |
my ($end,$start)=split(/\:/,$classlist{$student}); |
my ($name,$value)=split(/\=/,$_); |
my $active=1; |
my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value)); |
$active = 0 if (($end) && ($now>$end)); |
my $active=1; |
$active = 1 if ($ENV{'form.Status'} eq 'Any'); |
if (($end) && ($now>$end)) { $active=0; } |
$active = !$active if ($ENV{'form.Status'} eq 'Expired'); |
if ($active) { |
if ($active) { |
my $rowlabel=''; |
my $rowlabel=''; |
$name=&Apache::lonnet::unescape($name); |
my ($studentName,$studentDomain)=split(/\:/,$student); |
my ($sname,$sdom)=split(/\:/,$name); |
my $studentSection=&Apache::lonnet::usection($studentDomain, |
my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid); |
$studentName,$cid); |
if ($ssec==-1) { |
if ($studentSection==-1) { |
unless ($ENV{'form.showcsv'}) { |
unless ($ENV{'form.showcsv'}) { |
$rowlabel='<font color=red>Data not available: '.$name. |
$rowlabel='<font color=red>Data not available: '. |
'</font>'; |
$studentName.'</font>'; |
} else { |
|
$rowlabel='ERROR","'.$name. |
|
'","Data not available","","","'; |
|
} |
|
} else { |
} else { |
my %reply=&Apache::lonnet::idrget($sdom,$sname); |
$rowlabel='ERROR","'.$studentName. |
my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname. |
'","Data not available","","","'; |
':environment:firstname&middlename&lastname&generation', |
} |
&Apache::lonnet::homeserver($sname,$sdom)); |
} else { |
unless ($ENV{'form.showcsv'}) { |
my %reply=&Apache::lonnet::idrget($studentDomain,$studentName); |
$rowlabel='<a href="/adm/studentcalc?uname='.$sname. |
my %studentInformation=&Apache::lonnet::get |
'&udom='.$sdom.'">'. |
('environment', |
$ssec.' '.$reply{$sname}.'<br>'; |
['lastname','generation','firstname','middlename','id'], |
foreach ( split(/\&/,$reply)) { |
$studentDomain,$studentName); |
$rowlabel.=&Apache::lonnet::unescape($_).' '; |
if (! $ENV{'form.showcsv'}) { |
|
$rowlabel='<a href="/adm/studentcalc?uname='.$studentName. |
|
'&udom='.$studentDomain.'">'. |
|
$studentSection.' '; |
|
foreach ('id','firstname','middlename', |
|
'lastname','generation'){ |
|
$rowlabel.=$studentInformation{$_}." "; |
} |
} |
$rowlabel.='</a>'; |
$rowlabel.='</a>'; |
} else { |
} else { |
$rowlabel=$ssec.'","'.$reply{$sname}.'"'; |
$rowlabel= '"'.join('","', |
my $ncount=0; |
($studentSection, |
foreach (split(/\&/,$reply)) { |
$studentInformation{'id'}, |
$rowlabel.=',"'.&Apache::lonnet::unescape($_).'"'; |
$studentInformation{'firstname'}, |
$ncount++; |
$studentInformation{'middlename'}, |
} |
$studentInformation{'lastname'}, |
unless ($ncount==4) { $rowlabel.=',""'; } |
$studentInformation{'generation'}) |
$rowlabel=~s/\"$//; |
).'"'; |
} |
|
} |
} |
$currentlist{&Apache::lonnet::unescape($name)}=$rowlabel; |
|
} |
} |
} # end of foreach (split(/\&/,$classlst)) |
$currentlist{$student}=$rowlabel; |
# |
} # end of if ($active) |
# -------------------- Find discrepancies between the course row table and this |
} # end of foreach my $student (keys(%classlist)) |
# |
# |
my %f=&getformulas($safeeval); |
# Find discrepancies between the course row table and this |
my $changed=0; |
# |
|
my %f=&getformulas($safeeval); |
my $maxrow=0; |
my $changed=0; |
my %existing=(); |
# |
|
my $maxrow=0; |
# ----------------------------------------------------------- Now obsolete rows |
my %existing=(); |
foreach (keys(%f)) { |
# |
if ($_=~/^A(\d+)/) { |
# Now obsolete rows |
$maxrow=($1>$maxrow)?$1:$maxrow; |
foreach (keys(%f)) { |
$existing{$f{$_}}=1; |
if ($_=~/^A(\d+)/) { |
unless ((defined($currentlist{$f{$_}})) || (!$1)) { |
$maxrow=($1>$maxrow)?$1:$maxrow; |
$f{$_}='!!! Obsolete'; |
$existing{$f{$_}}=1; |
$changed=1; |
unless ((defined($currentlist{$f{$_}})) || (!$1) || |
} |
($f{$_}=~/^(\~\~\~|\-\-\-)/)) { |
|
$f{$_}='!!! Obsolete'; |
|
$changed=1; |
} |
} |
} |
} |
|
} |
# -------------------------------------------------------- New and unknown keys |
# |
|
# New and unknown keys |
foreach (sort keys(%currentlist)) { |
foreach (sort keys(%currentlist)) { |
unless ($existing{$_}) { |
unless ($existing{$_}) { |
$changed=1; |
$changed=1; |
$maxrow++; |
$maxrow++; |
$f{'A'.$maxrow}=$_; |
$f{'A'.$maxrow}=$_; |
} |
|
} |
} |
|
|
if ($changed) { &setformulas($safeeval,%f); } |
|
|
|
&setmaxrow($safeeval,$maxrow); |
|
&setrowlabels($safeeval,%currentlist); |
|
|
|
} else { |
|
return 'Could not access course data'; |
|
} |
} |
|
if ($changed) { &setformulas($safeeval,%f); } |
|
# |
|
&setmaxrow($safeeval,$maxrow); |
|
&setrowlabels($safeeval,%currentlist); |
} |
} |
|
|
# ----------------------------------- Update rows for student and assess sheets |
# ----------------------------------- Update rows for student and assess sheets |
Line 1239 sub updatestudentassesssheet {
|
Line 1750 sub updatestudentassesssheet {
|
unless ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) { |
unless ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) { |
# -------------------------------------------------------------------- Tie hash |
# -------------------------------------------------------------------- Tie hash |
if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db', |
if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db', |
&GDBM_READER,0640)) { |
&GDBM_READER(),0640)) { |
# --------------------------------------------------------- Get all assessments |
# --------------------------------------------------------- Get all assessments |
|
|
my %allkeys=('timestamp' => |
my %allkeys=('timestamp' => |
Line 1341 sub updatestudentassesssheet {
|
Line 1852 sub updatestudentassesssheet {
|
$maxrow=($1>$maxrow)?$1:$maxrow; |
$maxrow=($1>$maxrow)?$1:$maxrow; |
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_}); |
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_}); |
$existing{$usy}=1; |
$existing{$usy}=1; |
unless ((defined($current{$usy})) || (!$1)) { |
unless ((defined($current{$usy})) || (!$1) || |
$f{$_}='!!! Obsolete'; |
($f{$_}=~/^(\~\~\~|\-\-\-)/)){ |
|
$f{$_}='!!! Obsolete'; |
$changed=1; |
$changed=1; |
} elsif ($ufn) { |
} elsif ($ufn) { |
$current{$usy} |
$current{$usy} |
Line 1377 sub loadstudent {
|
Line 1889 sub loadstudent {
|
my %c=(); |
my %c=(); |
my %f=&getformulas($safeeval); |
my %f=&getformulas($safeeval); |
$cachedassess=&getuname($safeeval).':'.&getudom($safeeval); |
$cachedassess=&getuname($safeeval).':'.&getudom($safeeval); |
%cachedstores=(); |
# Get ALL the student preformance data |
{ |
my @tmp = &Apache::lonnet::dump(&getcid($safeeval), |
my $reply=&Apache::lonnet::reply('dump:'.&getudom($safeeval).':'. |
&getudom($safeeval), |
&getuname($safeeval).':'. |
&getuname($safeeval), |
&getcid($safeeval), |
undef); |
&getuhome($safeeval)); |
if ($tmp[0] !~ /^error:/) { |
unless ($reply=~/^error\:/) { |
%cachedstores = @tmp; |
foreach ( split(/\&/,$reply)) { |
|
my ($name,$value)=split(/\=/,$_); |
|
$cachedstores{&Apache::lonnet::unescape($name)}= |
|
&Apache::lonnet::unescape($value); |
|
} |
|
} |
|
} |
} |
|
undef @tmp; |
|
# |
my @assessdata=(); |
my @assessdata=(); |
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if ($_=~/^A(\d+)/) { |
if ($_=~/^A(\d+)/) { |
my $row=$1; |
my $row=$1; |
unless (($f{$_}=~/^\!/) || ($row==0)) { |
unless (($f{$_}=~/^[\!\~\-]/) || ($row==0)) { |
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_}); |
my ($usy,$ufn)=split(/__&&&\__/,$f{$_}); |
@assessdata=&exportsheet(&getuname($safeeval), |
@assessdata=&exportsheet(&getuname($safeeval), |
&getudom($safeeval), |
&getudom($safeeval), |
'assesscalc',$usy,$ufn); |
'assesscalc',$usy,$ufn); |
Line 1434 sub loadcourse {
|
Line 1942 sub loadcourse {
|
my $total=0; |
my $total=0; |
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if ($_=~/^A(\d+)/) { |
if ($_=~/^A(\d+)/) { |
unless ($f{$_}=~/^\!/) { $total++; } |
unless ($f{$_}=~/^[\!\~\-]/) { $total++; } |
} |
} |
} |
} |
my $now=0; |
my $now=0; |
Line 1454 ENDPOP
|
Line 1962 ENDPOP
|
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if ($_=~/^A(\d+)/) { |
if ($_=~/^A(\d+)/) { |
my $row=$1; |
my $row=$1; |
unless (($f{$_}=~/^\!/) || ($row==0)) { |
unless (($f{$_}=~/^[\!\~\-]/) || ($row==0)) { |
my @studentdata=&exportsheet(split(/\:/,$f{$_}), |
my @studentdata=&exportsheet(split(/\:/,$f{$_}), |
'studentcalc'); |
'studentcalc'); |
undef %userrdatas; |
undef %userrdatas; |
Line 1465 ENDPOP
|
Line 1973 ENDPOP
|
$r->rflush(); |
$r->rflush(); |
|
|
my $index=0; |
my $index=0; |
foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', |
foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z') { |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z') { |
if ($studentdata[$index]) { |
if ($studentdata[$index]) { |
my $col=$_; |
my $col=$_; |
if ($studentdata[$index]=~/\D/) { |
if ($studentdata[$index]=~/\D/) { |
$c{$col.$row}="'".$studentdata[$index]."'"; |
$c{$col.$row}="'".$studentdata[$index]."'"; |
} else { |
} else { |
$c{$col.$row}=$studentdata[$index]; |
$c{$col.$row}=$studentdata[$index]; |
} |
} |
unless ($col eq 'A') { |
unless ($col eq 'A') { |
$f{$col.$row}='import'; |
$f{$col.$row}='import'; |
} |
} |
} |
} |
$index++; |
$index++; |
} |
} |
Line 1614 sub loadassessment {
|
Line 2122 sub loadassessment {
|
my %c=(); |
my %c=(); |
|
|
if (tie(%parmhash,'GDBM_File', |
if (tie(%parmhash,'GDBM_File', |
&getcfn($safeeval).'_parms.db',&GDBM_READER,0640)) { |
&getcfn($safeeval).'_parms.db',&GDBM_READER(),0640)) { |
my %f=&getformulas($safeeval); |
my %f=&getformulas($safeeval); |
foreach (keys(%f)) { |
foreach (keys(%f)) { |
if ($_=~/^A/) { |
if ($_=~/^A/) { |
unless ($f{$_}=~/^\!/) { |
unless ($f{$_}=~/^[\!\~\-]/) { |
if ($f{$_}=~/^parameter/) { |
if ($f{$_}=~/^parameter/) { |
if ($thisassess{$f{$_}}) { |
if ($thisassess{$f{$_}}) { |
my $val=&parmval($f{$_},$safeeval); |
my $val=&parmval($f{$_},$safeeval); |
Line 1953 $tmpdir=$r->dir_config('lonDaemons').'/t
|
Line 2461 $tmpdir=$r->dir_config('lonDaemons').'/t
|
|
|
# --------------------------- Get query string for limited number of parameters |
# --------------------------- Get query string for limited number of parameters |
|
|
foreach (split(/&/,$ENV{'QUERY_STRING'})) { |
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, |
my ($name, $value) = split(/=/,$_); |
['uname','udom','usymb','ufn']); |
$value =~ tr/+/ /; |
|
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; |
|
if (($name eq 'uname') || ($name eq 'udom') || |
|
($name eq 'usymb') || ($name eq 'ufn')) { |
|
unless ($ENV{'form.'.$name}) { |
|
$ENV{'form.'.$name}=$value; |
|
} |
|
} |
|
} |
|
|
|
if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) { |
if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) { |
$ENV{'form.ufn'}='default_'.$1; |
$ENV{'form.ufn'}='default_'.$1; |
Line 2001 $tmpdir=$r->dir_config('lonDaemons').'/t
|
Line 2500 $tmpdir=$r->dir_config('lonDaemons').'/t
|
|
|
function celledit(cn,cf) { |
function celledit(cn,cf) { |
var cnf=prompt(cn,cf); |
var cnf=prompt(cn,cf); |
if (cnf!=null) { |
if (cnf!=null) { |
document.sheet.unewfield.value=cn; |
document.sheet.unewfield.value=cn; |
document.sheet.unewformula.value=cnf; |
document.sheet.unewformula.value=cnf; |
document.sheet.submit(); |
document.sheet.submit(); |
} |
} |
Line 2014 $tmpdir=$r->dir_config('lonDaemons').'/t
|
Line 2513 $tmpdir=$r->dir_config('lonDaemons').'/t
|
document.sheet.submit(); |
document.sheet.submit(); |
} |
} |
|
|
|
function insertrow(cn) { |
|
document.sheet.unewfield.value='insertrow'; |
|
document.sheet.unewformula.value=cn; |
|
document.sheet.submit(); |
|
} |
|
|
</script> |
</script> |
ENDSCRIPT |
ENDSCRIPT |
$r->print('</head><body bgcolor="#FFFFFF">'. |
$r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet'). |
'<img align=right src=/adm/lonIcons/lonlogos.gif>'. |
|
'<h1>LON-CAPA Spreadsheet</h1>'. |
|
'<form action="'.$r->uri.'" name=sheet method=post>'. |
'<form action="'.$r->uri.'" name=sheet method=post>'. |
&hiddenfield('uname',$ENV{'form.uname'}). |
&hiddenfield('uname',$ENV{'form.uname'}). |
&hiddenfield('udom',$ENV{'form.udom'}). |
&hiddenfield('udom',$ENV{'form.udom'}). |
Line 2082 ENDSCRIPT
|
Line 2585 ENDSCRIPT
|
} |
} |
} |
} |
|
|
# ---------------------------------------------------------------- Course title |
|
|
|
$r->print('<h1>'. |
|
$ENV{'course.'.$ENV{'request.course.id'}.'.description'}. |
|
'</h1><h3>'.localtime().'</h3>'); |
|
|
|
# ---------------------------------------------------- See if user can see this |
# ---------------------------------------------------- See if user can see this |
|
|
if ((&gettype($asheet) eq 'classcalc') || |
if ((&gettype($asheet) eq 'classcalc') || |
Line 2230 ENDSCRIPT
|
Line 2727 ENDSCRIPT
|
} |
} |
} |
} |
$r->print('>'); |
$r->print('>'); |
|
|
if (&gettype($asheet) eq 'classcalc') { |
if (&gettype($asheet) eq 'classcalc') { |
$r->print( |
$r->print( |
' Output CSV format: <input type=checkbox name=showcsv onClick="submit()"'); |
' Output CSV format: <input type=checkbox name=showcsv onClick="submit()"'); |
if ($ENV{'form.showcsv'}) { $r->print(' checked'); } |
if ($ENV{'form.showcsv'}) { $r->print(' checked'); } |
$r->print('>'); |
$r->print('>'); |
} |
} |
|
|
|
# ------------------------------------------------------------------ Insertrows |
|
$r->print(' Student Status: '. |
|
&Apache::lonhtmlcommon::StatusOptions |
|
($ENV{'form.Status'},'sheet')); |
|
|
|
$r->print(<<ENDINSERTBUTTONS); |
|
<br> |
|
<input type='button' onClick='insertrow("top");' |
|
value='Insert Row Top'> |
|
<input type='button' onClick='insertrow("bottom");' |
|
value='Insert Row Bottom'><br> |
|
ENDINSERTBUTTONS |
|
|
# ------------------------------------------------------------- Print out sheet |
# ------------------------------------------------------------- Print out sheet |
|
|
&outsheet($r,$asheet); |
&outsheet($r,$asheet); |