File:  [LON-CAPA] / loncom / interface / courseprefs.pm
Revision 1.8.2.14: download - view: text, annotated - select for diffs
Fri Sep 17 23:57:33 2010 UTC (13 years, 8 months ago) by raeburn
Branches: version_2_9_X
Diff to branchpoint 1.8: preferred, colored
- Backport 1.31.

# The LearningOnline Network with CAPA
# Handler to set configuration settings for a course
#
# $Id: courseprefs.pm,v 1.8.2.14 2010/09/17 23:57:33 raeburn Exp $
#
# 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/
#
#
###############################################################
##############################################################

=pod

=head1 NAME

courseprefs- Handler to set/modify course configuration

=head1 SYNOPSIS

courseprefs provides an interface for setting general course configuration

=head1 DESCRIPTION

This module is used for configuration of a course

=head1 INTERNAL SUBROUTINES

=over

=item get_allitems()

=item print_config_box()

=item process_changes()

=item get_sec_str()

=item check_clone()

=item store_changes()

=item update_env()

=item display_disallowed()

=item get_course()

=item get_jscript()

=item cloners_javascript()

=item print_courseinfo()

=item new_cloners_dom_row()

=item can_modify_catsettings()

=item assign_course_categories()

=item print_localization()

=item get_lang_choices()

=item print_feedback()

=item user_table()

=item select_recipient()

=item select_sections()

=item print_discussion()

=item role_checkboxes()

=item print_classlists()

=item print_appearance()

=item print_grading()

=item print_printouts()

=item print_spreadsheet()

=item print_bridgetasks()

=item print_other()

=item get_other_items()

=item item_table_row_start()

=item item_table_row_end()

=item yes_no_radio()

=item select_from_options()

=item make_item_rows()

Creates table used to display and set course configuration items.

Inputs: $cdom,$items,$ordered,$settings,$rowtotal,$crstype
where $cdom is course's domain, $items is HASH ref for current config
item, $ordered is ARRAY ref of items to include in row in
display order, $settings is HASH ref of current values forrow,
$rowtotal is SCALAR ref used to accumulate row count, $crstype is
course type.

Returns: $datatable
HTML mark-up of data table which accumulates individual rows.

=item nothidepriv_row()

Creates row containing form elements used to display and set
whether Domain coordinators who are currently included in
advanced course user .db file for a course are to be hidden (e.g.,
in syllabus, or from course user lists).

Inputs: $cdom,$item,$settings,$crstype
where $cdom is course domain, item is nothideprivileged, $settings is
HASH ref of the current values for nothideprivileged, $crstype is
course type (Course or Community).

Returns: $datatable
HTML mark-up for Privileged users (Domain Coordinators) in staff listing.

=item print_hdrfmt_row()

Creates row containing form elements used to display and set
substitution items and text to be used in the header included
on printouts.

Inputs: $item,$settings
where $item is print_header_format, and $settings is a HASH ref
of the current values stored for print_header_format.

Returns: $output
HTML mark-up containing Javascript functions: reOrder() and getIndexByName()
used to dynamically update position selectboxes, and HTML table elements
for the "Print header format" row.

=item position_selector()

Creates a select box which can be used to reorder substitutions
and text included in a printout header.

Inputs: $pos,$num,$maxnum
where $pos is current position, $num is the unique identifier,
and $maxnum is the total number of items (both substitutions
and text in the printout header.

Returns: $output
HTML mark-up for the selectbox and a hidden form element containing
the current position.

=item substitution_selector()

Creates a combination of select box for choosing an item
(student name, course ID or assignment note) to substitute,
and a corresponding size limit in the header used for printouts.

Inputs: $num,$subst,$limit,$crstype
where $num is the unique identifier, $subst is the current
substitution (n,c or a, for name, course or note respectively,
$limit is the current size limit (integer), and $crstype is
course type - course or community.

Returns: $output
HTML mark-up for selectbox and textbox (separate table cells).

=item change_clone()

Modifies the list of courses a user can clone (stored
in the user's environment.db file), called when a
change is made to the list of users allowed to clone
a course.

Inputs: $action,$cloner
where $action is add or drop, and $cloner is identity of
user for whom cloning ability is to be changed in course.

Returns: nothing

=back

=cut


package Apache::courseprefs;

use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::lonconfigsettings;
use Apache::lonlocal;
use LONCAPA qw(:DEFAULT :match);

sub handler {
    my $r=shift;
    if ($r->header_only) {
        &Apache::loncommon::content_type($r,'text/html');
        $r->send_http_header;
        return OK;
    }
    my $context = 'course';
    my $cid = $env{'request.course.id'};
    my ($cnum,$cdom) = &get_course($cid);
    my $crstype = &Apache::loncommon::course_type();
    my $parm_permission = &Apache::lonnet::allowed('opa',$cid);
    my $navmap = Apache::lonnavmaps::navmap->new();
    if ($parm_permission && $navmap) {
        &Apache::loncommon::content_type($r,'text/html');
        $r->send_http_header;
    } else {
        if ($navmap) {
            if ($crstype eq 'Community') {
                $env{'user.error.msg'}=
                    "/adm/courseprefs:opa:0:0:Cannot modify community settings";
            } else {
                $env{'user.error.msg'}=
                    "/adm/courseprefs:opa:0:0:Cannot modify course settings";
            }
        } else {
            if ($crstype eq 'Community') {
                $env{'user.error.msg'}=
                    "/adm/courseprefs::0:1:Course environment gone, reinitialize the community";
            } else {
                $env{'user.error.msg'}=
                    "/adm/courseprefs::0:1:Course environment gone, reinitialize the course";

            }
        }
        return HTTP_NOT_ACCEPTABLE;
    }

    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                            ['phase','actions','origin']);
    &Apache::lonhtmlcommon::clear_breadcrumbs();
    if ($env{'form.origin'} eq 'params') {
        &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset",
                                                text=>"Parameter Manager"});
    }
    my ($brtext,$brtitle,$crsinfotext,$crsinfodesc,$crscateg,$crshide);
    my %lt;
    if ($crstype eq 'Community') {
        %lt = (
                conf => 'Community Configuration',
                edit => 'Edit Community Configuration',
                gens => 'General community settings',
                idnu => 'Community ID or number',
                desc => 'Community Description',
                ownr => 'Community Owner',
                cown => 'Community Co-owners',
                catg => 'Categorize community',
                excc => 'Exclude from community catalog',
                clon => 'Users allowed to clone community',
                rept => 'Replacement titles for standard community roles',
                time => 'Timezone where the community is located',
                date => 'Locale used for community calendar',
                coco => 'Community Content',
                copo => 'Community Policy',
                priv => 'Domain Coordinators in community',
                defd => 'Default dates for member access',
                stuv => 'Member-viewable membership list options',
                stul => 'Member agreement needed to be listed',
                clas => 'Membership and Facilitator Listing',
                priv => 'Privileged users (Domain Coordinators) in facilitator listing',
                defc => 'Default Community Spreadsheet',
                defs => 'Default User Spreadsheet',
                seme => 'Send message to member when clicking Done on Tasks'
              );
    } else {
        %lt = (
                conf => 'Course Configuration',
                edit => 'Edit Course Configuration',
                gens => 'General course settings',
                idnu => 'Course ID or number',
                desc => 'Course Description',
                ownr => 'Course Owner',
                cown => 'Course Co-owners',
                catg => 'Categorize course',
                excc => 'Exclude from course catalog',
                clon => 'Users allowed to clone course',
                rept => 'Replacement titles for standard course roles',
                time => 'Timezone in which the course takes place',
                date => 'Locale used for course calendar',
                coco => 'Course Content',
                copo => 'Course Policy',
                priv => 'Domain Coordinators in course',
                defd => 'Default dates for student access',
                stuv => 'Student-viewable classlist options',
                stul => 'Student agreement needed to be listed',
                clas => 'Classlists and Staff Listing',
                priv => 'Privileged users (Domain Coordinators) in staff listing',
                defc => 'Default Course Spreadsheet',
                defs => 'Default Student Spreadsheet',
                seme => 'Send message to student when clicking Done on Tasks',
              );
    }
    &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/courseprefs',
        text=>$lt{'conf'}});
    my $breadcrumbs =
        &Apache::lonhtmlcommon::breadcrumbs($lt{'edit'});

    my $phase = 'pickactions';
    if ( exists($env{'form.phase'}) ) {
        $phase = $env{'form.phase'};
    }

    if ($phase eq 'categorizecourse') {
        &assign_course_categories($r,$crstype);
        return OK;
    }

    my %values=&Apache::lonnet::dump('environment',$cdom,$cnum);
    my @prefs_order = ('courseinfo','localization','feedback','discussion',
                       'classlists','appearance','grading','printouts',
                       'spreadsheet','bridgetasks','other');

    my %prefs = (
        'courseinfo' =>
                   { text => $lt{'gens'},
                     help => 'Course_Environment',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value'}],
                     ordered => ['owner','co-owners','description','courseid',
                                 'categories','hidefromcat','externalsyllabus',
                                 'cloners','url','rolenames'],
                     itemtext => {
                                   'owner'            => $lt{'ownr'},
                                   'co-owners'        => $lt{'cown'},
                                   'description'      => $lt{'desc'},
                                   'courseid'         => $lt{'idnu'},
                                   'categories'       => $lt{'catg'},
                                   'hidefromcat'      => $lt{'excc'},
                                   'cloners'          => $lt{'clon'}, 
                                   'externalsyllabus' => 'URL of Syllabus',
                                   'url'              => 'Top Level Map',
                                   'rolenames'        => $lt{'rept'},
                                 },
                    },
        'localization' =>
                    { text => 'Language/TimeZone/Locale',
                      help => 'Course_Environment',
                      header => [{col1 => 'Setting',
                                  col2 => 'Value',}],
                      ordered => ['languages','timezone','datelocale'],
                      itemtext => {
                                    languages  => 'Languages used',
                                    timezone   => $lt{'time'}, 
                                    datelocale => $lt{'date'},
                                  },
                    },
        'feedback' =>
                    { text => 'Feedback messages',
                      help => 'Course_Environment',
                      header => [{col1 => 'Questions about:',
                                  col2 => 'Recipients'},
                                 {col1 => 'Questions about:',
                                  col2 => 'Custom Text'}],
                      ordered => ['question.email','comment.email','policy.email'],
                      itemtext => {
                                     'question.email' => 'Resource Content',
                                     'comment.email'  => $lt{'coco'},
                                     'policy.email'   => $lt{'copo'},
                                  },
                    },
        'discussion' =>
                    { text => 'Discussion and Chat',
                      help => 'Course_Environment',
                      header => [{col1 => 'Setting',
                                  col2 => 'Value',}],
                      ordered => ['pch.roles.denied','pch.users.denied',
                                  'plc.roles.denied','plc.users.denied',
                                  'allow_limited_html_in_feedback',
                                  'allow_discussion_post_editing'],
                      itemtext => {
                         'pch.roles.denied'             => 'No Resource Discussion',
                         'pch.users.denied'             => 'No Resource Discussion',
                         'plc.roles.denied'             => 'No Chat room use',
                         'plc.users.denied'             => 'No Chat room use',
                         allow_limited_html_in_feedback => 'Allow limited HTML in discussion posts',
                         allow_discussion_post_editing  => 'Users can edit/delete own discussion posts',
                                  },
                    },
        'classlists' =>
                   { text => $lt{'clas'},
                     help => 'Course_Environment',
                     header => [{col1 => 'Type',
                                 col2 => $lt{'defd'}},
                                {col1 => 'Setting',
                                 col2 => $lt{'priv'}},
                                {col1 => 'Setting',
                                 col2 => $lt{'stuv'}}],
                     ordered => ['default_enrollment_start_date',
                                 'default_enrollment_end_date',
                                 'nothideprivileged','student_classlist_view',
                                 'student_classlist_opt_in','student_classlist_portfiles'],
                     itemtext => {
                         default_enrollment_start_date => 'Start date',
                         default_enrollment_end_date   => 'End date',
                         nothideprivileged             => $lt{'priv'},
                         student_classlist_view        => $lt{'stuv'},
                         student_classlist_opt_in      => $lt{'stul'},
                         student_classlist_portfiles   => 'Include link to accessible portfolio files',
                                  },
                   },
        'appearance' =>
                   { text => 'Display of resources ',
                     help => 'Course_Environment',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value'}],
                     ordered => ['default_xml_style','pageseparators',
                                 'disable_receipt_display','texengine',
                                 'tthoptions'],
                      itemtext => {
                          default_xml_style       => 'Default XML Style File',
                          pageseparators          => 'Visibly Separate Items on Pages',
                          disable_receipt_display => 'Disable display of problem receipts',
                          texengine               => 'Force use of a specific math rendering engine',
                          tthoptions              => 'Default set of options to pass to tth/m when converting TeX',
                                  },
                  },
        'grading' =>
                  { text => 'Grading',
                    help => 'Course_Environment',
                    header => [{col1 => 'Setting',
                                col2 => 'Value',}],
                    ordered => ['grading','rndseed',
                                'receiptalg','disablesigfigs'],
                    itemtext => {
                        grading        => 'Grading',
                        rndseed        => 'Randomization algorithm used',
                        receiptalg     => 'Receipt algorithm used',
                        disablesigfigs => 'Disable checking of Significant Figures',
                                },

                  },
        'printouts' =>
                  { text => 'Printout generation',
                    help => 'Course_Environment',
                    header => [{col1 => 'Setting',
                                col2 => 'Value',}],
                    ordered => ['problem_stream_switch','suppress_tries',
                                'default_paper_size','print_header_format',
                                'disableexampointprint'],
                    itemtext => {
                        problem_stream_switch => 'Allow problems to be split over pages',
                        suppress_tries        => 'Suppress number of tries in printing',
                        default_paper_size    => 'Default paper type',
                        print_header_format   => 'Print header format',
                        disableexampointprint => 'Disable automatically printing point values on exams',
                                },
                  },
        'spreadsheet' =>
                  { text => 'Spreadsheets',
                    help => 'Course_Environment',
                    header => [{col1 => 'Setting',
                                col2 => 'Value'}],
                    ordered => ['spreadsheet_default_classcalc',
                                'spreadsheet_default_studentcalc',
                                'spreadsheet_default_assesscalc','hideemptyrows'],
                    itemtext => {
                                  spreadsheet_default_classcalc   => $lt{'defc'},
                                  spreadsheet_default_studentcalc => $lt{'defs'},
                                  spreadsheet_default_assesscalc  => 'Default Assessment Spreadsheet',
                                  hideemptyrows                   => 'Hide Empty Rows in Spreadsheets',
                                },
                  },
        'bridgetasks' =>
                  { text => 'Bridge tasks',
                    help => 'Course_Environment',
                    header => [{col1 => 'Setting',
                                col2 => 'Value'}],
                    ordered => ['task_messages','task_grading',
                                'suppress_embed_prompt'],
                    itemtext => {
                        task_messages         => $lt{'seme'},
                        task_grading          => 'Bridge Task grading by instructors and TAs in sections' ,
                        suppress_embed_prompt => 'Hide upload references prompt if uploading file to portfolio',
                                },
                  },
        'other' =>
                  { text => 'Other settings',
                    help => 'Course_Environment',
                    header => [ {col1 => 'Item',
                                 col2 => 'Value',
                              }],
                  },
    );
    if ($phase eq 'process') {
        my @allitems = &get_allitems(%prefs);
        &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context,
                                                 \@prefs_order,\%prefs,\%values,
                                                  $cnum,undef,\@allitems);
    } elsif ($phase eq 'display') {
        my $jscript = &get_jscript($cdom,$phase,$crstype);
        my @allitems = &get_allitems(%prefs);
        &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context,
            \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype);
    } else {
        &Apache::lonconfigsettings::display_choices($r,$phase,$context,
                                                    \@prefs_order,\%prefs);
    }
    return OK;
}

