--- loncom/interface/domainprefs.pm 2008/05/01 00:01:16 1.47
+++ loncom/interface/domainprefs.pm 2008/05/07 23:01:50 1.48
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.47 2008/05/01 00:01:16 raeburn Exp $
+# $Id: domainprefs.pm,v 1.48 2008/05/07 23:01:50 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -37,7 +37,7 @@ use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::lonlocal;
use Apache::lonmsg();
-use LONCAPA();
+use LONCAPA;
use LONCAPA::Enrollment;
use File::Copy;
use Locale::Language;
@@ -70,11 +70,12 @@ sub handler {
my %domconfig =
&Apache::lonnet::get_dom('configuration',['login','rolecolors',
'quotas','autoenroll','autoupdate','directorysrch',
- 'usercreation','usermodification','contacts','defaults','scantron'],
- $dom);
+ 'usercreation','usermodification','contacts','defaults',
+ 'scantron','coursecategories'],$dom);
my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
'autoupdate','directorysrch','contacts',
- 'usercreation','usermodification','scantron');
+ 'usercreation','usermodification','scantron',
+ 'coursecategories');
my %prefs = (
'rolecolors' =>
{ text => 'Default color schemes',
@@ -158,6 +159,13 @@ sub handler {
col2 => '',
}],
},
+ 'coursecategories' =>
+ { text => 'Cataloging of courses',
+ help => 'Domain_Course_Catalog',
+ header => [ {col1 => 'Categories',
+ col2 => '',
+ }],
+ }
);
my @roles = ('student','coordinator','author','admin');
my @actions = &Apache::loncommon::get_env_multiple('form.actions');
@@ -316,9 +324,9 @@ sub handler {
$r->print('
'.
&mt('Display options').'
'."\n".
''.&mt('Display using: ')."\n".
- ' '.
- ''.
+ '
');
$r->print(&print_footer($r,$phase,'display','Go'));
$r->print('');
@@ -352,7 +360,9 @@ sub process_changes {
} elsif ($action eq 'defaults') {
$output = &modify_defaults($dom,$r);
} elsif ($action eq 'scantron') {
- $output = &modify_scantron($r,$dom,$confname,\%domconfig);
+ $output = &modify_scantron($r,$dom,$confname,%domconfig);
+ } elsif ($action eq 'coursecategories') {
+ $output = &modify_coursecategories($dom,%domconfig);
}
return $output;
}
@@ -460,10 +470,11 @@ sub print_config_box {
$output .= '
'.$item->{'header'}->[0]->{'col1'}.' | ';
}
+ my $colspan = ($action eq 'coursecategories')?' colspan="2"':'';
$output .= '
- '.$item->{'header'}->[0]->{'col2'}.' |
+ '.$item->{'header'}->[0]->{'col2'}.' |
';
- $rowtotal ++;
+ $rowtotal ++;
if ($action eq 'login') {
$output .= &print_login($dom,$confname,$phase,$settings,\$rowtotal);
} elsif ($action eq 'quotas') {
@@ -478,6 +489,8 @@ sub print_config_box {
$output .= &print_defaults($dom,\$rowtotal);
} elsif ($action eq 'scantron') {
$output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
+ } elsif ($action eq 'coursecategories'){
+ $output .= &print_coursecategories($dom,$item,$settings,\$rowtotal);
}
}
$output .= '
@@ -498,7 +511,7 @@ function changePage(formname,newphase) {
numchecked = 0;
if (formname == document.pickactions) {
if (formname.actions.length > 0) {
- for (var i = 0; i 'None',
);
return %lt;
-}
+}
sub authtype_names {
my %lt = &Apache::lonlocal::texthash(
@@ -1922,6 +1935,208 @@ sub legacy_scantronformat {
return ($url,$error);
}
+sub print_coursecategories {
+ my ($dom,$item,$settings,$rowtotal) = @_;
+ my ($datatable,$css_class);
+ my $itemcount = 1;
+ # FIXME Need to add javascrpt to update other select boxes when one is changed.
+ if (ref($settings) eq 'HASH') {
+ my (@cats,@trails,%allitems);
+ &extract_categories($settings,\@cats,\@trails,\%allitems);
+ my $maxdepth = scalar(@cats);
+ my $colattrib = '';
+ if ($maxdepth > 2) {
+ $colattrib = ' colspan="2" ';
+ }
+ my @path;
+ if (@cats > 0) {
+ if (ref($cats[0]) eq 'ARRAY') {
+ my $numtop = @{$cats[0]};
+ my $maxnum = $numtop;
+ if ((!grep(/^instcode$/,@{$cats[0]})) || ($settings->{'instcode::0'} eq '')) {
+ $maxnum ++;
+ }
+ for (my $i=0; $i<$numtop; $i++) {
+ my $parent = $cats[0][$i];
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $item = &escape($parent).'::0';
+ $datatable .= ''
+ .' | ';
+ if ($parent eq 'instcode') {
+ $datatable .= ''.&mt('Official courses')
+ .' ('
+ .&mt('with institutional codes').') | '
+ .' '
+ .' | ';
+ } else {
+ $datatable .= $parent
+ .' ';
+ }
+ my $depth = 1;
+ push(@path,$parent);
+ $datatable .= &build_category_rows($itemcount,\@cats,$depth,$parent,\@path);
+ pop(@path);
+ $datatable .= '
|
';
+ $itemcount ++;
+ }
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= ' | '.&mt('New:').' '
+ .' | '
+ .'
'."\n";
+ $itemcount ++;
+ if ((!grep(/^instcode$/,@{$cats[0]})) || ($settings->{'instcode::0'} eq '')) {
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= ' |
'.
+ ' | '
+ .&mt('Official courses').''.' ('
+ .&mt('with institutional codes').') | '
+ .' '
+ .' |
';
+ }
+ }
+ } else {
+ $datatable .= &initialize_categories($itemcount);
+ }
+ } else {
+ $datatable .= ''.$item->{'header'}->[0]->{'col2'}.' | '
+ .&initialize_categories($itemcount);
+ }
+ $$rowtotal += $itemcount;
+ return $datatable;
+}
+
+sub initialize_categories {
+ my ($itemcount) = @_;
+ my $datatable;
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable = ''
+ .' '
+ .&mt('Official courses (with institutional codes)')
+ .' | '
+ .' |
';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= ''
+ .' '
+ .&mt('Add category').' | '.&mt('Name:')
+ .' |
';
+ return $datatable;
+}
+
+sub build_category_rows {
+ my ($itemcount,$cats,$depth,$parent,$path) = @_;
+ my ($text,$name,$item);
+ if (ref($cats) eq 'ARRAY') {
+ my $maxdepth = scalar(@{$cats});
+ if (ref($cats->[$depth]) eq 'HASH') {
+ if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
+ my $numchildren = @{$cats->[$depth]{$parent}};
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $text .= ' | ';
+ } else {
+ my $higher = $depth-1;
+ if ($higher == 0) {
+ $name = &escape($parent).'::'.$higher;
+ } else {
+ if (ref($path) eq 'ARRAY') {
+ $name = &escape($parent).':'.&escape($path->[-2]).':'.$higher;
+ }
+ }
+ my $colspan;
+ if ($parent ne 'instcode') {
+ $colspan = $maxdepth - $depth - 1;
+ $text .= ''.&mt('Add subcategory:').' | ';
+ }
+ }
+ }
+ }
+ return $text;
+}
+
sub modifiable_userdata_row {
my ($context,$role,$settings,$numinrow,$rowcount) = @_;
my $rolename;
@@ -2438,7 +2653,7 @@ sub default_change_checker {
if ($confhash->{$role}{'font'}) {
$changes->{$role}{'font'} = 1;
}
-}
+}
sub display_colorchgs {
my ($dom,$changes,$roles,$confhash) = @_;
@@ -3753,7 +3968,7 @@ sub modify_defaults {
}
sub modify_scantron {
- my ($r,$dom,$confname,$domconfig) = @_;
+ my ($r,$dom,$confname,%domconfig) = @_;
my ($resulttext,%confhash,%changes,$errors);
my $custom = 'custom.tab';
my $default = 'default.tab';
@@ -3772,7 +3987,7 @@ sub modify_scantron {
$confname,'scantron','','',$custom);
if ($result eq 'ok') {
$confhash{'scantron'}{'scantronformat'} = $scantronurl;
- $changes{'scantron'}{'scantronformat'} = 1;
+ $changes{'scantronformat'} = 1;
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
}
@@ -3788,13 +4003,11 @@ sub modify_scantron {
$errors .= ''.$error.'';
}
}
- if (ref($domconfig) eq 'HASH') {
- if (ref($domconfig->{'scantron'}) eq 'HASH') {
- if ($domconfig->{'scantron'}{'scantronformat'} ne '') {
- if ($env{'form.scantronformat_del'}) {
- $confhash{'scantron'}{'scantronformat'} = '';
- $changes{'scantron'}{'scantronformat'} = 1;
- }
+ if (ref($domconfig{'scantron'}) eq 'HASH') {
+ if ($domconfig{'scantron'}{'scantronformat'} ne '') {
+ if ($env{'form.scantronformat_del'}) {
+ $confhash{'scantron'}{'scantronformat'} = '';
+ $changes{'scantronformat'} = 1;
}
}
}
@@ -3803,15 +4016,16 @@ sub modify_scantron {
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
- $resulttext = &mt('Changes made:').'';
- if (ref($changes{'scantron'}) eq 'HASH') {
- if ($changes{'scantron'}{'scantronformat'}) {
- if ($confhash{'scantron'}{'scantronformat'} eq '') {
- $resulttext .= '- '.&mt('[_1] scantron format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
';
- } else {
- $resulttext .= '- '.&mt('Custom scantron format file ([_1]) uploaded for use with courses in this domain.',$custom).'
';
- }
+ if (ref($confhash{'scantron'}) eq 'HASH') {
+ $resulttext = &mt('Changes made:').'';
+ if ($confhash{'scantron'}{'scantronformat'} eq '') {
+ $resulttext .= '- '.&mt('[_1] scantron format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
';
+ } else {
+ $resulttext .= '- '.&mt('Custom scantron format file ([_1]) uploaded for use with courses in this domain.',$custom).'
';
}
+ $resulttext .= '
';
+ } else {
+ $resulttext = &mt('Changes made to scantron format file.');
}
$resulttext .= '
';
&Apache::loncommon::devalidate_domconfig_cache($dom);
@@ -3832,4 +4046,251 @@ sub modify_scantron {
return $resulttext;
}
+sub modify_coursecategories {
+ my ($dom,%domconfig) = @_;
+ my ($resulttext,%deletions,%reorderings,%needreordering,%adds,$errors);
+ my @deletecategory = &Apache::loncommon::get_env_multiple('form.deletecategory');
+ if (($domconfig{'coursecategories'}{'instcode::0'} ne '') && ($env{'form.instcode'} == 0)) {
+ push (@deletecategory,'instcode::0');
+ }
+ my (@predelcats,@predeltrails,%predelallitems);
+ if (ref($domconfig{'coursecategories'}) eq 'HASH') {
+ if (@deletecategory > 0) {
+ #FIXME Need to remove category from all courses using a deleted category
+ &extract_categories($domconfig{'coursecategories'},\@predelcats,\@predeltrails,\%predelallitems);
+ foreach my $item (@deletecategory) {
+ if ($domconfig{'coursecategories'}{$item} ne '') {
+ delete($domconfig{'coursecategories'}{$item});
+ $deletions{$item} = 1;
+ &recurse_cat_deletes($item,$domconfig{'coursecategories'},
+ \%deletions);
+ }
+ }
+ }
+ foreach my $item (keys(%{$domconfig{'coursecategories'}})) {
+ my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
+ if ($domconfig{'coursecategories'}{$item} ne $env{'form.'.$item}) {
+ $reorderings{$item} = 1;
+ $domconfig{'coursecategories'}{$item} = $env{'form.'.$item};
+ }
+ if ($env{'form.addcategory_name_'.$item} ne '') {
+ my $newcat = $env{'form.addcategory_name_'.$item};
+ my $newdepth = $depth+1;
+ my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth;
+ $domconfig{'coursecategories'}{$newitem} = $env{'form.addcategory_pos_'.$item};
+ $adds{$newitem} = 1;
+ }
+ if ($env{'form.subcat_'.$item} ne '') {
+ my $newcat = $env{'form.subcat_'.$item};
+ my $newdepth = $depth+1;
+ my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth;
+ $domconfig{'coursecategories'}{$newitem} = 0;
+ $adds{$newitem} = 1;
+ }
+ }
+ }
+ if ($env{'form.instcode'} eq '1') {
+ if (ref($domconfig{'coursecategories'}) eq 'HASH') {
+ my $newitem = 'instcode::0';
+ if ($domconfig{'coursecategories'}{$newitem} eq '') {
+ $domconfig{'coursecategories'}{$newitem} = $env{'form.instcode_pos'};
+ $adds{$newitem} = 1;
+ }
+ } else {
+ my $newitem = 'instcode::0';
+ $domconfig{'coursecategories'}{$newitem} = $env{'form.instcode_pos'};
+ $adds{$newitem} = 1;
+ }
+ }
+ if ($env{'form.addcategory_name'} ne '') {
+ my $newitem = &escape($env{'form.addcategory_name'}).'::0';
+ $domconfig{'coursecategories'}{$newitem} = $env{'form.addcategory_pos'};
+ $adds{$newitem} = 1;
+ }
+ if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) {
+ my %sort_by_deltrail;
+ if (keys(%deletions) > 0) {
+ foreach my $key (keys(%deletions)) {
+ if ($predelallitems{$key} ne '') {
+ $sort_by_deltrail{$predelallitems{$key}} = $predeltrails[$predelallitems{$key}];
+ }
+ }
+ }
+ my (@chkcats,@chktrails,%chkallitems);
+ &extract_categories($domconfig{'coursecategories'},\@chkcats,\@chktrails,\%chkallitems);
+ if (ref($chkcats[0]) eq 'ARRAY') {
+ my $depth = 0;
+ my $chg = 0;
+ for (my $i=0; $i<@{$chkcats[0]}; $i++) {
+ my $name = $chkcats[0][$i];
+ my $item;
+ if ($name eq '') {
+ $chg ++;
+ } else {
+ $item = &escape($name).'::0';
+ if ($chg) {
+ $domconfig{'coursecategories'}{$item} -= $chg;
+ }
+ $depth ++;
+ &recurse_check(\@chkcats,$domconfig{'coursecategories'},$depth,$name);
+ $depth --;
+ }
+ }
+ }
+ my $putresult = &Apache::lonnet::put_dom('configuration',\%domconfig,$dom);
+ my (@cats,@trails,%allitems);
+ &extract_categories($domconfig{'coursecategories'},\@cats,\@trails,\%allitems);
+ if ($putresult eq 'ok') {
+ $resulttext = &mt('Changes made:').'';
+ if (keys(%deletions) > 0) {
+ $resulttext .= '- '.&mt('Deleted categories:').'
';
+ foreach my $predeltrail (sort {$a <=> $b } (keys(%sort_by_deltrail))) {
+ $resulttext .= '- '.$predeltrails[$predeltrail].'
';
+ }
+ $resulttext .= '
';
+ }
+ if (keys(%reorderings) > 0) {
+ my %sort_by_trail;
+ $resulttext .= '- '.&mt('Reordered categories:').'
';
+ foreach my $key (keys(%reorderings)) {
+ if ($allitems{$key} ne '') {
+ $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}];
+ }
+ }
+ foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) {
+ $resulttext .= '- '.$trails[$trail].'
';
+ }
+ $resulttext .= '
';
+ }
+ if (keys(%adds) > 0) {
+ my %sort_by_trail;
+ $resulttext .= '- '.&mt('Added categories:').'
';
+ foreach my $key (keys(%adds)) {
+ if ($allitems{$key} ne '') {
+ $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}];
+ }
+ }
+ foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) {
+ $resulttext .= '- '.$trails[$trail].'
';
+ }
+ $resulttext .= '
';
+ }
+ $resulttext .= '
';
+ } else {
+ $resulttext = ''.
+ &mt('An error occurred: [_1]',$putresult).'';
+ }
+ } else {
+ $resulttext = &mt('No changes made to course categories');
+ }
+ return $resulttext;
+}
+
+sub recurse_check {
+ my ($chkcats,$categories,$depth,$name) = @_;
+ if (ref($chkcats->[$depth]{$name}) eq 'ARRAY') {
+ my $chg = 0;
+ for (my $j=0; $j<@{$chkcats->[$depth]{$name}}; $j++) {
+ my $category = $chkcats->[$depth]{$name}[$j];
+ my $item;
+ if ($category eq '') {
+ $chg ++;
+ } else {
+ my $deeper = $depth + 1;
+ $item = &escape($category).':'.&escape($name).':'.$depth;
+ if ($chg) {
+ $categories->{$item} -= $chg;
+ }
+ &recurse_check($chkcats,$categories,$deeper,$category);
+ $deeper --;
+ }
+ }
+ }
+ return;
+}
+
+sub recurse_cat_deletes {
+ my ($item,$coursecategories,$deletions) = @_;
+ my ($deleted,$container,$depth) = map { &unescape($_); } split(/:/,$item);
+ my $subdepth = $depth + 1;
+ if (ref($coursecategories) eq 'HASH') {
+ foreach my $subitem (keys(%{$coursecategories})) {
+ my ($child,$parent,$itemdepth) = map { &unescape($_); } split(/:/,$subitem);
+ if (($parent eq $deleted) && ($itemdepth == $subdepth)) {
+ delete($coursecategories->{$subitem});
+ $deletions->{$subitem} = 1;
+ &recurse_cat_deletes($subitem,$coursecategories,$deletions);
+ }
+ }
+ }
+ return;
+}
+
+sub extract_categories {
+ my ($categories,$cats,$trails,$allitems) = @_;
+ if (ref($categories) eq 'HASH') {
+ foreach my $item (keys(%{$categories})) {
+ my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
+ if ($container eq '' && $depth == 0) {
+ $cats->[$depth][$categories->{$item}] = $cat;
+ } else {
+ $cats->[$depth]{$container}[$categories->{$item}] = $cat;
+ }
+ }
+ if (ref($cats->[0]) eq 'ARRAY') {
+ for (my $i=0; $i<@{$cats->[0]}; $i++) {
+ my $name = $cats->[0][$i];
+ my $item = &escape($name).'::0';
+ my $trailstr;
+ if ($name eq 'instcode') {
+ $trailstr = &mt('Official courses (with institutional codes)');
+ } else {
+ $trailstr = $name;
+ }
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ my @parents = ($name);
+ if (ref($cats->[1]{$name}) eq 'ARRAY') {
+ for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
+ my $category = $cats->[1]{$name}[$j];
+ &recurse_categories($cats,2,$category,$trails,$allitems,\@parents);
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+sub recurse_categories {
+ my ($cats,$depth,$category,$trails,$allitems,$parents) = @_;
+ if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
+ for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
+ my $shallower = $depth - 1;
+ my $name = $cats->[$depth]{$category}[$k];
+ my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
+ my $trailstr = join(' -> ',(@{$parents},$category));
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ my $deeper = $depth+1;
+ push(@{$parents},$category);
+ &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents);
+ pop(@{$parents});
+ }
+ } else {
+ $depth --;
+ my $item = &escape($category).':'.&escape($parents->[-1]).':'.$depth;
+ my $trailstr = join(' -> ',(@{$parents},$category));
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ }
+ return;
+}
+
1;