sub get_allitems {
    my (%prefs) = @_;
    my @allitems;
    foreach my $item (keys(%prefs)) {
        if (ref($prefs{$item}) eq 'HASH') {
            if (ref($prefs{$item}{'ordered'}) eq 'ARRAY') {
                push(@allitems,@{$prefs{$item}{'ordered'}});
                if ($item eq 'feedback') {
                    push(@allitems,(map { $_.'.text'; } @{$prefs{$item}{'ordered'}}));
                }
            }
        }
    }
    return @allitems;
}

sub print_config_box {
    my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype) = @_;
    my $ordered = $item->{'ordered'};
    my $itemtext = $item->{'itemtext'};
    my $rowtotal = 0;
    my $output =
         '<table class="LC_nested_outer">
          <tr>
           <th align="left" valign="middle"><span class="LC_font_larger">'.
           &mt($item->{text}).'&nbsp;'.
           &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".
          '</tr>';
    if (($action eq 'feedback') || ($action eq 'classlists')) {
        $output .= '
          <tr>
           <td>
            <table class="LC_nested">
             <tr class="LC_info_row">
              <td class="LC_left_item">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
              <td class="LC_right_item">'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
             </tr>';
        $rowtotal ++;
        if ($action eq 'feedback') {
            $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal);
        } elsif ($action eq 'classlists') {
            $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype);
        }
        $output .= '
           </table>
          </td>
         </tr>
         <tr>
           <td>
            <table class="LC_nested">
             <tr class="LC_info_row">
              <td class="LC_left_item">'.&mt($item->{'header'}->[1]->{'col1'}).'</td>';
        $output .= '
              <td class="LC_right_item">'.&mt($item->{'header'}->[1]->{'col2'}).'</td>
             </tr>';
        if ($action eq 'classlists') {
            $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype).
                       '
            </table>
           </td>
          </tr>
          <tr>
           <td>
            <table class="LC_nested">
             <tr class="LC_info_row">
              <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
              <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
             </tr>';
        }
    } else {
        $output .= '
          <tr>
           <td>
            <table class="LC_nested">
             <tr class="LC_info_row">
              <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
              <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
             </tr>';
    }
    $rowtotal ++;
    if ($action eq 'courseinfo') {
        $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'localization') {
        $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal);
    } elsif ($action eq 'feedback') {
        $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal);
    } elsif ($action eq 'discussion') {
        $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal);
    } elsif ($action eq 'classlists') {
        $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'appearance') {
        $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'grading') {
        $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'printouts') {
        $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'spreadsheet') {
        $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'bridgetasks') {
        $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype);
    } elsif ($action eq 'other') {
        $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype);
    }
    $output .= '
   </table>
  </td>
 </tr>
</table><br />';
    return ($output,$rowtotal);
}

sub process_changes {
    my ($cdom,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_;
    my %newvalues;
    if (ref($item) eq 'HASH') {
        if (ref($changes) eq 'HASH') {
            my @ordered;
            if ($action eq 'other') {
                @ordered = &get_other_items($cdom,$values,$allitems);
                if ($env{'form.newp_name'} ne '') {
                    my $newp = $env{'form.newp_name'};
                    if ($env{'form.newp_value'} ne '') {
                        if (ref($allitems) eq 'ARRAY') {
                            unless ((grep(/^\Q$newp\E$/,@ordered)) || 
                                    (grep(/^\Q$newp\E$/,@{$allitems}))) {
                                $changes->{$newp} = $env{'form.newp_value'};
                            }
                        }
                    }
                }
            } elsif (ref($item->{'ordered'}) eq 'ARRAY') {
                @ordered = @{$item->{'ordered'}};
            }
            if (@ordered > 0) {
                if ($action eq 'feedback') {
                    foreach my $entry (@ordered) {
                        my $userstr = '';
                        my $total = $env{'form.'.$entry.'_total'};
                        if ($total) {
                            my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete');
                            for (my $i=0; $i<$total; $i++) {
                                unless (grep(/^$i$/,@deletes)) {
                                    $userstr .= $env{'form.'.$entry.'_user_'.$i}.
                                                &get_sec_str($entry,$i).',';
                                }
                            }
                        } else {
                            $total = 0;
                        } 
                        if ($env{'form.'.$entry.'_uname_'.$total} ne '') {
                            my $uname = $env{'form.'.$entry.'_uname_'.$total};
                            my $udom = $env{'form.'.$entry.'_udom_'.$total};
                            if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') {
                                $userstr =~ s/,$//;
                                $disallowed->{'feedback'}{$entry} = $uname.':'.$udom;
                            } else {
                                $userstr .= $uname.':'.$udom.&get_sec_str($entry,$total);
                            }
                        } else {
                            $userstr =~ s/,$//;
                        }
                        $newvalues{$entry} = $userstr;
                        if ($newvalues{$entry} ne $values->{$entry}) {
                            $changes->{$entry} = $newvalues{$entry};
                        }
                        my $ext_entry = $entry.'.text';
                        $newvalues{$ext_entry} = $env{'form.'.$ext_entry};
                        if ($newvalues{$ext_entry} ne $values->{$ext_entry}) {
                            $changes->{$ext_entry} = $newvalues{$ext_entry};
                        }
                    }
                } else {
                    foreach my $entry (@ordered) {
                        if ($entry eq 'cloners') {
                            if ($env{'form.cloners_all'}) {
                                $newvalues{$entry} = '*';
                            } else {
                                my @clonedoms;
                                if (exists($env{'form.cloners_activate'})) {
                                    my $actnum = $env{'form.cloners_activate'};
                                    if ($actnum ne '') {
                                        if ($env{'form.clonersdom_'.$actnum} ne '') {
                                            my $clonedom = $env{'form.clonersdom_'.$actnum};
                                            if (&check_clone($clonedom,$disallowed) eq 'ok') {
                                                $newvalues{$entry} = '*:'.$clonedom;
                                                push(@clonedoms,$newvalues{$entry});
                                            }
                                        }
                                    }
                                } else {
                                    my $num = $env{'form.cloners_total'};
                                    my @deletes = 
                                        &Apache::loncommon::get_env_multiple('form.cloners_delete');
                                    for (my $i=0; $i<$num; $i++) {
                                        if (!grep(/^$i$/,@deletes)) {
                                            my $clonedom = $env{'form.cloners_dom_'.$i};
                                            if (&check_clone($clonedom,$disallowed) eq 'ok') {
                                                if (!grep(/^\*:\Q$clonedom\E$/,@clonedoms)) {
                                                    push (@clonedoms,'*:'.$clonedom);
                                                }
                                            }
                                        }
                                    }
                                    if (@clonedoms) {
                                        $newvalues{$entry}=join(',',@clonedoms);
                                    }
                                }
                                if ($env{'form.cloners_newdom'} ne '') {
                                    my $clonedom = $env{'form.cloners_newdom'};
                                    if (&check_clone($clonedom,$disallowed) eq 'ok') {
                                        my $newdom = '*:'.$env{'form.cloners_newdom'};
                                        if (@clonedoms) { 
                                            if (!grep(/^\Q$newdom\E$/,@clonedoms)) {
                                                $newvalues{$entry} .= ','.$newdom;
                                            }
                                        } else {
                                            $newvalues{$entry} = $newdom;
                                        }
                                    }
                                }
                                if ($env{'form.'.$entry} ne '') {
                                    my @cloners = split(',',$env{'form.'.$entry});
                                    my @okcloners;
                                    foreach my $cloner (@cloners) {
                                        $cloner =~ s/^\s+//;
                                        $cloner =~ s/\s+$//;
                                        unless ($cloner eq '') {
                                            my ($uname,$udom) = split(':',$cloner);
                                            if (&check_clone($udom,$disallowed,$uname) eq 'ok') {
                                                if (!grep(/^\Q$cloner\E$/,@okcloners)) {
                                                    push(@okcloners,$cloner);
                                                }
                                            }
                                        }
                                    }
                                    if (@okcloners) {
                                        my $okclonestr = join(',',@okcloners);
                                        if ($newvalues{$entry} ne '') {
                                            $newvalues{$entry} .= ','.$okclonestr;
                                        } else {
                                            $newvalues{$entry} = $okclonestr;
                                        }
                                    }
                                }
                            }
                            if (ref($disallowed) eq 'HASH') {
                                if (ref($disallowed->{'cloners'}) eq 'HASH') {
                                    foreach my $key (keys(%{$disallowed->{'cloners'}})) {
                                        $disallowed->{'cloners'}{$key} =~ s/,$//;
                                    }
                                }
                            }
                        } elsif ($entry eq 'co-owners') {
                            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                            my $coowners = $values->{'internal.co-owners'};
                            my @currcoown;
                            if ($coowners) {
                                @currcoown = split(',',$coowners);
                            }
                            if (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                                my $autocoowner;
                                if (($crstype eq 'Course') &&
                                    ($values->{'internal.coursecode'})) {
                                    my %domconf =
                                        &Apache::lonnet::get_dom('configuration',['autoenroll'],$cdom);
                                    if (ref($domconf{'autoenroll'}) eq 'HASH') {
                                        $autocoowner = $domconf{'autoenroll'}{'co-owners'};
                                    }
                                }
                                unless ($autocoowner) {
                                    my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners');
                                    my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners');
                                    my @invitecoowners =  &Apache::loncommon::get_env_multiple('form.invitecoowners');
                                    if (@invitecoowners) {
                                        push(@pendingcoowners,@invitecoowners);
                                    }
                                    $newvalues{'pendingco-owners'} = join(',',sort(@pendingcoowners));
                                    $newvalues{'co-owners'} = join(',',sort(@keepcoowners));
                                    if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) {
                                        $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'};
                                        push(@{$changes->{$entry}{'changed'}},'co-owners');
                                    }
                                    if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) {
                                        $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'};
                                        push(@{$changes->{$entry}{'changed'}},'pendingco-owners');
                                    }
                                }
                            } else {
                                my (@newpending,@newcoown);
                                my $uname = $env{'user.name'};
                                my $udom = $env{'user.domain'};
                                my $pendingcoowners = $values->{'internal.pendingco-owners'};
                                my @pendingcoown = split(',',$pendingcoowners);
                                if ($env{'form.pending_coowoner'}) {
                                    foreach my $item (@pendingcoown) {
                                        unless ($item eq $uname.':'.$udom) {
                                            push(@newpending,$item);
                                        }
                                    }
                                    @newcoown = @currcoown;
                                    if ($env{'form.pending_coowoner'} eq 'accept') {
                                        unless (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) {
                                            push(@newcoown,$uname.':'.$udom);
                                        }
                                    }
                                } elsif ($env{'form.remove_coowoner'}) {
                                    foreach my $item (@currcoown) {
                                        unless ($item eq $uname.':'.$udom) {
                                            push(@newcoown,$item);
                                        }
                                    }
                                    if ($pendingcoowners ne '') {
                                        @newpending = @pendingcoown;
                                    }
                                }
                                $newvalues{'pendingco-owners'} = join(',',sort(@newpending));
                                $newvalues{'co-owners'} = join(',',sort(@newcoown));
                                if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) {
                                    $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'};
                                    push(@{$changes->{$entry}{'changed'}},'co-owners');
                                }
                                if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) {
                                    $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'};
                                    push(@{$changes->{$entry}{'changed'}},'pendingco-owners');
                                }
                            }
                        } elsif ($entry =~ /^default_enrollment_(start|end)_date$/) {
                            $newvalues{$entry}=&Apache::lonhtmlcommon::get_date_from_form($entry);
                        } elsif ($entry eq 'rolenames') {
                            my %adv_roles =
                                &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1);
                            my @stds;
                            if ($crstype eq 'Community') {
                                @stds = ('co');
                            } else {
                                @stds = ('cc');
                            }
                            push(@stds,('in','ta','ep','ad','st'));
                            my (@replacements,@regulars);
                            foreach my $role (@stds) {
                                if ($values->{$role.'.plaintext'} ne '') {
                                    push(@replacements,$role);
                                } else {
                                    push(@regulars,$role);
                                }
                            }
                            foreach my $stdrole (@stds) {
                                my $ext_entry = $entry.'_'.$stdrole;
                                my $stdname = &Apache::lonnet::plaintext($stdrole,$crstype,
                                                                         $env{'request.course.id'},1);
                                if ($env{'form.'.$ext_entry} eq $stdname) {
                                    $newvalues{$ext_entry} = '';
                                } else {
                                    $newvalues{$ext_entry} = $env{'form.'.$ext_entry};
                                }
                                if ($newvalues{$ext_entry} ne $values->{$stdrole.'.plaintext'}) {
                                    my $dupname = 0;
                                    if ($newvalues{$ext_entry} ne '') {
                                        if (grep(/^\Q$newvalues{$ext_entry}\E$/,@replacements)) {
                                            $dupname = 1;
                                            push(@{$disallowed->{'rolenames'}{'replacements'}},$newvalues{$ext_entry});
                                        }
                                        if (!$dupname) {
                                            if (grep(/^\Q$newvalues{$ext_entry}\E$/,@regulars)) {
                                                $dupname = 1;
                                                push(@{$disallowed->{rolenames}{'regulars'}},$newvalues{$ext_entry});
                                            }
                                        }
                                        if (!$dupname) {
                                            foreach my $role (keys(%adv_roles)) {
                                                if ($role =~ m{^cr/$match_domain/$match_name/\Q$newvalues{$ext_entry}\E$}) {
                                                    $dupname = 1;
                                                    push(@{$disallowed->{rolenames}{'customrole'}},$newvalues{$ext_entry});
                                                    last;
                                                }
                                            }
                                        }
                                    }
                                    if (!$dupname) {
                                        $changes->{$ext_entry} = $newvalues{$ext_entry};
                                    }
                                }
                            }
                        } elsif (($entry eq 'plc.roles.denied') || ($entry eq 'pch.roles.denied')) {
                            my @denied = &Apache::loncommon::get_env_multiple('form.'.$entry);
                            @denied = sort(@denied);
                            my $deniedstr = '';
                            if (@denied > 0) {
                                $deniedstr = join(',',@denied);  
                            }
                            $newvalues{$entry} = $deniedstr;
                        } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied')) {
                            my $total = $env{'form.'.$entry.'_total'};
                            my $userstr = '';
                            my @denied;  
                            if ($total > 0) {
                                my @deletes = 
                                    &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete');
                                for (my $i=0; $i<$total; $i++) {
                                    unless (grep(/^$i$/,@deletes)) {
                                        $userstr .= $env{'form.'.$entry.'_user_'.$i}.',';
                                        push(@denied,$env{'form.'.$entry.'_user_'.$i});
                                    }
                                }
                            } else {
                                $total = 0;
                            }
                            if ($env{'form.'.$entry.'_uname_'.$total} ne '') {
                                my $uname = $env{'form.'.$entry.'_uname_'.$total};
                                my $udom = $env{'form.'.$entry.'_udom_'.$total};
                                if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') {
                                    $userstr =~ s/,$//;
                                    $disallowed->{'discussion'}{$entry} = $uname.':'.$udom;
                                } else {
                                    my $newuser .= $uname.':'.$udom;
                                    if (grep(/^\Q$newuser\E$/,@denied)) {
                                        $userstr =~ s/,$//;
                                    } else {
                                        $userstr .= $newuser;
                                    }
                                }
                            } else {
                                $userstr =~ s/,$//;
                            }
                            $newvalues{$entry} = $userstr;
                        } elsif ($entry eq 'allow_discussion_post_editing') {
                            my @canedit = &Apache::loncommon::get_env_multiple('form.'.$entry);
                            @canedit = sort(@canedit);
                            foreach my $role (@canedit) {
                                my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$role);
                                if ((grep(/^\s*$/,@secs)) || (@secs == 0)) {
                                    $newvalues{$entry} .= $role.',';
                                } else {
                                    foreach my $sec (@secs) {
                                        $newvalues{$entry} .= $role.':'.$sec.',';
                                    }
                                }
                            }
                            $newvalues{$entry} =~ s/,$//;
                        } elsif ($entry eq 'nothideprivileged') {
                            my @curr_nothide;
                            my @new_nothide;
                            if ($values->{$entry} ne '') {
                                foreach my $user (split(/\s*\,\s*/,$values->{$entry})) {
                                    my $nothide;
                                    if ($user !~ /:/) {
                                        $nothide = join(':',split(/[\@]/,$user));
                                    } else {
                                        $nothide = $user;
                                    }
                                    if ((defined($nothide)) && 
                                        (!grep(/^\Q$nothide\E$/,@curr_nothide))) {
                                        push(@curr_nothide,$nothide);   
                                    }
                                }
                            }
                            foreach my $key (keys(%env)) {
                                if ($key =~ /^form\.\Q$entry\E_($match_username:$match_domain)$/) {
                                    if ($env{$key}) {
                                       my $nothide = $1;
                                       if (!grep(/^\Q$nothide\E$/,@new_nothide)) {
                                           push(@new_nothide,$nothide); 
                                        }
                                    }
                                }
                            }
                            @new_nothide = sort(@new_nothide);
                            my @differences =
                                &Apache::loncommon::compare_arrays(\@curr_nothide,
                                                                   \@new_nothide);
                            if (@differences > 0) {
                                if (@new_nothide > 0) { 
                                    $newvalues{$entry} = join(',',@new_nothide);
                                } else {
                                    $newvalues{$entry} = '';
                                }
                            } else {
                                $newvalues{$entry} = $values->{$entry}; 
                            }
                        } elsif ($entry eq 'print_header_format') {
                            my $maxnum = $env{'form.printfmthdr_maxnum'};
                            my @newhdr;
                            if ($maxnum > 2) {
                                for (my $i=0; $i<$maxnum-2; $i++) {
                                    if ($env{'form.printfmthdr_del_'.$i}) {
                                        $newhdr[$env{'form.printfmthdr_pos_'.$i}] = '';
                                    } else {
                                        my $hdr;
                                        if ($env{'form.printfmthdr_sub_'.$i} =~ /^[nca]$/) {
                                            $hdr = '%';
                                            if ($env{'form.printfmthdr_limit_'.$i} =~ /^\d+$/) {
                                                $hdr .= $env{'form.printfmthdr_limit_'.$i};
                                            }
                                            $hdr .= $env{'form.printfmthdr_sub_'.$i};
                                        } elsif ($env{'form.printfmthdr_text_'.$i} ne '') {
                                            $hdr = $env{'form.printfmthdr_text_'.$i};
                                        }
                                        $newhdr[$env{'form.printfmthdr_pos_'.$i}] = $hdr;
                                    }
                                }
                            }
                            my $newsub = $maxnum-2;
                            if ($env{'form.printfmthdr_sub_'.$newsub} =~ /^[nca]$/) {
                                my $hdr = '%';
                                if ($env{'form.printfmthdr_limit_'.$newsub} =~ /^\d+$/) {
                                    $hdr .= $env{'form.printfmthdr_limit_'.$newsub};
                                }
                                $hdr .= $env{'form.printfmthdr_sub_'.$newsub};
                                $newhdr[$env{'form.printfmthdr_pos_'.$newsub}] = $hdr;
                            }
                            my $newtext = $maxnum-1;
                            $newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext};
                            $newvalues{$entry} = join('',@newhdr);
                        } elsif ($entry eq 'languages') {
                            my $langstr;
                            my $total = $env{'form.'.$entry.'_total'};
                            if ($total) {
                                my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete');
                                for (my $i=0; $i<$total; $i++) {
                                    unless (grep(/^$i$/,@deletes)) {
                                       $langstr .= $env{'form.'.$entry.'_'.$i}.',';
                                    }
                                }
                            } else {
                                $total = 0;
                            }
                            if ($env{'form.'.$entry.'_'.$total} ne '') {
                                my $newlang = $env{'form.'.$entry.'_'.$total};
                                my %langchoices = &get_lang_choices();
                                if ($langchoices{$newlang}) {
                                    $langstr .= $newlang;
                                } else {
                                    $langstr =~ s/,$//;
                                    $disallowed->{'localization'}{$entry} = $newlang;
                                }
                            } else {
                                $langstr =~ s/,$//;
                            }
                            $newvalues{$entry} = $langstr;
                        } else {
                            $newvalues{$entry} = $env{'form.'.$entry};
                        }
                        unless ($entry eq 'co-owners') {
                            if ($newvalues{$entry} ne $values->{$entry}) {
                                $changes->{$entry} = $newvalues{$entry};
                            }
                        }
                    }
                }
            }
        }
    }
    return;
}

sub get_sec_str {
    my ($entry,$num) = @_;
    my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$num);
    my $secstr;
    if (grep(/^\s*$/,@secs)) {
        $secstr = '';
    } elsif (@secs > 0) {
        $secstr = join(';',@secs);
    }
    if ($secstr ne '') {
        return '('.$secstr.')';
    }
    return;
}

sub check_clone {
    my ($clonedom,$disallowed,$clonename) = @_;
    return if (ref($disallowed) ne 'HASH');
    if ($clonedom !~ /^$match_domain$/) {
        $disallowed->{'cloners'}{'format'} .= $clonedom.',';
        return;
    } elsif (!&Apache::lonnet::domain($clonedom)) {
        $disallowed->{'cloners'}{'domain'} .= $clonedom.',';
        return;
    }
    if ($clonename ne '') {
        if ($clonename !~ /^$match_username$/) {
            $disallowed->{'cloners'}{'format'} .= $clonename.':'.$clonedom.',';
            return;
        } else {
            if (&Apache::lonnet::homeserver($clonename,$clonedom) eq 'no_host') {
                $disallowed->{'cloners'}{'newuser'} .= $clonename.':'.$clonedom.',';
                return;
            }
        }
    }
    return 'ok';
}

sub store_changes {
    my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_;
    my ($chome,$output);
    my (%storehash,@delkeys,@need_env_update,@oldcloner);
    if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) {
        %storehash = %{$values};
    } else {
        if ($crstype eq 'Community') {
            $output = &mt('No changes made to community settings.');
        } else {
            $output = &mt('No changes made to course settings.');
        }
        return $output;
    }
    my %yesno = (
                 hidefromcat           => '1',
                 problem_stream_switch => '1',
                 suppress_tries        => '1',
                 disableexampointprint => '1',
                 hideemptyrows         => '1',
                 suppress_embed_prompt => '1',
                );
    foreach my $item (@{$prefs_order}) {
        if (grep(/^\Q$item\E$/,@{$actions})) {
            $output .= '<h3>'.&mt($prefs->{$item}{'text'}).'</h3>';
            if (ref($changes->{$item}) eq 'HASH') {
                if (keys(%{$changes->{$item}}) > 0) {
                    $output .= &mt('Changes made:').'<ul>';
                    if ($item eq 'other') {
                        foreach my $key (sort(keys(%{$changes->{$item}}))) {
                            $storehash{$key} = $changes->{$item}{$key};
                            if ($changes->{$item}{$key} eq '') {
                                push(@delkeys,$key);
                                $output .= '<li>'.&mt('Deleted setting for [_1]','<i>'.$key.'</i>').'</li>';
                            } else {
                                $output .= '<li>'.&mt('[_1] set to [_2]','<i>'.$key.'</i>',
                                           "'$storehash{$key}'").'</li>';
                            }
                        }
                    } else {
                        if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') {
                            my @settings = @{$prefs->{$item}->{'ordered'}};
                            if ($item eq 'feedback') {
                                push(@settings,(map { $_.'.text'; } @settings));
                            }
                            foreach my $key (@settings) {
                                if ($key eq 'rolenames') {
                                    my $displayname = $prefs->{$item}->{'itemtext'}{$key};
                                    my $msg;
                                    my @roles;
                                    if ($crstype eq 'Community') {
                                        @roles = ('co');
                                    } else {
                                        @roles = ('cc');
                                    }
                                    push(@roles,('in','ta','ep','ad','st'));
                                    foreach my $role (@roles) {
                                        next if (!exists($changes->{$item}{$key.'_'.$role}));
                                        my $stdname = &Apache::lonnet::plaintext($role,$crstype,undef,1);
                                        my $newname = $changes->{$item}{$key.'_'.$role};
                                        $storehash{$role.'.plaintext'} = $newname;
                                        if ($newname eq '') {
                                            $newname = $stdname;
                                        }
                                        $msg .= '<li>'.&mt('[_1] set to [_2]','<i>'.$stdname.'</i>',
                                                "'<b>".$newname."</b>'").'</li>';
                                    }
                                    if ($msg ne '') {
                                        $output .= '<li>'.&mt($displayname).'<ul>'.$msg.'</ul></li>';
                                    }
                                } else {
                                    next if (!exists($changes->{$item}{$key}));
                                    my ($displayname,$text);
                                    $text = $prefs->{$item}->{'itemtext'}{$key};
                                    my $displayval;
                                    unless ($key eq 'co-owners') {
                                        $displayval = $changes->{$item}{$key};
                                    }
                                    if ($item eq 'feedback') {
                                        if ($key =~ /^(question|policy|comment)(\.email)\.text$/) {
                                            $text = $prefs->{$item}->{'itemtext'}{$1.$2};
                                            $displayname = &mt('Custom text for '.$text.' questions');
                                        } else {
                                            $displayname = &mt('Recipients of '.$text.' questions');
                                        }
                                    } elsif ($item eq 'discussion') {
                                        if ($key =~ /^p(lc|ch)\.roles\.denied/) {
                                            $displayname = &mt("$text (role-based)");
                                            if ($displayval ne '') {
                                                my @roles = split(',',$displayval);
                                                @roles = map { &Apache::lonnet::plaintext($_); } @roles;
                                                $displayval = join(', ',@roles);
                                            } 
                                        } elsif ($key =~ /^p(lc|ch)\.users\.denied/) {
                                            $displayname = &mt("$text (specific user(s))");
                                        } else {
                                            if ($key eq 'allow_discussion_post_editing') {
                                                if ($displayval ne '') {
                                                    my @roles = split(',',$displayval);
                                                    my @longroles;
                                                    foreach my $role (@roles) {
                                                        my ($trole,$sec) = split(':',$role);
                                                        my $rolename = 
                                                            &Apache::lonnet::plaintext($trole);
                                                        if ($sec ne '') {
                                                            $rolename .= ':'.$sec;
                                                        }
                                                        push(@longroles,$rolename);
                                                    }
                                                    $displayval = join(', ',@longroles);
                                                }
                                            }
                                            $displayname = &mt($text);
                                        }
                                    } elsif ($item eq 'spreadsheet') {
                                        if ($key =~ /^spreadsheet_default_(studentcalc|assesscalc)$/x) {
                                            my $sheettype = $1;
                                            if ($sheettype eq 'studentcalc') {
                                                &Apache::lonnet::expirespread('','','studentcalc');
                                            } else {
                                                &Apache::lonnet::expirespread('','','assesscalc');
                                                &Apache::lonnet::expirespread('','','studentcalc');
                                            }
                                        }
                                        $displayname = &mt($text);
                                    } else {
                                        $displayname = &mt($text);
                                    }
                                    if (defined($yesno{$key})) {
                                        $displayval = &mt('No');
                                        if ($changes->{$item}{$key} eq 'yes') {
                                            $displayval = &mt('Yes');         
                                        }
                                    } elsif (($key =~ /^default_enrollment_(start|end)_date$/) && ($displayval)) {
                                        $displayval = &Apache::lonlocal::locallocaltime($displayval);
                                    } elsif ($key eq 'categories') {
                                        $displayval = $env{'form.categories_display'};
                                    }
                                    if ($key eq 'co-owners') {
                                        if (ref($changes->{$item}{$key}) eq 'HASH') {
                                            if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') {
                                                foreach my $type ('co-owners','pendingco-owners') {
                                                    next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}}));
                                                    if ($type eq 'pendingco-owners') {
                                                        if (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                                                            $displayname = &mt('Invited as co-owners, pending acceptance');
                                                        }
                                                    }
                                                    if ($changes->{$item}{$key}{$type} eq '') {
                                                        push(@delkeys,'internal.'.$type);
                                                        if (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                                                            $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',
                                                            '<i>'.$displayname.'</i>')).'</li>';
                                                        }
                                                    } elsif (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                                                        $displayval = join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } split(',',$changes->{$item}{$key}{$type}));
                                                        $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
                                                                   '<i>'.$displayname.'</i>',
                                                                   "'<b>$displayval</b>'")).'</li>';
                                                    }
                                                }
                                            }
                                            unless (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                                                if ($env{'form.pending_coowoner'} eq 'accept') {
                                                        $displayval = &mt('on');
                                                } elsif ($env{'form.pending_coowoner'} eq 'decline') {
                                                        $displayval = '';
                                                        $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'</li>';
                                                } elsif ($env{'form.remove_coowoner'}) {
                                                    $displayval = &mt('off');
                                                }
                                                if ($displayval) {
                                                    $displayname = &mt('Your co-ownership status');
                                                    $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
                                                   '<i>'.$displayname.'</i>',
                                                   "'<b>$displayval</b>'")).'</li>';
                                                }
                                            }
                                        }
                                    } elsif ($changes->{$item}{$key} eq '') {
                                        push(@delkeys,$key);
                                        $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',
                                                   '<i>'.$displayname.'</i>')).'</li>';
                                    } else {
                                        $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
                                                   '<i>'.$displayname.'</i>',
                                                   "'<b>$displayval</b>'"));
                                        if ($key eq 'url') {
                                            my $bkuptime=time;
                                            $output .= ('&nbsp;'x2).&mt('(Previous URL backed up)').': '.
                                            $storehash{'top level map backup '.$bkuptime} => $values->{$key};
                                        }
                                        $output .= '</li>';
                                    }
                                    if ($key eq 'co-owners') {
                                        if (ref($changes->{$item}{$key}) eq 'HASH') {
                                            if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') {
                                                foreach my $type ('co-owners','pendingco-owners') {
                                                    next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}}));
                                                    $storehash{'internal.'.$type} = $changes->{$item}{$key}{$type};
                                                }
                                            }
                                        }
                                    } else {
                                        $storehash{$key} = $changes->{$item}{$key};
                                    }
                                }
                                if ($key eq 'cloners') {
                                    # Get existing cloners
                                    my %clonenames =
                                        &Apache::lonnet::dump('environment',$cdom,$cnum,'cloners');
                                    if ($clonenames{'cloners'} =~ /,/) {
                                        @oldcloner = split(/\s*\,\s*/,$clonenames{'cloners'});
                                    } else {
                                        $oldcloner[0] = $clonenames{'cloners'};
                                    }
                                }
                                if (($key eq 'description') || ($key eq 'cloners') ||
                                    ($key eq 'hidefromcat') || ($key eq 'categories') ||
                                    ($key eq 'co-owners')) {
                                    push(@need_env_update,$key);
                                }
                            }
                        }
                    }
                    $output .= '</ul>';
                } else {
                    if ($crstype eq 'Community') {
                        $output = &mt('No changes made to community settings.');
                    } else {
                        $output = &mt('No changes made to course settings.');
                    }
                }
            }
        }
    }
    if (&Apache::lonnet::put('environment',\%storehash,$cdom,$cnum) eq 'ok') {
        if (ref($changes) eq 'HASH') {
            if (ref($changes->{'courseinfo'}) eq 'HASH') {
                if (exists($changes->{'courseinfo'}{'cloners'})) {
                    &change_clone($cdom,$cnum,$changes->{'courseinfo'}{'cloners'},
                                  \@oldcloner);
                }
            }
        }
        if (@delkeys) {
            if (&Apache::lonnet::del('environment',\@delkeys,$cdom,$cnum) ne 'ok') {
                $output .= '<br /><span class="LC_error">';
                if ($crstype eq 'Community') {
                    $output .= &mt('An error occurred when removing community settings which are no longer in use.');
                } else {
                    $output .= &mt('An error occurred when removing course settings which are no longer in use.');
                }
                $output .= '</span>';
            }
        } else {
            foreach my $key (@delkeys) {
                &Apache::lonnet::delenv('course.'.$cdom.'_'.$cnum.'.'.$key);
            }
        }
        if (@need_env_update) {
            $chome = &Apache::lonnet::homeserver($cnum,$cdom);
            &update_env($cnum,$cdom,$chome,\@need_env_update,\%storehash);
        }
        &Apache::lonnet::coursedescription($env{'request.course.id'},
                                           {'freshen_cache' => 1});
    } else {
        $output = '<span class="LC_error">';
        if ($crstype eq 'Community') {
            $output .= &mt('An error occurred when saving changes to community settings, which remain unchanged.');
        } else {          
            $output .= &mt('An error occurred when saving changes to course settings, which remain unchanged.');
        }
        $output .= '</span>';
    }
    return $output;
}

sub update_env {
    my ($cnum,$cdom,$chome,$need_env_update,$storehash)  = @_;
    my $count = 0;
    if ((ref($need_env_update) eq 'ARRAY') && (ref($storehash) eq 'HASH')) {    
        my %crsinfo = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.');
        if (ref($crsinfo{$env{'request.course.id'}}) eq 'HASH') {
            foreach my $key (@{$need_env_update}) {
                if ($key eq 'description' && defined($storehash->{$key})) {
                    &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.description' => $storehash->{$key}});
                    $crsinfo{$env{'request.course.id'}}{'description'} = $storehash->{$key};
                    $count ++;
                } elsif (($key eq 'cloners') || ($key eq 'hidefromcat') || ($key eq 'categories')) {
                    &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash->{$key}});
                    $crsinfo{$env{'request.course.id'}}{$key} = $storehash->{$key};
                    $count ++;
                } elsif ($key eq 'co-owners') {
                    if ($storehash->{'internal.co-owners'} ne '') {
                        &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.internal.co-owners' => $storehash->{'internal.co-owners'}});
                    }
                    if ($storehash->{'internal.pendingco-owners'} ne '') {
                        &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.internal.pendingco-owners' => $storehash->{'internal.pendingco-owners'}});
                    }
                    my @coowners = split(',',$storehash->{'internal.'.$key});
                    $crsinfo{$env{'request.course.id'}}{'co-owners'} = \@coowners;
                    $count ++;
                }
            }
            if ($count) {
                my $putresult = &Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime');
            }
        }
    }
    return;
}

sub display_disallowed {
    my ($item,$disallowed,$prefs,$crstype) = @_;
    my $output;
    if ((ref($disallowed) eq 'HASH') && (ref($prefs) eq 'HASH')) {
        if (keys(%{$disallowed})) {
            if ($item eq 'cloners') {
                my @fails;
                my %lt = &Apache::lonlocal::texthash (
                                 format  => 'Invalid format',
                                 domain  => 'Domain does not exist',
                                 newuser => 'LON-CAPA user(s) do(es) not exist.',
                         );
                foreach my $error ('format','domain','newuser') {
                    if (defined($disallowed->{$error})) {
                        my $msg = '<b>'.$disallowed->{$error}.'</b>, '.&mt('reason').' - '.
                                  $lt{$error}; 
                        if ($error eq 'newuser') {
                            $msg .= '<br />'.&mt("Please [_1]add the user(s)[_2] before returning to the [_3]$crstype Configuration[_2] to add as potential cloners.",'<a href="/adm/createuser">','</a>','<a href="/adm/courseprefs">');
                        }
                        push(@fails,$msg);
                    }
                }
                if (@fails) {
                    $output .= '<span class="LC_warning">'.&mt('Unable to add to allowed cloners: ').
                               '</span>'.join(';&nbsp;&nbsp;',@fails).'.<br />';
                }
            } elsif ($item eq 'rolenames') {
                my %lt = &Apache::lonlocal::texthash (
                    replacements => 'Name already used to replace a different standard role name',
                    regulars     => 'Name already used as a standard role name',
                    customrole   => 'Name already used as the name of a custom role',
                );
                my @fails;
                foreach my $error ('replacements','regulars','customrole') {
                    if (ref($disallowed->{$error}) eq 'ARRAY') {
                        push(@fails,'<b>'.join(', ',@{$disallowed->{$error}}).
                                    '</b>, '.&mt('reason').' - '.$lt{'error'});
                    }
                }
                if (@fails) {
                    $output .= '<span class="LC_warning">'.
                               &mt('Unable to include amongst replacements for role names: ').
                               '</span>'.join(';&nbsp;&nbsp;',@fails).'.<br />';
                }

            } elsif (($item eq 'feedback') || ($item eq 'discussion') || ($item eq 'localization')) {
                $output .= '<span class="LC_warning">';
                if ($item eq 'feedback') {
                    if ($crstype eq 'Community') {
                        $output .= &mt('Unable to include as a recipient of community feedback for:');
                    } else {
                        $output .= &mt('Unable to include as a recipient of course feedback for:');
                    }
                } elsif ($item eq 'discussion') {
                    $output .= &mt('Unable to include in user-based access control for:');
                } elsif ($item eq 'localization') {
                    if ($crstype eq 'Community') {
                        $output .= &mt('Unable to include in community localization:');
                    } else {
                        $output .= &mt('Unable to include in course localization:');
                    }
                }
                $output .= '</span><ul>';
                foreach my $key (sort(keys(%{$disallowed}))) {
                    my $itemtext = $prefs->{$item}{'itemtext'}{$key};
                    $output .=  '<li><i>'.$itemtext.'</i> - ';
                    if ($item eq 'localization') {
                        $output .= &mt('reason - unsupported language: [_1]',
                                       '<b>'.$disallowed->{$key}.'</b>');
                    } else {
                        $output .= &mt('reason - invalid user: [_1]',
                                       '<b>'.$disallowed->{$key}.'</b>').'</li>';
                    }
                }
                $output .= '</ul><br />';
            }
        }
    }
    return $output;
}

sub get_course {
    my ($courseid) = @_;
    if (!defined($courseid)) {
        $courseid = $env{'request.course.id'};
    }
    my $cdom=$env{'course.'.$courseid.'.domain'};
    my $cnum=$env{'course.'.$courseid.'.num'};
    return ($cnum,$cdom);
}

sub get_jscript {
    my ($cdom,$phase,$crstype) = @_;
    my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype);
    my ($jscript,$categorize_js);
    my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript();
    my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset');
    my $cloners_js = &cloners_javascript($phase);
    if ($can_categorize) {
        $categorize_js = <<ENDSCRIPT;
function catsbrowser() {
    var catswin = null;
    var url = '/adm/courseprefs?phase=categorizecourse';
    if (!catswin || catswin.closed) {
        catswin=window.open(url,'categorieswin','height=480,width=600,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no');
    } else {
        catswin.focus();
    }
}
ENDSCRIPT
    }
    $jscript = '<script type="text/javascript" language="Javascript">'."\n".
               $browse_js."\n".$categorize_js."\n".$cloners_js."\n".'</script>'.
               "\n".$stubrowse_js."\n";
    return $jscript;
}

sub cloners_javascript {
    my ($formname) = @_;
    return <<"ENDSCRIPT";

function update_cloners(caller,num) {
    var delidx = getIndexByName('cloners_delete');
    var actidx = getIndexByName('cloners_activate');
    if (caller == 'cloners_all') {
        var selall;
        for (var i=0; i<document.$formname.cloners_all.length; i++) {
            if (document.$formname.cloners_all[i].checked) {
                selall = document.$formname.cloners_all[i].value;
            }
        }
        if (selall == 1) {
            if (delidx != -1) {
                if (document.$formname.cloners_delete.length) {
                    for (var j=0; j<document.$formname.cloners_delete.length; j++) {
                        document.$formname.cloners_delete[j].checked = true;
                    }
                } else {
                    document.$formname.elements[delidx].checked = true;
                }
            }
            if (actidx != -1) {
                if (document.$formname.cloners_activate.length) {
                    for (var i=0; i<document.$formname.cloners_activate.length; i++) {
                        if (document.$formname.cloners_activate[i].value == '0') {
                            document.$formname.cloners_activate[i].checked = false;
                        }
                        if (document.$formname.cloners_activate[i].value == '') {
                            document.$formname.cloners_activate[i].checked = true;
                        }
                    }
                }
            }
            document.$formname.cloners_newdom.selectedIndex = 0;
        }
    }
    if (caller == 'cloners_activate') {
        if (document.$formname.cloners_activate.length) {
            for (var j=0; j<document.$formname.cloners_activate.length; j++) {
                if (document.$formname.cloners_activate[j].value == num) {
                    if (document.$formname.cloners_activate[j].checked) {
                        for (var i=0; i<document.$formname.cloners_all.length; i++) {
                            if (document.$formname.cloners_all[i].value == '1') {
                                document.$formname.cloners_all[i].checked = false;
                            }
                            if (document.$formname.cloners_all[i].value == '0') {
                                document.$formname.cloners_all[i].checked = true;
                            }
                        }
                    }
                }
            }
        } else {
            for (var i=0; i<document.$formname.cloners_all.length; i++) {
                if (document.$formname.cloners_all[i].value == '1') {
                    document.$formname.cloners_all[i].checked = false;
                }
                if (document.$formname.cloners_all[i].value == '0') {
                    document.$formname.cloners_all[i].checked = true;
                }
            }
        }
    }
    return;
}

function getIndexByName(item) {
    for (var i=0;i<document.$formname.elements.length;i++) {
        if (document.$formname.elements[i].name == item) {
            return i;
        }
    }
    return -1;
}

ENDSCRIPT
}


sub print_courseinfo {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my ($cathash,$categoriesform,$autocoowner);
    my %domconf = 
        &Apache::lonnet::get_dom('configuration',['coursecategories','autoenroll'],$cdom);
    if (ref($domconf{'coursecategories'}) eq 'HASH') {
        $cathash = $domconf{'coursecategories'}{'cats'};
        if (ref($cathash) eq 'HASH') {
            $categoriesform = 
                &Apache::loncommon::assign_categories_table($cathash,
                                                $settings->{'categories'},$crstype)."\n";
        }
    }
    if (ref($domconf{'autoenroll'}) eq 'HASH') {
        $autocoowner = $domconf{'autoenroll'}{'co-owners'};
    }
    if (!defined($categoriesform)) {
        $categoriesform = &mt('No categories defined in this domain.');
    }

    my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype);

    my $replace;
    if ($crstype eq 'Community') {
        $replace = &mt('To replace the standard title for a course role, enter a title, otherwise leave blank');
    } else {
        $replace = &mt('To replace the standard title for a course role, enter a title, otherwise leave blank');
    }
    my %items = (
        'url' => {
                   text => '<b>'.&mt($itemtext->{'url'}).'</b>'.('&nbsp;'x2).
                           '<a href="javascript:openbrowser'.
                           "('display','url','sequence')\">".
                           &mt('Select Map').'</a><br /><span class="LC_warning"> '.
                           &mt('Modification may make assessment data inaccessible!').
                           '</span>',
                   input => 'textbox',
                   size  => '40',
                 },
        'description'  => { 
                   text => '<b>'.&mt($itemtext->{'description'}).'</b>',
                   input => 'textbox',
                   size  => '25',
                          },
        'owner'        => {
                   text => '<b>'.&mt($itemtext->{'owner'}).'</b>',
                          },
        'co-owners'    => {
                   text => '<b>'.&mt($itemtext->{'co-owners'}).'</b>',
                          },
        'courseid'     => { 
                   text => '<b>'.&mt($itemtext->{'courseid'}).'</b><br />'.'('.
                           &mt('internal, optional').')',
                   input => 'textbox',
                   size  => '25',
                          },
        'cloners'      => { 
                   text => '<b>'.&mt($itemtext->{'cloners'}).'</b><br />'.
                           &mt('Owner and Coordinators included automatically'),
                   input => 'textbox',
                   size  => '40',
                         },
        'rolenames'  => { 
                   text  => '<b>'.&mt($itemtext->{'rolenames'}).'</b><br />'.
                            '('.$replace.')',
                   input => 'textbox',
                   size  => '20',
                        },
        'externalsyllabus' => {
                   text => '<b>'.&mt($itemtext->{'externalsyllabus'}).'</b><br />('.
                           &mt('not using syllabus template)'),
                   input => 'textbox',
                   size  => '40',
                        },
        'hidefromcat' => {
                   text => '<b>'.&mt($itemtext->{'hidefromcat'}).'</b><br />'.
                           ' ('.&mt('included by default if assigned institutional code, or categorized').')',
                   input => 'radio',
                         },
        'categories' => {
                   text => '<b>'.&mt($itemtext->{'categories'}).'</b> <a href="javascript:catsbrowser()">'.
                           &mt('Display Categories').'</a>',
                   input => 'textbox',
                   size  => '25',
                        },
    );
    my $datatable;
    my $count = 0;
    foreach my $item (@{$ordered}) {
        if ($item eq 'hidefromcat') {
            next if (!$can_toggle_cat);
        } elsif ($item eq 'categories') {
            next if (!$can_categorize);
        }
        $count ++;
        $datatable .= &item_table_row_start($items{$item}{text},$count);
        if ($items{$item}{input} eq 'radio') {
            $datatable .= &yesno_radio($item,$settings);
        } elsif ($item eq 'cloners') {
            my $includeempty = 1;
            my $num = 0;
            $datatable .= &Apache::loncommon::start_data_table().
                          &Apache::loncommon::start_data_table_row().
                          '<td><span class="LC_nobreak"><label>'.
                          &mt('Any user in any domain:').
                          '&nbsp;<input type="radio" name="cloners_all" value="1" ';
            if ($settings->{$item} eq '*') {
                $datatable .= ' checked="checked" ';
            }
            $datatable .= 'onchange="javascript:update_cloners('.
                          "'cloners_all'".');" />'.&mt('Yes').'</label>'.
                          ('&nbsp;'x2).'<input type="radio" name="cloners_all" value="0" ';
            if ($settings->{$item} ne '*') {
                $datatable .= ' checked="checked" ';
            }
            $datatable .= ' onchange="javascript:update_cloners('.
                          "'cloners_all'".');"/>'.&mt('No').'</label></td>'.
                          &Apache::loncommon::end_data_table_row().
                          &Apache::loncommon::end_data_table().
                          '<table><tr><td align="left">'.&mt('Or').
                          '</td></tr></table>'.
                          &Apache::loncommon::start_data_table();
            my @cloners;
            if ($settings->{$item} eq '') {
                $datatable .= &new_cloners_dom_row($cdom,'0');
            } elsif ($settings->{$item} ne '*') {
                my @entries = split(/,/,$settings->{$item});
                if (@entries > 0) {
                    foreach my $entry (@entries) {
                        my ($uname,$udom) = split(/:/,$entry);
                        if ($udom =~ /^$match_domain$/) {
                            unless (&Apache::lonnet::domain($udom)) {
                                next;
                            }
                        } else {
                            next;
                        }
                        if ($uname eq '*') {
                            $datatable .= 
                                &Apache::loncommon::start_data_table_row().
                                '<td valign="top" align="left"><span class="LC_nobreak">'.
                                &mt('Any user in domain:').'<b>&nbsp;'.$udom.
                                '</b><input type="hidden" name="cloners_dom_'.$num.
                                '" value="'.$udom.'" /></span><br />'.
                                '<span class="LC_nobreak"><label><input type="checkbox" '.
                                'name="cloners_delete" value="'.$num.'" onchange="javascript:update_cloners('."'cloners_delete','$num'".');" />'.
                                &mt('Delete').'</label></span></td>'.
                                &Apache::loncommon::end_data_table_row();
                            $num ++;
                        } elsif (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') {
                            unless (grep(/^\Q$entry\E$/,@cloners)) {
                                push(@cloners,$entry);
                            }
                        }
                    }
                }
            }
            my $add_domtitle = &mt('Any user in additional domain:');
            if ($settings->{$item} eq '*') {
                $add_domtitle = &mt('Any user in specific domain:');
            } elsif ($settings->{$item} eq '') {
                $add_domtitle = &mt('Any user in other domain:');
            }
            my $cloners_str = join(',',@cloners);
            $datatable .= &Apache::loncommon::start_data_table_row().
                          '<td align="left"><span class="LC_nobreak">'.
                          $add_domtitle.'</span><br />'.
                          &Apache::loncommon::select_dom_form('','cloners_newdom',
                                                              $includeempty).
                          '<input type="hidden" name="cloners_total" value="'.$num.'" />'.
                          '</td>'.&Apache::loncommon::end_data_table_row().
                          &Apache::loncommon::end_data_table().
                          '<table><tr><td align="left">'.&mt('And').
                          '</td></tr></table>'.
                          &Apache::loncommon::start_data_table().
                          &Apache::loncommon::start_data_table_row().
                          '<td align="left">'.
                          &mt('Specific users').'&nbsp;(<tt>'.
                          &mt('user:domain,user:domain').'</tt>)<br />'.
                          &Apache::lonhtmlcommon::textbox($item,$cloners_str,
                                                          $items{$item}{'size'}).
                          '</td>'.&Apache::loncommon::end_data_table_row().
                          &Apache::loncommon::end_data_table();
        } elsif ($item eq 'rolenames') {
            $datatable .= &Apache::loncommon::start_data_table();
            my @roles;
            if ($crstype eq 'Community') {
                @roles = ('co');
            } else {
                @roles = ('cc');
            }
            push (@roles,('in','ta','ep','ad','st'));
            foreach my $role (@roles) {
                $datatable .= &Apache::loncommon::start_data_table_row().
                              '<td align="left"><span class="LC_nobreak">'.
                              &Apache::lonnet::plaintext($role,$crstype,undef,1).
                              '</span></td><td align="left">'.
                              &Apache::lonhtmlcommon::textbox('rolenames_'.$role,
                                                 $settings->{$role.'.plaintext'},
                                                 $items{$item}{size}).'</td>'.
                              &Apache::loncommon::end_data_table_row();
            }
            $datatable .= &Apache::loncommon::end_data_table().'</td>';
        } elsif ($item eq 'categories') {
            my $launcher = 'onFocus="this.blur();javascript:catsbrowser();";';
            $datatable .= '<input type="hidden" name="categories" value="'.$settings->{$item}.'" />'.
                          &Apache::lonhtmlcommon::textbox($item.'_display',$settings->{$item},
                                                          $items{$item}{size},$launcher);
        } elsif ($item eq 'owner') {
            my $owner = $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'};
            if ($owner =~ /:/) {
                my ($ownername,$ownerdom) = split(':',$owner);
                $owner = &Apache::loncommon::plainname($ownername,$ownerdom);
            } elsif ($owner ne '') {
                $owner = &Apache::loncommon::plainname($owner,$cdom);
            } else {
                $owner = &mt('None specified');
            }
            my $domdesc = &Apache::lonnet::domain($cdom,'description');
            $datatable .= $owner;
        } elsif ($item eq 'co-owners') {
            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
            my $coowners = $env{'course.'.$env{'request.course.id'}.'.internal.co-owners'};
            my @currcoown;
            if ($coowners) {
                @currcoown = split(',',$coowners);
            }
            if (&Apache::lonnet::is_course_owner($cdom,$cnum)) {
                if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) {
                    $datatable .= &show_autocoowners(@currcoown);
                } else {
                    $datatable .= &coowner_invitations($cnum,$cdom,@currcoown);
                }
            } else {
                if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) {
                    $datatable .= &show_autocoowners(@currcoown);
                } else {
                    $datatable .= &manage_coownership($cnum,$cdom,@currcoown);
                }
            }
        } else {
            $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size});
        }
        $datatable .= &item_table_row_end();
    }
    $$rowtotal += scalar(@{$ordered});
    return $datatable;
}

sub new_cloners_dom_row {
    my ($newdom,$num) = @_;
    my $output;
    if ($newdom ne '') {
        $output .= &Apache::loncommon::start_data_table_row().
                   '<td valign="top"><span class="LC_nobreak">'.
                   &mt('Any user in domain:').'&nbsp;<b>'.$newdom.'</b>'.
                   ('&nbsp;'x2).'<label><input type="radio" '.
                   'name="cloners_activate" value="'.$num.'" '.
                   'onchange="javascript:update_cloners('.
                   "'cloners_activate','$num'".');" />'.
                   &mt('Yes').'</label>'.('&nbsp;'x2).
                   '<label><input type="radio" '.
                   'name="cloners_activate" value="" checked="checked" '.
                   'onchange="javascript:update_cloners('.
                   "'cloners_activate','$num'".');" />'.
                   &mt('No').'</label><input type="hidden" name="cloners_dom_'.
                   $num.'" value="'.$newdom.'" /></span></td>'.
                   &Apache::loncommon::end_data_table_row();
    }
    return $output;
}

sub can_modify_catsettings {
    my ($dom,$crstype) = @_;
    my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$dom);
    my ($can_toggle_cat,$can_categorize);
    if (ref($domconf{'coursecategories'}) eq 'HASH') {
        if ($crstype eq 'Community') {
            if ($domconf{'coursecategories'}{'togglecatscomm'} eq 'comm') {
                $can_toggle_cat = 1;
            }
            if ($domconf{'coursecategories'}{'categorizecomm'} eq 'comm') {
                $can_categorize = 1;
            }
        } else {
            if ($domconf{'coursecategories'}{'togglecats'} eq 'crs') {
                $can_toggle_cat = 1;
            }
            if ($domconf{'coursecategories'}{'categorize'} eq 'crs') {
                $can_categorize = 1;
            }
        }
    }
    return ($can_toggle_cat,$can_categorize);
}

sub assign_course_categories {
    my ($r,$crstype) = @_;
    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
    my $hascats = 0;
    my $cathash;
    my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$cdom);
    if (ref($domconf{'coursecategories'}) eq 'HASH') {
        $cathash = $domconf{'coursecategories'}{'cats'};
        if (ref($cathash) eq 'HASH') {
            foreach my $cat (keys(%{$cathash})) {
                next if ($cat eq 'instcode::0');
                unless ($crstype eq 'Community') {
                    next if ($cat eq 'communities::0');
                }
                $hascats ++; 
            }
        }
    }
    my $catwin_js;
    if ($hascats) {
        my $alert;
        if ($crstype eq 'Community') {
            $alert = &mt("Use 'Save' in the main window to save community categories");
        } else {
            $alert = &mt("Use 'Save' in the main window to save course categories");
        }
        $catwin_js = <<ENDSCRIPT;
<script type="text/javascript">

function updateCategories() {
    var newcategories = '';
    var unescapedcats = '';
    if (document.chgcats.usecategory.length) {
        for (var i=0; i<document.chgcats.usecategory.length; i++) {
            if (document.chgcats.usecategory[i].checked == true) {
                newcategories = newcategories + document.chgcats.usecategory[i].value + '&';
                unescapedcats = unescapedcats + document.chgcats.catname[i].value + ' & ';
            }
        }
        if (newcategories.length > 0) {
            newcategories = newcategories.slice(0,-1);
        }
        if (unescapedcats.length > 0) {
            unescapedcats = unescapedcats.slice(0,-3);
        }
    } else {
         if (document.chgcats.usecategory.checked == true) {
             newcategories = document.chgcats.usecategory.value;
             unescapedcats = document.chgcats.catname.value;
         }
    }
    opener.document.display.categories.value = newcategories;
    opener.document.display.categories_display.value = unescapedcats;
    alert("$alert");
    self.close();
    return;
}

</script>
ENDSCRIPT
    } else {
        my $onload;
    }
    my ($crscat,$catcrs,$assign);
    if ($crstype eq 'Community') {
        $crscat = 'Community Categories';
        $catcrs = &mt('Categorize Community');
        $assign = &mt('Assign one or more categories to this community.')
    } else {
        $crscat = 'Course Categories';
        $catcrs = &mt('Categorize Course');
        $assign = &mt('Assign one or more categories to this course.')
    }
    my $start_page =
        &Apache::loncommon::start_page($crscat,$catwin_js,
                                       {'only_body'      => 1,});
    my $end_page = &Apache::loncommon::end_page();
    my $categoriesform = '<h3>'.$catcrs.'</h3>';
    if ($hascats) {
        my %currsettings =
            &Apache::lonnet::get('environment',['hidefromcat','categories'],$cdom,$cnum);
        my $cattable = &Apache::loncommon::assign_categories_table($cathash,
                                       $currsettings{'categories'},$crstype);
        if ($cattable eq '') {
            $categoriesform .= &mt('No suitable categories defined for this course type in this domain.'); 
        } else {
            $categoriesform .= $assign.'<br /><br />'.
                               '<form name="chgcats" action="/adm/courseprefs" method="post">'."\n".
                               $cattable."\n".
                               '<br /><input type="button" name="changes" value="'.
                               &mt('Copy to main window').'" '.
                               'onclick="javascript:updateCategories()" /></form><br />';
        }
    } else {
        $categoriesform .= &mt('No categories defined in this domain.');
    }
    $r->print($start_page.$categoriesform.$end_page);
    return;
}

sub show_autocoowners {
    my (@currcoown) = @_;
    my $output = '<i>'.&mt('Co-ownership is set automatically when a Course Coordinator role is assigned to official course personnel (from institutional data).').'</i>';
    if (@currcoown > 0) {
        $output .= '<br />'.&mt('Current co-owners are:').'&nbsp;'.
                   join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown));
    } else {
        $output .= '<br />'.&mt('Currently no co-owners.');
    }
    return $output;
}

sub coowner_invitations {
    my ($cnum,$cdom,@currcoown) = @_;
    my ($output,@pendingcoown,@othercoords);
    my $pendingcoowners =
        $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'};
    if ($pendingcoowners) {
        @pendingcoown = split(',',$pendingcoowners);
    }
    my $ccrole = 'cc';
    my %ccroles = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,undef,[$ccrole]);
    foreach my $key (sort(keys(%ccroles))) {
        my ($ccname,$ccdom,$role) = split(':',$key);
        next if ($key eq $env{'user.name'}.':'.$env{'user.domain'}.':'.$ccrole);
        unless (grep(/^\Q$ccname\E:\Q$ccdom\E$/,@currcoown,@pendingcoown)) {
            push(@othercoords,$ccname.':'.$ccdom);
        }
    }
    my $coowner_rows = @currcoown + @pendingcoown + @othercoords;
    if ($coowner_rows) {
        $output .= &Apache::loncommon::start_data_table();
        if (@currcoown) {
            $output .= &Apache::loncommon::start_data_table_row().
                          '<td><i>'.&mt('Current co-owners').'</i></td><td>';
            foreach my $person (@currcoown) {
                my ($co_uname,$co_dom) = split(':',$person);
                $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="coowners" checked="checked" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.('&nbsp;'x2).' ';
            }
            $output .= '</td>'.
                          &Apache::loncommon::end_data_table_row();
        }
        if ($pendingcoowners) {
            $output .= &Apache::loncommon::start_data_table_row().
                          '<td><i>'.&mt('Invited as co-owners [_1](agreement pending)','<br />').'</i></td><td>';
            foreach my $person (@pendingcoown) {
                my ($co_uname,$co_dom) = split(':',$person);
                $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="pendingcoowners" checked="checked" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.('&nbsp;'x2).' ';
            }
            $output .= '</td>'.
                       &Apache::loncommon::end_data_table_row();
        }
        if (@othercoords) {
            $output .= &Apache::loncommon::start_data_table_row().
                          '<td><i>'.&mt('Invite other Coordinators [_1]to become co-owners','<br />').'</i></td><td>';
            foreach my $person (@othercoords) {
                my ($co_uname,$co_dom) = split(':',$person);
                $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="invitecoowners" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.('&nbsp;'x2).' ';
            }
            $output .= '</td>'.
                          &Apache::loncommon::end_data_table_row();
        }
        $output .= &Apache::loncommon::end_data_table();
    } else {
        $output = &mt('There are no coordinators to select as co-owners');
    }
    return $output;
}

sub manage_coownership  {
    my ($cnum,$cdom,@currcoown) = @_;
    my (@pendingcoown);
    my $pendingcoowners =
        $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'};
    if ($pendingcoowners) {
        @pendingcoown = split(',',$pendingcoowners);
    }
    my ($is_coowner,$is_pending,$output);
    my $uname = $env{'user.name'};
    my $udom = $env{'user.domain'};
    if (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) {
        $is_coowner = 1;
    }
    if (grep(/^\Q$uname\E:\Q$udom\E$/,@pendingcoown)) {
        $is_pending = 1;
    }
    if (@currcoown && ($is_coowner || $is_pending)) {
        $output = &Apache::loncommon::start_data_table();
    }
    if (@currcoown) {
        if ($is_coowner || $is_pending) {
            $output .= &Apache::loncommon::start_data_table().
                       &Apache::loncommon::start_data_table_row().'<td>';
        }
        $output .= &mt('Current co-owners are:').'&nbsp;'.
                   join(', ', map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown));
        if ($is_coowner || $is_pending) {
            $output .= '</td>'.&Apache::loncommon::end_data_table_row();
        }
    }
    if ($is_coowner || $is_pending) {
        if (@currcoown) {
            $output .= &Apache::loncommon::start_data_table_row().'<td>';
        }
        $output .= '<span class="LC_nobreak">';
        if ($is_coowner) {
            $output .= &mt('You are currently a co-owner:').'&nbsp;<label><input type="checkbox" name="remove_coowoner" value="'.$uname.':'.$udom.'" />'.&mt('Discontinue?').'</label>';
        } else {
            $output .= &mt('The course owner has invited you to become a co-owner:').'&nbsp;<label><input type="radio" name="pending_coowoner" value="accept" />'.&mt('Accept?').'</label>'.('&nbsp;'x2).
                       '<label><input type="radio" name=pending_coowoner" value="decline" />'.&mt('Decline?').'</label>';
        }
        $output .= '</span>';
        if (@currcoown) {
            $output .= '</td>'.&Apache::loncommon::end_data_table_row();
        }
    }
    if (@currcoown && ($is_coowner || $is_pending)) {
        $output .= &Apache::loncommon::end_data_table();
    }
    return $output;
}

sub print_localization {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my %items = (
        languages => {
                        text => &mt($itemtext->{'languages'}).'<br />'.
                                &mt("(will override user's preference)"),
                        input => 'selectbox',
                     }, 
        timezone => {
                        text  => &mt($itemtext->{'timezone'}),
                        input => 'selectbox',
                    },
        datelocale  => { 
                         text => &mt($itemtext->{'datelocale'}),
                         input => 'selectbox',
                       },
    );
    my $datatable;
    my $count = 0;
    foreach my $item (@{$ordered}) {
        $count ++;
        $datatable .= &item_table_row_start($items{$item}{text},$count);
        if ($item eq 'timezone') {
            my $includeempty = 1;
            my $timezone = &Apache::lonlocal::gettimezone();
            $datatable .= 
                &Apache::loncommon::select_timezone($item,$timezone,undef,
                                                    $includeempty);
        } elsif ($item eq 'datelocale') {
            my $includeempty = 1;
            my $locale_obj = &Apache::lonlocal::getdatelocale();
            my $currdatelocale;
            if (ref($locale_obj)) {
                $currdatelocale = $locale_obj->id();
            }
            $datatable .= 
                &Apache::loncommon::select_datelocale($item,$currdatelocale,
                                                      undef,$includeempty);
        } else {
            if ($settings->{$item} eq '') {
                $datatable .= 
                    &Apache::loncommon::select_language('languages_0','',1);
            } else {
                my $num = 0;
                my @languages = split(/\s*[,;:]\s*/,$settings->{$item});
                $datatable .= &Apache::loncommon::start_data_table();
                if (@languages > 0) {
                    my %langchoices = &get_lang_choices();
                    foreach my $lang (@languages) {
                        my $showlang = $lang;
                        if (exists($langchoices{$lang})) {
                            $showlang = $langchoices{$lang};
                        }
                        $datatable .=
                            &Apache::loncommon::start_data_table_row().
                            '<td align="left"><span class="LC_nobreak">'.
                            &mt('Language:').'<b>&nbsp;'.$showlang.
                            '</b><input type="hidden" name="languages_'.$num.
                            '" value="'.$lang.'" /></span><br />'.
                            '<span class="LC_nobreak"><label><input type="checkbox" '.
                            'name="languages_delete" value="'.$num.'" />'.
                            &mt('Delete').'</label></span></td>'.
                            &Apache::loncommon::end_data_table_row();
                            $num ++;
                    }
                }
                $datatable .= &Apache::loncommon::start_data_table_row().
                              '<td align="left"><span class="LC_nobreak">'.
                              &mt('Additional language:'). '</span><br />'.
                              &Apache::loncommon::select_language('languages_'.$num,'',1).
                              '<input type="hidden" name="languages_total" value="'.$num.'" />'.
                              '</td>'.&Apache::loncommon::end_data_table_row().
                              &Apache::loncommon::end_data_table();
            }
        }
        $datatable .= &item_table_row_end();
    }
    $$rowtotal += scalar(@{$ordered});
    return $datatable;
}

sub get_lang_choices {
    my %langchoices;
    foreach my $id (&Apache::loncommon::languageids()) {
        my $code = &Apache::loncommon::supportedlanguagecode($id);
        if ($code) {
            $langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id);
        }
    }
    return %langchoices;
}

sub print_feedback {
    my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my %items = (
        'question.email' => {
                   text => '<b>'.&mt($itemtext->{'question.email'}).'</b>',
                   input => 'textbox',
                   size  => '50',
                 },

        'comment.email'  => {
                   text => '<b>'.&mt($itemtext->{'comment.email'}).'</b>',
                   input => 'textbox',
                   size  => '50',
                 },

        'policy.email'   => {
                   text => '<b>'.&mt($itemtext->{'policy.email'}).'</b>',
                   input => 'textbox',
                   size  => '50',
                 },
    );
    my $datatable;
    my $count = 0;
    my ($cnum) = &get_course();
    my %sections = &Apache::loncommon::get_sections($cdom,$cnum);
    my @sections = sort( { $a <=> $b } keys(%sections));
    my %lt = &Apache::lonlocal::texthash (
                                           currone  => 'Current recipient:',
                                           currmult => 'Current recipients:',
                                           add      => 'Additional recipient:',
                                           del      => 'Delete?',
                                           sec      => 'Sections:',
                                         );

    foreach my $item (@{$ordered}) {
        $count ++;
        $datatable .= &item_table_row_start($items{$item}{text},$count);
        if ($position eq 'top') {
            my $includeempty = 0;
            $datatable .= &user_table($cdom,$item,\@sections,
                                      $settings->{$item},\%lt);
        } else {
            $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text',
                              $settings->{$item.'.text'},$items{$item}{size});  
        }
        $datatable .= &item_table_row_end();
    }
    $$rowtotal += scalar(@{$ordered});
    return $datatable;
}

sub user_table {
    my ($cdom,$item,$sections,$currvalue,$lt) = @_;
    my $output;
    if ($currvalue eq '') {
        $output .= &select_recipient($item,'0',$cdom,$sections);
    } else {
        my $num = 0;
        my @curr = split(/,/,$currvalue);
        $output .= '<table class="LC_nested_outer">';
        my ($currusers);
        foreach my $val (@curr) {
            next if ($val eq '');
            my ($uname,$udom,$seclist) = ($val =~ /^($match_username):($match_domain)(\(?[^\)]*\)?)$/);
            my @selsec;
            if ($seclist) {
                $seclist =~ s/(^\(|\)$)//g;
                @selsec = split(/\s*;\s*/,$seclist);
            }
            $currusers .= '<tr>'.
                        '<td valign="top"><span class="LC_nobreak">'.
                        '<label><input type="checkbox" '.
                        'name="'.$item.'_delete" value="'.$num.'" />'.
                        $lt->{'del'}.'</label>'.
                        '<input type="hidden" name="'.$item.'_user_'.
                        $num.'" value="'.$uname.':'.$udom.'" />'.('&nbsp;'x2).
                        &Apache::loncommon::aboutmewrapper(
                            &Apache::loncommon::plainname($uname,$udom,'firstname'),
                            $uname,$udom,'aboutuser');
            if (ref($sections) eq 'ARRAY') {
                if (@{$sections}) {
                    $currusers.= ('&nbsp;'x3).$lt->{'sec'}.'&nbsp;'.
                                  &select_sections($item,$num,$sections,
                                  \@selsec);
                }
            }
            $currusers .= '</span></td></tr>';
            $num ++;
        }
        if ($num) {
            $output .= '<tr>'.
                       '<td align="left"><i>';
            if ($num == 1) {
                $output .= $lt->{'currone'};
            } else {
                $output .= $lt->{'currmult'};
            }
            $output .= '</i><br />'.
                          '<table>'.$currusers.'</table></td>'.
                          '</tr>';
        }
        $output .= '<tr>'.
                  '<td align="left"><span class="LC_nobreak"><i>'.
                  $lt->{'add'}.'</i></span><br />'.
                  &select_recipient($item,$num,$cdom,$sections).
                  '<input type="hidden" name="'.$item.'_total" value="'.$num.'" />'.
                  '</td></tr></table>';
    }
    return $output;
}

sub select_recipient {
    my ($item,$num,$cdom,$sections,$selected,$includeempty) = @_;
    my $domform = &Apache::loncommon::select_dom_form($cdom,$item.'_udom_'.$num,$includeempty);
    my $selectlink =
        &Apache::loncommon::selectstudent_link('display',$item.'_uname_'.$num,
                                               $item.'_udom_'.$num,1);
    my $output = 
        '<table><tr><td align="center">'.&mt('Username').'<br />'.
        '<input type="text" name="'.$item.'_uname_'.$num.'" value="" /></td>'.
        '<td align="center">'.&mt('Domain').'<br />'.$domform.'</td>';
    if (ref($sections) eq 'ARRAY') {
        if (@{$sections}) {
            $output .= '<td align="center">'.&mt('Sections').'<br />'.
                       &select_sections($item,$num,$sections,$selected).'</td>'; 
        }
    }
    $output .= '<td valign="top">'.
               $selectlink.'</td></tr></table>';
    return $output;
}

sub select_sections {
    my ($item,$num,$sections,$selected) = @_;
    my ($output,@currsecs,$allsec);
    if (ref($selected) eq 'ARRAY') {
        @currsecs = @{$selected};
    }
    if (!@currsecs) {
        $allsec = ' selected="selected"';
    }
    if (ref($sections) eq 'ARRAY') {
        if (@{$sections}) {
            my $mult;
            if (@{$sections} > 1) {
                $mult = ' multiple="multiple"';
                if (@{$sections} > 3) {
                    $mult .= ' size="4"';
                }
            }
            $output = '<select name="'.$item.'_sections_'.$num.'"'.$mult.'>'.
                      ' <option value=""'.$allsec.'>'.&mt('All').'</option>';
            foreach my $sec (@{$sections}) {
                my $is_sel;
                if ((@currsecs) && (grep(/^\Q$sec\E$/,@currsecs))) {
                    $is_sel = 'selected="selected"';
                }
                $output .= '<option value="'.$sec.'"'.$is_sel.'>'.$sec.'</option>';
            }
            $output .= '</select>';
        }
    }
    return $output;
}

sub print_discussion {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my %items = (
        'plc.roles.denied' => {
                   text => '<span class="LC_nobreak"><b>'.&mt($itemtext->{'plc.roles.denied'}).'</b>'.
                           &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'</span><br />'.
                           &mt('(role-based)'),
                   input => 'checkbox',
                 },

        'plc.users.denied'  => {
                   text => '<b>'.&mt($itemtext->{'plc.users.denied'}).'</b><br />'.
                           &mt('(specific user(s))'),
                   input => 'checkbox',
                 },

        'pch.roles.denied'   => {
                   text => '<span class="LC_nobreak"><b>'.&mt($itemtext->{'pch.roles.denied'}).'</b>'.
                           &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'</span><br />'.
                           &mt('(role-based)'),
                   input => 'checkbox',
                 },

        'pch.users.denied'   => {
                   text => '<b>'.&mt($itemtext->{'pch.users.denied'}).'</b><br />'.
                           &mt('(specific user(s))'),
                   input => 'checkbox',
                 },
        'allow_limited_html_in_feedback' => {
                   text => '<b>'.&mt($itemtext->{'allow_limited_html_in_feedback'}).'</b>',
                   input => 'radio',
                 },

        'allow_discussion_post_editing' => {
                   text => '<b>'.&mt($itemtext->{'allow_discussion_post_editing'}).'</b>',
                   input => 'checkbox',
                 },
    );
    my $datatable;
    my $count;
    my ($cnum) = &get_course();
    my %sections = &Apache::loncommon::get_sections($cdom,$cnum);
    my @sections = sort( { $a <=> $b } keys(%sections));
    my %lt = &Apache::lonlocal::texthash (
                                          currone  => 'Disallowed:',
                                          currmult => 'Disallowed:',
                                          add      => 'Disallow more:',
                                          del      => 'Delete?',
                                          sec      => 'Sections:',
                                         );

    foreach my $item (@{$ordered}) {
        $count ++;
        $datatable .= &item_table_row_start($items{$item}{text},$count);
        if ($item eq 'plc.roles.denied') {
            $datatable .= '<table>'.&role_checkboxes($cdom,$cnum,$item,$settings).
                          '</table>';
        } elsif ($item eq 'plc.users.denied') {
            $datatable .= &user_table($cdom,$item,undef,
                                      $settings->{$item},\%lt);
        } elsif ($item eq 'pch.roles.denied') {
            $datatable .= '<table>'.&role_checkboxes($cdom,$cnum,$item,$settings).
                          '</table>';
        } elsif ($item eq 'pch.users.denied') {
            $datatable .= &user_table($cdom,$item,undef,
                                      $settings->{$item},\%lt);
        } elsif ($item eq 'allow_limited_html_in_feedback') {
            $datatable .= &yesno_radio($item,$settings);
        } elsif ($item eq 'allow_discussion_post_editing') {
            $datatable .= &Apache::loncommon::start_data_table().
                          &Apache::loncommon::start_data_table_row().
                          '<th align="left">'.&mt('Role').'</th><th>'.
                          &mt('Sections').'</th>'.
                          &Apache::loncommon::end_data_table_row().
                          &role_checkboxes($cdom,$cnum,$item,$settings,1).
                          &Apache::loncommon::end_data_table();
        }
        $datatable .= &item_table_row_end();
    }
    $$rowtotal += scalar(@{$ordered});
    return $datatable;
}

sub role_checkboxes {
    my ($cdom,$cnum,$item,$settings,$showsections,$crstype) = @_;
    my @roles = ('st','ad','ta','ep','in');
    if ($crstype eq 'Community') {
        push(@roles,'co');
    } else {
        push(@roles,'cc');
    }
    my $output;
    my (@current,@curr_roles,%currsec,@sections);
    if ($showsections) {
        my %sections = &Apache::loncommon::get_sections($cdom,$cnum);
        @sections = sort( { $a <=> $b } keys(%sections));
    }
    if (ref($settings) eq 'HASH') {
        if ($settings->{$item}) {
            @current = split(',',$settings->{$item});
            if ($showsections) {
                foreach my $role (@current) {
                    if ($role =~ /:/) {
                        my ($trole,$sec) = split(':',$role);
                        push(@curr_roles,$trole);
                        if (ref($currsec{$trole}) eq 'ARRAY') {
                            if (!grep(/^\Q$sec\E/,@{$currsec{$trole}})) {
                                push(@{$currsec{$trole}},$sec);
                            }
                        } else {
                            $currsec{$trole} = [$sec];
                        }
                    } else {
                        push(@curr_roles,$role);
                    }
                }
                @current = @curr_roles;
            }
        }
    }
    my $numinrow = 3;
    my $count = 0;
    foreach my $role (@roles) {
        my $checked = '';
        if (grep(/^\Q$role\E$/,@current)) {
            $checked = ' checked="checked" ';
        }
        my $plrole=&Apache::lonnet::plaintext($role,$crstype);
        if ($showsections) {
            $output .= &Apache::loncommon::start_data_table_row();
        } else {
            my $rem = $count%($numinrow);
            if ($rem == 0) {
                if ($count > 0) {
                    $output .= '</tr>';
                }
                $output .= '<tr>';
            }
        }
        $output .= '<td align="left"><span class="LC_nobreak"><label><input type="checkbox" name="'.
                   $item.'" value="'.$role.'"'.$checked.'/>&nbsp;'.
                   $plrole.'</label></span></td>';
        if ($showsections) {
            $output .= '<td align="left">'.
                       &select_sections($item,$role,\@sections,$currsec{$role}).
                       '</td></tr>';
        }
        $count ++;
    }
    my %adv_roles =
        &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1);
    my $total = @roles;
    foreach my $role (sort(keys(%adv_roles))) {
        if ($role =~ m{^cr/($match_domain)/($match_name)/\w$}) {
            my $rolename = $3;
            my $value = 'cr_'.$1.'_'.$2.'_'.$rolename;
            my $checked = '';
            if (grep(/^\Q$value\E$/,@current)) {
                $checked = ' checked="checked" ';
            }
            if ($showsections) {
                $output .= &Apache::loncommon::start_data_table_row();
            } else {
                my $rem = $count%($numinrow);
                if ($rem == 0) {
                    if ($count > 0) {
                        $output .= '</tr>';
                    }
                    $output .= '<tr>';
                }
            }
            $output .= '<td><span class="LC_nobreak"><label><input type="checkbox" name="'.
                       $item.'" value="'.$value.'"'.$checked.' />&nbsp;'.$rolename.
                       '</label></span></td>';
            if ($showsections) {
                $output .= '<td>'.
                           &select_sections($item,$role,\@sections,$currsec{$role}).
                           '</td>'.&Apache::loncommon::end_data_table_row();
            }
            $total ++;
            $count ++;
        }
    }
    if (!$showsections) {
        my $rem = $total%($numinrow);
        my $colsleft = $numinrow - $rem;
        if ($colsleft > 1 ) {
            $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                       '&nbsp;</td>';
        } elsif ($colsleft == 1) {
            $output .= '<td class="LC_left_item">&nbsp;</td>';
        }
        $output .= '</tr>';
    }
    return $output;
}

sub print_classlists {
    my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype) = @_;
    my @ordered;
    if ($position eq 'top') {
        @ordered = ('default_enrollment_start_date',
                    'default_enrollment_end_date');
    } elsif ($position eq 'middle') {
        @ordered = ('nothideprivileged');
    } else {
        @ordered = ('student_classlist_view',
                    'student_classlist_opt_in',
                    'student_classlist_portfiles');
    }
    my %lt;

    if ($crstype eq 'Community') {
        %lt = &Apache::lonlocal::texthash (
                 disabled => 'No viewable membership list',
                 section  => "Membership of viewer's section",
                 all      => 'List of all members',
              );
    } else {
        %lt = &Apache::lonlocal::texthash (
                 disabled => 'No viewable classlist',
                 section  => "Classlist of viewer's section",
                 all      => 'Classlist of all students',
              );
    }

    my %items = (
        'default_enrollment_start_date' => {
                   text => '<b>'.&mt($itemtext->{'default_enrollment_start_date'}).'</b>',
                   input => 'dates',
                 },
        'default_enrollment_end_date'  => {
                   text => '<b>'.&mt($itemtext->{'default_enrollment_end_date'}).'</b>',
                   input => 'dates',
                 },

        'nothideprivileged'   => {
                   text => '<b>'.&mt($itemtext->{'nothideprivileged'}).'</b>',
                   input => 'checkbox',
                 },

        'student_classlist_view'   => {
                   text => '<b>'.&mt($itemtext->{'student_classlist_view'}).'</b>',
                   input => 'selectbox',
                   options => \%lt,
                   order => ['disabled','all','section'],
                 },
        'student_classlist_opt_in' => {
                   text => '<b>'.&mt($itemtext->{'student_classlist_opt_in'}).'</b>',
                   input => 'radio',
                 },

        'student_classlist_portfiles' => {
                   text => '<b>'.&mt($itemtext->{'student_classlist_portfiles'}).'</b>',
                   input => 'radio',
                 },
    );
    unless (($settings->{'student_classlist_view'} eq 'all') || 
            ($settings->{'student_classlist_view'} eq 'section')) { 
        $settings->{'student_classlist_view'} = 'disabled';
    }
    return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype);
}

sub print_appearance {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my $mathdef;
    if ($crstype eq 'Community') {
        $mathdef = &mt("None specified - use member's choice");
    } else {
        $mathdef = &mt("None specified - use student's choice");
    }
    my %items = (
        'default_xml_style' => {
                   text => '<b>'.&mt($itemtext->{'default_xml_style'}).'</b> '.
                           '<a href="javascript:openbrowser'.
                           "('display','default_xml_style'".
                           ",'sty')".'">'.&mt('Select Style File').'</a>',
                   input => 'textbox',
                   size => 35,
                 },

        'pageseparators'  => {
                   text => '<b>'.&mt($itemtext->{'pageseparators'}).'</b>',
                   input => 'radio',
                 },
        'disable_receipt_display' => {
                   text => '<b>'.&mt($itemtext->{'disable_receipt_display'}).'</b>',
                   input => 'radio',
                 },
        'texengine'  => {
                   text => '<b>'.&mt($itemtext->{'texengine'}).'</b>',
                   input => 'selectbox',
                   options => {
                                jsMath   => 'jsMath',
                                mimetex => &mt('Convert to Images'),
                                tth      => &mt('TeX to HTML'),
                              },
                   order  => ['jsMath','mimetex','tth'],
                   nullval => $mathdef,
                 },
        'tthoptions' => {
                   text => '<b>'.&mt($itemtext->{'tthoptions'}).'</b>',
                   input => 'textbox',
                   size => 40,
                 },
    );
    return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype);
}

sub print_grading {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my %items = (
        'grading'  => {
                   text => '<b>'.&mt($itemtext->{'grading'}).'</b>'.
                           &Apache::loncommon::help_open_topic('GradingOptions'),
                   input => 'selectbox',
                   options => {
                                standard => &mt('Standard: shows points'),
                                external => &mt('External: shows number of completed parts and totals'),
                                externalnototals => &mt('External: shows only number of completed parts'),
                                spreadsheet => &mt('Spreadsheet: (with link to detailed scores)'), 
                              },
                   order => ['standard','external','externalnototals','spreadsheet'],
                 },
        'rndseed' => {
                   text => '<b>'.&mt($itemtext->{'rndseed'}).'</b>'.
                           '<span class="LC_error">'.'<br />'.
                           &mt('Modifying this will make problems have different numbers and answers!').
                           '</span>',
                   input => 'selectbox',
                   options => {
                                '32bit'  => '32bit',
                                '64bit'  => '64bit',
                                '64bit2' => '64bit2',
                                '64bit3' => '64bit3',
                                '64bit4' => '64bit4',
                                '64bit5' => '64bit5',
                              },
                   order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'],
                 },
        'receiptalg'  => {
                   text => '<b>'.&mt($itemtext->{'receiptalg'}).'</b><br />'.
                           &mt('This controls how receipt numbers are generated'),
                   input => 'selectbox',
                   options => {
                                receipt  => 'receipt',
                                receipt2 => 'receipt2',
                                receipt3 => 'receipt3',
                              },
                   order => ['receipt','receipt2','receipt3'],
                 },
        'disablesigfigs' => {
                   text => '<b>'.&mt($itemtext->{'disablesigfigs'}).'</b>',
                   input => 'radio',
                 },
    );
    return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype);
}

sub print_printouts {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my %items = (
        problem_stream_switch => {
            text => '<b>'.&mt($itemtext->{'problem_stream_switch'}).'</b>',
            input => 'radio',
                                 },
        suppress_tries => {
            text => '<b>'.&mt($itemtext->{'suppress_tries'}).'</b>',
            input => 'radio',
                          },
        default_paper_size => {
            text => '<b>'.&mt($itemtext->{'default_paper_size'}).'</b>',
            input => 'selectbox',
            options => {
                         Letter    => &mt('Letter').' [8 1/2x11 in]',
                         Legal     => &mt('Legal').' [8 1/2x14 in]',
                         Tabloid   => &mt('Tabloid').' [11x17 in]',
                         Executive => &mt('Executive').' [7 1/2x10 in]',
                         A2        => &mt('A2').' [420x594 mm]',
                         A3        => &mt('A3').' [297x420 mm]',
                         A4        => &mt('A4').' [210x297 mm]',
                         A5        => &mt('A5').' [148x210 mm]',
                         A6        => &mt('A6').' [105x148 mm]',
                       },
            order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'],
            nullval => 'None specified',
                              },
        print_header_format => {
            text => '<b>'.&mt($itemtext->{'print_header_format'}).'</b>',
            input => 'checkbox',
                               },
        disableexampointprint => {
            text => '<b>'.&mt($itemtext->{'disableexampointprint'}).'</b>',
            input => 'radio',
                                 },
    );
    return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype);
}

sub print_spreadsheet {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my $SelectSpreadsheetFile=&mt('Select Spreadsheet File');
    my %items = (
        spreadsheet_default_classcalc => {
            text => '<b>'.&mt($itemtext->{'spreadsheet_default_classcalc'}).'</b> '.
                    '<span class="LC_nobreak"><a href="javascript:openbrowser'.
                    "('display','spreadsheet_default_classcalc'".
                    ",'spreadsheet')".'">'.$SelectSpreadsheetFile.'</a></span>',
            input => 'textbox',
                                         },
        spreadsheet_default_studentcalc => {
            text => '<b>'.&mt($itemtext->{'spreadsheet_default_studentcalc'}).'</b> '.
                    '<span class="LC_nobreak"><a href="javascript:openbrowser'.
                    "('display','spreadsheet_default_calc'".
                    ",'spreadsheet')".'">'.$SelectSpreadsheetFile.'</a></span>',
            input => 'textbox',
                                           },
        spreadsheet_default_assesscalc => {
            text => '<b>'.&mt($itemtext->{'spreadsheet_default_assesscalc'}).'</b> '.
                    '<span class="LC_nobreak"><a href="javascript:openbrowser'.
                    "('display','spreadsheet_default_assesscalc'".
                    ",'spreadsheet')".'">'.$SelectSpreadsheetFile.'</a></span>',
            input => 'textbox',
                                          },
        hideemptyrows => {
            text => '<b>'.&mt($itemtext->{'hideemptyrows'}).'</b>',
            input => 'radio',
                         },
                );
    return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype);
}

sub print_bridgetasks {
    my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
        return;
    }
    my ($stumsg,$msgnote);
    if ($crstype eq 'Community') {
        $stumsg = &mt('Send message to member');
        $msgnote = &mt('Message to member and add to user notes');
    } else {
        $stumsg = &mt('Send message to student');
        $msgnote = &mt('Message to student and add to user notes');
    }
    my %items = (
         task_messages => {
              text => '<b>'.&mt($itemtext->{'task_messages'}).'</b>',
              input => 'selectbox',
              options => {
                           only_student => $stumsg,
                           student_and_user_notes_screen => $msgnote,
                         },
              order   => ['only_student','student_and_user_notes_screen'],
              nullval => &mt('No message or record in user notes'),
                          },
         task_grading => {
              text => '<b>'.&mt($itemtext->{'task_grading'}).'</b>',
              input => 'selectbox',
              options => {
                           any => &mt('Grade BTs in any section'),
                           section => &mt('Grade BTs only in own section')
                         },
              order => ['any','section'],
                         },
         suppress_embed_prompt => {
             text => '<b>'.&mt($itemtext->{'suppress_embed_prompt'}).'</b><span class="LC_nobreak">'.
                     '&nbsp;'.&mt('(applies when current role is student)').'</span>',
             input => 'radio',
                                  },
                );
    return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype);
}

sub print_other {
    my ($cdom,$settings,$allitems,$rowtotal,$crstype) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) {
        return;
    }
    my @ordered = &get_other_items($cdom,$settings,$allitems);
    my %items;
    foreach my $parameter (@ordered) {
        $items{$parameter} = {
                               text  => '<b>'.$parameter.'</b>',
                               input => 'textbox',
                               size  => '15',
                             },
    }
    push (@ordered,'newp_value');
    $items{'newp_value'} = {
                            text  => '<b>'.&mt('Create New Environment Variable').'</b><br />'.
                                     '<input type="textbox" name="newp_name"'.
                                     ' value="" size="30" />',
                            input => 'textbox',
                            size  => '30',
                           };
    my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype);
}

sub get_other_items {
    my ($cdom,$settings,$allitems) = @_;
    unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) {
        return;
    }
    my @ordered;
    if (ref($settings) eq 'HASH') {
        foreach my $parameter (sort(keys(%{$settings}))) {
            next if (grep/^\Q$parameter\E$/,@{$allitems});
            next if (($parameter eq 'course.helper.not.run') &&
                     (!exists($env{'user.role.dc./'.$env{'request.role.domain'}.'/'})));
            unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./) ||
                    ($parameter =~ m/^selfenroll_/) || ($parameter =~ /_selfenroll$/)
                    || ($parameter eq 'type') ||
                    ($parameter =~ m/^(cc|co|in|ta|ep|ad|st)\.plaintext$/)) {
                push(@ordered,$parameter);
            }
        }
    }
    return @ordered;
}

sub item_table_row_start {
    my ($text,$count) = @_;
    my $output;
    if ($count%2) {
        $output .= '<tr class="LC_odd_row">';
    } else {
        $output .= '<tr>';
    }
    $output .= '<td class="LC_left_item">'.$text.
               '</td><td class="LC_right_item" align="right">';
    return $output;
}

sub item_table_row_end {
    return '</td></tr>';
}

sub yesno_radio {
    my ($item,$settings) = @_;
    my $itemon = ' ';
    my $itemoff = ' checked="checked" ';
    if (ref($settings) eq 'HASH') {
        if ($settings->{$item} eq 'yes') {
            $itemon = $itemoff;
            $itemoff = ' ';
        }
    }
    return '<span class="LC_nobreak"><label>'.
           '<input type="radio" name="'.$item.'"'.
           $itemon.' value="yes" />'.&mt('Yes').'</label>&nbsp;'.
           '<label><input type="radio" name="'.$item.'"'.
           $itemoff.' value="" />'.&mt('No').'</label></span>';
}

sub select_from_options {
    my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange) = @_;
    my $output;
    if ((ref($order) eq 'ARRAY') && (ref($options) eq 'HASH')) {
        $output='<select name="'.$item.'" '.$onchange;
        if ($multiple) {
            $output .= ' multiple="multiple"';
            my $num = @{$order};
            $num ++ if ($nullval ne '');
            if (($maxsize) && ($maxsize < $num)) {
                $output .= ' size="'.$maxsize.'"';
            }
        }
        $output .= '>'."\n";
        if ($nullval ne '') {
            $output .= '<option value=""';
            if (ref($curr) eq 'ARRAY') {
                if ((@{$curr} == 0) || (grep(/^$/,@{$curr}))) {
                    $output .= ' selected="selected" ';
                }
            } else {
                if ($curr eq '') {
                    $output .= ' selected="selected" ';
                }
            }
            $output .= '>'.$nullval.'</option>';
        }
        foreach my $option (@{$order}) {
            $output.= '<option value="'.$option.'"';
            if (ref($curr) eq 'ARRAY') {
                if (grep(/^\Q$option\E$/,@{$curr})) {
                    $output .= ' selected="selected" ';
                }
            } else {
                if ($option eq $curr) {
                    $output.=' selected="selected"';
                }
            }
            $output.=">$options->{$option}</option>\n";
        }
        $output.="</select>";
    }
    return $output;
}

sub make_item_rows {
    my ($cdom,$items,$ordered,$settings,$rowtotal,$crstype) = @_;
    my $datatable;
    if ((ref($items) eq 'HASH') && (ref($ordered) eq 'ARRAY')) {
        my $count = 0;
        foreach my $item (@{$ordered}) {
            $count ++;
            $datatable .= &item_table_row_start($items->{$item}{text},$count);
            if ($item eq 'nothideprivileged') {
                $datatable .= &nothidepriv_row($cdom,$item,$settings,$crstype);
            } elsif ($item eq 'print_header_format') {
                $datatable .= &print_hdrfmt_row($item,$settings);
            } elsif ($items->{$item}{input} eq 'dates') {
               $datatable .=
                   &Apache::lonhtmlcommon::date_setter('display',$item,
                                                       $settings->{$item});
            } elsif ($items->{$item}{input} eq 'radio') {
                $datatable .= &yesno_radio($item,$settings);
            } elsif ($items->{$item}{input} eq 'selectbox') {
                my $curr = $settings->{$item};
                $datatable .=
                    &select_from_options($item,$items->{$item}{'order'},
                                         $items->{$item}{'options'},$curr,
                                         $items->{$item}{'nullval'});
            } elsif ($items->{$item}{input} eq 'textbox') {
                $datatable .= 
                    &Apache::lonhtmlcommon::textbox($item,$settings->{$item},
                                                    $items->{$item}{size});
            }
            $datatable .= &item_table_row_end();
        }
        if (ref($rowtotal)) {
            $$rowtotal += scalar(@{$ordered});
        }
    }
    return $datatable;
}

sub nothidepriv_row {
    my ($cdom,$item,$settings,$crstype) = @_;
    my ($cnum) = &get_course();
    my %nothide;
    my $datatable;
    if (ref($settings) eq 'HASH') {
        if ($settings->{$item} ne '') {
            foreach my $user (split(/\s*\,\s*/,$settings->{$item})) {
                if ($user !~ /:/) {
                    $nothide{join(':',split(/[\@]/,$user))}=1;
                } else {
                    $nothide{$user} = 1;
                }
            }
        }
    }
    my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
    my $now = time;
    my @privusers;
    my %privileged;
    foreach my $person (keys(%coursepersonnel)) {
        my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
        $user =~ s/:$//;
        my ($end,$start) = split(/:/,$coursepersonnel{$person});
        if ($end == -1 || $start == -1) {
            next;
        }
        my ($uname,$udom) = split(':',$user);
        unless (ref($privileged{$udom}) eq 'HASH') {
            my %dompersonnel = &Apache::lonnet::get_domain_roles($udom,['dc'],undef,$now);
            $privileged{$udom} = {};
            if (keys(%dompersonnel)) {
                foreach my $server (keys(%dompersonnel)) {
                    foreach my $user (sort(keys(%{$dompersonnel{$server}}))) {
                        my ($trole,$uname,$udom) = split(/:/,$user); 
                        $privileged{$udom}{$uname} = $trole;
                    }
                }
            }
        }
        if (exists($privileged{$udom}{$uname})) {
            unless (grep(/^\Q$user\E$/,@privusers)) {
                push(@privusers,$user);
            }
        }
    }
    if (@privusers) {
        $datatable .= '<table align="right">';
        foreach my $user (sort(@privusers)) {
            my $hideon = ' checked="checked" ';
            my $hideoff = '';
            if ($nothide{$user}) {
                $hideoff = $hideon;
                $hideon = '';
            }
            my ($uname,$udom) = split(':',$user);
            $datatable .=  '<tr><td align="left">'.
                           &Apache::loncommon::aboutmewrapper(
                           &Apache::loncommon::plainname($uname,$udom,'firstname'),
                           $uname,$udom,'aboutuser').
                          '</td><td align="left">'.
                          '<span class="LC_nobreak"><label>'.
                          '<input type="radio" name="'.$item.'_'.$user.'"'.
                          $hideon.' value="" />'.&mt('Hidden').'</label>&nbsp;'.
                          '<label><input type="radio" name="'.$item.'_'.$user.'"'.                          $hideoff.' value="yes" />'.&mt('Shown').'</label></span></td>'.
                          '</tr>';
        }
        $datatable .= '</table>';
    } else {
        if ($crstype eq 'Community') {
            $datatable .= &mt('No Domain Coordinators have community roles');
        } else {
            $datatable .= &mt('No Domain Coordinators have course roles');
        }
    }
    return $datatable;
}

sub print_hdrfmt_row {
    my ($item,$settings) = @_;
    my @curr;
    my $currnum = 0;
    my $maxnum = 2;
    my $currstr;
    if ($settings->{$item} ne '') {
        $currstr .= '<b>'.&mt('Current print header:').' <span class="LC_warning"><tt>'.
                   $settings->{$item}.'</tt></span></b><br />';
        my @current = split(/(%\d*[nca])/,$settings->{$item});
        foreach my $val (@current) {
            unless ($val eq '') {
                push(@curr,$val);
            }
        }
        $currnum = @curr;
        $maxnum += $currnum;
    }

    my $output = <<ENDJS;

<script type="text/javascript" language="Javascript">

function reOrder(chgnum) {
    var maxnum = $maxnum;
    var oldidx = 'printfmthdr_oldpos_'+chgnum;
    var newidx = 'printfmthdr_pos_'+chgnum;
    oldidx = getIndexByName(oldidx);
    newidx = getIndexByName(newidx);
    var oldpos = document.display.elements[oldidx].value;
    var newpos = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value;
    document.display.elements[oldidx].value = newpos;
    var chgtype = 'up';
    if (newpos < oldpos) {
        chgtype = 'down';
    }
    for (var j=0; j<maxnum; j++) {
        if (j != chgnum) {
            oldidx = 'printfmthdr_oldpos_'+j;
            newidx = 'printfmthdr_pos_'+j;
            oldidx = getIndexByName(oldidx);
            newidx = getIndexByName(newidx);
            var currpos = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value;
            var currsel = document.display.elements[newidx].selectedIndex;
            if (chgtype == 'up') {
                if ((currpos > oldpos) && (currpos <= newpos)) {
                    document.display.elements[newidx].selectedIndex = currsel-1;
                    document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value;
                }
            } else {
                if ((currpos >= newpos) && (currpos < oldpos)) {
                    document.display.elements[newidx].selectedIndex = currsel+1;
                    document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value;
                }
            }
        }
    }
    return;
}

function getIndexByName(item) {
    for (var i=0;i<document.display.elements.length;i++) {
        if (document.display.elements[i].name == item) {
            return i;
        }
    }
    return -1;
}

</script>

ENDJS
    $output .= $currstr.'<table class="LC_nested_outer">';
    if (@curr > 0) {
        for (my $i=0; $i<@curr; $i++) {
            my $pos = $i+1;
            $output .= '<tr>'.
                       '<td align="left"><span class="LC_nobreak">'.
                       &position_selector($pos,$i,$maxnum).&mt('Delete:').
                       '<input type="checkbox" name="printfmthdr_del_'.$i.
                       '" /></span></td>';
            if ($curr[$i] =~ /^%\d*[nca]$/) {
                my ($limit,$subst) = ($curr[$i] =~ /^%(\d*)([nca])$/);
                $output .= '<td align="left">'.
                           &substitution_selector($i,$subst,$limit).'</td>';
            } else {
                $output .= '<td colspan="2" align="left">'.&mt('Text').'<br />'.
                           '<input type="textbox" name="printfmthdr_text_'.$i.'"'.
                           ' value="'.$curr[$i].'" size="25" /></td>';
            }
            $output .= '</tr>';
        }
    }
    my $pos = $currnum+1; 
    $output .= '<tr>'.
               '<td align="left"><span class="LC_nobreak">'.
               &position_selector($pos,$currnum,$maxnum).
               '<b>'.&mt('New').'</b></span></td><td align="left">'.
               &substitution_selector($currnum).'</td>'.
               '</tr>'; 
    $pos ++;
    $currnum ++;
    $output .= '<tr>'.
               '<td align="left"><span class="LC_nobreak">'.
               &position_selector($pos,$currnum,$maxnum).
               '<b>'.&mt('New').'</b></span></td>'.
               '<td colspan="2" align="left">'.&mt('Text').'<br />'.
               '<input type="textbox" name="printfmthdr_text_'.$currnum.
               '" value="" size ="25" />'.
               '<input type="hidden" name="printfmthdr_maxnum" value="'.
                $maxnum.'" /></td>'.
               '</tr>'.
               '</table>'; 
    return $output;
}

sub position_selector {
    my ($pos,$num,$maxnum) = @_;
    my $output = '<select name="printfmthdr_pos_'.$num.'" onchange="reOrder('."'$num'".');">';
    for (my $j=1; $j<=$maxnum; $j++) {
        my $sel = '';
        if ($pos == $j) {
            $sel = ' selected="selected"';
        }
        $output .= '<option value="'.$j.'"'.$sel.'">'.$j.'</option>';
    }
    $output .= '</select><input type="hidden" name="printfmthdr_oldpos_'.$num.
               '" value="'.$pos.'" />';
    return $output;
}

sub substitution_selector {
    my ($num,$subst,$limit,$crstype) = @_;
    my ($stunametxt,$crsidtxt);
    if ($crstype eq 'Community') {
        $stunametxt = 'member name';
        $crsidtxt = 'community ID',
    } else {
        $stunametxt = 'student name';
        $crsidtxt = 'course ID',
    }
    my %lt = &Apache::lonlocal::texthash(
                    n => $stunametxt,
                    c => $crsidtxt,
                    a => 'assignment note',
             );
    my $output .= &mt('Substitution').'<br />'.
                  '<select name="printfmthdr_sub_'.$num.'">';
    if ($subst eq '') {
        $output .= '<option value="" selected="selected"> </option>';
    }
    foreach my $field ('n','c','a') {
        my $sel ='';
        if ($subst eq $field) {
            $sel = ' selected="selected"';
        }
        $output .= '<option value="'.$field.'"'.$sel.'>'.
                   $lt{$field}.'</option>';
    }
    $output .= '</select></td><td align="left">'.&mt('Size limit').'<br />'.
               '<input type="textbox" name="printfmthdr_limit_'.$num.
               '" value="'.$limit.'" size="5" /></span>';
    return $output;
}

sub change_clone {
    my ($cdom,$cnum,$clonelist,$oldcloner) = @_;
    my $clone_crs = $cnum.':'.$cdom;
    if ($cnum && $cdom) {
        my $clone_crs = $cnum.':'.$cdom;
        my @allowclone;
        if ($clonelist =~ /,/) {
            @allowclone = split(',',$clonelist);
        } else {
            $allowclone[0] = $clonelist;
        }
        foreach my $currclone (@allowclone) {
            if (!grep(/^$currclone$/,@$oldcloner)) {
                if ($currclone ne '*') {
                    my ($uname,$udom) = split(/:/,$currclone);
                    if ($uname && $udom && $uname ne '*') {
                        if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') {
                            my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable');
                            if ($currclonecrs{'cloneable'} !~ /\Q$clone_crs\E/) {
                                if ($currclonecrs{'cloneable'} eq '') {
                                    $currclonecrs{'cloneable'} = $clone_crs;
                                } else {
                                    $currclonecrs{'cloneable'} .= ','.$clone_crs;
                                }
                                &Apache::lonnet::put('environment',\%currclonecrs,$udom,$uname);
                            }
                        }
                    }
                }
            }
        }
        foreach my $oldclone (@$oldcloner) {
            if (!grep(/^\Q$oldclone\E$/,@allowclone)) {
                if ($oldclone ne '*') {
                    my ($uname,$udom) = split(/:/,$oldclone);
                    if ($uname && $udom && $uname ne '*' ) {
                        if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') {
                            my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable');
                            my %newclonecrs = ();
                            if ($currclonecrs{'cloneable'} =~ /\Q$clone_crs\E/) {
                                if ($currclonecrs{'cloneable'} =~ /,/) {
                                    my @currclonecrs = split/,/,$currclonecrs{'cloneable'};
                                    foreach my $crs (@currclonecrs) {
                                        if ($crs ne $clone_crs) {
                                            $newclonecrs{'cloneable'} .= $crs.',';
                                        }
                                    }
                                    $newclonecrs{'cloneable'} =~ s/,$//;
                                } else {
                                    $newclonecrs{'cloneable'} = '';
                                }
                                &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname);
                            }
                        }
                    }
                }
            }
        }
    }
    return;
}

1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.