Annotation of loncom/interface/lonparmset.pm, revision 1.625

1.1       www         1: # The LearningOnline Network with CAPA
                      2: # Handler to set parameters for assessments
                      3: #
1.625   ! raeburn     4: # $Id: lonparmset.pm,v 1.624 2025/06/30 21:12:21 raeburn Exp $
1.40      albertel    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
1.59      matthew    28: ###################################################################
                     29: ###################################################################
                     30: 
                     31: =pod
                     32: 
                     33: =head1 NAME
                     34: 
                     35: lonparmset - Handler to set parameters for assessments and course
                     36: 
                     37: =head1 SYNOPSIS
                     38: 
1.579     raeburn    39: lonparmset provides an interface to setting content parameters in a 
                     40: course.
1.560     damieng    41: 
                     42: It contains all the code for the "Content and Problem Settings" UI, except
                     43: for the helpers parameter.helper and resettimes.helper, and lonhelper.pm,
                     44: and lonblockingmenu.pm.
1.59      matthew    45: 
                     46: =head1 DESCRIPTION
                     47: 
                     48: This module sets coursewide and assessment parameters.
                     49: 
                     50: =head1 INTERNAL SUBROUTINES
                     51: 
1.416     jms        52: =over
1.59      matthew    53: 
1.416     jms        54: =item parmval()
1.59      matthew    55: 
                     56: Figure out a cascading parameter.
                     57: 
1.71      albertel   58: Inputs:  $what - a parameter spec (incluse part info and name I.E. 0.weight)
1.162     albertel   59:          $id   - a bighash Id number
1.71      albertel   60:          $def  - the resource's default value   'stupid emacs
                     61: 
1.556     raeburn    62: Returns:  A list, the first item is the index into the remaining list of items of parm values that is the active one, the list consists of parm values at the 18 possible levels
1.71      albertel   63: 
1.556     raeburn    64: 18 - General Course
                     65: 17 - Map or Folder level in course (recursive) 
                     66: 16 - Map or Folder level in course (non-recursive)
                     67: 15 - resource default
                     68: 14 - map default
                     69: 13 - resource level in course
                     70: 12 - General for section
                     71: 11 - Map or Folder level for section (recursive)
                     72: 10 - Map or Folder level for section (non-recursive)
                     73: 9 - resource level in section
                     74: 8 - General for group
                     75: 7 - Map or Folder level for group (recursive)
                     76: 6 - Map or Folder level for group (non-recursive)
                     77: 5 - resource level in group
                     78: 4 - General for specific student
                     79: 3 - Map or Folder level for specific student (recursive)
                     80: 2 - Map or Folder level for specific student (non-recursive)
1.71      albertel   81: 1 - resource level for specific student
1.2       www        82: 
1.416     jms        83: =item parmval_by_symb()
                     84: 
                     85: =item reset_caches()
                     86: 
                     87: =item cacheparmhash() 
                     88: 
                     89: =item parmhash()
                     90: 
                     91: =item symbcache()
                     92: 
                     93: =item preset_defaults()
                     94: 
                     95: =item date_sanity_info()
                     96: 
                     97: =item storeparm()
                     98: 
                     99: Store a parameter by symb
                    100: 
                    101:     Takes
                    102:     - symb
                    103:     - name of parameter
                    104:     - level
                    105:     - new value
                    106:     - new type
                    107:     - username
                    108:     - userdomain
                    109: 
                    110: =item log_parmset()
                    111: 
                    112: =item storeparm_by_symb_inner()
                    113: 
                    114: =item valout()
                    115: 
                    116: Format a value for output.
                    117: 
                    118: Inputs:  $value, $type, $editable
                    119: 
                    120: Returns: $value, formatted for output.  If $type indicates it is a date,
                    121: localtime($value) is returned.
                    122: $editable will return an icon to click on
                    123: 
                    124: =item plink()
                    125: 
                    126: Produces a link anchor.
                    127: 
                    128: Inputs: $type,$dis,$value,$marker,$return,$call
                    129: 
                    130: Returns: scalar with html code for a link which will envoke the 
                    131: javascript function 'pjump'.
                    132: 
                    133: =item page_js()
                    134: 
                    135: =item startpage()
                    136: 
                    137: =item print_row()
                    138: 
                    139: =item print_td()
                    140: 
1.580     raeburn   141: =item check_other_groups()
1.416     jms       142: 
                    143: =item parm_control_group()
                    144: 
                    145: =item extractResourceInformation() : 
                    146: 
1.512     foxr      147:  extractResourceInformation extracts lots of information about all of the the course's resources into a variety of hashes.
1.416     jms       148: 
1.542     raeburn   149: Input: See list below
                    150: 
                    151: =over 4
1.416     jms       152: 
1.512     foxr      153: =item * B<env{'user.name'}> : Current username
1.416     jms       154: 
1.512     foxr      155: =item * B<env{'user.domain'}> : Domain of current user.
1.416     jms       156: 
1.542     raeburn   157: =item * B<env{"request.course.fn"}> : Course
                    158: 
                    159: =back
1.416     jms       160: 
1.512     foxr      161: Outputs: See list below:
1.416     jms       162: 
1.542     raeburn   163: =over 4
                    164: 
1.512     foxr      165: =item * B<ids> (out) : An array that will contain all of the ids in the course.
1.416     jms       166: 
1.512     foxr      167: =item * B<typep>(out) : hash, id->type, where "type" contains the extension of the file, thus, I<problem exam quiz assess survey form>.
1.416     jms       168: 
1.512     foxr      169: =item * B<keyp> (out) : hash, id->key list, will contain a comma separated list of the meta-data keys available for the given id
1.416     jms       170: 
1.512     foxr      171: =item * B<allparms> (out) : hash, name of parameter->display value (what is the display value?)
1.416     jms       172: 
1.512     foxr      173: =item * B<allparts> (out) : hash, part identification->text representation of part, where the text representation is "[Part $part]"
                    174: 
                    175: =item * B<allmaps> (out) : hash, ???
1.416     jms       176: 
                    177: =item * B<mapp> : ??
                    178: 
                    179: =item * B<symbp> : hash, id->full sym?
                    180: 
1.512     foxr      181: =item * B<maptitles>
                    182: 
                    183: =item * B<uris>
1.416     jms       184: 
1.512     foxr      185: =item * B<keyorder>
                    186: 
                    187: =item * B<defkeytype>
1.416     jms       188: 
1.542     raeburn   189: =back
                    190: 
1.416     jms       191: =item isdateparm()
                    192: 
                    193: =item parmmenu()
                    194: 
                    195: =item partmenu()
                    196: 
                    197: =item usermenu()
                    198: 
                    199: =item displaymenu()
                    200: 
                    201: =item mapmenu()
                    202: 
                    203: =item levelmenu()
                    204: 
                    205: =item sectionmenu()
                    206: 
                    207: =item keysplit()
                    208: 
                    209: =item keysinorder()
                    210: 
                    211: =item keysinorder_bytype()
                    212: 
                    213: =item keysindisplayorder()
                    214: 
                    215: =item standardkeyorder()
                    216: 
                    217: =item assessparms() : 
                    218: 
                    219: Show assessment data and parameters.  This is a large routine that should
                    220: be simplified and shortened... someday.
                    221: 
1.513     foxr      222: Inputs: $r - the Apache request object.
                    223:   
1.416     jms       224: Returns: nothing
                    225: 
                    226: Variables used (guessed by Jeremy):
                    227: 
1.542     raeburn   228: =over
                    229: 
1.416     jms       230: =item * B<pscat>: ParameterS CATegories? ends up a list of the types of parameters that exist, e.g., tol, weight, acc, opendate, duedate, answerdate, sig, maxtries, type.
                    231: 
                    232: =item * B<psprt>: ParameterS PaRTs? a list of the parts of a problem that we are displaying? Used to display only selected parts?
                    233: 
                    234: =item * B<@catmarker> contains list of all possible parameters including part #s
                    235: 
                    236: =item * B<$fullkeyp> contains the full part/id # for the extraction of proper parameters
                    237: 
                    238: =item * B<$tempkeyp> contains part 0 only (no ids - ie, subparts)
                    239:         When storing information, store as part 0
                    240:         When requesting information, request from full part
                    241: 
1.542     raeburn   242: =back
                    243: 
1.416     jms       244: =item tablestart()
                    245: 
                    246: =item tableend()
                    247: 
                    248: =item extractuser()
                    249: 
                    250: =item parse_listdata_key()
                    251: 
                    252: =item listdata()
                    253: 
                    254: =item date_interval_selector()
                    255: 
                    256: =item get_date_interval_from_form()
                    257: 
                    258: =item default_selector()
                    259: 
                    260: =item string_selector()
                    261: 
                    262: =item dateshift()
                    263: 
                    264: =item newoverview()
                    265: 
                    266: =item secgroup_lister()
                    267: 
                    268: =item overview()
                    269: 
                    270: =item clean_parameters()
                    271: 
                    272: =item date_shift_one()
                    273: 
                    274: =item date_shift_two()
                    275: 
                    276: =item parse_key()
                    277: 
                    278: =item header()
                    279: 
                    280: Output html header for page
                    281: 
                    282: =item print_main_menu()
                    283: 
                    284: =item output_row()
                    285: 
                    286: Set portfolio metadata
                    287: 
                    288: =item order_meta_fields()
                    289: 
                    290: =item addmetafield()
                    291: 
                    292: =item setrestrictmeta()
                    293: 
                    294: =item get_added_meta_fieldnames()
                    295: 
                    296: =item get_deleted_meta_fieldnames()
                    297: 
                    298: =item defaultsetter()
                    299: 
                    300: =item components()
                    301: 
                    302: =item load_parameter_names()
                    303: 
                    304: =item parm_change_log()
                    305: 
                    306: =item handler() : 
                    307: 
1.450     raeburn   308: Main handler.  Calls &assessparms subroutine.
1.416     jms       309: 
                    310: =back
                    311: 
1.59      matthew   312: =cut
                    313: 
1.416     jms       314: ###################################################################
                    315: ###################################################################
                    316: 
                    317: package Apache::lonparmset;
                    318: 
                    319: use strict;
                    320: use Apache::lonnet;
                    321: use Apache::Constants qw(:common :http REDIRECT);
                    322: use Apache::lonhtmlcommon();
                    323: use Apache::loncommon;
                    324: use GDBM_File;
                    325: use Apache::lonhomework;
                    326: use Apache::lonxml;
                    327: use Apache::lonlocal;
                    328: use Apache::lonnavmaps;
                    329: use Apache::longroup;
                    330: use Apache::lonrss;
1.506     www       331: use HTML::Entities;
1.623     raeburn   332: use POSIX qw (floor);
1.617     raeburn   333: use Text::Wrap();
1.416     jms       334: use LONCAPA qw(:DEFAULT :match);
                    335: 
                    336: 
1.560     damieng   337: ##################################################
                    338: # CONTENT AND PROBLEM SETTINGS HTML PAGE HEADER/FOOTER
                    339: ##################################################
                    340: 
                    341: # Page header
1.561     damieng   342: #
                    343: # @param {Apache2::RequestRec} $r - Apache request object
                    344: # @param {string} $mode - selected tab, 'parmset' for course and problem settings, or 'coursepref' for course settings
                    345: # @param {string} $crstype - course type ('Community' for community settings)
1.507     www       346: sub startSettingsScreen {
1.531     raeburn   347:     my ($r,$mode,$crstype)=@_;
1.507     www       348: 
1.531     raeburn   349:     my $tabtext = &mt('Course Settings');
                    350:     if ($crstype eq 'Community') {
                    351:         $tabtext = &mt('Community Settings');
                    352:     } 
1.507     www       353:     $r->print("\n".'<ul class="LC_TabContentBigger" id="main">');
                    354:     $r->print("\n".'<li'.($mode eq 'coursepref'?' class="active"':'').'><a href="/adm/courseprefs"><b>&nbsp;&nbsp;&nbsp;&nbsp;'.
1.531     raeburn   355:                                           $tabtext.
1.507     www       356:                                           '&nbsp;&nbsp;&nbsp;&nbsp;</b></a></li>');
                    357: 
1.523     raeburn   358:     $r->print("\n".'<li'.($mode eq 'parmset'?' class="active"':'').' id="tabbededitor"><a href="/adm/parmset"><b>'.
1.507     www       359:                                                                  &mt('Content and Problem Settings').'</b></a></li>');
                    360:     $r->print("\n".'</ul>'."\n");
1.523     raeburn   361:     $r->print('<div class="LC_Box" style="clear:both;margin:0;" id="parameditor"><div id="maincoursedoc" style="margin:0 0;padding:0 0;"><div class="LC_ContentBox" id="mainCourseDocuments" style="display: block;">');
1.507     www       362: }
                    363: 
1.560     damieng   364: # Page footer
1.507     www       365: sub endSettingsScreen {
                    366:    my ($r)=@_;
                    367:    $r->print('</div></div></div>');
                    368: }
                    369: 
                    370: 
                    371: 
1.560     damieng   372: ##################################################
1.563     damieng   373: # (mostly) TABLE MODE
1.560     damieng   374: # (parmval is also used for the log of parameter changes)
                    375: ##################################################
                    376: 
1.566     damieng   377: # Calls parmval_by_symb, getting the symb from $id with &symbcache.
1.561     damieng   378: #
                    379: # @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight'
1.566     damieng   380: # @param {string} $id - resource id or map pc
1.561     damieng   381: # @param {string} $def - the resource's default value for this parameter
                    382: # @param {string} $uname - user name
                    383: # @param {string} $udom - user domain
                    384: # @param {string} $csec - section name
                    385: # @param {string} $cgroup - group name
                    386: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
                    387: # @returns {Array}
1.2       www       388: sub parmval {
1.275     raeburn   389:     my ($what,$id,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_;
                    390:     return &parmval_by_symb($what,&symbcache($id),$def,$uname,$udom,$csec,
                    391:                                                            $cgroup,$courseopt);
1.201     www       392: }
                    393: 
1.561     damieng   394: # Returns an array containing
                    395: # - the most specific level that is defined for that parameter (integer)
                    396: # - an array with the level as index and the parameter value as value (when defined)
                    397: #   (level 1 is the most specific and will have precedence)
                    398: #
                    399: # @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight'
1.566     damieng   400: # @param {string} $symb - resource symb or map src
1.561     damieng   401: # @param {string} $def - the resource's default value for this parameter
                    402: # @param {string} $uname - user name
                    403: # @param {string} $udom - user domain
                    404: # @param {string} $csec - section name
                    405: # @param {string} $cgroup - group name
                    406: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
                    407: # @returns {Array}
1.201     www       408: sub parmval_by_symb {
1.275     raeburn   409:     my ($what,$symb,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_;
1.200     www       410: 
1.352     albertel  411:     my $useropt;
                    412:     if ($uname ne '' && $udom ne '') {
1.561     damieng   413:         $useropt = &Apache::lonnet::get_userresdata($uname,$udom);
1.352     albertel  414:     }
1.200     www       415: 
1.8       www       416:     my $result='';
1.44      albertel  417:     my @outpar=();
1.2       www       418: # ----------------------------------------------------- Cascading lookup scheme
1.446     bisitz    419:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.305     albertel  420:     $map = &Apache::lonnet::deversion($map);
1.561     damieng   421:     
                    422:     # NOTE: some of that code looks redondant with code in lonnavmaps::parmval_real,
                    423:     # any change should be reflected there.
                    424:     
1.201     www       425:     my $symbparm=$symb.'.'.$what;
1.556     raeburn   426:     my $recurseparm=$map.'___(rec).'.$what; 
1.201     www       427:     my $mapparm=$map.'___(all).'.$what;
1.10      www       428: 
1.269     raeburn   429:     my $grplevel=$env{'request.course.id'}.'.['.$cgroup.'].'.$what;
                    430:     my $grplevelr=$env{'request.course.id'}.'.['.$cgroup.'].'.$symbparm;
1.556     raeburn   431:     my $grpleveli=$env{'request.course.id'}.'.['.$cgroup.'].'.$recurseparm;
1.269     raeburn   432:     my $grplevelm=$env{'request.course.id'}.'.['.$cgroup.'].'.$mapparm;
                    433: 
1.190     albertel  434:     my $seclevel=$env{'request.course.id'}.'.['.$csec.'].'.$what;
                    435:     my $seclevelr=$env{'request.course.id'}.'.['.$csec.'].'.$symbparm;
1.556     raeburn   436:     my $secleveli=$env{'request.course.id'}.'.['.$csec.'].'.$recurseparm;
1.190     albertel  437:     my $seclevelm=$env{'request.course.id'}.'.['.$csec.'].'.$mapparm;
                    438: 
                    439:     my $courselevel=$env{'request.course.id'}.'.'.$what;
                    440:     my $courselevelr=$env{'request.course.id'}.'.'.$symbparm;
1.556     raeburn   441:     my $courseleveli=$env{'request.course.id'}.'.'.$recurseparm;
1.190     albertel  442:     my $courselevelm=$env{'request.course.id'}.'.'.$mapparm;
1.2       www       443: 
1.11      www       444: 
1.182     albertel  445: # --------------------------------------------------------- first, check course
1.11      www       446: 
1.561     damieng   447: # 18 - General Course
1.200     www       448:     if (defined($$courseopt{$courselevel})) {
1.556     raeburn   449:         $outpar[18]=$$courseopt{$courselevel};
                    450:         $result=18;
                    451:     }
                    452: 
1.561     damieng   453: # 17 - Map or Folder level in course (recursive) 
1.556     raeburn   454:     if (defined($$courseopt{$courseleveli})) {
                    455:         $outpar[17]=$$courseopt{$courseleveli};
                    456:         $result=17;
1.43      albertel  457:     }
1.11      www       458: 
1.561     damieng   459: # 16 - Map or Folder level in course (non-recursive)
1.200     www       460:     if (defined($$courseopt{$courselevelm})) {
1.556     raeburn   461:         $outpar[16]=$$courseopt{$courselevelm};
                    462:         $result=16;
1.43      albertel  463:     }
1.11      www       464: 
1.182     albertel  465: # ------------------------------------------------------- second, check default
                    466: 
1.561     damieng   467: # 15 - resource default
1.556     raeburn   468:     if (defined($def)) { $outpar[15]=$def; $result=15; }
1.182     albertel  469: 
                    470: # ------------------------------------------------------ third, check map parms
                    471: 
1.556     raeburn   472:     
1.561     damieng   473: # 14 - map default
1.376     albertel  474:     my $thisparm=&parmhash($symbparm);
1.556     raeburn   475:     if (defined($thisparm)) { $outpar[14]=$thisparm; $result=14; }
1.182     albertel  476: 
1.561     damieng   477: # 13 - resource level in course
1.200     www       478:     if (defined($$courseopt{$courselevelr})) {
1.556     raeburn   479:         $outpar[13]=$$courseopt{$courselevelr};
                    480:         $result=13;
1.43      albertel  481:     }
1.11      www       482: 
1.182     albertel  483: # ------------------------------------------------------ fourth, back to course
1.352     albertel  484:     if ($csec ne '') {
1.561     damieng   485: # 12 - General for section
1.200     www       486:         if (defined($$courseopt{$seclevel})) {
1.556     raeburn   487:             $outpar[12]=$$courseopt{$seclevel};
                    488:             $result=12;
                    489:         }
1.561     damieng   490: # 11 - Map or Folder level for section (recursive)
1.556     raeburn   491:         if (defined($$courseopt{$secleveli})) {
                    492:             $outpar[11]=$$courseopt{$secleveli};
                    493:             $result=11;
                    494:         }
1.561     damieng   495: # 10 - Map or Folder level for section (non-recursive)
1.200     www       496:         if (defined($$courseopt{$seclevelm})) {
1.556     raeburn   497:             $outpar[10]=$$courseopt{$seclevelm};
                    498:             $result=10;
                    499:         }
1.561     damieng   500: # 9 - resource level in section
1.200     www       501:         if (defined($$courseopt{$seclevelr})) {
1.556     raeburn   502:             $outpar[9]=$$courseopt{$seclevelr};
                    503:             $result=9;
                    504:         }
1.43      albertel  505:     }
1.275     raeburn   506: # ------------------------------------------------------ fifth, check course group
1.352     albertel  507:     if ($cgroup ne '') {
1.561     damieng   508: # 8 - General for group
1.269     raeburn   509:         if (defined($$courseopt{$grplevel})) {
1.556     raeburn   510:             $outpar[8]=$$courseopt{$grplevel};
                    511:             $result=8;
                    512:         }
1.561     damieng   513: # 7 - Map or Folder level for group (recursive)
1.556     raeburn   514:         if (defined($$courseopt{$grpleveli})) {
                    515:             $outpar[7]=$$courseopt{$grpleveli};
                    516:             $result=7;
1.269     raeburn   517:         }
1.561     damieng   518: # 6 - Map or Folder level for group (non-recursive)
1.269     raeburn   519:         if (defined($$courseopt{$grplevelm})) {
1.556     raeburn   520:             $outpar[6]=$$courseopt{$grplevelm};
                    521:             $result=6;
1.269     raeburn   522:         }
1.561     damieng   523: # 5 - resource level in group
1.269     raeburn   524:         if (defined($$courseopt{$grplevelr})) {
1.556     raeburn   525:             $outpar[5]=$$courseopt{$grplevelr};
                    526:             $result=5;
1.269     raeburn   527:         }
                    528:     }
1.11      www       529: 
1.556     raeburn   530: # ---------------------------------------------------------- sixth, check user
1.11      www       531: 
1.352     albertel  532:     if ($uname ne '') {
1.561     damieng   533: # 4 - General for specific student
                    534:         if (defined($$useropt{$courselevel})) {
                    535:             $outpar[4]=$$useropt{$courselevel};
                    536:             $result=4;
                    537:         }
1.556     raeburn   538: 
1.561     damieng   539: # 3 - Map or Folder level for specific student (recursive)
                    540:         if (defined($$useropt{$courseleveli})) {
                    541:             $outpar[3]=$$useropt{$courseleveli};
                    542:             $result=3;
                    543:         }
1.473     amueller  544: 
1.561     damieng   545: # 2 - Map or Folder level for specific student (non-recursive)
                    546:         if (defined($$useropt{$courselevelm})) {
                    547:             $outpar[2]=$$useropt{$courselevelm};
                    548:             $result=2;
                    549:         }
1.473     amueller  550: 
1.561     damieng   551: # 1 - resource level for specific student
                    552:         if (defined($$useropt{$courselevelr})) {
                    553:             $outpar[1]=$$useropt{$courselevelr};
                    554:             $result=1;
                    555:         }
1.43      albertel  556:     }
1.44      albertel  557:     return ($result,@outpar);
1.2       www       558: }
                    559: 
1.198     www       560: 
                    561: 
1.376     albertel  562: # --- Caches local to lonparmset
                    563: 
1.446     bisitz    564: 
1.561     damieng   565: # Reset lonparmset caches (called at the beginning and end of the handler).
1.376     albertel  566: sub reset_caches {
                    567:     &resetparmhash();
                    568:     &resetsymbcache();
                    569:     &resetrulescache();
1.203     www       570: }
                    571: 
1.561     damieng   572: # cache for map parameters, stored temporarily in $env{'request.course.fn'}_parms.db
                    573: # (these parameters come from param elements in .sequence files created with the advanced RAT)
1.376     albertel  574: {
1.561     damieng   575:     my $parmhashid; # course identifier, to initialize the cache only once for a course
                    576:     my %parmhash; # the parameter cache
                    577:     # reset map parameter hash
1.376     albertel  578:     sub resetparmhash {
1.560     damieng   579:         undef($parmhashid);
                    580:         undef(%parmhash);
1.376     albertel  581:     }
1.446     bisitz    582: 
1.561     damieng   583:     # dump the _parms.db database into %parmhash
1.376     albertel  584:     sub cacheparmhash {
1.560     damieng   585:         if ($parmhashid eq  $env{'request.course.fn'}) { return; }
                    586:         my %parmhashfile;
                    587:         if (tie(%parmhashfile,'GDBM_File',
                    588:             $env{'request.course.fn'}.'_parms.db',&GDBM_READER(),0640)) {
                    589:             %parmhash=%parmhashfile;
                    590:             untie(%parmhashfile);
                    591:             $parmhashid=$env{'request.course.fn'};
                    592:         }
1.201     www       593:     }
1.446     bisitz    594: 
1.561     damieng   595:     # returns a parameter value for an identifier symb.parts.parameter, using the map parameter cache
1.376     albertel  596:     sub parmhash {
1.560     damieng   597:         my ($id) = @_;
                    598:         &cacheparmhash();
                    599:         return $parmhash{$id};
1.376     albertel  600:     }
1.560     damieng   601: }
1.376     albertel  602: 
1.566     damieng   603: # cache resource id or map pc -> resource symb or map src, using lonnavmaps to find association
1.446     bisitz    604: {
1.561     damieng   605:     my $symbsid; # course identifier, to initialize the cache only once for a course
                    606:     my %symbs; # hash id->symb
                    607:     # reset the id->symb cache
1.376     albertel  608:     sub resetsymbcache {
1.560     damieng   609:         undef($symbsid);
                    610:         undef(%symbs);
1.376     albertel  611:     }
1.446     bisitz    612: 
1.566     damieng   613:     # returns the resource symb or map src corresponding to a resource id or map pc
                    614:     # (using lonnavmaps and a cache)
1.376     albertel  615:     sub symbcache {
1.560     damieng   616:         my $id=shift;
                    617:         if ($symbsid ne $env{'request.course.id'}) {
                    618:             undef(%symbs);
                    619:         }
                    620:         if (!$symbs{$id}) {
                    621:             my $navmap = Apache::lonnavmaps::navmap->new();
                    622:             if ($id=~/\./) {
                    623:                 my $resource=$navmap->getById($id);
                    624:                 $symbs{$id}=$resource->symb();
                    625:             } else {
                    626:                 my $resource=$navmap->getByMapPc($id);
                    627:                 $symbs{$id}=&Apache::lonnet::declutter($resource->src());
                    628:             }
                    629:             $symbsid=$env{'request.course.id'};
1.473     amueller  630:         }
1.560     damieng   631:         return $symbs{$id};
1.473     amueller  632:     }
1.560     damieng   633: }
1.201     www       634: 
1.561     damieng   635: # cache for parameter default actions (stored in parmdefactions.db)
1.446     bisitz    636: {
1.561     damieng   637:     my $rulesid; # course identifier, to initialize the cache only once for a course
                    638:     my %rules; # parameter default actions hash
1.376     albertel  639:     sub resetrulescache {
1.560     damieng   640:         undef($rulesid);
                    641:         undef(%rules);
1.376     albertel  642:     }
1.446     bisitz    643: 
1.561     damieng   644:     # returns the value for a given key in the parameter default action hash
1.376     albertel  645:     sub rulescache {
1.560     damieng   646:         my $id=shift;
                    647:         if ($rulesid ne $env{'request.course.id'}
                    648:             && !defined($rules{$id})) {
                    649:             my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                    650:             my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                    651:             %rules=&Apache::lonnet::dump('parmdefactions',$dom,$crs);
                    652:             $rulesid=$env{'request.course.id'};
                    653:         }
                    654:         return $rules{$id};
1.221     www       655:     }
                    656: }
                    657: 
1.416     jms       658: 
1.561     damieng   659: # Returns the values of the parameter type default action
                    660: # "default value when manually setting".
                    661: # If none is defined, ('','','','','') is returned.
                    662: #
                    663: # @param {string} $type - parameter type
                    664: # @returns {Array<string>} - (hours, min, sec, value)
1.229     www       665: sub preset_defaults {
                    666:     my $type=shift;
                    667:     if (&rulescache($type.'_action') eq 'default') {
1.560     damieng   668:         # yes, there is something
                    669:         return (&rulescache($type.'_hours'),
                    670:             &rulescache($type.'_min'),
                    671:             &rulescache($type.'_sec'),
                    672:             &rulescache($type.'_value'));
1.229     www       673:     } else {
1.560     damieng   674:         # nothing there or something else
                    675:         return ('','','','','');
1.229     www       676:     }
                    677: }
                    678: 
1.416     jms       679: 
1.561     damieng   680: # Checks that a date is after enrollment start date and before
                    681: # enrollment end date.
                    682: # Returns HTML with a warning if it is not, or the empty string otherwise.
                    683: # This is used by both overview and table modes.
                    684: #
                    685: # @param {integer} $checkdate - the date to check.
                    686: # @returns {string} - HTML possibly containing a localized warning message.
1.277     www       687: sub date_sanity_info {
                    688:    my $checkdate=shift;
                    689:    unless ($checkdate) { return ''; }
                    690:    my $result='';
                    691:    my $crsprefix='course.'.$env{'request.course.id'}.'.';
                    692:    if ($env{$crsprefix.'default_enrollment_end_date'}) {
                    693:       if ($checkdate>$env{$crsprefix.'default_enrollment_end_date'}) {
1.413     bisitz    694:          $result.='<div class="LC_warning">'
                    695:                  .&mt('After course enrollment end!')
                    696:                  .'</div>';
1.277     www       697:       }
                    698:    }
                    699:    if ($env{$crsprefix.'default_enrollment_start_date'}) {
                    700:       if ($checkdate<$env{$crsprefix.'default_enrollment_start_date'}) {
1.413     bisitz    701:          $result.='<div class="LC_warning">'
                    702:                  .&mt('Before course enrollment start!')
                    703:                  .'</div>';
1.277     www       704:       }
                    705:    }
1.413     bisitz    706: # Preparation for additional warnings about dates in the past/future.
                    707: # An improved, more context sensitive version is recommended,
                    708: # e.g. warn for due and answer dates which are defined before the corresponding open date, etc.
                    709: #   if ($checkdate<time) {
                    710: #      $result.='<div class="LC_info">'
                    711: #              .'('.&mt('in the past').')'
                    712: #              .'</div>';
                    713: #      }
                    714: #   if ($checkdate>time) {
                    715: #      $result.='<div class="LC_info">'
                    716: #              .'('.&mt('in the future').')'
                    717: #              .'</div>';
                    718: #      }
1.277     www       719:    return $result;
                    720: }
1.561     damieng   721: 
                    722: 
                    723: # Store a parameter value and type by ID, also triggering more parameter changes based on parameter default actions.
1.186     www       724: #
1.566     damieng   725: # @param {string} $sresid - resource id or map pc
1.565     damieng   726: # @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight'
1.561     damieng   727: # @param {integer} $snum - level
                    728: # @param {string} $nval - new value
                    729: # @param {string} $ntype - new type
                    730: # @param {string} $uname - username
                    731: # @param {string} $udom - userdomain
                    732: # @param {string} $csec - section name
                    733: # @param {string} $cgroup - group name
1.186     www       734: sub storeparm {
1.269     raeburn   735:     my ($sresid,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_;
1.275     raeburn   736:     &storeparm_by_symb(&symbcache($sresid),$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,'',$cgroup);
1.197     www       737: }
                    738: 
1.561     damieng   739: my %recstack; # hash parameter name -> 1 when a parameter was used before in a recursive call to storeparm_by_symb
                    740: 
                    741: # Store a parameter value and type by symb, also triggering more parameter changes based on parameter default actions.
                    742: # Uses storeparm_by_symb_inner to actually store the parameter, ignoring any returned error.
                    743: #
1.566     damieng   744: # @param {string} $symb - resource symb or map src
1.565     damieng   745: # @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight'
1.561     damieng   746: # @param {integer} $snum - level
                    747: # @param {string} $nval - new value
                    748: # @param {string} $ntype - new type
                    749: # @param {string} $uname - username
                    750: # @param {string} $udom - userdomain
                    751: # @param {string} $csec - section name
                    752: # @param {boolean} $recflag - should be true for recursive calls to storeparm_by_symb, false otherwise
                    753: # @param {string} $cgroup - group name
1.197     www       754: sub storeparm_by_symb {
1.275     raeburn   755:     my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$recflag,$cgroup)=@_;
1.226     www       756:     unless ($recflag) {
1.560     damieng   757:         # first time call
                    758:         %recstack=();
                    759:         $recflag=1;
1.226     www       760:     }
1.560     damieng   761:     # store parameter
1.226     www       762:     &storeparm_by_symb_inner
1.473     amueller  763:     ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup);
1.560     damieng   764:     # don't do anything if parameter was reset
1.266     www       765:     unless ($nval) { return; }
1.226     www       766:     my ($prefix,$parm)=($spnam=~/^(.*[\_\.])([^\_\.]+)$/);
1.560     damieng   767:     # remember that this was set
1.226     www       768:     $recstack{$parm}=1;
1.560     damieng   769:     # what does this trigger?
1.226     www       770:     foreach my $triggered (split(/\:/,&rulescache($parm.'_triggers'))) {
1.560     damieng   771:         # don't backfire
                    772:         unless ((!$triggered) || ($recstack{$triggered})) {
                    773:             my $action=&rulescache($triggered.'_action');
                    774:             my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                    775:             # set triggered parameter on same level
                    776:             my $newspnam=$prefix.$triggered;
                    777:             my $newvalue='';
                    778:             my $active=1;
                    779:             if ($action=~/^when\_setting/) {
                    780:             # are there restrictions?
                    781:                 if (&rulescache($triggered.'_triggervalue')=~/\w/) {
                    782:                     $active=0;
1.565     damieng   783:                     foreach my $possiblevalue (split(/\s*\,\s*/,&rulescache($triggered.'_triggervalue'))) {
1.560     damieng   784:                         if (lc($possiblevalue) eq lc($nval)) { $active=1; }
                    785:                     }
                    786:                 }
                    787:                 $newvalue=&rulescache($triggered.'_value');
                    788:             } else {
                    789:                 my $totalsecs=((&rulescache($triggered.'_days')*24+&rulescache($triggered.'_hours'))*60+&rulescache($triggered.'_min'))*60+&rulescache($triggered.'_sec');
                    790:                 if ($action=~/^later\_than/) {
                    791:                     $newvalue=$nval+$totalsecs;
                    792:                 } else {
                    793:                     $newvalue=$nval-$totalsecs;
                    794:                 }
                    795:             }
                    796:             if ($active) {
                    797:                 &storeparm_by_symb($symb,$newspnam,$snum,$newvalue,&rulescache($triggered.'_type'),
                    798:                         $uname,$udom,$csec,$recflag,$cgroup);
                    799:             }
                    800:         }
1.226     www       801:     }
                    802:     return '';
                    803: }
                    804: 
1.561     damieng   805: # Adds all given arguments to the course parameter log.
                    806: # @returns {string} - the answer to the lonnet query.
1.293     www       807: sub log_parmset {
1.525     raeburn   808:     return &Apache::lonnet::write_log('course','parameterlog',@_);
1.284     www       809: }
                    810: 
1.561     damieng   811: # Store a parameter value and type by symb, without using the parameter default actions.
                    812: # Expire related sheets.
                    813: #
1.566     damieng   814: # @param {string} $symb - resource symb or map src
1.561     damieng   815: # @param {string} $spnam - part info and parameter name separated by a dot, e.g. '0.weight'
                    816: # @param {integer} $snum - level
                    817: # @param {string} $nval - new value
                    818: # @param {string} $ntype - new type
                    819: # @param {string} $uname - username
                    820: # @param {string} $udom - userdomain
                    821: # @param {string} $csec - section name
                    822: # @param {string} $cgroup - group name
                    823: # @returns {string} - HTML code with an error message if the parameter could not be stored.
1.226     www       824: sub storeparm_by_symb_inner {
1.197     www       825: # ---------------------------------------------------------- Get symb, map, etc
1.269     raeburn   826:     my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_;
1.197     www       827: # ---------------------------------------------------------- Construct prefixes
1.186     www       828:     $spnam=~s/\_([^\_]+)$/\.$1/;
1.446     bisitz    829:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.305     albertel  830:     $map = &Apache::lonnet::deversion($map);
                    831: 
1.197     www       832:     my $symbparm=$symb.'.'.$spnam;
1.556     raeburn   833:     my $recurseparm=$map.'___(rec).'.$spnam;
1.197     www       834:     my $mapparm=$map.'___(all).'.$spnam;
                    835: 
1.269     raeburn   836:     my $grplevel=$env{'request.course.id'}.'.['.$cgroup.'].'.$spnam;
                    837:     my $grplevelr=$env{'request.course.id'}.'.['.$cgroup.'].'.$symbparm;
1.556     raeburn   838:     my $grpleveli=$env{'request.course.id'}.'.['.$cgroup.'].'.$recurseparm;
1.269     raeburn   839:     my $grplevelm=$env{'request.course.id'}.'.['.$cgroup.'].'.$mapparm;
                    840: 
1.190     albertel  841:     my $seclevel=$env{'request.course.id'}.'.['.$csec.'].'.$spnam;
                    842:     my $seclevelr=$env{'request.course.id'}.'.['.$csec.'].'.$symbparm;
1.556     raeburn   843:     my $secleveli=$env{'request.course.id'}.'.['.$csec.'].'.$recurseparm;
1.190     albertel  844:     my $seclevelm=$env{'request.course.id'}.'.['.$csec.'].'.$mapparm;
1.446     bisitz    845: 
1.190     albertel  846:     my $courselevel=$env{'request.course.id'}.'.'.$spnam;
                    847:     my $courselevelr=$env{'request.course.id'}.'.'.$symbparm;
1.556     raeburn   848:     my $courseleveli=$env{'request.course.id'}.'.'.$recurseparm;
1.190     albertel  849:     my $courselevelm=$env{'request.course.id'}.'.'.$mapparm;
1.446     bisitz    850: 
1.186     www       851:     my $storeunder='';
1.578     raeburn   852:     my $possreplace='';
1.556     raeburn   853:     if (($snum==18) || ($snum==4)) { $storeunder=$courselevel; }
1.578     raeburn   854:     if (($snum==17) || ($snum==3)) { 
                    855:         $storeunder=$courseleveli;
                    856:         $possreplace=$courselevelm; 
                    857:     } 
                    858:     if (($snum==16) || ($snum==2)) { 
                    859:         $storeunder=$courselevelm;
                    860:         $possreplace=$courseleveli;
                    861:     }
1.556     raeburn   862:     if (($snum==13) || ($snum==1)) { $storeunder=$courselevelr; }
                    863:     if ($snum==12) { $storeunder=$seclevel; }
1.578     raeburn   864:     if ($snum==11) { 
                    865:         $storeunder=$secleveli;
                    866:         $possreplace=$seclevelm; 
                    867:     }
                    868:     if ($snum==10) { 
                    869:         $storeunder=$seclevelm;
                    870:         $possreplace=$secleveli;
                    871:     }
1.556     raeburn   872:     if ($snum==9) { $storeunder=$seclevelr; }
                    873:     if ($snum==8) { $storeunder=$grplevel; }
1.578     raeburn   874:     if ($snum==7) { 
                    875:         $storeunder=$grpleveli;
                    876:         $possreplace=$grplevelm;
                    877:     }
                    878:     if ($snum==6) {
                    879:         $storeunder=$grplevelm;
                    880:         $possreplace=$grpleveli;
                    881:     }
1.556     raeburn   882:     if ($snum==5) { $storeunder=$grplevelr; }
1.269     raeburn   883: 
1.446     bisitz    884: 
1.186     www       885:     my $delete;
                    886:     if ($nval eq '') { $delete=1;}
                    887:     my %storecontent = ($storeunder         => $nval,
1.473     amueller  888:             $storeunder.'.type' => $ntype);
1.186     www       889:     my $reply='';
1.560     damieng   890:     
1.556     raeburn   891:     if ($snum>4) {
1.186     www       892: # ---------------------------------------------------------------- Store Course
                    893: #
1.560     damieng   894:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                    895:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                    896:         # Expire sheets
                    897:         &Apache::lonnet::expirespread('','','studentcalc');
                    898:         if (($snum==13) || ($snum==9) || ($snum==5)) {
                    899:             &Apache::lonnet::expirespread('','','assesscalc',$symb);
1.578     raeburn   900:         } elsif (($snum==17) || ($snum==16) || ($snum==11) || ($snum==10) || ($snum==7) || ($snum==6)) {
1.560     damieng   901:             &Apache::lonnet::expirespread('','','assesscalc',$map);
                    902:         } else {
                    903:             &Apache::lonnet::expirespread('','','assesscalc');
                    904:         }
                    905:         # Store parameter
                    906:         if ($delete) {
                    907:             $reply=&Apache::lonnet::del
                    908:             ('resourcedata',[keys(%storecontent)],$cdom,$cnum);
                    909:                 &log_parmset(\%storecontent,1);
                    910:         } else {
                    911:             $reply=&Apache::lonnet::cput
                    912:             ('resourcedata',\%storecontent,$cdom,$cnum);
                    913:             &log_parmset(\%storecontent);
1.578     raeburn   914:             if ($possreplace) {
                    915:                 my $resdata = &Apache::lonnet::get_courseresdata($cnum,$cdom);
                    916:                 if (ref($resdata) eq 'HASH') {
                    917:                     if (exists($resdata->{$possreplace})) {
                    918:                         if (&Apache::lonnet::del
                    919:                             ('resourcedata',[$possreplace,$possreplace.'.type'],$cdom,$cnum) eq 'ok') {
                    920:                             &log_parmset({$possreplace => '', $possreplace.'.type' => $ntype},1);   
                    921:                         }
                    922:                     }
                    923:                 }
                    924:             }
1.560     damieng   925:         }
                    926:         &Apache::lonnet::devalidatecourseresdata($cnum,$cdom);
1.186     www       927:     } else {
                    928: # ------------------------------------------------------------------ Store User
                    929: #
1.560     damieng   930:         # Expire sheets
                    931:         &Apache::lonnet::expirespread($uname,$udom,'studentcalc');
                    932:         if ($snum==1) {
                    933:             &Apache::lonnet::expirespread
                    934:             ($uname,$udom,'assesscalc',$symb);
1.578     raeburn   935:         } elsif (($snum==2) || ($snum==3)) {
1.560     damieng   936:             &Apache::lonnet::expirespread
                    937:             ($uname,$udom,'assesscalc',$map);
                    938:         } else {
                    939:             &Apache::lonnet::expirespread($uname,$udom,'assesscalc');
                    940:         }
                    941:         # Store parameter
                    942:         if ($delete) {
                    943:             $reply=&Apache::lonnet::del
                    944:             ('resourcedata',[keys(%storecontent)],$udom,$uname);
                    945:             &log_parmset(\%storecontent,1,$uname,$udom);
                    946:         } else {
                    947:             $reply=&Apache::lonnet::cput
                    948:             ('resourcedata',\%storecontent,$udom,$uname);
                    949:             &log_parmset(\%storecontent,0,$uname,$udom);
1.578     raeburn   950:             if ($possreplace) {
                    951:                 my $resdata = &Apache::lonnet::get_userresdata($uname,$udom);
                    952:                 if (ref($resdata) eq 'HASH') {
                    953:                     if (exists($resdata->{$possreplace})) {
                    954:                         if (&Apache::lonnet::del
                    955:                             ('resourcedata',[$possreplace,$possreplace.'.type'],$udom,$uname) eq 'ok') {
                    956:                             &log_parmset({$possreplace => '',$possreplace.'.type' => $ntype},1,
                    957:                                           $uname,$udom);
                    958:                         }
                    959:                     }
                    960:                 }
                    961:             }
1.560     damieng   962:         }
                    963:         &Apache::lonnet::devalidateuserresdata($uname,$udom);
1.186     www       964:     }
1.446     bisitz    965: 
1.186     www       966:     if ($reply=~/^error\:(.*)/) {
1.560     damieng   967:         return "<span class=\"LC_error\">Write Error: $1</span>";
1.186     www       968:     }
                    969:     return '';
                    970: }
                    971: 
1.9       www       972: 
1.561     damieng   973: # Returns HTML with the value of the given parameter,
                    974: # using a readable format for dates, and
                    975: # a warning if there is a problem with a date.
                    976: # Used by table mode.
                    977: # Returns HTML for the editmap.png image if no value is defined and $editable is true.
                    978: #
                    979: # @param {string} $value - the parameter value
                    980: # @param {string} $type - the parameter type
                    981: # @param {boolean} $editable - Set to true to get an icon when no value is defined.
1.9       www       982: sub valout {
1.600     raeburn   983:     my ($value,$type,$editable)=@_;
1.59      matthew   984:     my $result = '';
                    985:     # Values of zero are valid.
                    986:     if (! $value && $value ne '0') {
1.528     bisitz    987:         if ($editable) {
                    988:             $result =
                    989:                 '<img src="/res/adm/pages/editmap.png"'
                    990:                .' alt="'.&mt('Change').'"'
1.539     raeburn   991:                .' title="'.&mt('Change').'" style="border:0;" />';
1.528     bisitz    992:         } else {
                    993:             $result='&nbsp;';
                    994:         }
1.59      matthew   995:     } else {
1.622     raeburn   996:         if (($type eq 'date_interval') || ($type eq 'string_grace')) {
                    997:             if ($type eq 'string_grace') {
                    998:                 my @items;
                    999:                 if ($value =~ /,/) {
                   1000:                     @items = split(/,/,$value);
1.558     raeburn  1001:                 } else {
1.622     raeburn  1002:                     @items = ($value);
                   1003:                 }
                   1004:                 foreach my $item (@items) {
                   1005:                     if ($item =~ /^\d+:(0|1)\.?\d*:(0|1)$/) {
                   1006:                         my ($totalsecs,$fraction,$grad) = split(/:/,$item);
1.623     raeburn  1007:                         $result .= &grace_to_humanstr($totalsecs);
1.622     raeburn  1008:                         if (($fraction >=0) && ($fraction <=1)) {
                   1009:                             $result .= '&nbsp;|&nbsp;'.$fraction.'&nbsp;'.&mt('pts');
                   1010:                             if ($grad == 1) {
                   1011:                                 $result .= '&nbsp;('.&mt('gradual').')';
                   1012:                             }
                   1013:                         }
                   1014:                         $result .= ', ';
                   1015:                     }
                   1016:                 }
                   1017:                 $result =~ s/, $//;
                   1018:             } else {
                   1019:                 my ($totalsecs,$donesuffix) = split(/_/,$value,2);
                   1020:                 $result = &interval_to_humanstr($totalsecs);
                   1021:                 my ($usesdone,$donebuttontext,$proctor,$secretkey);
                   1022:                 if ($donesuffix =~ /^done\:([^\:]+)\:(.*)$/) {
                   1023:                     $donebuttontext = $1;
                   1024:                     (undef,$proctor,$secretkey) = split(/_/,$2);
                   1025:                     $usesdone = 'done';
                   1026:                 } elsif ($donesuffix =~ /^done(|_.+)$/) {
                   1027:                     $donebuttontext = &mt('Done');
                   1028:                     ($usesdone,$proctor,$secretkey) = split(/_/,$donesuffix);
                   1029:                 }
                   1030:                 if ($usesdone eq 'done') {
                   1031:                     if ($secretkey) {
                   1032:                         $result .= ' '.&mt('+ "[_1]" with proctor key: [_2]',$donebuttontext,$secretkey);
                   1033:                     } else {
                   1034:                         $result .= ' + "'.$donebuttontext.'"';
                   1035:                     }
1.559     raeburn  1036:                 }
1.554     raeburn  1037:             }
1.213     www      1038:         } elsif (&isdateparm($type)) {
1.361     albertel 1039:             $result = &Apache::lonlocal::locallocaltime($value).
1.560     damieng  1040:                 &date_sanity_info($value);
1.59      matthew  1041:         } else {
                   1042:             $result = $value;
1.517     www      1043:             $result=~s/\,/\, /gs;
1.560     damieng  1044:             $result = &HTML::Entities::encode($result,'"<>&');
1.59      matthew  1045:         }
                   1046:     }
                   1047:     return $result;
1.9       www      1048: }
                   1049: 
1.622     raeburn  1050: sub interval_to_humanstr {
                   1051:     my ($totalsecs) = @_;
                   1052:     my ($sec,$min,$hour,$mday,$mon,$year)=gmtime($totalsecs);
                   1053:     my @timer;
                   1054:     $year=$year-70;
                   1055:     $mday--;
                   1056:     if ($year) {
                   1057:         push(@timer,&mt('[quant,_1,yr]',$year));
                   1058:     }
                   1059:     if ($mon) {
                   1060:         push(@timer,&mt('[quant,_1,mth]',$mon));
                   1061:     }
                   1062:     if ($mday) {
                   1063:         push(@timer,&mt('[quant,_1,day]',$mday));
                   1064:     }
                   1065:     if ($hour) {
                   1066:         push(@timer,&mt('[quant,_1,hr]',$hour));
                   1067:     }
                   1068:     if ($min) {
                   1069:         push(@timer,&mt('[quant,_1,min]',$min));
                   1070:     }
                   1071:     if ($sec) {
                   1072:         push(@timer,&mt('[quant,_1,sec]',$sec));
                   1073:     }
                   1074:     if (!@timer) { # Special case: all entries 0 -> display "0 secs" intead of empty field to keep this field editable
                   1075:         push(@timer,&mt('[quant,_1,sec]',0));
                   1076:     }
                   1077:     return '<span style="white-space:nowrap">'.join('</span>, <span style="white-space:nowrap">',@timer).'</span>';
                   1078: }
1.59      matthew  1079: 
1.623     raeburn  1080: sub grace_to_humanstr {
                   1081:     my ($totalsecs) = @_;
                   1082:     my @timer;
                   1083:     my $weeks = floor($totalsecs/604800);
                   1084:     $totalsecs -= $weeks*604800;
                   1085:     my $days = floor($totalsecs/86400);
                   1086:     $totalsecs -= $days*86400;
                   1087:     my $hours = floor($totalsecs/3600);
                   1088:     $totalsecs -= $hours*3600;
                   1089:     my $mins= floor($totalsecs/60);
                   1090:     $totalsecs -= $mins*60;
                   1091:     if ($weeks) {
                   1092:         push(@timer,&mt('[quant,_1,wk]',$weeks));
                   1093:     }
                   1094:     if ($days) {
                   1095:         push(@timer,&mt('[quant,_1,day]',$days));
                   1096:     }
                   1097:     if ($hours) {
                   1098:         push(@timer,&mt('[quant,_1,hr]',$hours));
                   1099:     }
                   1100:     if ($mins) {
                   1101:         push(@timer,&mt('[quant,_1,min]',$mins));
                   1102:     }
                   1103:     if (!@timer) { # Special case: all entries 0 -> display "0 mins" intead of empty field to keep this field editable
                   1104:         push(@timer,&mt('[quant,_1,min]',0));
                   1105:     }
                   1106:     return '<span style="white-space:nowrap">'.join('</span>, <span style="white-space:nowrap">',@timer).'</span>';
                   1107: }
                   1108: 
1.561     damieng  1109: # Returns HTML containing a link on a parameter value, for table mode.
                   1110: # The link uses the javascript function 'pjump'.
                   1111: #
                   1112: # @param {string} $type - parameter type
                   1113: # @param {string} $dis - dialog title for editing the parameter value and type
                   1114: # @param {string} $value - parameter value
                   1115: # @param {string} $marker - identifier for the parameter, "resource id&part_parameter name&level", will be passed as pres_marker when the user submits a change.
                   1116: # @param {string} $return - prefix for the name of the form and field names that will be used to submit the form ('parmform.pres')
                   1117: # @param {string} $call - javascript function to call to submit the form ('psub')
1.588     raeburn  1118: # @param {boolean} $recursive - true if link is for a map/folder where parameter is currently set to be recursive.
                   1119: # @param {string} $extra - optional additional information to send as tenth arg in call to javascript pjump function.
1.5       www      1120: sub plink {
1.588     raeburn  1121:     my ($type,$dis,$value,$marker,$return,$call,$recursive,$extra)=@_;
1.23      www      1122:     my $winvalue=$value;
                   1123:     unless ($winvalue) {
1.592     raeburn  1124:         if (&isdateparm($type) || (&is_specialstring($type))) {
1.190     albertel 1125:             $winvalue=$env{'form.recent_'.$type};
1.591     raeburn  1126:         } elsif ($type eq 'string_yesno') {
                   1127:             if ($env{'form.recent_string'} =~ /^(yes|no)$/i) {
                   1128:                 $winvalue=$env{'form.recent_string'};
                   1129:             }
1.23      www      1130:         } else {
1.190     albertel 1131:             $winvalue=$env{'form.recent_'.(split(/\_/,$type))[0]};
1.23      www      1132:         }
                   1133:     }
1.229     www      1134:     my ($parmname)=((split(/\&/,$marker))[1]=~/\_([^\_]+)$/);
                   1135:     my ($hour,$min,$sec,$val)=&preset_defaults($parmname);
                   1136:     unless (defined($winvalue)) { $winvalue=$val; }
1.593     raeburn  1137:     my $valout = &valout($value,$type,1);
1.429     raeburn  1138:     my $unencmarker = $marker;
1.378     albertel 1139:     foreach my $item (\$type, \$dis, \$winvalue, \$marker, \$return, \$call,
1.588     raeburn  1140:               \$hour, \$min, \$sec, \$extra) {
1.560     damieng  1141:         $$item = &HTML::Entities::encode($$item,'"<>&');
                   1142:         $$item =~ s/\'/\\\'/g;
1.378     albertel 1143:     }
1.429     raeburn  1144:     return '<table width="100%"><tr valign="top" align="right"><td><a name="'.$unencmarker.'" /></td></tr><tr><td align="center">'.
1.473     amueller 1145:     '<a href="javascript:pjump('."'".$type."','".$dis."','".$winvalue."','"
1.588     raeburn  1146:         .$marker."','".$return."','".$call."','".$hour."','".$min."','".$sec."','".$extra."'".');">'.
1.578     raeburn  1147:         $valout.'</a></td></tr>'.($recursive?'<tr><td align="center" class="LC_parm_recursive">'.
                   1148:                                               &mt('recursive').'</td></tr>' : '').'</table>';
                   1149: 
1.5       www      1150: }
                   1151: 
1.561     damieng  1152: # Javascript for table mode.
1.280     albertel 1153: sub page_js {
                   1154: 
1.81      www      1155:     my $selscript=&Apache::loncommon::studentbrowser_javascript();
1.88      matthew  1156:     my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition();
1.280     albertel 1157: 
                   1158:     return(<<ENDJS);
                   1159: <script type="text/javascript">
1.454     bisitz   1160: // <![CDATA[
1.44      albertel 1161: 
1.88      matthew  1162:     $pjump_def
1.44      albertel 1163: 
                   1164:     function psub() {
1.591     raeburn  1165:         var specstring = /^string_!(yesno|any)/i;
1.44      albertel 1166:         if (document.parmform.pres_marker.value!='') {
                   1167:             document.parmform.action+='#'+document.parmform.pres_marker.value;
                   1168:             var typedef=new Array();
                   1169:             typedef=document.parmform.pres_type.value.split('_');
1.562     damieng  1170:             if (document.parmform.pres_type.value!='') {
1.589     raeburn  1171:                 if ((typedef[0]=='date') || 
1.591     raeburn  1172:                     (specstring.test(document.parmform.pres_type.value)))  {
1.562     damieng  1173:                     eval('document.parmform.recent_'+
                   1174:                         document.parmform.pres_type.value+
                   1175:                         '.value=document.parmform.pres_value.value;');
                   1176:                 } else {
                   1177:                     eval('document.parmform.recent_'+typedef[0]+
                   1178:                         '.value=document.parmform.pres_value.value;');
                   1179:                 }
1.44      albertel 1180:             }
                   1181:             document.parmform.submit();
                   1182:         } else {
                   1183:             document.parmform.pres_value.value='';
                   1184:             document.parmform.pres_marker.value='';
                   1185:         }
                   1186:     }
                   1187: 
1.57      albertel 1188:     function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
                   1189:         var options = "width=" + w + ",height=" + h + ",";
                   1190:         options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
                   1191:         options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
                   1192:         var newWin = window.open(url, wdwName, options);
                   1193:         newWin.focus();
                   1194:     }
1.523     raeburn  1195: 
1.454     bisitz   1196: // ]]>
1.523     raeburn  1197: 
1.44      albertel 1198: </script>
1.81      www      1199: $selscript
1.280     albertel 1200: ENDJS
                   1201: 
                   1202: }
1.507     www      1203: 
1.561     damieng  1204: # Javascript to show or hide the map selection (function showHide_courseContent),
                   1205: # for table and overview modes.
1.523     raeburn  1206: sub showhide_js {
                   1207:     return <<"COURSECONTENTSCRIPT";
                   1208: 
                   1209: function showHide_courseContent() {
                   1210:     var parmlevValue=document.getElementById("parmlev").value;
                   1211:     if (parmlevValue == 'general') {
                   1212:         document.getElementById('mapmenu').style.display="none";
                   1213:     } else {
                   1214:         if ((parmlevValue == "full") || (parmlevValue == "map")) {
                   1215:             document.getElementById('mapmenu').style.display ="";
                   1216:         } else {
                   1217:             document.getElementById('mapmenu').style.display="none";
                   1218:         }
                   1219:     }
                   1220:     return;
                   1221: }
                   1222: 
                   1223: COURSECONTENTSCRIPT
                   1224: }
                   1225: 
1.561     damieng  1226: # Javascript functions showHideLenient and toggleParmTextbox, for overview mode
1.549     raeburn  1227: sub toggleparmtextbox_js {
                   1228:     return <<"ENDSCRIPT";
                   1229: 
                   1230: if (!document.getElementsByClassName) {
                   1231:     function getElementsByClassName(node, classname) {
                   1232:         var a = [];
                   1233:         var re = new RegExp('(^| )'+classname+'( |$)');
                   1234:         var els = node.getElementsByTagName("*");
                   1235:         for(var i=0,j=els.length; i<j; i++)
                   1236:             if(re.test(els[i].className))a.push(els[i]);
                   1237:         return a;
                   1238:     }
                   1239: }
                   1240: 
                   1241: function showHideLenient() {
                   1242:     var lenients;
                   1243:     var setRegExp = /^set_/;
                   1244:     if (document.getElementsByClassName) {
                   1245:         lenients = document.getElementsByClassName('LC_lenient_radio');
                   1246:     } else {
                   1247:         lenients = getElementsByClassName(document.body,'LC_lenient_radio');
                   1248:     }
                   1249:     if (lenients != 'undefined') {
                   1250:         for (var i=0; i<lenients.length; i++) {
                   1251:             if (lenients[i].checked) {
                   1252:                 if (lenients[i].value == 'weighted') {
                   1253:                     if (setRegExp.test(lenients[i].name)) {
                   1254:                         var identifier = lenients[i].name.replace(setRegExp,'');
                   1255:                         toggleParmTextbox(document.parmform,identifier);
                   1256:                     }
                   1257:                 }
                   1258:             }
                   1259:         }
                   1260:     }
                   1261:     return;
                   1262: }
                   1263: 
                   1264: function toggleParmTextbox(form,key) {
                   1265:     var divfortext = document.getElementById('LC_parmtext_'+key);
                   1266:     if (divfortext) {
                   1267:         var caller = form.elements['set_'+key];
                   1268:         if (caller.length) {
                   1269:             for (i=0; i<caller.length; i++) {
                   1270:                 if (caller[i].checked) {
                   1271:                     if (caller[i].value == 'weighted') {
                   1272:                         divfortext.style.display = 'inline';
                   1273:                     } else {
                   1274:                         divfortext.style.display = 'none';
                   1275:                     }
                   1276:                 }
                   1277:             }
                   1278:         }
                   1279:     }
                   1280:     return;
                   1281: }
                   1282: 
                   1283: ENDSCRIPT
                   1284: }
                   1285: 
1.561     damieng  1286: # Javascript function validateParms, for overview mode
1.549     raeburn  1287: sub validateparms_js {
1.625   ! raeburn  1288:     my %lt = &Apache::lonlocal::texthash (
        !          1289:                nodom => "A link type of 'domain LTI launch' was selected but no domain LTI launcher was selected.",
        !          1290:                nocrs => "A link type of 'course LTI launch' was selected but no course LTI launcher was selected.",
        !          1291:                plss  => 'Please select one, or choose a different supported link type.',
        !          1292:                disa  => 'disallowed character(s) removed from deeplink key.',
        !          1293:                nokyr => "A link type of 'deep with key' was selected but the key value was blank, after removing disallowed characters.",
        !          1294:                plse  => 'Please enter a key using one or more of:',
        !          1295:                nokey => "A link type of 'deep with key' was selected but the key value was blank.",
        !          1296:                plsk  => 'Please enter a key.',
        !          1297:                dise  => 'disallowed character(s) removed from Exit Button text.',
        !          1298:                exit  => "An exit link type of 'In use' was selected but the button text value was blank, after removing disallowed characters.",
        !          1299:                disc  => 'Disallowed characters are ',
        !          1300:                notxt => "An exit link type of 'In use' was selected but the button text value was blank.",
        !          1301:                plst  => 'Please enter the text to use.',
        !          1302:                gppc  => 'Grace Period Past-Due: enter partial credit (number between 0 and 1.0).',
        !          1303:                gpsn  => 'Grace Period Past-Due: select a number in at least one of the time past due select boxes, or delete the value for partial credit.',
        !          1304:     );
        !          1305:     &js_escape(\%lt);
        !          1306:     return <<"ENDSCRIPT";
1.549     raeburn  1307: 
                   1308: function validateParms() {
                   1309:     var textRegExp = /^settext_/;
1.625   ! raeburn  1310:     var tailLenient = /\.lenient\$/;
        !          1311:     var patternRelWeight = /^\-?[\d.]+\$/;
        !          1312:     var patternLenientStd = /^(yes|no|default)\$/;
1.597     raeburn  1313:     var ipRegExp = /^setip/;
1.549     raeburn  1314:     var ipallowRegExp = /^setipallow_/;
                   1315:     var ipdenyRegExp = /^setipdeny_/; 
1.622     raeburn  1316:     var graceRegExp = /^setgrace_/;
1.597     raeburn  1317:     var deeplinkRegExp = /^deeplink_/;
1.601     raeburn  1318:     var dlListScopeRegExp = /^deeplink_(state|others|listing|scope)_/; 
                   1319:     var dlLinkProtectRegExp = /^deeplink_protect_/;
                   1320:     var dlLtidRegExp = /^deeplink_ltid_/;
                   1321:     var dlLticRegExp = /^deeplink_ltic_/;
1.597     raeburn  1322:     var dlKeyRegExp = /^deeplink_key_/;
                   1323:     var dlMenusRegExp = /^deeplink_menus_/;
                   1324:     var dlCollsRegExp = /^deeplink_colls_/;
1.613     raeburn  1325:     var dlTargetRegExp = /^deeplink_target_/;
1.616     raeburn  1326:     var dlExitRegExp = /^deeplink_exit_/;
                   1327:     var dlExitTextRegExp = /^deeplink_exittext_/;
1.549     raeburn  1328:     var patternIP = /[\[\]\*\.a-zA-Z\d\-]+/;
1.623     raeburn  1329:     var patternGrace = /^\d+:(0|1)\.?\d*:(0|1)\$/;
1.616     raeburn  1330:     var numelements = document.parmform.elements.length;
                   1331:     if ((typeof(numelements) != 'undefined') && (numelements != null)) {
                   1332:         if (numelements) {
                   1333:             for (i=0; i<numelements; i++) {
1.549     raeburn  1334:                 var name=document.parmform.elements[i].name;
1.588     raeburn  1335:                 if (textRegExp.test(name)) {
1.549     raeburn  1336:                     var identifier = name.replace(textRegExp,'');
                   1337:                     if (tailLenient.test(identifier)) {
                   1338:                         if (document.parmform.elements['set_'+identifier].length) {
                   1339:                             for (var j=0; j<document.parmform.elements['set_'+identifier].length; j++) {
                   1340:                                 if (document.parmform.elements['set_'+identifier][j].checked) {
                   1341:                                     if (!(patternLenientStd.test(document.parmform.elements['set_'+identifier][j].value))) {
                   1342:                                         var relweight = document.parmform.elements[i].value;
1.625   ! raeburn  1343:                                         relweight = relweight.replace(/^\s+|\s+\$/g,'');
1.549     raeburn  1344:                                         if (!patternRelWeight.test(relweight)) {
                   1345:                                             relweight = '0.0';
                   1346:                                         }
                   1347:                                         if (document.parmform.elements['set_'+identifier][j].value == 'weighted') {
                   1348:                                             document.parmform.elements['set_'+identifier][j].value = relweight;
                   1349:                                         } else {
                   1350:                                             document.parmform.elements['set_'+identifier][j].value += ','+relweight;
                   1351:                                         }
                   1352:                                     }
                   1353:                                     break;
                   1354:                                 }
                   1355:                             }
                   1356:                         }
                   1357:                     }
1.597     raeburn  1358:                 } else if (ipRegExp.test(name)) {
                   1359:                     if (ipallowRegExp.test(name)) {
                   1360:                         var identifier = name.replace(ipallowRegExp,'');
                   1361:                         var possallow = document.parmform.elements[i].value;
1.625   ! raeburn  1362:                         possallow = possallow.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1363:                         if (patternIP.test(possallow)) {
                   1364:                             if (document.parmform.elements['set_'+identifier].value) {
                   1365:                                 possallow = ','+possallow;
                   1366:                             }
                   1367:                             document.parmform.elements['set_'+identifier].value += possallow;
                   1368:                         }
                   1369:                     } else if (ipdenyRegExp.test(name)) {
                   1370:                         var identifier = name.replace(ipdenyRegExp,'');
                   1371:                         var possdeny = document.parmform.elements[i].value;
1.625   ! raeburn  1372:                         possdeny = possdeny.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1373:                         if (patternIP.test(possdeny)) {
                   1374:                             possdeny = '!'+possdeny;
                   1375:                             if (document.parmform.elements['set_'+identifier].value) {
                   1376:                                 possdeny = ','+possdeny;
                   1377:                             }
                   1378:                             document.parmform.elements['set_'+identifier].value += possdeny;
1.588     raeburn  1379:                         }
                   1380:                     }
                   1381:                 } else if (deeplinkRegExp.test(name)) {
1.597     raeburn  1382:                     if (dlListScopeRegExp.test(name)) {
                   1383:                         var identifier =  name.replace(dlListScopeRegExp,'');
                   1384:                         var idx = document.parmform.elements[i].selectedIndex;
                   1385:                         if (idx > 0) { 
                   1386:                             var possdeeplink = document.parmform.elements[i].options[idx].value
1.625   ! raeburn  1387:                             possdeeplink = possdeeplink.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1388:                             if (document.parmform.elements['set_'+identifier].value) {
                   1389:                                 possdeeplink = ','+possdeeplink;
                   1390:                             }
                   1391:                             document.parmform.elements['set_'+identifier].value += possdeeplink;
                   1392:                         }
1.601     raeburn  1393:                     } else if (dlLinkProtectRegExp.test(name)) {
1.597     raeburn  1394:                         if (document.parmform.elements[i].checked) {
1.601     raeburn  1395:                             var identifier =  name.replace(dlLinkProtectRegExp,'');
1.597     raeburn  1396:                             var posslinkurl = document.parmform.elements[i].value;
1.625   ! raeburn  1397:                             posslinkurl = posslinkurl.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1398:                             if (document.parmform.elements['set_'+identifier].value) {
                   1399:                                 posslinkurl = ','+posslinkurl;
                   1400:                             }
                   1401:                             document.parmform.elements['set_'+identifier].value += posslinkurl;
                   1402:                         }
1.601     raeburn  1403:                     } else if (dlLtidRegExp.test(name)) {
                   1404:                         var identifier = name.replace(dlLtidRegExp,'');
                   1405:                         if (isRadioSet('deeplink_protect_'+identifier,'ltid')) {
                   1406:                             var possltid = document.parmform.elements[i].value;
                   1407:                             possltid = possltid.replace(/\D+/g,'');
                   1408:                             if (possltid.length) {
1.597     raeburn  1409:                                 if (document.parmform.elements['set_'+identifier].value) {
1.601     raeburn  1410:                                     possltid = ':'+possltid;
1.597     raeburn  1411:                                 }
1.601     raeburn  1412:                                 document.parmform.elements['set_'+identifier].value += possltid;
1.597     raeburn  1413:                             } else {
                   1414:                                 document.parmform.elements['set_'+identifier].value = '';
1.625   ! raeburn  1415:                                 alert("$lt{'nodom'}\\n$lt{'plss'}");
1.597     raeburn  1416:                                 return false;  
                   1417:                             }
                   1418:                         }
1.601     raeburn  1419:                     } else if (dlLticRegExp.test(name)) {
                   1420:                         var identifier = name.replace(dlLticRegExp,'');
                   1421:                         if (isRadioSet('deeplink_protect_'+identifier,'ltic')) {
                   1422:                             var possltic = document.parmform.elements[i].value;
                   1423:                             possltic = possltic.replace(/\D+/g,'');
                   1424:                             if (possltic.length) {
                   1425:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1426:                                     possltic = ':'+possltic;
                   1427:                                 }
                   1428:                                 document.parmform.elements['set_'+identifier].value += possltic;
                   1429:                             } else {
                   1430:                                 document.parmform.elements['set_'+identifier].value = '';
1.625   ! raeburn  1431:                                 alert("$lt{'nocrs'}\\n$lt{'plss'}");
1.601     raeburn  1432:                                 return false;
                   1433:                             }
                   1434:                         }
1.597     raeburn  1435:                     } else if (dlKeyRegExp.test(name)) {
                   1436:                         var identifier = name.replace(dlKeyRegExp,'');
1.601     raeburn  1437:                         if (isRadioSet('deeplink_protect_'+identifier,'key')) {
1.597     raeburn  1438:                             var posskey = document.parmform.elements[i].value;
1.625   ! raeburn  1439:                             posskey = posskey.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1440:                             var origlength = posskey.length;
1.625   ! raeburn  1441:                             posskey = posskey.replace(/[^a-zA-Z\d_.!\@#\$%^&*()+=-]/g,'');
1.597     raeburn  1442:                             var newlength = posskey.length;
                   1443:                             if (newlength > 0) {
                   1444:                                 var change = origlength - newlength;
                   1445:                                 if (change) {
1.625   ! raeburn  1446:                                     alert(change+" $lt{'disa'}"); 
1.597     raeburn  1447:                                 }
                   1448:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1449:                                     posskey = ':'+posskey;
                   1450:                                 }
                   1451:                                 document.parmform.elements['set_'+identifier].value += posskey;
                   1452:                             } else {
                   1453:                                 document.parmform.elements['set_'+identifier].value = '';
                   1454:                                 if (newlength < origlength) {
1.625   ! raeburn  1455:                                     alert("$lt{'nokyr'}\\n$lt{'plse'} "+'a-zA-Z0-9_.!\@#\$%^&*()+=-');
1.597     raeburn  1456:                                 } else {
1.625   ! raeburn  1457:                                     alert("$lt{'nokey'}\\n$lt{'plsk'}");
1.597     raeburn  1458:                                 }
                   1459:                                 return false;
                   1460:                             }
                   1461:                         }
                   1462:                     } else if (dlMenusRegExp.test(name)) {
                   1463:                         if (document.parmform.elements[i].checked) {
                   1464:                             var identifier =  name.replace(dlMenusRegExp,'');
                   1465:                             var posslinkmenu = document.parmform.elements[i].value;
1.625   ! raeburn  1466:                             posslinkmenu = posslinkmenu.replace(/^\s+|\s+\$/g,'');
1.597     raeburn  1467:                             if (posslinkmenu == 'std') {
                   1468:                                 posslinkmenu = '0';
                   1469:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1470:                                     posslinkmenu = ','+posslinkmenu;
                   1471:                                 }
                   1472:                                 document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1473:                             }
                   1474:                         }
                   1475:                     } else if (dlCollsRegExp.test(name)) {
                   1476:                         var identifier =  name.replace(dlCollsRegExp,'');
                   1477:                         if (isRadioSet('deeplink_menus_'+identifier,'colls')) {
                   1478:                             var posslinkmenu = document.parmform.elements[i].value;
                   1479:                             if (document.parmform.elements['set_'+identifier].value) {
                   1480:                                 posslinkmenu = ','+posslinkmenu;
                   1481:                             }
                   1482:                             document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1483:                         }
1.614     raeburn  1484:                     } else if (dlTargetRegExp.test(name)) {
                   1485:                         var identifier =  name.replace(dlTargetRegExp,'');
1.613     raeburn  1486:                         var idx = document.parmform.elements[i].selectedIndex;
                   1487:                         if (idx > 0) {
1.616     raeburn  1488:                             var linktarget = document.parmform.elements[i].options[idx].value
1.625   ! raeburn  1489:                             linktarget = linktarget.replace(/^\s+|\s+\$/g,'');
1.616     raeburn  1490:                             if (document.parmform.elements['set_'+identifier].value) {
                   1491:                                 linktarget = ','+linktarget;
                   1492:                             }
                   1493:                             document.parmform.elements['set_'+identifier].value += linktarget;
                   1494:                         }
                   1495:                     } else if (dlExitRegExp.test(name)) {
                   1496:                         if (document.parmform.elements[i].checked) {
                   1497:                             var identifier =  name.replace(dlExitRegExp,'');
                   1498:                             var posslinkexit = document.parmform.elements[i].value;
1.625   ! raeburn  1499:                             posslinkexit = posslinkexit.replace(/^\s+|\s+\$/g,'');
1.613     raeburn  1500:                             if (document.parmform.elements['set_'+identifier].value) {
1.616     raeburn  1501:                                 posslinkexit = ','+posslinkexit;
                   1502:                             }
                   1503:                             document.parmform.elements['set_'+identifier].value += posslinkexit;
                   1504:                         }
                   1505:                     } else if (dlExitTextRegExp.test(name)) {
                   1506:                         var identifier = name.replace(dlExitTextRegExp,'');
                   1507:                         if ((isRadioSet('deeplink_exit_'+identifier,'yes')) ||
                   1508:                             (isRadioSet('deeplink_exit_'+identifier,'url'))) {
                   1509:                             var posstext = document.parmform.elements[i].value;
1.625   ! raeburn  1510:                             posstext = posstext.replace(/^\s+|\s+\$/g,'');
1.616     raeburn  1511:                             var origlength = posstext.length;
                   1512:                             posstext = posstext.replace(/[:;'",]/g,'');
                   1513:                             var newlength = posstext.length;
                   1514:                             if (newlength > 0) {
                   1515:                                 var change = origlength - newlength;
                   1516:                                 if (change) {
1.625   ! raeburn  1517:                                     alert(change+" $lt{'dise'}");
1.616     raeburn  1518:                                 }
                   1519:                                 if (posstext !== 'Exit Tool') {
                   1520:                                     posstext = ':'+posstext;
                   1521:                                     document.parmform.elements['set_'+identifier].value += posstext;
                   1522:                                 }
                   1523:                             } else {
                   1524:                                 document.parmform.elements['set_'+identifier].value = '';
                   1525:                                 if (newlength < origlength) {
1.625   ! raeburn  1526:                                     alert("$lt{'exit'}\\n$lt{'disc'}"+'":;\\'');
1.616     raeburn  1527:                                 } else {
1.625   ! raeburn  1528:                                     alert("$lt{'notxt'}\\n$lt{'plst'}");
1.616     raeburn  1529:                                 }
                   1530:                                 return false;
1.613     raeburn  1531:                             }
                   1532:                         }
1.549     raeburn  1533:                     }
1.622     raeburn  1534:                 } else if (graceRegExp.test(name)) {
                   1535:                     var identifier = name.replace(graceRegExp,'');
                   1536:                     var divElem = document.parmform.elements[i].closest('div'); 
                   1537:                     var timeSels = divElem.getElementsByTagName("select");
                   1538:                     var total = 0;
1.623     raeburn  1539:                     var numnotnull = 0;
1.622     raeburn  1540:                     if (timeSels.length) {
                   1541:                          for (var j=0; j<timeSels.length; j++) {
                   1542:                             var sname = timeSels[j].getAttribute('name');
1.623     raeburn  1543:                             var value = timeSels[j].options[timeSels[j].selectedIndex].value;
                   1544:                             if ((value !== null) && (value !== '') && (value !== 'undefined')) {
                   1545:                                 numnotnull ++;
                   1546:                                 var poss = parseInt(value);
                   1547:                                 if (sname == 'weeks_'+identifier) {
                   1548:                                     if ((poss > 0) && (poss <= 52)) {
                   1549:                                         total += (poss * 604800);
                   1550:                                     }
                   1551:                                 } else if (sname == 'days_'+identifier) {
                   1552:                                     if ((poss > 0) && (poss <= 6)) {
                   1553:                                         total += (poss * 86400); 
                   1554:                                     }
                   1555:                                 } else if (sname == 'hours_'+identifier) {
                   1556:                                     if ((poss > 0) && (poss < 24)) {
                   1557:                                         total += (poss * 3600);
                   1558:                                     }
                   1559:                                 } else if (sname == 'minutes_'+identifier) {
                   1560:                                     if ((poss > 0) && (poss < 60)) {
                   1561:                                         total += (poss * 60);
                   1562:                                     }
1.622     raeburn  1563:                                 }
                   1564:                             }
                   1565:                         }
                   1566:                     }
1.623     raeburn  1567:                     if (!numnotnull) {
                   1568:                         total = '';
                   1569:                     }
1.622     raeburn  1570:                     var inputElems = divElem.getElementsByTagName("input");
                   1571:                     var frac = '';
                   1572:                     var grad = '';
                   1573:                     if (inputElems.length) {
                   1574:                         for (var j=0; j<inputElems.length; j++) {
                   1575:                             var iname = inputElems[j].getAttribute('name');
                   1576:                             if (iname == 'frac_'+identifier) {
                   1577:                                 var ival = inputElems[j].value;
                   1578:                                 ival.trim();
1.623     raeburn  1579:                                 if ((ival != '') && (value != 'undefined')) {
                   1580:                                     var poss = parseFloat(ival);
                   1581:                                     if ((typeof poss === 'number') && (!isNaN(poss))) {
                   1582:                                         if ((poss => 0) && (poss <= 1)) {
                   1583:                                             frac = poss;
                   1584:                                             numnotnull ++;
                   1585:                                         }
1.622     raeburn  1586:                                     }
                   1587:                                 }
                   1588:                             } else if (iname == 'grad_'+identifier) {
                   1589:                                 if (inputElems[j].checked) {
                   1590:                                     grad = 1;
                   1591:                                 } else {
                   1592:                                     grad = 0;
                   1593:                                 }
                   1594:                             }
                   1595:                         }
                   1596:                     }
1.623     raeburn  1597:                     if (numnotnull) {
                   1598:                         var possgrace = total+':'+frac+':'+grad;   
                   1599:                         if (patternGrace.test(possgrace)) {
                   1600:                             document.parmform.elements[i].value = possgrace;
                   1601:                             if (document.parmform.elements['set_'+identifier].value) {
                   1602:                                 document.parmform.elements['set_'+identifier].value += ',';
                   1603:                             }
                   1604:                             document.parmform.elements['set_'+identifier].value += document.parmform.elements[i].value;
                   1605:                         } else {
                   1606:                             if (frac == '') {
1.625   ! raeburn  1607:                                 alert("$lt{'gppc'}");
1.623     raeburn  1608:                                 return false;
                   1609:                             } else {
1.625   ! raeburn  1610:                                 alert("$lt{'gpsn'}");
1.623     raeburn  1611:                                 return false;
                   1612:                             }
                   1613:                         }
1.622     raeburn  1614:                     }
1.549     raeburn  1615:                 }
                   1616:             }
                   1617:         }
                   1618:     }
                   1619:     return true;
                   1620: }
                   1621: 
1.597     raeburn  1622: function isRadioSet(name,expected) {
                   1623:     var menuitems = document.getElementsByName(name);
                   1624:     var radioLength = menuitems.length;
                   1625:     result = false;
                   1626:     if (radioLength  > 1) {
                   1627:         for (var j=0; j<radioLength; j++) {
                   1628:             if (menuitems[j].checked) {
                   1629:                 if (menuitems[j].value == expected) {
                   1630:                     result = true;
                   1631:                     break;
                   1632:                 }
                   1633:             }
                   1634:         }
                   1635:     }
                   1636:     return result;
                   1637: }
                   1638: 
1.549     raeburn  1639: ENDSCRIPT
                   1640: }
                   1641: 
1.561     damieng  1642: # Javascript initialization, for overview mode
1.549     raeburn  1643: sub ipacc_boxes_js  {
                   1644:     my $remove = &mt('Remove');
                   1645:     return <<"END";
                   1646: \$(document).ready(function() {
                   1647:     var wrapper         = \$(".LC_string_ipacc_wrap");
                   1648:     var add_button      = \$(".LC_add_ipacc_button");
                   1649:     var ipaccRegExp     = /^LC_string_ipacc_/;
                   1650: 
                   1651:     \$(add_button).click(function(e){
                   1652:         e.preventDefault();
                   1653:         var identifier = \$(this).closest("div").attr("id");
                   1654:         identifier = identifier.replace(ipaccRegExp,'');
1.551     raeburn  1655:         \$(this).closest('div').find('.LC_string_ipacc_inner').append('<div><input type="text" name="setip'+identifier+'" /><a href="#" class="LC_remove_ipacc">$remove</a></div>');
1.549     raeburn  1656:     });
                   1657: 
                   1658:     \$(wrapper).delegate(".LC_remove_ipacc","click", function(e){
                   1659:         e.preventDefault(); \$(this).closest("div").remove();
                   1660:     })
                   1661: });
                   1662: 
                   1663: 
                   1664: END
                   1665: }
                   1666: 
1.622     raeburn  1667: sub grace_js {
                   1668:     my %lt = &grace_titles();
                   1669:     &js_escape(\%lt);
                   1670:     my $overdue = '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
1.623     raeburn  1671:     foreach my $which (['weeks', 604800, 52],
                   1672:                        ['days', 86400, 6],
1.622     raeburn  1673:                        ['hours', 3600, 23],
1.623     raeburn  1674:                        ['minutes', 60, 59]) {
1.622     raeburn  1675:         my ($name, $factor, $max) = @{ $which };
                   1676:         my %select = ((map {$_ => $_} (0..$max)),
                   1677:                       'select_form_order' => [0..$max]);
1.623     raeburn  1678:         unshift(@{$select{'select_form_order'}},'');
                   1679:         $select{''} = '';
1.622     raeburn  1680:         my $selector = &Apache::loncommon::select_form('',$name."_'+identifier+'",
                   1681:                                                        \%select);
                   1682:         $selector =~ s/([\r\n\f]+)//g;
                   1683:         $overdue .= $selector.'&nbsp;'.$lt{$name}.('&nbsp;'x2).' ';
                   1684:     }
                   1685:     $overdue .= '</fieldset>';
                   1686:     return <<"END";
                   1687: \$(document).ready(function() {
                   1688:     var wrapper         = \$(".LC_string_grace_wrap");
                   1689:     var add_button      = \$(".LC_add_grace_button");
                   1690:     var graceRegExp     = /^LC_string_grace_/;
                   1691: 
                   1692:     \$(add_button).click(function(e){
                   1693:         e.preventDefault();
                   1694:         var identifier = \$(this).closest("div").attr("id");
                   1695:         identifier = identifier.replace(graceRegExp,'');
1.623     raeburn  1696:         \$(this).closest('div').find('.LC_string_grace_inner').append('<div><input type="hidden" name="setgrace_'+identifier+'" value="" />$overdue<fieldset class="LC_grace"><legend>$lt{pcr}</legend><input type="text" size="3" name="frac_'+identifier+'" value="" />&nbsp;&nbsp;<label><input type="checkbox" value="1" name="grad_'+identifier+'" />$lt{grad}</label></fieldset><a href="#" class="LC_remove_grace">$lt{remo}</a></div>');
1.622     raeburn  1697:     });
                   1698: 
                   1699:     \$(wrapper).delegate(".LC_remove_grace","click", function(e){
                   1700:         e.preventDefault(); \$(this).closest("div").remove();
                   1701:     })
                   1702: });
                   1703: 
                   1704: 
                   1705: END
                   1706: }
                   1707: 
1.561     damieng  1708: # Javascript function toggleSecret, for overview mode.
1.558     raeburn  1709: sub done_proctor_js {
1.611     raeburn  1710:     my $defaultdone = &mt('Done');
                   1711:     &js_escape(\$defaultdone);
1.558     raeburn  1712:     return <<"END";
                   1713: function toggleSecret(form,radio,key) {
                   1714:     var radios = form[radio+key];
                   1715:     if (radios.length) {
                   1716:         for (var i=0; i<radios.length; i++) {
                   1717:             if (radios[i].checked) {
                   1718:                 if (radios[i].value == '_done_proctor') {
                   1719:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1720:                         document.getElementById('done_'+key+'_proctorkey').type='text';
                   1721:                     }
                   1722:                 } else {
                   1723:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1724:                         document.getElementById('done_'+key+'_proctorkey').type='hidden';
                   1725:                         document.getElementById('done_'+key+'_proctorkey').value='';
                   1726:                     }
                   1727:                 }
1.611     raeburn  1728:                 if (document.getElementById('done_'+key+'_buttontext')) {
                   1729:                     if (radios[i].value == '') {
                   1730:                         document.getElementById('done_'+key+'_buttontext').value = '';
                   1731:                     } else {
                   1732:                         if (document.getElementById('done_'+key+'_buttontext').value == '') {
                   1733:                             document.getElementById('done_'+key+'_buttontext').value = '$defaultdone';
                   1734:                         }
                   1735:                     }
                   1736:                 }
1.558     raeburn  1737:             }
                   1738:         }
                   1739:     }
                   1740: }
                   1741: END
                   1742: 
                   1743: }
                   1744: 
1.588     raeburn  1745: # Javascript function toggle
                   1746: sub deeplink_js {
                   1747:     return <<"END";
                   1748: function toggleDeepLink(form,item,key) {
                   1749:     var radios = form['deeplink_'+item+'_'+key];
                   1750:     if (radios.length) {
                   1751:         var keybox;
                   1752:         if (document.getElementById('deeplink_key_'+item+'_'+key)) {
                   1753:             keybox = document.getElementById('deeplink_key_'+item+'_'+key);
                   1754:         }
1.601     raeburn  1755:         var divoptions = new Array();
                   1756:         if (item == 'protect') {
                   1757:             divoptions = ['ltic','ltid'];
1.597     raeburn  1758:         } else {
                   1759:             if (item == 'menus') {
1.601     raeburn  1760:                 divoptions = ['colls'];
1.597     raeburn  1761:             }
                   1762:         }
1.601     raeburn  1763:         var seldivs = new Array();
                   1764:         if ((item == 'protect') || (item == 'menus')) {
                   1765:             for (var i=0; i<divoptions.length; i++) {
                   1766:                 if (document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key)) {
                   1767:                     seldivs[i] = document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key);
                   1768:                 } else {
                   1769:                     seldivs[i] = '';
                   1770:                 }
                   1771:             }
1.588     raeburn  1772:         }
                   1773:         for (var i=0; i<radios.length; i++) {
                   1774:             if (radios[i].checked) {
1.601     raeburn  1775:                 if ((item == 'protect') || (item == 'menus')) {
                   1776:                     for (var j=0; j<seldivs.length; j++) {
                   1777:                         if (radios[i].value == divoptions[j]) {
                   1778:                             if (seldivs[j] != '') {
                   1779:                                 seldivs[j].style.display = 'inline-block';
                   1780:                             }
                   1781:                             if (item == 'protect') {
                   1782:                                 keybox.type = 'hidden';
                   1783:                                 keybox.value = '';
                   1784:                             }
                   1785:                         } else {
                   1786:                             if (seldivs[j] != '') {
                   1787:                                 seldivs[j].style.display = 'none';
                   1788:                                 form['deeplink_'+divoptions[j]+'_'+key].selectedIndex = 0;
                   1789:                             }
                   1790:                         }
1.597     raeburn  1791:                     }
1.601     raeburn  1792:                     if (item == 'protect') {
1.597     raeburn  1793:                         if (radios[i].value == 'key') {
                   1794:                             keybox.type = 'text';
                   1795:                         } else {
                   1796:                             keybox.type = 'hidden';
                   1797:                         }
1.588     raeburn  1798:                     }
1.616     raeburn  1799:                 } else if (item == 'exit') {
                   1800:                     if (document.getElementById('deeplinkdiv_'+item+'_'+key)) {
                   1801:                         if (radios[i].value == 'no') {
                   1802:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'none';          
                   1803:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1804:                                 if (document.getElementById('deeplink_exittext_'+key).value != '') {
                   1805:                                     document.getElementById('deeplink_exittext_'+key).value = '';    
                   1806:                                 }
                   1807:                             }
                   1808:                         } else {
                   1809:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'inline-block';
                   1810:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1811:                                 if (document.getElementById('deeplink_exittext_'+key).value == '') {
                   1812:                                     document.getElementById('deeplink_exittext_'+key).value = 'Exit Tool';
                   1813:                                 }
                   1814:                             }
                   1815:                         }
                   1816:                     }
1.588     raeburn  1817:                 }
                   1818:             }
                   1819:         }
                   1820:     }
                   1821: }
                   1822: END
                   1823: 
                   1824: }
                   1825: 
1.561     damieng  1826: # Prints HTML page start for table mode.
                   1827: # @param {Apache2::RequestRec} $r - the Apache request
                   1828: # @param {string} $psymb - resource symb
                   1829: # @param {string} $crstype - course type (Community / Course / Placement Test)
1.280     albertel 1830: sub startpage {
1.531     raeburn  1831:     my ($r,$psymb,$crstype) = @_;
1.281     albertel 1832: 
1.515     raeburn  1833:     my %loaditems = (
                   1834:                       'onload'   => "group_or_section('cgroup')",
                   1835:                     );
                   1836:     if (!$psymb) {
1.523     raeburn  1837:         $loaditems{'onload'} = "showHide_courseContent(); group_or_section('cgroup'); resize_scrollbox('mapmenuscroll','1','1');";
1.515     raeburn  1838:     }
1.280     albertel 1839: 
1.560     damieng  1840:     if ((($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   1841:             (!$env{'form.dis'})) || ($env{'form.symb'})) {
                   1842:         &Apache::lonhtmlcommon::add_breadcrumb({help=>'Problem_Parameters',
                   1843:             text=>"Problem Parameters"});
1.414     droeschl 1844:     } else {
1.560     damieng  1845:         &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
                   1846:             text=>"Table Mode",
                   1847:             help => 'Course_Setting_Parameters'});
1.414     droeschl 1848:     }
1.523     raeburn  1849:     my $js = &page_js().'
                   1850: <script type="text/javascript">
                   1851: // <![CDATA[
                   1852: '.
                   1853:             &Apache::lonhtmlcommon::resize_scrollbox_js('params').'
                   1854: // ]]>
                   1855: </script>
                   1856: ';
1.446     bisitz   1857:     my $start_page =
1.523     raeburn  1858:         &Apache::loncommon::start_page('Set/Modify Course Parameters',$js,
                   1859:                                        {'add_entries' => \%loaditems,});
1.446     bisitz   1860:     my $breadcrumbs =
1.473     amueller 1861:     &Apache::lonhtmlcommon::breadcrumbs('Table Mode Parameter Setting','Table_Mode');
1.506     www      1862:     my $escfilter=&Apache::lonhtmlcommon::entity_encode($env{'form.filter'});
                   1863:     my $escpart=&Apache::lonhtmlcommon::entity_encode($env{'form.part'});
1.507     www      1864:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  1865:     &startSettingsScreen($r,'parmset',$crstype);
1.280     albertel 1866:     $r->print(<<ENDHEAD);
1.193     albertel 1867: <form method="post" action="/adm/parmset?action=settable" name="parmform">
1.419     bisitz   1868: <input type="hidden" value="" name="pres_value" />
                   1869: <input type="hidden" value="" name="pres_type" />
                   1870: <input type="hidden" value="" name="pres_marker" />
                   1871: <input type="hidden" value="1" name="prevvisit" />
1.506     www      1872: <input type="hidden" value="$escfilter" name="filter" />
                   1873: <input type="hidden" value="$escpart" name="part" />
1.44      albertel 1874: ENDHEAD
                   1875: }
                   1876: 
1.209     www      1877: 
1.561     damieng  1878: # Prints a row for table mode (except for the tr start).
                   1879: # Every time a hash reference is passed, a single entry is used, so print_row
                   1880: # could just use these values, but why make it simple when it can be complicated ?
                   1881: #
                   1882: # @param {Apache2::RequestRec} $r - the Apache request
                   1883: # @param {string} $which - parameter key ('parameter_'.part.'_'.name)
                   1884: # @param {hash reference} $part - parameter key -> parameter part (can be problem part.'_'.response id for response parameters)
                   1885: # @param {hash reference} $name - parameter key -> parameter name
1.566     damieng  1886: # @param {hash reference} $symbp - map pc or resource/map id -> map src.'___(all)' or resource symb
1.561     damieng  1887: # @param {string} $rid - resource id
                   1888: # @param {hash reference} $default - parameter key -> resource parameter default value
                   1889: # @param {hash reference} $defaulttype - parameter key -> resource parameter default type
                   1890: # @param {hash reference} $display - parameter key -> full title for the parameter
                   1891: # @param {string} $defbgone - user level and other levels background color
                   1892: # @param {string} $defbgtwo - section level background color, also used for part number
                   1893: # @param {string} $defbgthree - group level background color
                   1894: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   1895: # @param {string} $uname - user name
                   1896: # @param {string} $udom - user domain
                   1897: # @param {string} $csec - section name
                   1898: # @param {string} $cgroup - group name
                   1899: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   1900: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.582     raeburn  1901: # @param {boolean} $readonly - true if no editing allowed.
                   1902: # @param {array reference} - $recurseup - list of maps containing current one, ending at top-level.
                   1903: # @param {hash reference} - $maptitles - - hash map id or src -> map title 
                   1904: # @param {hash reference} - $allmaps_inverted - hash map src -> map pc
                   1905: # @param {scalar reference} - $reclinks - number of "parameter in effect" cells with link to map where recursive param was set 
1.44      albertel 1906: sub print_row {
1.201     www      1907:     my ($r,$which,$part,$name,$symbp,$rid,$default,$defaulttype,$display,$defbgone,
1.568     raeburn  1908:     $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp,
1.582     raeburn  1909:     $readonly,$recurseup,$maptitles,$allmaps_inverted,$reclinks)=@_;
1.275     raeburn  1910:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   1911:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   1912:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.582     raeburn  1913:     my $numlinks = 0;
1.553     raeburn  1914: 
1.560     damieng  1915:     # get the values for the parameter in cascading order
                   1916:     # empty levels will remain empty
1.44      albertel 1917:     my ($result,@outpar)=&parmval($$part{$which}.'.'.$$name{$which},
1.473     amueller 1918:       $rid,$$default{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1919:     # get the type for the parameters
                   1920:     # problem: these may not be set for all levels
1.66      www      1921:     my ($typeresult,@typeoutpar)=&parmval($$part{$which}.'.'.
1.275     raeburn  1922:                                           $$name{$which}.'.type',$rid,
1.473     amueller 1923:          $$defaulttype{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1924:     # cascade down manually
1.182     albertel 1925:     my $cascadetype=$$defaulttype{$which};
1.556     raeburn  1926:     for (my $i=18;$i>0;$i--) {
1.560     damieng  1927:         if ($typeoutpar[$i]) {
1.66      www      1928:             $cascadetype=$typeoutpar[$i];
1.560     damieng  1929:         } else {
1.66      www      1930:             $typeoutpar[$i]=$cascadetype;
                   1931:         }
                   1932:     }
1.57      albertel 1933:     my $parm=$$display{$which};
                   1934: 
1.203     www      1935:     if ($parmlev eq 'full') {
1.419     bisitz   1936:         $r->print('<td style="background-color:'.$defbgtwo.';" align="center">'
1.506     www      1937:                   .($$part{$which} eq '0'?'0 ('.&mt('default').')':$$part{$which}).'</td>');
1.433     raeburn  1938:     } else {
1.57      albertel 1939:         $parm=~s|\[.*\]\s||g;
                   1940:     }
1.231     www      1941:     my $automatic=&rulescache(($which=~/\_([^\_]+)$/)[0].'_triggers');
                   1942:     if ($automatic) {
1.560     damieng  1943:         $parm.='<span class="LC_warning"><br />'.&mt('Automatically sets').' '.join(', ',split(/\:/,$automatic)).'</span>';
1.231     www      1944:     }
1.619     raeburn  1945:     my $advice;
                   1946:     if ((ref($name) eq 'HASH') && ($name->{$which} eq 'mapalias') &&
                   1947:         (ref($symbp) eq 'HASH') && ($parmlev eq 'full')) {
                   1948:         if ($symbp->{$rid} =~ m{^uploaded/}) {
                   1949:             if ($result == 14) {
                   1950:                 $advice = &mt('Use Course Editor to modify this.');
                   1951:             } else {
                   1952:                 $advice = &mt('Use Course Editor to set this.');
                   1953:             }
                   1954:         } else {
                   1955:             if ($result == 14) {
                   1956:                 $advice = &mt('Use Resource Assembly Tool to modify this.');
                   1957:             } else {
                   1958:                 $advice = &mt('Use Resource Assembly Tool to set this.');
                   1959:             }
                   1960:         }
                   1961:         $parm .= '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   1962:     }
1.427     bisitz   1963:     $r->print('<td>'.$parm.'</td>');
1.446     bisitz   1964: 
1.44      albertel 1965:     my $thismarker=$which;
                   1966:     $thismarker=~s/^parameter\_//;
                   1967:     my $mprefix=$rid.'&'.$thismarker.'&';
1.582     raeburn  1968:     my ($parmname)=($thismarker=~/\_([^\_]+)$/);
                   1969:     my ($othergrp,$grp_parm,$controlgrp,$effective_parm,$effparm_rec,$effparm_level,
1.588     raeburn  1970:         $eff_groupparm,$recurse_check,$recursinfo,$extra);
1.582     raeburn  1971:     if ((ref($recurseup) eq 'ARRAY') && (@{$recurseup} > 0)) {
                   1972:         if ($result eq '') {
                   1973:             $recurse_check = 1;
                   1974:         } elsif (($uname ne '') && ($result > 3)) {
                   1975:             $recurse_check = 1;
                   1976:         } elsif (($cgroup ne '') && ($result > 7)) {
                   1977:             $recurse_check = 1;
                   1978:         } elsif (($csec ne '') && ($result > 11)) {
                   1979:             $recurse_check = 1;
                   1980:         } elsif ($result > 17) {
                   1981:             $recurse_check = 1;
                   1982:         }
                   1983:         if ($recurse_check) {
                   1984:             my $what = $$part{$which}.'.'.$$name{$which};
                   1985:             my $prefix;
                   1986:             if (($uname ne '') && ($udom ne '')) {
                   1987:                 my $useropt = &Apache::lonnet::get_userresdata($uname,$udom);
                   1988:                 $prefix = $env{'request.course.id'};
                   1989:                 $recursinfo = &get_recursive($recurseup,$useropt,$what,$prefix);
                   1990:                 if (ref($recursinfo) eq 'ARRAY') {
                   1991:                     $effparm_rec = 1;
                   1992:                     $effparm_level = &mt('user: [_1]',$uname);
                   1993:                 }
                   1994:             }
                   1995:             if (($cgroup ne '') && (!$effparm_rec)) {
                   1996:                 $prefix = $env{'request.course.id'}.'.['.$cgroup.']';
                   1997:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   1998:                 if (ref($recursinfo) eq 'ARRAY') {
                   1999:                     $effparm_rec = 1;
                   2000:                     $effparm_level = &mt('group: [_1]',$cgroup);
                   2001:                 }
                   2002:             }
                   2003:             if (($csec ne '') && (!$effparm_rec)) {
                   2004:                 $prefix = $env{'request.course.id'}.'.['.$csec.']';
                   2005:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   2006:                 if (ref($recursinfo) eq 'ARRAY') {
                   2007:                     $effparm_rec = 1;
                   2008:                     $effparm_level = &mt('section: [_1]',$csec);
                   2009:                 }
                   2010:             }
                   2011:             if (!$effparm_rec) {
                   2012:                 $prefix = $env{'request.course.id'};
                   2013:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); 
                   2014:                 if (ref($recursinfo) eq 'ARRAY') {
                   2015:                     $effparm_rec = 1;
                   2016:                 }
                   2017:             }
                   2018:         }
                   2019:     }
                   2020:     if ((!$effparm_rec) && ($result == 17 || $result == 11 || $result == 7 || $result == 3)) {
                   2021:         $effparm_rec = 1;
                   2022:     }
                   2023:     if ((!$effparm_rec) && 
                   2024:         (($$name{$which} eq 'encrypturl') || ($$name{$which} eq 'hiddenresource')) && 
                   2025:         ($result == 16 || $result == 10 || $result == 6 || $result == 2)) {
1.578     raeburn  2026:         $effparm_rec = 1;
                   2027:     }
1.588     raeburn  2028:     if ($parmname eq 'deeplink') {
1.601     raeburn  2029:         my ($domltistr,$crsltistr);
1.588     raeburn  2030:         my %lti =
                   2031:             &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  2032:                                             'linkprot');
1.601     raeburn  2033:         if (keys(%lti)) {
                   2034:             foreach my $item (sort { $a <=> $b }  (keys(%lti))) {
1.604     raeburn  2035:                 if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   2036:                     $domltistr .= $item.':'.&escape(&escape($lti{$item}{'name'})).',';
1.588     raeburn  2037:                 }
                   2038:             }
1.601     raeburn  2039:             $domltistr =~ s/,$//;
                   2040:             if ($domltistr) {
                   2041:                 $extra = 'ltid_'.$domltistr;
                   2042:             }
1.588     raeburn  2043:         }
1.620     raeburn  2044:         my %courselti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
1.601     raeburn  2045:         if (keys(%courselti)) {
                   2046:             foreach my $item (sort { $a <=> $b } keys(%courselti)) {
                   2047:                 if (($item =~ /^\d+$/) && (ref($courselti{$item}) eq 'HASH')) {
                   2048:                     $crsltistr .= $item.':'.&escape(&escape($courselti{$item}{'name'})).',';
                   2049:                 }
                   2050:             }
                   2051:             $crsltistr =~ s/,$//;
                   2052:             if ($crsltistr) {
                   2053:                 if ($extra) {
                   2054:                     $extra .= '&';
                   2055:                 }
                   2056:                 $extra .= 'ltic_'.$crsltistr;
1.588     raeburn  2057:             }
                   2058:         }
1.597     raeburn  2059:         if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   2060:             my @colls;
                   2061:             foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   2062:                 my ($num,$value) = split(/\%/,$item);
                   2063:                 if ($num =~ /^\d+$/) {
                   2064:                     push(@colls,$num);
                   2065:                 }
                   2066:             }
                   2067:             if (@colls) {
                   2068:                 if ($extra) {
                   2069:                     $extra .= '&';
                   2070:                 }
                   2071:                 $extra .= 'menus_'.join(',',@colls);
                   2072:             }
                   2073:         }
1.588     raeburn  2074:     }
1.57      albertel 2075:     if ($parmlev eq 'general') {
                   2076:         if ($uname) {
1.588     raeburn  2077:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.269     raeburn  2078:         } elsif ($cgroup) {
1.588     raeburn  2079:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
1.57      albertel 2080:         } elsif ($csec) {
1.588     raeburn  2081:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2082:         } else {
1.588     raeburn  2083:             &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2084:         }
                   2085:     } elsif ($parmlev eq 'map') {
                   2086:         if ($uname) {
1.588     raeburn  2087:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.269     raeburn  2088:         } elsif ($cgroup) {
1.588     raeburn  2089:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
1.57      albertel 2090:         } elsif ($csec) {
1.588     raeburn  2091:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2092:         } else {
1.588     raeburn  2093:             &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2094:         }
                   2095:     } else {
1.275     raeburn  2096:         if ($uname) {
                   2097:             if (@{$usersgroups} > 1) {
1.582     raeburn  2098:                 (my $coursereply,$othergrp,$grp_parm,$controlgrp,my $grp_is_rec) =
1.580     raeburn  2099:                     &check_other_groups($$part{$which}.'.'.$$name{$which},
1.275     raeburn  2100:                        $rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt);
1.582     raeburn  2101:                 if (($coursereply) && ($result > 4)) {
1.275     raeburn  2102:                     if (defined($controlgrp)) {
                   2103:                         if ($cgroup ne $controlgrp) {
1.582     raeburn  2104:                             $eff_groupparm = $grp_parm;
                   2105:                             undef($result);
                   2106:                             undef($effparm_rec);
                   2107:                             if ($grp_is_rec) {
                   2108:                                  $effparm_rec = 1;
                   2109:                             }
1.275     raeburn  2110:                         }
                   2111:                     }
                   2112:                 }
                   2113:             }
                   2114:         }
1.57      albertel 2115: 
1.588     raeburn  2116:         &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2117:         &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2118:         &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2119:         &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2120:         &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2121: 
                   2122:         if ($csec) {
1.588     raeburn  2123:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2124:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2125:             &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2126:         }
1.269     raeburn  2127: 
                   2128:         if ($cgroup) {
1.588     raeburn  2129:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
                   2130:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
                   2131:             &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly,'',$extra);
1.269     raeburn  2132:         }
1.446     bisitz   2133: 
1.548     raeburn  2134:         if ($uname) {
1.275     raeburn  2135:             if ($othergrp) {
                   2136:                 $r->print($othergrp);
                   2137:             }
1.588     raeburn  2138:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2139:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2140:             &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2141:         }
1.57      albertel 2142:     } # end of $parmlev if/else
1.582     raeburn  2143:     if (ref($recursinfo) eq 'ARRAY') {
                   2144:         my $rectitle = &mt('recursive');
                   2145:         if ((ref($maptitles) eq 'HASH') && (exists($maptitles->{$recursinfo->[2]}))) {
                   2146:             if ((ref($allmaps_inverted) eq 'HASH') && (exists($allmaps_inverted->{$recursinfo->[2]}))) {
                   2147:                 $rectitle = &mt('set in: [_1]','"'.
                   2148:                                 '<a href="javascript:pjumprec('."'".$allmaps_inverted->{$recursinfo->[2]}."',".
                   2149:                                                               "'$parmname','$$part{$which}'".');">'.
                   2150:                                 $maptitles->{$recursinfo->[2]}.'</a>"');
                   2151:               
                   2152:                 $numlinks ++;
                   2153:             }
                   2154:         }
                   2155:         my ($parmname)=($thismarker=~/\_([^\_]+)$/);
1.593     raeburn  2156:         $effective_parm = &valout($recursinfo->[0],$recursinfo->[1]);
1.582     raeburn  2157:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2158:                   '<br /><span class="LC_parm_recursive">'.$rectitle.'&nbsp;'.
                   2159:                   $effparm_level.'</span></td>');
                   2160:     } else {
                   2161:         if ($result) {
1.593     raeburn  2162:             $effective_parm = &valout($outpar[$result],$typeoutpar[$result]);
1.582     raeburn  2163:         }
                   2164:         if ($eff_groupparm) {
                   2165:             $effective_parm = $eff_groupparm;
                   2166:         }
                   2167:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2168:                   ($effparm_rec?'<br /><span class="LC_parm_recursive">'.&mt('recursive').
                   2169:                                 '</span>':'').'</td>');
                   2170:     }
1.203     www      2171:     if ($parmlev eq 'full') {
1.136     albertel 2172:         my $sessionval=&Apache::lonnet::EXT('resource.'.$$part{$which}.
1.201     www      2173:                                         '.'.$$name{$which},$$symbp{$rid});
1.136     albertel 2174:         my $sessionvaltype=$typeoutpar[$result];
1.560     damieng  2175:         if (!defined($sessionvaltype)) {
                   2176:             $sessionvaltype=$$defaulttype{$which};
                   2177:         }
1.419     bisitz   2178:         $r->print('<td style="background-color:#999999;" align="center"><font color="#FFFFFF">'.
1.593     raeburn  2179:                   &valout($sessionval,$sessionvaltype).'&nbsp;'.
1.57      albertel 2180:                   '</font></td>');
1.136     albertel 2181:     }
1.44      albertel 2182:     $r->print('</tr>');
1.57      albertel 2183:     $r->print("\n");
1.582     raeburn  2184:     if (($numlinks) && (ref($reclinks))) {
                   2185:         $$reclinks = $numlinks;
                   2186:     }
1.44      albertel 2187: }
1.59      matthew  2188: 
1.561     damieng  2189: # Prints a cell for table mode.
                   2190: #
                   2191: # FIXME: some of these parameter names are uninspired ($which and $value)
                   2192: # Also, it would make more sense to pass the display for this cell rather
                   2193: # than the full display hash and the key to use.
                   2194: #
                   2195: # @param {Apache2::RequestRec} $r - the Apache request
                   2196: # @param {integer} $which - level
                   2197: # @param {string} $defbg - cell background color
                   2198: # @param {integer} $result - the most specific level that is defined for that parameter
                   2199: # @param {array reference} $outpar - array level -> parameter value (when defined)
                   2200: # @param {string} $mprefix - resource id.'&'.part.'_'.parameter name.'&'
                   2201: # @param {string} $value - parameter key ('parameter_'.part.'_'.name)
                   2202: # @param {array reference} $typeoutpar - array level -> parameter type (when defined)
                   2203: # @param {hash reference} $display - parameter key -> full title for the parameter
                   2204: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.568     raeburn  2205: # @param {boolean} $readonly -true if editing not allowed.
1.588     raeburn  2206: # @param {boolean} $ismaplevel - true if level is for a map.
1.597     raeburn  2207: # @param {string} $extra - extra information to pass to plink.
1.44      albertel 2208: sub print_td {
1.578     raeburn  2209:     my ($r,$which,$defbg,$result,$outpar,$mprefix,$value,$typeoutpar,$display,
1.588     raeburn  2210:         $noeditgrp,$readonly,$ismaplevel,$extra)=@_;
1.578     raeburn  2211:     my ($ineffect,$recursive,$currval,$currtype,$currlevel);
                   2212:     $ineffect = 0;
                   2213:     $currval = $$outpar[$which];
                   2214:     $currtype = $$typeoutpar[$which];
                   2215:     $currlevel = $which;
                   2216:     if (($result) && ($result == $which)) {
                   2217:         $ineffect = 1;
                   2218:     } 
                   2219:     if ($ismaplevel) {
                   2220:         if ($mprefix =~ /(hiddenresource|encrypturl)\&/) {
                   2221:             if (($result) && ($result == $which)) {
                   2222:                 $recursive = 1;
                   2223:             }
                   2224:         } elsif ($$outpar[$which+1] ne '') {
                   2225:             $recursive = 1;
                   2226:             $currlevel = $which+1;
                   2227:             $currval = $$outpar[$currlevel];
                   2228:             $currtype = $$typeoutpar[$currlevel];
                   2229:             if (($result) && ($result == $currlevel)) {
                   2230:                 $ineffect = 1;
                   2231:             }
                   2232:         }
                   2233:     }
                   2234:     $r->print('<td style="background-color:'.($ineffect?'#AAFFAA':$defbg).
1.419     bisitz   2235:               ';" align="center">');
1.437     raeburn  2236:     my $nolink = 0;
1.568     raeburn  2237:     if ($readonly) {
1.552     raeburn  2238:         $nolink = 1;
1.568     raeburn  2239:     } else { 
1.578     raeburn  2240:         if ($which == 14 || $which == 15 || $mprefix =~ /mapalias\&$/) {
1.553     raeburn  2241:             $nolink = 1;
1.568     raeburn  2242:         } elsif (($env{'request.course.sec'} ne '') && ($which > 12)) {
1.533     raeburn  2243:             $nolink = 1;
1.568     raeburn  2244:         } elsif ($which == 5 || $which ==  6 || $which == 7 || $which == 8) {
                   2245:             if ($noeditgrp) {
                   2246:                 $nolink = 1;
                   2247:             }
                   2248:         } elsif ($mprefix =~ /availablestudent\&$/) {
1.599     raeburn  2249:             $nolink = 1;
1.568     raeburn  2250:         } elsif ($mprefix =~ /examcode\&$/) {
                   2251:             unless ($which == 2) {
                   2252:                 $nolink = 1;
                   2253:             }
1.533     raeburn  2254:         }
1.437     raeburn  2255:     }
                   2256:     if ($nolink) {
1.577     raeburn  2257:         my ($parmname)=((split(/\&/,$mprefix))[1]=~/\_([^\_]+)$/);
1.593     raeburn  2258:         $r->print(&valout($currval,$currtype));
1.114     www      2259:     } else {
1.578     raeburn  2260:         $r->print(&plink($currtype,
                   2261:                          $$display{$value},$currval,
1.588     raeburn  2262:                          $mprefix.$currlevel,'parmform.pres','psub',$recursive,
                   2263:                          $extra));
1.114     www      2264:     }
                   2265:     $r->print('</td>'."\n");
1.57      albertel 2266: }
                   2267: 
1.561     damieng  2268: # Returns HTML and other info for the cell added when a user is selected
                   2269: # and that user is in several groups. This is the cell with the title "Control by other group".
                   2270: #
                   2271: # @param {string} $what - parameter part.'.'.parameter name
                   2272: # @param {string} $rid - resource id
                   2273: # @param {string} $cgroup - group name
                   2274: # @param {string} $defbg - cell background color
                   2275: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2276: # @param {integer} $result - level
                   2277: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
1.582     raeburn  2278: # @returns {Array} - array (parameter value for the other group, HTML for the cell, HTML with the value, name of the other group, true if recursive)
1.580     raeburn  2279: sub check_other_groups {
                   2280:     my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_;
1.275     raeburn  2281:     my $courseid = $env{'request.course.id'};
                   2282:     my $output;
                   2283:     my $symb = &symbcache($rid);
                   2284:     my $symbparm=$symb.'.'.$what;
                   2285:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.556     raeburn  2286:     my $recurseparm=$map.'___(rec).'.$what; 
1.275     raeburn  2287:     my $mapparm=$map.'___(all).'.$what;
                   2288:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype) =
1.556     raeburn  2289:           &parm_control_group($courseid,$usersgroups,$symbparm,$mapparm,
                   2290:                               $recurseparm,$what,$courseopt);
1.275     raeburn  2291:     my $bgcolor = $defbg;
1.582     raeburn  2292:     my ($grp_parm,$grp_is_rec);
1.446     bisitz   2293:     if (($coursereply) && ($cgroup ne $resultgroup)) {
1.582     raeburn  2294:         my ($parmname) = ($what =~ /\.([^.]+)$/);
1.275     raeburn  2295:         if ($result > 3) {
1.419     bisitz   2296:             $bgcolor = '#AAFFAA';
1.275     raeburn  2297:         }
1.593     raeburn  2298:         $grp_parm = &valout($coursereply,$resulttype);
1.419     bisitz   2299:         $output = '<td style="background-color:'.$bgcolor.';" align="center">';
1.275     raeburn  2300:         if ($resultgroup && $resultlevel) {
1.582     raeburn  2301:             if ($resultlevel eq 'recursive') {
                   2302:                 $resultlevel = 'map/folder';
                   2303:                 $grp_is_rec = 1;
                   2304:             }
                   2305:             $output .= '<small><b>'.$resultgroup.'</b> ('.$resultlevel.'): </small>'.$grp_parm.
                   2306:                        ($grp_is_rec?'<span class="LC_parm_recursive">'.&mt('recursive').'</span>':'');
                   2307:              
1.275     raeburn  2308:         } else {
                   2309:             $output .= '&nbsp;';
                   2310:         }
                   2311:         $output .= '</td>';
                   2312:     } else {
1.419     bisitz   2313:         $output .= '<td style="background-color:'.$bgcolor.';">&nbsp;</td>';
1.275     raeburn  2314:     }
1.582     raeburn  2315:     return ($coursereply,$output,$grp_parm,$resultgroup,$grp_is_rec);
1.275     raeburn  2316: }
                   2317: 
1.561     damieng  2318: # Looks for a group with a defined parameter for given user and parameter.
1.580     raeburn  2319: # Used by check_other_groups.
1.561     damieng  2320: #
                   2321: # @param {string} $courseid - the course id
                   2322: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2323: # @param {string} $symbparm - end of the course parameter hash key for the group resource level
                   2324: # @param {string} $mapparm - end of the course parameter hash key for the group map/folder level
                   2325: # @param {string} $recurseparm - end of the course parameter hash key for the group recursive level
                   2326: # @param {string} $what - parameter part.'.'.parameter name
                   2327: # @param {hash reference} $courseopt - course parameters hash
                   2328: # @returns {Array} - (parameter value for the group, course parameter hash key for the parameter, name of the group, level name, parameter type)
1.275     raeburn  2329: sub parm_control_group {
1.556     raeburn  2330:     my ($courseid,$usersgroups,$symbparm,$mapparm,$recurseparm,$what,$courseopt) = @_;
1.275     raeburn  2331:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2332:     my $grpfound = 0;
1.556     raeburn  2333:     my @levels = ($symbparm,$mapparm,$recurseparm,$what);
                   2334:     my @levelnames = ('resource','map/folder','recursive','general');
1.275     raeburn  2335:     foreach my $group (@{$usersgroups}) {
                   2336:         if ($grpfound) { last; }
                   2337:         for (my $i=0; $i<@levels; $i++) {
                   2338:             my $item = $courseid.'.['.$group.'].'.$levels[$i];
                   2339:             if (defined($$courseopt{$item})) {
                   2340:                 $coursereply = $$courseopt{$item};
                   2341:                 $resultitem = $item;
                   2342:                 $resultgroup = $group;
                   2343:                 $resultlevel = $levelnames[$i];
                   2344:                 $resulttype = $$courseopt{$item.'.type'};
                   2345:                 $grpfound = 1;
                   2346:                 last;
                   2347:             }
                   2348:         }
                   2349:     }
                   2350:     return($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2351: }
1.201     www      2352: 
1.63      bowersj2 2353: 
                   2354: 
1.562     damieng  2355: # Extracts lots of information about all of the the course's resources into a variety of hashes, using lonnavmaps and lonnet::metadata.
                   2356: # All the parameters are references and are filled by the sub.
                   2357: #
1.566     damieng  2358: # @param {array reference} $ids - resource and map ids
                   2359: # @param {hash reference} $typep - hash resource/map id -> resource type (file extension)
                   2360: # @param {hash reference} $keyp - hash resource/map id -> comma-separated list of parameter keys from lonnet::metadata
1.562     damieng  2361: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2362: # @param {hash reference} $allparts - hash parameter part -> part title (a parameter part can be problem part.'_'.response id for response parameters)
1.566     damieng  2363: # @param {hash reference} $allmaps - hash map pc -> map src
                   2364: # @param {hash reference} $mapp - hash map pc or resource/map id -> enclosing map src
                   2365: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' for a map or resource symb for a resource
                   2366: # @param {hash reference} $maptitles - hash map pc or src -> map title (this should really be two separate hashes)
                   2367: # @param {hash reference} $uris - hash resource/map id -> resource src
1.562     damieng  2368: # @param {hash reference} $keyorder - hash parameter key -> appearance rank for this parameter when looking through every resource and every parameter, starting at 100 (integer)
                   2369: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.608     raeburn  2370: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.63      bowersj2 2371: sub extractResourceInformation {
                   2372:     my $ids = shift;
                   2373:     my $typep = shift;
                   2374:     my $keyp = shift;
                   2375:     my $allparms = shift;
                   2376:     my $allparts = shift;
                   2377:     my $allmaps = shift;
                   2378:     my $mapp = shift;
                   2379:     my $symbp = shift;
1.82      www      2380:     my $maptitles=shift;
1.196     www      2381:     my $uris=shift;
1.210     www      2382:     my $keyorder=shift;
1.211     www      2383:     my $defkeytype=shift;
1.603     raeburn  2384:     my $pssymb=shift;
1.196     www      2385: 
1.210     www      2386:     my $keyordercnt=100;
1.63      bowersj2 2387: 
1.196     www      2388:     my $navmap = Apache::lonnavmaps::navmap->new();
1.603     raeburn  2389:     return unless(ref($navmap));
                   2390:     my @allres;
                   2391:     if ($pssymb ne '') {
                   2392:         my $res = $navmap->getBySymb($pssymb);
                   2393:         if (ref($res)) {
                   2394:             @allres = ($res);
                   2395:         }
                   2396:     }
                   2397:     if (!@allres) { 
                   2398:         @allres=$navmap->retrieveResources(undef,undef,1,undef,1);
                   2399:     }
1.196     www      2400:     foreach my $resource (@allres) {
1.480     amueller 2401:         my $id=$resource->id();
1.196     www      2402:         my ($mapid,$resid)=split(/\./,$id);
1.480     amueller 2403:         if ($mapid eq '0') { next; }
                   2404:         $$ids[$#$ids+1]=$id;
                   2405:         my $srcf=$resource->src();
                   2406:         $srcf=~/\.(\w+)$/;
                   2407:         $$typep{$id}=$1;
1.584     raeburn  2408:         my $toolsymb;
                   2409:         if ($srcf =~ /ext\.tool$/) {
                   2410:             $toolsymb = $resource->symb();
                   2411:         }
1.480     amueller 2412:         $$keyp{$id}='';
1.196     www      2413:         $$uris{$id}=$srcf;
1.512     foxr     2414: 
1.584     raeburn  2415:         foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys',$toolsymb))) {
1.480     amueller 2416:             next if ($key!~/^parameter_/);
1.363     albertel 2417: 
1.209     www      2418: # Hidden parameters
1.584     raeburn  2419:             next if (&Apache::lonnet::metadata($srcf,$key.'.hidden',$toolsymb) eq 'parm');
1.209     www      2420: #
                   2421: # allparms is a hash of parameter names
                   2422: #
1.584     raeburn  2423:             my $name=&Apache::lonnet::metadata($srcf,$key.'.name',$toolsymb);
1.480     amueller 2424:             if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) {
                   2425:                 my ($display,$parmdis);
                   2426:                 $display = &standard_parameter_names($name);
                   2427:                 if ($display eq '') {
1.584     raeburn  2428:                     $display= &Apache::lonnet::metadata($srcf,$key.'.display',$toolsymb);
1.480     amueller 2429:                     $parmdis = $display;
                   2430:                     $parmdis =~ s/\s*\[Part.*$//g;
                   2431:                 } else {
                   2432:                     $parmdis = &mt($display);
                   2433:                 }
                   2434:                 $$allparms{$name}=$parmdis;
                   2435:                 if (ref($defkeytype)) {
                   2436:                     $$defkeytype{$name}=
1.584     raeburn  2437:                     &Apache::lonnet::metadata($srcf,$key.'.type',$toolsymb);
1.480     amueller 2438:                 }
                   2439:             }
1.363     albertel 2440: 
1.209     www      2441: #
                   2442: # allparts is a hash of all parts
                   2443: #
1.584     raeburn  2444:             my $part= &Apache::lonnet::metadata($srcf,$key.'.part',$toolsymb);
1.480     amueller 2445:             $$allparts{$part} = &mt('Part: [_1]',$part);
1.209     www      2446: #
                   2447: # Remember all keys going with this resource
                   2448: #
1.480     amueller 2449:             if ($$keyp{$id}) {
                   2450:                 $$keyp{$id}.=','.$key;
                   2451:             } else {
                   2452:                 $$keyp{$id}=$key;
                   2453:             }   
1.210     www      2454: #
                   2455: # Put in order
1.446     bisitz   2456: #
1.480     amueller 2457:             unless ($$keyorder{$key}) {
                   2458:                 $$keyorder{$key}=$keyordercnt;
                   2459:                 $keyordercnt++;
                   2460:             }
1.473     amueller 2461:         }
                   2462: 
                   2463: 
1.480     amueller 2464:         if (!exists($$mapp{$mapid})) {
                   2465:             $$mapp{$id}=
                   2466:             &Apache::lonnet::declutter($resource->enclosing_map_src());
                   2467:             $$mapp{$mapid}=$$mapp{$id};
                   2468:             $$allmaps{$mapid}=$$mapp{$id};
                   2469:             if ($mapid eq '1') {
1.532     raeburn  2470:                 $$maptitles{$mapid}=&mt('Main Content');
1.480     amueller 2471:             } else {
                   2472:                 $$maptitles{$mapid}=&Apache::lonnet::gettitle($$mapp{$id});
                   2473:             }
                   2474:             $$maptitles{$$mapp{$id}}=$$maptitles{$mapid};
1.556     raeburn  2475:             $$symbp{$mapid}=$$mapp{$id}.'___(all)';  # Added in rev. 1.57, but seems not to be used.
                   2476:                                                      # Lines 1038 and 1114 which use $symbp{$mapid}
                   2477:                                                      # are commented out in rev. 1.57
1.473     amueller 2478:         } else {
1.480     amueller 2479:             $$mapp{$id} = $$mapp{$mapid};
1.473     amueller 2480:         }
1.480     amueller 2481:         $$symbp{$id}=&Apache::lonnet::encode_symb($$mapp{$id},$resid,$srcf);
1.63      bowersj2 2482:     }
                   2483: }
                   2484: 
1.582     raeburn  2485: sub get_recursive {
                   2486:     my ($recurseup,$resdata,$what,$prefix) = @_; 
                   2487:     if ((ref($resdata) eq 'HASH') && (ref($recurseup) eq 'ARRAY')) {
                   2488:         foreach my $item (@{$recurseup}) {
                   2489:             my $norecursechk=$prefix.'.'.$item.'___(all).'.$what;
                   2490:             if (defined($resdata->{$norecursechk})) {
                   2491:                 if ($what =~ /\.(encrypturl|hiddenresource)$/) {
                   2492:                     my $type = $resdata->{$norecursechk.'.type'};
                   2493:                     return [$resdata->{$norecursechk},$type,$item];
                   2494:                 } else {
                   2495:                     last;
                   2496:                 }
                   2497:             }
                   2498:             my $recursechk=$prefix.'.'.$item.'___(rec).'.$what;
                   2499:             if (defined($resdata->{$recursechk})) {
                   2500:                 my $type = $resdata->{$recursechk.'.type'};
                   2501:                 return [$resdata->{$recursechk},$type,$item];
                   2502:             }
                   2503:         }
                   2504:     }
                   2505:     return;
                   2506: }
                   2507: 
1.208     www      2508: 
1.562     damieng  2509: # Tells if a parameter type is a date.
                   2510: #
                   2511: # @param {string} type - parameter type
                   2512: # @returns{boolean} - true if it is a date
1.213     www      2513: sub isdateparm {
                   2514:     my $type=shift;
                   2515:     return (($type=~/^date/) && (!($type eq 'date_interval')));
                   2516: }
                   2517: 
1.589     raeburn  2518: # Determine if parameter type is specialized string type (i.e.,
                   2519: # not just string or string_yesno.  
                   2520: 
                   2521: sub is_specialstring {
                   2522:     my $type=shift;
1.603     raeburn  2523:     return (($type=~/^string_/) && ($type ne 'string_yesno'));
1.589     raeburn  2524: }
                   2525: 
1.562     damieng  2526: # Prints the HTML and Javascript to select parameters, with various shortcuts.
1.468     amueller 2527: #
1.581     raeburn  2528: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      2529: sub parmmenu {
1.581     raeburn  2530:     my ($r)=@_;
1.208     www      2531:     $r->print(<<ENDSCRIPT);
                   2532: <script type="text/javascript">
1.454     bisitz   2533: // <![CDATA[
1.208     www      2534:     function checkall(value, checkName) {
1.453     schualex 2535: 
                   2536:         var li = "_li";
                   2537:         var displayOverview = "";
                   2538:         
                   2539:         if (value == false) {
                   2540:             displayOverview = "none"
                   2541:         }
                   2542: 
1.562     damieng  2543:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.208     www      2544:             ele = document.forms.parmform.elements[i];
                   2545:             if (ele.name == checkName) {
                   2546:                 document.forms.parmform.elements[i].checked=value;
                   2547:             }
                   2548:         }
                   2549:     }
1.210     www      2550: 
                   2551:     function checkthis(thisvalue, checkName) {
1.562     damieng  2552:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.210     www      2553:             ele = document.forms.parmform.elements[i];
                   2554:             if (ele.name == checkName) {
1.562     damieng  2555:                 if (ele.value == thisvalue) {
                   2556:                     document.forms.parmform.elements[i].checked=true;
                   2557:                 }
1.210     www      2558:             }
                   2559:         }
                   2560:     }
                   2561: 
                   2562:     function checkdates() {
1.562     damieng  2563:         checkthis('duedate','pscat');
                   2564:         checkthis('opendate','pscat');
                   2565:         checkthis('answerdate','pscat');
1.218     www      2566:     }
                   2567: 
                   2568:     function checkdisset() {
1.562     damieng  2569:         checkthis('discussend','pscat');
                   2570:         checkthis('discusshide','pscat');
                   2571:         checkthis('discussvote','pscat');
1.218     www      2572:     }
                   2573: 
                   2574:     function checkcontdates() {
1.562     damieng  2575:         checkthis('contentopen','pscat');
                   2576:         checkthis('contentclose','pscat');
1.218     www      2577:     }
1.446     bisitz   2578: 
1.210     www      2579:     function checkvisi() {
1.562     damieng  2580:         checkthis('hiddenresource','pscat');
                   2581:         checkthis('encrypturl','pscat');
                   2582:         checkthis('problemstatus','pscat');
                   2583:         checkthis('contentopen','pscat');
                   2584:         checkthis('opendate','pscat');
1.210     www      2585:     }
                   2586: 
                   2587:     function checkparts() {
1.562     damieng  2588:         checkthis('hiddenparts','pscat');
                   2589:         checkthis('display','pscat');
                   2590:         checkthis('ordered','pscat');
1.210     www      2591:     }
                   2592: 
                   2593:     function checkstandard() {
                   2594:         checkall(false,'pscat');
1.562     damieng  2595:         checkdates();
                   2596:         checkthis('weight','pscat');
                   2597:         checkthis('maxtries','pscat');
                   2598:         checkthis('type','pscat');
                   2599:         checkthis('problemstatus','pscat');
1.210     www      2600:     }
                   2601: 
1.454     bisitz   2602: // ]]>
1.208     www      2603: </script>
                   2604: ENDSCRIPT
1.453     schualex 2605: 
1.491     bisitz   2606:     $r->print('<hr />');
1.581     raeburn  2607:     &shortCuts($r);
1.491     bisitz   2608:     $r->print('<hr />');
1.453     schualex 2609: }
1.562     damieng  2610: 
                   2611: # Returns parameter categories.
                   2612: #
                   2613: # @returns {hash} - category name -> title in English
1.465     amueller 2614: sub categories {
                   2615:     return ('time_settings' => 'Time Settings',
                   2616:     'grading' => 'Grading',
                   2617:     'tries' => 'Tries',
                   2618:     'problem_appearance' => 'Problem Appearance',
                   2619:     'behaviour_of_input_fields' => 'Behaviour of Input Fields',
                   2620:     'hiding' => 'Hiding',
                   2621:     'high_level_randomization' => 'High Level Randomization',
                   2622:     'slots' => 'Slots',
                   2623:     'file_submission' => 'File Submission',
                   2624:     'misc' => 'Miscellaneous' ); 
                   2625: }
                   2626: 
1.562     damieng  2627: # Returns the category for each parameter.
                   2628: #
                   2629: # @returns {hash} - parameter name -> category name
1.465     amueller 2630: sub lookUpTableParameter {
                   2631:  
                   2632:     return ( 
                   2633:         'opendate' => 'time_settings',
                   2634:         'duedate' => 'time_settings',
                   2635:         'answerdate' => 'time_settings',
1.622     raeburn  2636:         'grace' => 'time_settings',
1.465     amueller 2637:         'interval' => 'time_settings',
                   2638:         'contentopen' => 'time_settings',
                   2639:         'contentclose' => 'time_settings',
                   2640:         'discussend' => 'time_settings',
1.560     damieng  2641:         'printstartdate' => 'time_settings',
                   2642:         'printenddate' => 'time_settings',
1.465     amueller 2643:         'weight' => 'grading',
                   2644:         'handgrade' => 'grading',
                   2645:         'maxtries' => 'tries',
                   2646:         'hinttries' => 'tries',
1.503     raeburn  2647:         'randomizeontries' => 'tries',
1.465     amueller 2648:         'type' => 'problem_appearance',
                   2649:         'problemstatus' => 'problem_appearance',
                   2650:         'display' => 'problem_appearance',
                   2651:         'ordered' => 'problem_appearance',
                   2652:         'numbubbles' => 'problem_appearance',
                   2653:         'tol' => 'behaviour_of_input_fields',
                   2654:         'sig' => 'behaviour_of_input_fields',
                   2655:         'turnoffunit' => 'behaviour_of_input_fields',
                   2656:         'hiddenresource' => 'hiding',
                   2657:         'hiddenparts' => 'hiding',
                   2658:         'discusshide' => 'hiding',
                   2659:         'buttonshide' => 'hiding',
                   2660:         'turnoffeditor' => 'hiding',
                   2661:         'encrypturl' => 'hiding',
1.587     raeburn  2662:         'deeplink' => 'hiding',
1.465     amueller 2663:         'randomorder' => 'high_level_randomization',
                   2664:         'randompick' => 'high_level_randomization',
                   2665:         'available' => 'slots',
                   2666:         'useslots' => 'slots',
                   2667:         'availablestudent' => 'slots',
                   2668:         'uploadedfiletypes' => 'file_submission',
                   2669:         'maxfilesize' => 'file_submission',
                   2670:         'cssfile' => 'misc',
                   2671:         'mapalias' => 'misc',
                   2672:         'acc' => 'misc',
                   2673:         'maxcollaborators' => 'misc',
                   2674:         'scoreformat' => 'misc',
1.514     raeburn  2675:         'lenient' => 'grading',
1.519     raeburn  2676:         'retrypartial' => 'tries',
1.521     raeburn  2677:         'discussvote'  => 'misc',
1.621     raeburn  2678:         'texdisplay' => 'misc',
1.584     raeburn  2679:         'examcode' => 'high_level_randomization',
1.575     raeburn  2680:     );
1.465     amueller 2681: }
                   2682: 
1.562     damieng  2683: # Adds the given parameter name to an array of arrays listing all parameters for each category.
                   2684: #
                   2685: # @param {string} $name - parameter name
                   2686: # @param {array reference} $catList - array reference category name -> array reference of parameter names
1.465     amueller 2687: sub whatIsMyCategory {
                   2688:     my $name = shift;
                   2689:     my $catList = shift;
                   2690:     my @list;
                   2691:     my %lookUpList = &lookUpTableParameter; #Initilize the lookupList
                   2692:     my $cat = $lookUpList{$name};
                   2693:     if (defined($cat)) {
                   2694:         if (!defined($$catList{$cat})){
                   2695:             push @list, ($name);
                   2696:             $$catList{$cat} = \@list;
                   2697:         } else {
                   2698:             push @{${$catList}{$cat}}, ($name);     
                   2699:         }
                   2700:     } else {
                   2701:         if (!defined($$catList{'misc'})){
                   2702:             push @list, ($name);
                   2703:             $$catList{'misc'} = \@list;
                   2704:         } else {
                   2705:             push @{${$catList}{'misc'}}, ($name);     
                   2706:         }
                   2707:     }        
                   2708: }
                   2709: 
1.562     damieng  2710: # Sorts parameter names based on appearance order.
                   2711: #
                   2712: # @param {array reference} name - array reference of parameter names
                   2713: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   2714: # @returns {Array} - array of parameter names
1.465     amueller 2715: sub keysindisplayorderCategory {
                   2716:     my ($name,$keyorder)=@_;
                   2717:     return sort {
1.473     amueller 2718:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b}; 
1.465     amueller 2719:     } ( @{$name});
                   2720: }
                   2721: 
1.562     damieng  2722: # Returns a hash category name -> order, starting at 1 (integer)
                   2723: #
                   2724: # @returns {hash}
1.467     amueller 2725: sub category_order {
                   2726:     return (
                   2727:         'time_settings' => 1,
                   2728:         'grading' => 2,
                   2729:         'tries' => 3,
                   2730:         'problem_appearance' => 4,
                   2731:         'hiding' => 5,
                   2732:         'behaviour_of_input_fields' => 6,
                   2733:         'high_level_randomization'  => 7,
                   2734:         'slots' => 8,
                   2735:         'file_submission' => 9,
                   2736:         'misc' => 10
                   2737:     );
                   2738: 
                   2739: }
1.453     schualex 2740: 
1.562     damieng  2741: # Prints HTML to let the user select parameters, from a list of all parameters organized by category.
                   2742: #
                   2743: # @param {Apache2::RequestRec} $r - the Apache request
                   2744: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2745: # @param {array reference} $pscat - list of selected parameter names
                   2746: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
1.453     schualex 2747: sub parmboxes {
                   2748:     my ($r,$allparms,$pscat,$keyorder)=@_;
1.548     raeburn  2749:     my %categories = &categories();
1.467     amueller 2750:     my %category_order = &category_order();
1.465     amueller 2751:     my %categoryList = (
                   2752:         'time_settings' => [],
                   2753:         'grading' => [],
                   2754:         'tries' => [],
                   2755:         'problem_appearance' => [],
                   2756:         'behaviour_of_input_fields' => [],
                   2757:         'hiding' => [],
                   2758:         'high_level_randomization' => [],
                   2759:         'slots' => [],
                   2760:         'file_submission' => [],
                   2761:         'misc' => [],
1.489     bisitz   2762:     );
1.510     www      2763: 
1.548     raeburn  2764:     foreach my $tempparameter (keys(%$allparms)) {
1.465     amueller 2765:         &whatIsMyCategory($tempparameter, \%categoryList);
                   2766:     }
1.453     schualex 2767:     #part to print the parm-list
1.618     raeburn  2768:     $Text::Wrap::columns=60;
                   2769:     $Text::Wrap::separator='<br />';
1.536     raeburn  2770:     foreach my $key (sort { $category_order{$a} <=> $category_order{$b} } keys(%categoryList)) {
                   2771:         next if (@{$categoryList{$key}} == 0);
                   2772:         next if ($key eq '');
                   2773:         $r->print('<div class="LC_Box LC_400Box">'
                   2774:                  .'<h4 class="LC_hcell">'.&mt($categories{$key}).'</h4>'."\n");
                   2775:         foreach my $tempkey (&keysindisplayorderCategory($categoryList{$key},$keyorder)) {
1.575     raeburn  2776:             next if ($tempkey eq '');
1.536     raeburn  2777:             $r->print('<span class="LC_nobreak">'
                   2778:                      .'<label><input type="checkbox" name="pscat" '
                   2779:                      .'value="'.$tempkey.'" ');
                   2780:             if ($$pscat[0] eq "all" || grep $_ eq $tempkey, @{$pscat}) {
                   2781:                 $r->print( ' checked="checked"');
                   2782:             }
1.617     raeburn  2783:             $r->print(' />'.($$allparms{$tempkey}=~/\S/ ? 
                   2784:                              Text::Wrap::wrap('','&nbsp;'x4,$$allparms{$tempkey})
                   2785:                              : $tempkey)
1.536     raeburn  2786:                      .'</label></span><br />'."\n");
1.465     amueller 2787:         }
1.536     raeburn  2788:         $r->print('</div>');
1.465     amueller 2789:     }
1.536     raeburn  2790:     $r->print("\n");
1.453     schualex 2791: }
1.562     damieng  2792: 
                   2793: # Prints HTML with shortcuts to select groups of parameters in one click, or deselect all.
1.468     amueller 2794: #
1.562     damieng  2795: # @param {Apache2::RequestRec} $r - the Apache request
1.453     schualex 2796: sub shortCuts {
1.581     raeburn  2797:     my ($r)=@_;
1.453     schualex 2798: 
1.491     bisitz   2799:     # Parameter Selection
                   2800:     $r->print(
                   2801:         &Apache::lonhtmlcommon::start_funclist(&mt('Parameter Selection'))
                   2802:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2803:             '<a href="javascript:checkall(true, \'pscat\')">'.&mt('Select All').'</a>')
                   2804:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2805:             '<a href="javascript:checkstandard()">'.&mt('Select Common Only').'</a>')
                   2806:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2807:             '<a href="javascript:checkall(false, \'pscat\')">'.&mt('Unselect All').'</a>')
                   2808:        .&Apache::lonhtmlcommon::end_funclist()
                   2809:     );
                   2810: 
                   2811:     # Add Selection for...
                   2812:     $r->print(
                   2813:         &Apache::lonhtmlcommon::start_funclist(&mt('Add Selection for...'))
                   2814:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2815:             '<a href="javascript:checkdates()">'.&mt('Problem Dates').'</a>')
                   2816:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2817:             '<a href="javascript:checkcontdates()">'.&mt('Content Dates').'</a>')
                   2818:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2819:             '<a href="javascript:checkdisset()">'.&mt('Discussion Settings').'</a>')
                   2820:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2821:             '<a href="javascript:checkvisi()">'.&mt('Visibilities').'</a>')
                   2822:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2823:             '<a href="javascript:checkparts()">'.&mt('Part Parameters').'</a>')
                   2824:        .&Apache::lonhtmlcommon::end_funclist()
                   2825:     );
1.208     www      2826: }
                   2827: 
1.562     damieng  2828: # Prints HTML to select parts to view (except for the title).
                   2829: # Used by table and overview modes.
                   2830: #
                   2831: # @param {Apache2::RequestRec} $r - the Apache request
                   2832: # @param {hash reference} $allparts - hash parameter part -> part title
                   2833: # @param {array reference} $psprt - list of selected parameter parts
1.209     www      2834: sub partmenu {
1.446     bisitz   2835:     my ($r,$allparts,$psprt)=@_;
1.523     raeburn  2836:     my $selsize = 1+scalar(keys(%{$allparts}));
                   2837:     if ($selsize > 8) {
                   2838:         $selsize = 8;
                   2839:     }
1.446     bisitz   2840: 
1.523     raeburn  2841:     $r->print('<select multiple="multiple" name="psprt" size="'.$selsize.'">');
1.208     www      2842:     $r->print('<option value="all"');
1.562     damieng  2843:     $r->print(' selected="selected"') unless (@{$psprt}); # useless, the array is never empty
1.208     www      2844:     $r->print('>'.&mt('All Parts').'</option>');
                   2845:     my %temphash=();
                   2846:     foreach (@{$psprt}) { $temphash{$_}=1; }
1.234     albertel 2847:     foreach my $tempkey (sort {
1.560     damieng  2848:                 if ($a==$b) { return ($a cmp $b) } else { return ($a <=> $b); }
                   2849:             } keys(%{$allparts})) {
                   2850:         unless ($tempkey =~ /\./) {
                   2851:             $r->print('<option value="'.$tempkey.'"');
                   2852:             if ($$psprt[0] eq "all" ||  $temphash{$tempkey}) {
                   2853:                 $r->print(' selected="selected"');
                   2854:             }
                   2855:             $r->print('>'.$$allparts{$tempkey}.'</option>');
1.473     amueller 2856:         }
1.208     www      2857:     }
1.446     bisitz   2858:     $r->print('</select>');
1.209     www      2859: }
                   2860: 
1.562     damieng  2861: # Prints HTML to select a user and/or a group.
                   2862: # Used by table mode.
                   2863: #
                   2864: # @param {Apache2::RequestRec} $r - the Apache request
                   2865: # @param {string} $uname - selected user name
                   2866: # @param {string} $id - selected Student/Employee ID
                   2867: # @param {string} $udom - selected user domain
                   2868: # @param {string} $csec - selected section name
                   2869: # @param {string} $cgroup - selected group name
                   2870: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   2871: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2872: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.209     www      2873: sub usermenu {
1.553     raeburn  2874:     my ($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,$usersgroups,$pssymb)=@_;
1.209     www      2875:     my $chooseopt=&Apache::loncommon::select_dom_form($udom,'udom').' '.
1.596     raeburn  2876:                   &Apache::loncommon::selectstudent_link('parmform','uname','udom','condition').
                   2877:                   &Apache::lonhtmlcommon::scripttag(<<ENDJS);
                   2878: function setCourseadv(form,caller) {
                   2879:     if (caller.value == 'st') {
                   2880:         form.courseadv.value = 'none';
                   2881:     } else {
                   2882:         form.courseadv.value = '';
                   2883:     }
                   2884:     return;
                   2885: }
                   2886: ENDJS
1.412     bisitz   2887: 
1.596     raeburn  2888:     my (%chkroles,$stuonly,$courseadv);
                   2889:     if ($env{'form.userroles'} eq 'any') {
                   2890:         $chkroles{'any'} = ' checked="checked"';
                   2891:     } else {
                   2892:         $chkroles{'st'} = ' checked="checked"';
                   2893:         $courseadv = 'none';
                   2894:     }
                   2895:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   2896:     if ($crstype eq 'Community') {
                   2897:         $stuonly = &mt('member only');
                   2898:     } else {
                   2899:         $stuonly = &mt('student only');
                   2900:     }
                   2901:     $chooseopt .= '<br /><span class="LC_cusr_subheading">'.
                   2902:                   &mt("User's role").':&nbsp;'.
                   2903:                   '<label><input type="radio" name="userroles" value="st"'.$chkroles{'st'}.' onclick="setCourseadv(this.form,this);" />'.
                   2904:                   $stuonly.'</label>&nbsp;&nbsp;'.
                   2905:                   '<label><input type="radio" name="userroles" value="any"'.$chkroles{'any'}.' onclick="setCourseadv(this.form,this);" />'.
                   2906:                   &mt('any role').'</label><input type="hidden" id="courseadv" name="courseadv" value="'.$courseadv.'" /></span>';
1.209     www      2907:     my $sections='';
1.300     albertel 2908:     my %sectionhash = &Apache::loncommon::get_sections();
                   2909: 
1.269     raeburn  2910:     my $groups;
1.553     raeburn  2911:     my %grouphash;
                   2912:     if (($pssymb) || &Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   2913:         %grouphash = &Apache::longroup::coursegroups();
                   2914:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  2915:         map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  2916:     }
1.299     albertel 2917: 
1.412     bisitz   2918:     my $g_s_header='';
                   2919:     my $g_s_footer='';
1.446     bisitz   2920: 
1.552     raeburn  2921:     my $currsec = $env{'request.course.sec'};
                   2922:     if ($currsec) {
                   2923:         $sections=&mt('Section:').' '.$currsec;
                   2924:         if (%grouphash) {
                   2925:             $sections .= ';'.('&nbsp;' x2);
                   2926:         }
                   2927:     } elsif (%sectionhash && $currsec eq '') {
1.412     bisitz   2928:         $sections=&mt('Section:').' <select name="csec"';
1.299     albertel 2929:         if (%grouphash && $parmlev ne 'full') {
1.269     raeburn  2930:             $sections .= qq| onchange="group_or_section('csec')" |;
                   2931:         }
                   2932:         $sections .= '>';
1.548     raeburn  2933:     foreach my $section ('',sort(keys(%sectionhash))) {
1.473     amueller 2934:         $sections.='<option value="'.$section.'" '.
                   2935:         ($section eq $csec?'selected="selected"':'').'>'.$section.
1.275     raeburn  2936:                                                               '</option>';
1.209     www      2937:         }
                   2938:         $sections.='</select>';
1.269     raeburn  2939:     }
1.412     bisitz   2940: 
1.552     raeburn  2941:     if (%sectionhash && %grouphash && $parmlev ne 'full' && $currsec eq '') {
1.412     bisitz   2942:         $sections .= '&nbsp;'.&mt('or').'&nbsp;';
1.269     raeburn  2943:         $sections .= qq|
                   2944: <script type="text/javascript">
1.454     bisitz   2945: // <![CDATA[
1.269     raeburn  2946: function group_or_section(caller) {
                   2947:    if (caller == "cgroup") {
                   2948:        if (document.parmform.cgroup.selectedIndex != 0) {
                   2949:            document.parmform.csec.selectedIndex = 0;
                   2950:        }
                   2951:    } else {
                   2952:        if (document.parmform.csec.selectedIndex != 0) {
                   2953:            document.parmform.cgroup.selectedIndex = 0;
                   2954:        }
                   2955:    }
                   2956: }
1.454     bisitz   2957: // ]]>
1.269     raeburn  2958: </script>
                   2959: |;
1.554     raeburn  2960:     } else {
1.269     raeburn  2961:         $sections .= qq|
                   2962: <script type="text/javascript">
1.454     bisitz   2963: // <![CDATA[
1.269     raeburn  2964: function group_or_section(caller) {
                   2965:     return;
                   2966: }
1.454     bisitz   2967: // ]]>
1.269     raeburn  2968: </script>
                   2969: |;
1.446     bisitz   2970:     }
1.299     albertel 2971: 
                   2972:     if (%grouphash) {
1.597     raeburn  2973:         $groups=&mt('Group').': <select name="cgroup"';
1.552     raeburn  2974:         if (%sectionhash && $env{'form.action'} eq 'settable' && $currsec eq '') {
1.269     raeburn  2975:             $groups .= qq| onchange="group_or_section('cgroup')" |;
                   2976:         }
                   2977:         $groups .= '>';
1.548     raeburn  2978:         foreach my $grp ('',sort(keys(%grouphash))) {
1.275     raeburn  2979:             $groups.='<option value="'.$grp.'" ';
                   2980:             if ($grp eq $cgroup) {
                   2981:                 unless ((defined($uname)) && ($grp eq '')) {
                   2982:                     $groups .=  'selected="selected" ';
                   2983:                 }
                   2984:             } elsif (!defined($cgroup)) {
                   2985:                 if (@{$usersgroups} == 1) {
                   2986:                     if ($grp eq $$usersgroups[0]) {
                   2987:                         $groups .=  'selected="selected" ';
                   2988:                     }
                   2989:                 }
                   2990:             }
                   2991:             $groups .= '>'.$grp.'</option>';
1.269     raeburn  2992:         }
                   2993:         $groups.='</select>';
                   2994:     }
1.412     bisitz   2995: 
1.445     neumanie 2996:     if (%sectionhash || %grouphash) {
1.446     bisitz   2997:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Group/Section')));
                   2998:         $r->print($sections.$groups);
1.448     bisitz   2999:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.554     raeburn  3000:     } else {
                   3001:         $r->print($sections); 
1.445     neumanie 3002:     }
1.446     bisitz   3003: 
                   3004:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('User')));
1.443     neumanie 3005:     $r->print(&mt('For User [_1] or Student/Employee ID [_2] at Domain [_3]'
1.412     bisitz   3006:                  ,'<input type="text" value="'.$uname.'" size="12" name="uname" />'
                   3007:                  ,'<input type="text" value="'.$id.'" size="12" name="id" /> '
1.446     bisitz   3008:                  ,$chooseopt));
1.209     www      3009: }
                   3010: 
1.562     damieng  3011: # Prints HTML to select parameters from a list of all parameters.
                   3012: # Uses parmmenu and parmboxes.
                   3013: # Used by table and overview modes.
1.468     amueller 3014: #
1.562     damieng  3015: # @param {Apache2::RequestRec} $r - the Apache request
                   3016: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   3017: # @param {array reference} $pscat - list of selected parameter names
                   3018: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3019: # @param {string} [$divid] - name used to give an id to the HTML element for the scroll box
1.209     www      3020: sub displaymenu {
1.581     raeburn  3021:     my ($r,$allparms,$pscat,$keyorder,$divid)=@_;
1.510     www      3022: 
1.445     neumanie 3023:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.510     www      3024:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameters to View')));
                   3025: 
1.581     raeburn  3026:     &parmmenu($r);
1.536     raeburn  3027:     $r->print(&Apache::loncommon::start_scrollbox('480px','440px','200px',$divid));
1.510     www      3028:     &parmboxes($r,$allparms,$pscat,$keyorder);
                   3029:     $r->print(&Apache::loncommon::end_scrollbox());
                   3030: 
                   3031:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.453     schualex 3032:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.510     www      3033:  
1.209     www      3034: }
                   3035: 
1.562     damieng  3036: # Prints HTML to select a map.
                   3037: # Used by table mode and overview mode.
                   3038: #
                   3039: # @param {Apache2::RequestRec} $r - the Apache request
1.566     damieng  3040: # @param {hash reference} $allmaps - hash map pc -> map src
                   3041: # @param {string} $pschp - selected map pc, or 'all'
1.562     damieng  3042: # @param {hash reference} $maptitles - hash map id or src -> map title
1.566     damieng  3043: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.610     raeburn  3044: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
1.445     neumanie 3045: sub mapmenu {
1.610     raeburn  3046:     my ($r,$allmaps,$pschp,$maptitles,$symbp,$parmlev)=@_;
1.468     amueller 3047:     my %allmaps_inverted = reverse %$allmaps;
1.461     neumanie 3048:     my $navmap = Apache::lonnavmaps::navmap->new();
                   3049:     my $tree=[];
                   3050:     my $treeinfo={};
                   3051:     if (defined($navmap)) {
1.499     raeburn  3052:         my $it=$navmap->getIterator(undef,undef,undef,1,1,undef);
1.461     neumanie 3053:         my $curRes;
                   3054:         my $depth = 0;
1.468     amueller 3055:         my %parent = ();
                   3056:         my $startcount = 5;
                   3057:         my $lastcontainer = $startcount;
                   3058: # preparing what is to show ...
1.461     neumanie 3059:         while ($curRes = $it->next()) {
                   3060:             if ($curRes == $it->BEGIN_MAP()) {
                   3061:                 $depth++;
1.468     amueller 3062:                 $parent{$depth}= $lastcontainer;
1.461     neumanie 3063:             }
                   3064:             if ($curRes == $it->END_MAP()) {
                   3065:                 $depth--;
1.468     amueller 3066:                 $lastcontainer = $parent{$depth};
1.461     neumanie 3067:             }
                   3068:             if (ref($curRes)) {
1.468     amueller 3069:                 my $symb = $curRes->symb();
                   3070:                 my $ressymb = $symb;
1.461     neumanie 3071:                 if (($curRes->is_sequence()) || ($curRes->is_page())) {
                   3072:                     my $type = 'sequence';
                   3073:                     if ($curRes->is_page()) {
                   3074:                         $type = 'page';
                   3075:                     }
                   3076:                     my $id= $curRes->id();
1.468     amueller 3077:                     my $srcf = $curRes->src();
                   3078:                     my $resource_name = &Apache::lonnet::gettitle($srcf);
                   3079:                     if(!exists($treeinfo->{$id})) {
                   3080:                         push(@$tree,$id);
1.473     amueller 3081:                         my $enclosing_map_folder = &Apache::lonnet::declutter($curRes->enclosing_map_src());        
1.468     amueller 3082:                         $treeinfo->{$id} = {
1.461     neumanie 3083:                                     depth => $depth,
                   3084:                                     type  => $type,
1.468     amueller 3085:                                     name  => $resource_name,
                   3086:                                     enclosing_map_folder => $enclosing_map_folder,
1.461     neumanie 3087:                                     };
1.462     neumanie 3088:                     }
1.461     neumanie 3089:                 }
                   3090:             }
                   3091:         }
1.462     neumanie 3092:     }
1.473     amueller 3093: # Show it ...    
1.610     raeburn  3094:     my $rowattr = ' id="mapmenu"';
                   3095:     if ($parmlev eq 'general') {
                   3096:         $rowattr .= ' style="display:none"';
                   3097:     }
                   3098:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Enclosing Map or Folder'),'','',$rowattr));
1.461     neumanie 3099:     if ((ref($tree) eq 'ARRAY') && (ref($treeinfo) eq 'HASH')) {
                   3100:         my $icon = '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.497     bisitz   3101:         my $whitespace =
                   3102:             '<img src="'
                   3103:            .&Apache::loncommon::lonhttpdurl('/adm/lonIcons/whitespace_21.gif')
                   3104:            .'" alt="" />';
                   3105: 
1.498     bisitz   3106:         # Info about selectable folders/maps
                   3107:         $r->print(
                   3108:             '<div class="LC_info">'
1.508     www      3109:            .&mt('You can only select maps and folders which have modifiable settings.')
                   3110:            .' '.&Apache::loncommon::help_open_topic('Parameter_Set_Folder') 
1.498     bisitz   3111:            .'</div>'
                   3112:         );
                   3113: 
1.536     raeburn  3114:         $r->print(&Apache::loncommon::start_scrollbox('700px','680px','400px','mapmenuscroll'));
1.523     raeburn  3115:         $r->print(&Apache::loncommon::start_data_table(undef,'mapmenuinner'));
1.497     bisitz   3116: 
1.498     bisitz   3117:         # Display row: "All Maps or Folders"
                   3118:         $r->print(
1.523     raeburn  3119:             &Apache::loncommon::start_data_table_row(undef,'picklevel')
1.498     bisitz   3120:            .'<td>'
                   3121:            .'<label>'
                   3122:            .'<input type="radio" name="pschp"'
1.497     bisitz   3123:         );
                   3124:         $r->print(' checked="checked"') if ($pschp eq 'all' || !$pschp);
1.498     bisitz   3125:         $r->print(
                   3126:             ' value="all" />&nbsp;'.$icon.'&nbsp;'
                   3127:            .&mt('All Maps or Folders')
                   3128:            .'</label>'
                   3129:            .'<hr /></td>'
                   3130:            .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3131:         );
1.497     bisitz   3132: 
1.532     raeburn  3133:         # Display row: "Main Content"
1.468     amueller 3134:         if (exists($$allmaps{1})) {
1.498     bisitz   3135:             $r->print(
                   3136:                 &Apache::loncommon::start_data_table_row()
                   3137:                .'<td>'
                   3138:                .'<label>'
                   3139:                .'<input type="radio" name="pschp" value="1"'
1.468     amueller 3140:             );
1.497     bisitz   3141:             $r->print(' checked="checked"') if ($pschp eq '1');
1.498     bisitz   3142:             $r->print(
                   3143:                 '/>&nbsp;'.$icon.'&nbsp;'
                   3144:                .$$maptitles{1}
                   3145:                .($$allmaps{1} !~/^uploaded/?' ['.$$allmaps{1}.']':'')
                   3146:                .'</label>'
                   3147:                .'</td>'
                   3148:                .&Apache::loncommon::end_data_table_row()
1.468     amueller 3149:             );
                   3150:         }
1.497     bisitz   3151: 
                   3152:         # Display rows for all course maps and folders
1.468     amueller 3153:         foreach my $id (@{$tree}) {
                   3154:             my ($mapid,$resid)=split(/\./,$id);
1.464     bisitz   3155:             # Indentation
1.468     amueller 3156:             my $depth = $treeinfo->{$id}->{'depth'};
1.464     bisitz   3157:             my $indent;
                   3158:             for (my $i = 0; $i < $depth; $i++) {
                   3159:                 $indent.= $whitespace;
                   3160:             }
1.461     neumanie 3161:             $icon =  '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.468     amueller 3162:             if ($treeinfo->{$id}->{'type'} eq 'page') {
1.461     neumanie 3163:                 $icon = '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" />';
                   3164:             }
1.468     amueller 3165:             my $symb_name = $$symbp{$id};
                   3166:             my ($front, $tail) = split (/___${resid}___/, $symb_name);
                   3167:             $symb_name = $tail;
1.498     bisitz   3168:             $r->print(
                   3169:                 &Apache::loncommon::start_data_table_row()
                   3170:                .'<td>'
                   3171:                .'<label>'
1.463     bisitz   3172:             );
1.498     bisitz   3173:             # Only offer radio button for folders/maps which can be parameterized
                   3174:             if ($allmaps_inverted{$symb_name}) {
                   3175:                 $r->print(
                   3176:                     '<input type ="radio" name="pschp"'
                   3177:                    .' value="'.$allmaps_inverted{$symb_name}.'"'
                   3178:                 );
                   3179:                 $r->print(' checked="checked"') if ($allmaps_inverted{$symb_name} eq $pschp);
                   3180:                 $r->print('/>');
                   3181:             } else {
                   3182:                 $r->print($whitespace);
1.461     neumanie 3183:             }
1.498     bisitz   3184:             $r->print(
                   3185:                 $indent.$icon.'&nbsp;'
                   3186:                .$treeinfo->{$id}->{name}
                   3187:                .($$allmaps{$mapid}!~/^uploaded/?' ['.$$allmaps{$mapid}.']':'')
                   3188:                .'</label>'
                   3189:                .'</td>'
                   3190:                .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3191:             );
1.461     neumanie 3192:         }
1.497     bisitz   3193: 
1.523     raeburn  3194:         $r->print(&Apache::loncommon::end_data_table().
                   3195:                   '<br style="line-height:2px;" />'.
                   3196:                   &Apache::loncommon::end_scrollbox());
1.209     www      3197:     }
                   3198: }
                   3199: 
1.563     damieng  3200: # Prints HTML to select the parameter level (resource, map/folder or course).
                   3201: # Used by table and overview modes.
                   3202: #
                   3203: # @param {Apache2::RequestRec} $r - the Apache request
                   3204: # @param {hash reference} $alllevs - all parameter levels, hash English title -> value
                   3205: # @param {string} $parmlev - selected level value (full|map|general), or ''
1.209     www      3206: sub levelmenu {
1.446     bisitz   3207:     my ($r,$alllevs,$parmlev)=@_;
                   3208: 
1.548     raeburn  3209:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameter Level').
                   3210:                                                 &Apache::loncommon::help_open_topic('Course_Parameter_Levels')));
1.474     amueller 3211:     $r->print('<select id="parmlev" name="parmlev" onchange="showHide_courseContent()">');
1.548     raeburn  3212:     foreach my $lev (reverse(sort(keys(%{$alllevs})))) {
                   3213:         $r->print('<option value="'.$$alllevs{$lev}.'"');
                   3214:         if ($parmlev eq $$alllevs{$lev}) {
                   3215:             $r->print(' selected="selected"');
                   3216:         }
                   3217:         $r->print('>'.&mt($lev).'</option>');
1.208     www      3218:     }
1.446     bisitz   3219:     $r->print("</select>");
1.208     www      3220: }
                   3221: 
1.211     www      3222: 
1.563     damieng  3223: # Returns HTML to select a section (with a select HTML element).
                   3224: # Used by overview mode.
                   3225: #
                   3226: # @param {array reference} $selectedsections - list of selected section ids
                   3227: # @returns {string}
1.211     www      3228: sub sectionmenu {
1.553     raeburn  3229:     my ($selectedsections)=@_;
1.300     albertel 3230:     my %sectionhash = &Apache::loncommon::get_sections();
1.553     raeburn  3231:     return '' if (!%sectionhash);
1.300     albertel 3232: 
1.552     raeburn  3233:     my (@possibles,$disabled);
                   3234:     if ($env{'request.course.sec'} ne '') {
                   3235:         @possibles = ($env{'request.course.sec'});
                   3236:         $selectedsections = [$env{'request.course.sec'}];
                   3237:         $disabled = ' disabled="disabled"';
                   3238:     } else {
                   3239:         @possibles = ('all',sort(keys(%sectionhash)));
                   3240:     }
1.553     raeburn  3241:     my $output = '<select name="Section" multiple="multiple" size="8"'.$disabled.'>';
1.552     raeburn  3242:     foreach my $s (@possibles) {
1.553     raeburn  3243:         $output .= '    <option value="'.$s.'"';
                   3244:         if ((@{$selectedsections}) && (grep(/^\Q$s\E$/,@{$selectedsections}))) {  
                   3245:             $output .= ' selected="selected"';
1.473     amueller 3246:         }
1.553     raeburn  3247:         $output .= '>'."$s</option>\n";
1.300     albertel 3248:     }
1.553     raeburn  3249:     $output .= "</select>\n";
                   3250:     return $output;
1.269     raeburn  3251: }
                   3252: 
1.563     damieng  3253: # Returns HTML to select a group (with a select HTML element).
                   3254: # Used by overview mode.
                   3255: #
                   3256: # @param {array reference} $selectedgroups - list of selected group names
                   3257: # @returns {string}
1.269     raeburn  3258: sub groupmenu {
1.553     raeburn  3259:     my ($selectedgroups)=@_;
                   3260:     my %grouphash;
                   3261:     if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3262:         %grouphash = &Apache::longroup::coursegroups();
                   3263:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  3264:          map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  3265:     }
                   3266:     return '' if (!%grouphash);
1.299     albertel 3267: 
1.553     raeburn  3268:     my $output = '<select name="Group" multiple="multiple" size="8">';
1.299     albertel 3269:     foreach my $group (sort(keys(%grouphash))) {
1.553     raeburn  3270:         $output .= '    <option value="'.$group.'"';
                   3271:         if ((@{$selectedgroups}) && (grep(/^\Q$group\E$/,\@{$selectedgroups}))) {
                   3272:             $output .=  ' selected="selected"';
1.473     amueller 3273:         }
1.553     raeburn  3274:         $output .= '>'."$group</option>\n";
1.211     www      3275:     }
1.553     raeburn  3276:     $output .= "</select>\n";
                   3277:     return $output;
1.211     www      3278: }
                   3279: 
1.563     damieng  3280: # Returns an array with the given parameter split by comma.
                   3281: # Used by assessparms (table mode).
                   3282: #
                   3283: # @param {string} $keyp - the string to split
                   3284: # @returns {Array<string>}
1.210     www      3285: sub keysplit {
                   3286:     my $keyp=shift;
                   3287:     return (split(/\,/,$keyp));
                   3288: }
                   3289: 
1.563     damieng  3290: # Returns the keys in $name, sorted using $keyorder.
                   3291: # Parameters are sorted by key, which means they are sorted by part first, then by name.
                   3292: # Used by assessparms (table mode) for resource level.
                   3293: #
                   3294: # @param {hash reference} $name - parameter key -> parameter name
                   3295: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3296: # @returns {Array<string>}
1.210     www      3297: sub keysinorder {
                   3298:     my ($name,$keyorder)=@_;
                   3299:     return sort {
1.560     damieng  3300:         $$keyorder{$a} <=> $$keyorder{$b};
1.548     raeburn  3301:     } (keys(%{$name}));
1.210     www      3302: }
                   3303: 
1.563     damieng  3304: # Returns the keys in $name, sorted using $keyorder to sort parameters by name first, then by part.
                   3305: # Used by assessparms (table mode) for map and general levels.
                   3306: #
                   3307: # @param {hash reference} $name - parameter key -> parameter name
                   3308: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3309: # @returns {Array<string>}
1.236     albertel 3310: sub keysinorder_bytype {
                   3311:     my ($name,$keyorder)=@_;
                   3312:     return sort {
1.563     damieng  3313:         my $ta=(split('_',$a))[-1]; # parameter name
1.560     damieng  3314:         my $tb=(split('_',$b))[-1];
                   3315:         if ($$keyorder{'parameter_0_'.$ta} == $$keyorder{'parameter_0_'.$tb}) {
                   3316:             return ($a cmp $b);
                   3317:         }
                   3318:         $$keyorder{'parameter_0_'.$ta} <=> $$keyorder{'parameter_0_'.$tb};
1.548     raeburn  3319:     } (keys(%{$name}));
1.236     albertel 3320: }
                   3321: 
1.563     damieng  3322: # Returns the keys in $name, sorted using $keyorder to sort parameters by name.
                   3323: # Used by defaultsetter (parameter settings default actions).
                   3324: #
                   3325: # @param {hash reference} $name - hash parameter name -> parameter title
                   3326: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3327: # @returns {Array<string>}
1.211     www      3328: sub keysindisplayorder {
                   3329:     my ($name,$keyorder)=@_;
                   3330:     return sort {
1.560     damieng  3331:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b};
1.548     raeburn  3332:     } (keys(%{$name}));
1.211     www      3333: }
                   3334: 
1.563     damieng  3335: # Prints HTML with a choice to sort results by realm or student first.
                   3336: # Used by overview mode.
                   3337: #
                   3338: # @param {Apache2::RequestRec} $r - the Apache request
                   3339: # @param {string} $sortorder - realmstudent|studentrealm
1.608     raeburn  3340: # @param {string} $context - newoverview|overview
1.214     www      3341: sub sortmenu {
1.608     raeburn  3342:     my ($r,$sortorder,$context)=@_;
                   3343:     my %text;
                   3344:     if ($context eq 'newoverview') {
                   3345:         %text = &Apache::lonlocal::texthash (
                   3346:                    realmstudent => 'Sort by location in course first, then student (group/section)',
                   3347:                    studentrealm => 'Sort by student (group/section) first, then location in course',
                   3348:         );
                   3349:     } else {
                   3350:         %text = &Apache::lonlocal::texthash (
                   3351:                    realmstudent => 'Sort by realm first, then student (group/section)',
                   3352:                    studentrealm => 'Sort by student (group/section) first, then realm',
                   3353:         );
1.214     www      3354:     }
1.608     raeburn  3355:     my %sortchecked = (
                   3356:        realmstudent => ' checked="checked"',
                   3357:        studentrealm => '',
                   3358:     );
1.214     www      3359:     if ($sortorder eq 'studentrealm') {
1.608     raeburn  3360:         $sortchecked{'studentrealm'} = $sortchecked{'realmstudent'};
                   3361:         $sortchecked{'realmstudent'} = '';
                   3362:     }
                   3363:     foreach my $sorttype ('realmstudent','studentrealm') {
                   3364:         $r->print('<br /><label><input type="radio" name="sortorder" value="'.$sorttype.'"'.$sortchecked{$sorttype}.' />'.
                   3365:                   $text{$sorttype}.'</label>');
1.214     www      3366:     }
                   3367: }
                   3368: 
1.563     damieng  3369: # Returns a hash parameter key -> order (integer) giving the order for some parameters.
                   3370: #
                   3371: # @returns {hash}
1.211     www      3372: sub standardkeyorder {
                   3373:     return ('parameter_0_opendate' => 1,
1.473     amueller 3374:         'parameter_0_duedate' => 2,
                   3375:         'parameter_0_answerdate' => 3,
1.622     raeburn  3376:         'parameter_0_grace' => 4,
                   3377:         'parameter_0_interval' => 5,
                   3378:         'parameter_0_weight' => 6,
                   3379:         'parameter_0_maxtries' => 7,
                   3380:         'parameter_0_hinttries' => 8,
                   3381:         'parameter_0_contentopen' => 9,
                   3382:         'parameter_0_contentclose' => 10,
                   3383:         'parameter_0_type' => 11,
                   3384:         'parameter_0_problemstatus' => 12,
                   3385:         'parameter_0_hiddenresource' => 13,
                   3386:         'parameter_0_hiddenparts' => 14,
                   3387:         'parameter_0_display' => 15,
                   3388:         'parameter_0_ordered' => 16,
                   3389:         'parameter_0_tol' => 17,
                   3390:         'parameter_0_sig' => 18,
                   3391:         'parameter_0_turnoffunit' => 19,
                   3392:         'parameter_0_discussend' => 20,
                   3393:         'parameter_0_discusshide' => 21,
                   3394:         'parameter_0_discussvote' => 22,
                   3395:         'parameter_0_printstartdate' => 23,
                   3396:         'parameter_0_printenddate' => 24);
1.211     www      3397: }
                   3398: 
1.59      matthew  3399: 
1.560     damieng  3400: # Table mode UI.
1.563     damieng  3401: # If nothing is selected, prints HTML forms to select resources, parts, parameters, user, group and section.
                   3402: # Otherwise, prints the parameter table, with a link to change the selection unless a single resource is selected.
                   3403: #
                   3404: # Parameters used from the request:
                   3405: # action - handler action (see handler), usermenu is checking for value 'settable'
                   3406: # cgroup - selected group
                   3407: # command - 'set': direct access to table mode for a resource
                   3408: # csec - selected section
                   3409: # dis - set when the "Update Display" button was used, used only to discard command 'set'
                   3410: # hideparmsel - can be 'hidden' to hide the parameter selection div initially and display the "Change Parameter Selection" link instead (which displays the div)
                   3411: # id - student/employee ID
                   3412: # parmlev - selected level (full|map|general)
                   3413: # part - selected part (unused ?)
                   3414: # pres_marker - &&&-separated parameter identifiers, "resource id&part_parameter name&level"
                   3415: # pres_type - &&&-separated parameter types
                   3416: # pres_value - &&&-separated parameter values
                   3417: # prevvisit - '1' if the user has submitted the form before
                   3418: # pscat (multiple values) - selected parameter names
1.566     damieng  3419: # pschp - selected map pc, or 'all'
1.563     damieng  3420: # psprt (multiple values) - list of selected parameter parts
                   3421: # filter - part of or whole parameter name, to be filtered out when parameters are displayed (unused ?)
                   3422: # recent_* (* = parameter type) - recent values entered by the user for parameter types
                   3423: # symb - resource symb (when a single resource is selected)
                   3424: # udom - selected user domain
                   3425: # uname - selected user name
                   3426: # url - used only with command 'set', the resource url
                   3427: #
                   3428: # @param {Apache2::RequestRec} $r - the Apache request
1.568     raeburn  3429: # @param $parm_permission - ref to hash of permissions
                   3430: #                           if $parm_permission->{'edit'} is true, editing is allowed.
1.30      www      3431: sub assessparms {
1.1       www      3432: 
1.568     raeburn  3433:     my ($r,$parm_permission) = @_;
1.201     www      3434: 
1.512     foxr     3435: 
                   3436: # -------------------------------------------------------- Variable declaration
1.566     damieng  3437:     my @ids=(); # resource and map ids
                   3438:     my %symbp=(); # hash map pc or resource/map id -> map src.'___(all)' or resource symb
                   3439:     my %mapp=(); # hash map pc or resource/map id -> enclosing map src
                   3440:     my %typep=(); # hash resource/map id -> resource type (file extension)
                   3441:     my %keyp=(); # hash resource/map id -> comma-separated list of parameter keys
                   3442:     my %uris=(); # hash resource/map id -> resource src
                   3443:     my %maptitles=(); # hash map pc or src -> map title
                   3444:     my %allmaps=(); # hash map pc -> map src
1.582     raeburn  3445:     my %allmaps_inverted=(); # hash map src -> map pc
1.563     damieng  3446:     my %alllevs=(); # hash English level title -> value
                   3447: 
                   3448:     my $uname; # selected user name
                   3449:     my $udom; # selected user domain
                   3450:     my $uhome; # server with the user's files, or 'no_host'
                   3451:     my $csec; # selected section name
                   3452:     my $cgroup; # selected group name
                   3453:     my @usersgroups = (); # list of the user groups
1.582     raeburn  3454:     my $numreclinks = 0;
1.446     bisitz   3455: 
1.190     albertel 3456:     my $coursename=$env{'course.'.$env{'request.course.id'}.'.description'};
1.187     www      3457: 
1.57      albertel 3458:     $alllevs{'Resource Level'}='full';
1.215     www      3459:     $alllevs{'Map/Folder Level'}='map';
1.57      albertel 3460:     $alllevs{'Course Level'}='general';
                   3461: 
1.563     damieng  3462:     my %allparms; # hash parameter name -> parameter title
                   3463:     my %allparts; # hash parameter part -> part title
1.512     foxr     3464: # ------------------------------------------------------------------------------
                   3465: 
1.210     www      3466: #
                   3467: # Order in which these parameters will be displayed
                   3468: #
1.211     www      3469:     my %keyorder=&standardkeyorder();
                   3470: 
1.512     foxr     3471: #    @ids=();
                   3472: #    %symbp=();       # These seem defined above already.
                   3473: #    %typep=();
1.43      albertel 3474: 
                   3475:     my $message='';
                   3476: 
1.190     albertel 3477:     $csec=$env{'form.csec'};
1.552     raeburn  3478:     if ($env{'request.course.sec'} ne '') {
                   3479:         $csec = $env{'request.course.sec'};    
                   3480:     }
                   3481: 
1.553     raeburn  3482: # Check group privs.
1.269     raeburn  3483:     $cgroup=$env{'form.cgroup'};
1.553     raeburn  3484:     my $noeditgrp; 
                   3485:     if ($cgroup ne '') {
                   3486:         unless (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3487:             if (($env{'request.course.groups'} eq '') || 
1.585     raeburn  3488:                 (!grep(/^\Q$cgroup\E$/,split(/:/,$env{'request.course.groups'})))) {
1.553     raeburn  3489:                 $noeditgrp = 1;
                   3490:             }
                   3491:         }
                   3492:     }
1.188     www      3493: 
1.190     albertel 3494:     if      ($udom=$env{'form.udom'}) {
                   3495:     } elsif ($udom=$env{'request.role.domain'}) {
                   3496:     } elsif ($udom=$env{'user.domain'}) {
1.172     albertel 3497:     } else {
1.473     amueller 3498:         $udom=$r->dir_config('lonDefDomain');
1.172     albertel 3499:     }
1.468     amueller 3500:     
1.43      albertel 3501: 
1.134     albertel 3502:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
1.190     albertel 3503:     my $pschp=$env{'form.pschp'};
1.506     www      3504: 
                   3505: 
1.134     albertel 3506:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      3507:     if (!@psprt) { $psprt[0]='all'; }
1.506     www      3508:     if (($env{'form.part'}) && ($psprt[0] ne 'all')) { $psprt[0]=$env{'form.part'}; }
1.57      albertel 3509: 
1.43      albertel 3510:     my $pssymb='';
1.57      albertel 3511:     my $parmlev='';
1.446     bisitz   3512: 
1.190     albertel 3513:     unless ($env{'form.parmlev'}) {
1.57      albertel 3514:         $parmlev = 'map';
                   3515:     } else {
1.190     albertel 3516:         $parmlev = $env{'form.parmlev'};
1.57      albertel 3517:     }
1.26      www      3518: 
1.29      www      3519: # ----------------------------------------------- Was this started from grades?
                   3520: 
1.560     damieng  3521:     if (($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   3522:             (!$env{'form.dis'})) {
1.473     amueller 3523:         my $url=$env{'form.url'};
                   3524:         $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
                   3525:         $pssymb=&Apache::lonnet::symbread($url);
                   3526:         if (!@pscat) { @pscat=('all'); }
                   3527:         $pschp='';
1.57      albertel 3528:         $parmlev = 'full';
1.190     albertel 3529:     } elsif ($env{'form.symb'}) {
1.473     amueller 3530:         $pssymb=$env{'form.symb'};
                   3531:         if (!@pscat) { @pscat=('all'); }
                   3532:         $pschp='';
1.57      albertel 3533:         $parmlev = 'full';
1.43      albertel 3534:     } else {
1.473     amueller 3535:         $env{'form.url'}='';
1.43      albertel 3536:     }
                   3537: 
1.190     albertel 3538:     my $id=$env{'form.id'};
1.43      albertel 3539:     if (($id) && ($udom)) {
1.555     raeburn  3540:         $uname=(&Apache::lonnet::idget($udom,[$id],'ids'))[1];
1.473     amueller 3541:         if ($uname) {
                   3542:             $id='';
                   3543:         } else {
                   3544:             $message=
1.540     bisitz   3545:                 '<p class="LC_warning">'.
                   3546:                 &mt('Unknown ID [_1] at domain [_2]',
                   3547:                     "'".$id."'","'".$udom."'").
                   3548:                 '</p>';
1.473     amueller 3549:         }
1.43      albertel 3550:     } else {
1.473     amueller 3551:         $uname=$env{'form.uname'};
1.43      albertel 3552:     }
                   3553:     unless ($udom) { $uname=''; }
                   3554:     $uhome='';
                   3555:     if ($uname) {
1.473     amueller 3556:         $uhome=&Apache::lonnet::homeserver($uname,$udom);
1.43      albertel 3557:         if ($uhome eq 'no_host') {
1.473     amueller 3558:             $message=
1.540     bisitz   3559:                 '<p class="LC_warning">'.
                   3560:                 &mt('Unknown user [_1] at domain [_2]',
                   3561:                     "'".$uname."'","'".$udom."'").
                   3562:                 '</p>';
1.473     amueller 3563:             $uname='';
1.12      www      3564:         } else {
1.473     amueller 3565:             $csec=&Apache::lonnet::getsection($udom,$uname,
                   3566:                           $env{'request.course.id'});
                   3567:             if ($csec eq '-1') {
1.596     raeburn  3568:                 my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   3569:                 if ($env{'form.userroles'} eq 'any') {
                   3570:                     if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
                   3571:                         $csec = $env{'request.course.sec'};
                   3572:                         $message = '<span class="LC_info">';
                   3573:                         if ($crstype eq 'Community') {
                   3574:                             $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3575:                                             $uname,$udom);
                   3576:                         } else {
                   3577:                             $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3578:                                             $uname,$udom);
                   3579:                         }
                   3580:                         $message .= '</span>';
                   3581:                     } else {
                   3582:                         my @possroles = ('in','ep','ta','cr');
                   3583:                         if ($crstype eq 'Community') {
                   3584:                             unshift(@possroles,'co');
                   3585:                         } else {
                   3586:                             unshift(@possroles,'cc');
                   3587:                         }
                   3588:                         my %not_student_roles =
                   3589:                             &Apache::lonnet::get_my_roles($uname,$udom,'userroles',['active'],
                   3590:                                                           \@possroles,[$udom],1,1);
                   3591:                         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3592:                         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   3593:                         my %sections_by_role;
                   3594:                         foreach my $role (keys(%not_student_roles)) {
                   3595:                             if ($role =~ /^\Q$cnum:$cdom:\E([^:]+):(|[^:]+)$/) {
                   3596:                                 my ($rolename,$sec) = ($1,$2);
                   3597:                                 if ($rolename =~ m{^cr/}) {
                   3598:                                     $rolename = 'cr';
                   3599:                                 }
                   3600:                                 push(@{$sections_by_role{$rolename}},$sec);
                   3601:                             }
                   3602:                         }
                   3603:                         my $numroles = scalar(keys(%sections_by_role));
                   3604:                         if ($numroles) {
                   3605:                             foreach my $role (@possroles) {
                   3606:                                 if (ref($sections_by_role{$role}) eq 'ARRAY') {
                   3607:                                     my @secs = sort { $a <=> $b } @{$sections_by_role{$role}};
                   3608:                                     $csec = $secs[0];
                   3609:                                     last;
                   3610:                                 }
                   3611:                             }
                   3612:                         }
                   3613:                         if ($csec eq '-1') {
                   3614:                             $message = '<span class="LC_warning">';
                   3615:                             if ($crstype eq 'Community') {
                   3616:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this community',
                   3617:                                                 $uname,$udom);
                   3618:                             } else {
                   3619:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this course',
                   3620:                                                 $uname,$udom);
                   3621:                             }
                   3622:                             $message .= '</span>';
                   3623:                             $uname='';
                   3624:                             if ($env{'request.course.sec'} ne '') {
                   3625:                                 $csec=$env{'request.course.sec'};
                   3626:                             } else {
                   3627:                                 $csec=$env{'form.csec'};
                   3628:                             }
                   3629:                             $cgroup=$env{'form.cgroup'};
                   3630:                         } else {
                   3631:                             $message = '<span class="LC_info">';
                   3632:                             if ($crstype eq 'Community') {
                   3633:                                 $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3634:                                          $uname,$udom);
                   3635:                             } else {
                   3636:                                 $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3637:                                                 $uname,$udom);
                   3638:                             }
                   3639:                             $message .= '</span>';
                   3640:                         }
                   3641:                     }
1.594     raeburn  3642:                 } else {
1.596     raeburn  3643:                     $message = '<span class="LC_warning">';
                   3644:                     if ($crstype eq 'Community') {
                   3645:                         $message .= &mt('User [_1] at domain [_2] does not have a member role in this community',
                   3646:                                          $uname,$udom);
                   3647:                     } else {
                   3648:                          $message .= &mt('User [_1] at domain [_2] does not have a student role in this course',
                   3649:                                          $uname,$udom);
                   3650:                     }
                   3651:                     $message .= '</span>';
                   3652:                     $uname='';
                   3653:                     if ($env{'request.course.sec'} ne '') {
                   3654:                         $csec=$env{'request.course.sec'};
                   3655:                     } else {
                   3656:                         $csec=$env{'form.csec'};
                   3657:                     }
                   3658:                     $cgroup=$env{'form.cgroup'};
1.594     raeburn  3659:                 }
                   3660:             } elsif ($env{'request.course.sec'} ne '') {
                   3661:                 if ($csec ne $env{'request.course.sec'}) {
1.596     raeburn  3662:                     $message='<span class="LC_warning">'.
1.594     raeburn  3663:                               &mt("User '[_1]' at domain '[_2]' not in section '[_3]'",
                   3664:                                   $uname,$udom,$env{'request.course.sec'}).
                   3665:                               '</span>';
                   3666:                     $uname='';
                   3667:                     $csec=$env{'request.course.sec'};
                   3668:                 }
1.269     raeburn  3669:                 $cgroup=$env{'form.cgroup'};
1.596     raeburn  3670:             }
                   3671:             if ($uname ne '') {
1.473     amueller 3672:                 my %name=&Apache::lonnet::userenvironment($udom,$uname,
                   3673:                   ('firstname','middlename','lastname','generation','id'));
1.596     raeburn  3674:                 $message .= "\n<p>\n".&mt('Full Name').': '
                   3675:                             .$name{'firstname'}.' '.$name{'middlename'}.' '
                   3676:                             .$name{'lastname'}.' '.$name{'generation'}
                   3677:                             ."<br />\n".&mt('Student/Employee ID').': '.$name{'id'}.'</p>';
                   3678:                 @usersgroups = &Apache::lonnet::get_users_groups(
                   3679:                                    $udom,$uname,$env{'request.course.id'});
                   3680:                 if (@usersgroups > 0) {
                   3681:                     unless (grep(/^\Q$cgroup\E$/,@usersgroups)) {
                   3682:                         $cgroup = $usersgroups[0];
                   3683:                     }
                   3684:                 } else {
                   3685:                     $cgroup = '';
1.297     raeburn  3686:                 }
1.269     raeburn  3687:             }
1.12      www      3688:         }
1.43      albertel 3689:     }
1.2       www      3690: 
1.43      albertel 3691:     unless ($csec) { $csec=''; }
1.269     raeburn  3692:     unless ($cgroup) { $cgroup=''; }
1.12      www      3693: 
1.14      www      3694: # --------------------------------------------------------- Get all assessments
1.446     bisitz   3695:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 3696:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  3697:                 \%keyorder,undef,$pssymb);
1.63      bowersj2 3698: 
1.582     raeburn  3699:     %allmaps_inverted = reverse(%allmaps);
                   3700: 
1.57      albertel 3701:     $mapp{'0.0'} = '';
                   3702:     $symbp{'0.0'} = '';
1.99      albertel 3703: 
1.14      www      3704: # ---------------------------------------------------------- Anything to store?
1.568     raeburn  3705:     if ($env{'form.pres_marker'} && $parm_permission->{'edit'}) {
1.205     www      3706:         my @markers=split(/\&\&\&/,$env{'form.pres_marker'});
                   3707:         my @values=split(/\&\&\&/,$env{'form.pres_value'});
                   3708:         my @types=split(/\&\&\&/,$env{'form.pres_type'});
1.500     raeburn  3709:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3710:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.504     raeburn  3711:         my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   3712:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   3713:         my $totalstored = 0;
1.605     raeburn  3714:         my $totalskippeduser = 0;
1.546     raeburn  3715:         my $now = time;
1.473     amueller 3716:         for (my $i=0;$i<=$#markers;$i++) {
1.557     raeburn  3717:             my ($needsrelease,$needsnewer,$name,$namematch);
1.556     raeburn  3718:             if (($env{'request.course.sec'} ne '') && ($markers[$i] =~ /\&(9|10|11|12)$/)) {
1.552     raeburn  3719:                 next if ($csec ne $env{'request.course.sec'});
                   3720:             }
1.556     raeburn  3721:             if ($markers[$i] =~ /\&(8|7|6|5)$/) {
1.553     raeburn  3722:                 next if ($noeditgrp);
1.605     raeburn  3723:             } elsif ($markers[$i] =~ /\&(4|3|2|1)$/) {
                   3724:                 if ($uname eq '') {
                   3725:                     $totalskippeduser ++;
                   3726:                     next;
                   3727:                 }
1.557     raeburn  3728:             }
                   3729:             if ($markers[$i] =~ /\&(17|11|7|3)$/) {
                   3730:                 $namematch = 'maplevelrecurse';
                   3731:             }
1.556     raeburn  3732:             if ($markers[$i] =~ /^[\d.]+\&0_availablestudent\&(1|2|3|4)$/) {
1.437     raeburn  3733:                 my (@ok_slots,@fail_slots,@del_slots);
                   3734:                 my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
                   3735:                 my ($level,@all) =
                   3736:                     &parmval_by_symb('0.availablestudent',$pssymb,'',$uname,$udom,
                   3737:                                      $csec,$cgroup,$courseopt);
                   3738:                 foreach my $slot_name (split(/:/,$values[$i])) {
                   3739:                     next if ($slot_name eq '');
                   3740:                     if (&update_slots($slot_name,$cdom,$cnum,$pssymb,$uname,$udom) eq 'ok') {
                   3741:                         push(@ok_slots,$slot_name);
                   3742: 
                   3743:                     } else {
                   3744:                         push(@fail_slots,$slot_name);
                   3745:                     }
                   3746:                 }
                   3747:                 if (@ok_slots) {
                   3748:                     $values[$i] = join(':',@ok_slots);
                   3749:                 } else {
                   3750:                     $values[$i] = '';
                   3751:                 }
                   3752:                 if ($all[$level] ne '') {
                   3753:                     my @existing = split(/:/,$all[$level]);
                   3754:                     foreach my $slot_name (@existing) {
                   3755:                         if (!grep(/^\Q$slot_name\E$/,split(/:/,$values[$i]))) {
                   3756:                             if (&delete_slots($slot_name,$cdom,$cnum,$uname,$udom,$pssymb) eq 'ok') {
                   3757:                                 push(@del_slots,$slot_name);
                   3758:                             }
                   3759:                         }
                   3760:                     }
                   3761:                 }
1.554     raeburn  3762:             } elsif ($markers[$i] =~ /_(type|lenient|retrypartial|discussvote|examcode|printstartdate|printenddate|acc|interval)\&\d+$/) {
1.514     raeburn  3763:                 $name = $1;
1.533     raeburn  3764:                 my $val = $values[$i];
1.549     raeburn  3765:                 my $valmatch = '';
1.533     raeburn  3766:                 if ($name eq 'examcode') {
1.544     raeburn  3767:                     if (&Apache::lonnet::validCODE($values[$i])) {
                   3768:                         $val = 'valid';
                   3769:                     }
1.546     raeburn  3770:                 } elsif ($name eq 'printstartdate') {
                   3771:                     if ($val =~ /^\d+$/) {
                   3772:                         if ($val > $now) {
                   3773:                             $val = 'future';
                   3774:                         }
                   3775:                     } 
                   3776:                 } elsif ($name eq 'printenddate') {
                   3777:                     if ($val =~ /^\d+$/) {
                   3778:                         if ($val < $now) {
                   3779:                             $val = 'past';
                   3780:                         }
                   3781:                     }
1.549     raeburn  3782:                 } elsif (($name eq 'lenient') || ($name eq 'acc')) {
                   3783:                     my $stringtype = &get_stringtype($name);
                   3784:                     my $stringmatch = &standard_string_matches($stringtype);
                   3785:                     if (ref($stringmatch) eq 'ARRAY') {
                   3786:                         foreach my $item (@{$stringmatch}) {
                   3787:                             if (ref($item) eq 'ARRAY') {
                   3788:                                 my ($regexpname,$pattern) = @{$item};
                   3789:                                 if ($pattern ne '') {
                   3790:                                     if ($val =~ /$pattern/) {
                   3791:                                         $valmatch = $regexpname;
                   3792:                                         $val = '';
                   3793:                                         last;
                   3794:                                     }
                   3795:                                 }
                   3796:                             }
                   3797:                         }
                   3798:                     }
1.554     raeburn  3799:                 } elsif ($name eq 'interval') {
                   3800:                     my $intervaltype = &get_intervaltype($name);
                   3801:                     my $intervalmatch = &standard_interval_matches($intervaltype);
                   3802:                     if (ref($intervalmatch) eq 'ARRAY') {
                   3803:                         foreach my $item (@{$intervalmatch}) {
                   3804:                             if (ref($item) eq 'ARRAY') {
                   3805:                                 my ($regexpname,$pattern) = @{$item};
                   3806:                                 if ($pattern ne '') {
                   3807:                                     if ($val =~ /$pattern/) {
                   3808:                                         $valmatch = $regexpname;
                   3809:                                         $val = '';
                   3810:                                         last;
                   3811:                                     }
                   3812:                                 }
                   3813:                             }
                   3814:                         }
                   3815:                     }
1.533     raeburn  3816:                 }
1.504     raeburn  3817:                 $needsrelease =
1.557     raeburn  3818:                     $Apache::lonnet::needsrelease{"parameter:$name:$val:$valmatch:"};
1.504     raeburn  3819:                 if ($needsrelease) {
1.505     raeburn  3820:                     unless ($got_chostname) {
1.514     raeburn  3821:                         ($chostname,$cmajor,$cminor) = &parameter_release_vars();
1.504     raeburn  3822:                         $got_chostname = 1;
1.546     raeburn  3823:                     } 
1.557     raeburn  3824:                     $needsnewer = &parameter_releasecheck($name,$val,$valmatch,undef,
1.514     raeburn  3825:                                                           $needsrelease,
                   3826:                                                           $cmajor,$cminor);
1.500     raeburn  3827:                 }
1.437     raeburn  3828:             }
1.504     raeburn  3829:             if ($needsnewer) {
1.557     raeburn  3830:                 undef($namematch);
                   3831:             } else {
                   3832:                 my $currneeded;
                   3833:                 if ($needsrelease) {
                   3834:                     $currneeded = $needsrelease;
                   3835:                 }
                   3836:                 if ($namematch) {
                   3837:                     $needsrelease =
                   3838:                         $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   3839:                     if (($needsrelease) && (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   3840:                         unless ($got_chostname) {
                   3841:                             ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   3842:                             $got_chostname = 1;
                   3843:                         }
                   3844:                         $needsnewer = &parameter_releasecheck(undef,undef,undef,$namematch,
                   3845:                                                               $needsrelease,
                   3846:                                                               $cmajor,$cminor);
                   3847:                     } else {
                   3848:                         undef($namematch);
                   3849:                     }
                   3850:                 }
                   3851:             }
                   3852:             if ($needsnewer) {
                   3853:                 $message .= &oldversion_warning($name,$namematch,$values[$i],$chostname,$cmajor,
1.504     raeburn  3854:                                                 $cminor,$needsrelease);
                   3855:             } else {
                   3856:                 $message.=&storeparm(split(/\&/,$markers[$i]),
                   3857:                                      $values[$i],
                   3858:                                      $types[$i],
                   3859:                                      $uname,$udom,$csec,$cgroup);
                   3860:                 $totalstored ++;
                   3861:             }
1.473     amueller 3862:         }
1.68      www      3863: # ---------------------------------------------------------------- Done storing
1.504     raeburn  3864:         if ($totalstored) {
                   3865:             $message.='<p class="LC_warning">'
1.605     raeburn  3866:                      .&mt('Changes for [quant,_1,parameter] saved.',$totalstored)
                   3867:                      .'<br />'
1.504     raeburn  3868:                      .&mt('Changes can take up to 10 minutes before being active for all students.')
                   3869:                      .&Apache::loncommon::help_open_topic('Caching')
                   3870:                      .'</p>';
1.605     raeburn  3871:         } else {
                   3872:             $message.='<p class="LC_info">'.&mt('No parameter changes saved.').'</p>';
                   3873:         }
                   3874:         if ($totalskippeduser) {
                   3875:             $message .= '<p class="LC_warning">';
                   3876:             if ($uhome eq 'no_host') {
                   3877:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the username or ID was invalid.',
                   3878:                                 $totalskippeduser);
                   3879:             } elsif ($env{'form.userroles'} eq 'any') {
                   3880:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user does not have a course role.',
                   3881:                                 $totalskippeduser);
                   3882:             } else {
                   3883:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user is not a student.',
                   3884:                                 $totalskippeduser);
                   3885:             }
                   3886:             $message .= '</p>';
1.504     raeburn  3887:         }
1.68      www      3888:     }
1.584     raeburn  3889: 
1.57      albertel 3890: #----------------------------------------------- if all selected, fill in array
1.563     damieng  3891:     if ($pscat[0] eq "all") {
                   3892:         @pscat = (keys(%allparms));
                   3893:     }
                   3894:     if (!@pscat) {
                   3895:         @pscat=('duedate','opendate','answerdate','weight','maxtries','type','problemstatus')
                   3896:     };
                   3897:     if ($psprt[0] eq "all" || !@psprt) {
                   3898:         @psprt = (keys(%allparts));
                   3899:     }
1.2       www      3900: # ------------------------------------------------------------------ Start page
1.63      bowersj2 3901: 
1.531     raeburn  3902:     my $crstype = &Apache::loncommon::course_type();
                   3903:     &startpage($r,$pssymb,$crstype);
1.57      albertel 3904: 
1.548     raeburn  3905:     foreach my $item ('tolerance','date_default','date_start','date_end',
1.589     raeburn  3906:             'date_interval','int','float','string','string_lenient',
                   3907:             'string_examcode','string_deeplink','string_discussvote',
                   3908:             'string_useslots','string_problemstatus','string_ip',
1.622     raeburn  3909:             'string_questiontype','string_tex','string_grace') {
1.473     amueller 3910:         $r->print('<input type="hidden" value="'.
1.563     damieng  3911:             &HTML::Entities::encode($env{'form.recent_'.$item},'"&<>').
                   3912:             '" name="recent_'.$item.'" />');
1.44      albertel 3913:     }
1.446     bisitz   3914: 
1.459     bisitz   3915:     # ----- Start Parameter Selection
                   3916: 
1.606     raeburn  3917:     # Hide parm selection and possibly table?
                   3918:     my ($tablejs,$tabledivsty);
                   3919:     if (((($env{'form.uname'} ne '') || ($env{'form.id'} ne '')) && ($uname eq '')) &&
                   3920:         ($env{'form.dis'}) && ($pssymb eq '')) {
                   3921:         $tablejs = 'document.getElementById('."'parmtable'".').style.display = "";';
                   3922:         $tabledivsty = ' style="display:none"';
                   3923:     }
1.459     bisitz   3924:     $r->print(<<ENDPARMSELSCRIPT);
                   3925: <script type="text/javascript">
                   3926: // <![CDATA[
                   3927: function parmsel_show() {
1.562     damieng  3928:     document.getElementById('parmsel').style.display = "";
                   3929:     document.getElementById('parmsellink').style.display = "none";
1.606     raeburn  3930:     $tablejs
1.459     bisitz   3931: }
                   3932: // ]]>
                   3933: </script>
                   3934: ENDPARMSELSCRIPT
1.474     amueller 3935:     
1.445     neumanie 3936:     if (!$pssymb) {
1.563     damieng  3937:         # No single resource selected, print forms to select things (hidden after first selection)
1.486     www      3938:         my $parmselhiddenstyle=' style="display:none"';
                   3939:         if($env{'form.hideparmsel'} eq 'hidden') {
                   3940:            $r->print('<div id="parmsel"'.$parmselhiddenstyle.'>');
                   3941:         } else  {
                   3942:            $r->print('<div id="parmsel">');
                   3943:         }
                   3944: 
1.491     bisitz   3945:         # Step 1
1.523     raeburn  3946:         $r->print(&Apache::lonhtmlcommon::topic_bar(1,&mt('Resource Specification'),'parmstep1'));
                   3947:         $r->print('
1.474     amueller 3948: <script type="text/javascript">
1.523     raeburn  3949: // <![CDATA['.
                   3950:                  &showhide_js().'
1.474     amueller 3951: // ]]>
                   3952: </script>
1.523     raeburn  3953: ');
                   3954:         $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.209     www      3955:         &levelmenu($r,\%alllevs,$parmlev);
1.491     bisitz   3956:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.610     raeburn  3957:         &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.491     bisitz   3958:         $r->print(&Apache::lonhtmlcommon::row_closure());
                   3959:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
                   3960:         &partmenu($r,\%allparts,\@psprt);
1.474     amueller 3961:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3962:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3963: 
                   3964:         # Step 2
1.523     raeburn  3965:         $r->print(&Apache::lonhtmlcommon::topic_bar(2,&mt('Parameter Specification'),'parmstep2'));
1.581     raeburn  3966:         &displaymenu($r,\%allparms,\@pscat,\%keyorder,'parmmenuscroll');
1.491     bisitz   3967: 
                   3968:         # Step 3
1.523     raeburn  3969:         $r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('User Specification (optional)'),'parmstep3'));
1.486     www      3970:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  3971:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      3972:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3973:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3974: 
                   3975:         # Update Display Button
1.486     www      3976:         $r->print('<p>'
                   3977:              .'<input type="submit" name="dis"'
1.511     www      3978:              .' value="'.&mt('Update Display').'" />'
1.486     www      3979:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
                   3980:              .'</p>');
                   3981:         $r->print('</div>');
1.491     bisitz   3982: 
1.486     www      3983:         # Offer link to display parameter selection again
                   3984:         $r->print('<p id="parmsellink"');
                   3985:         if ($env{'form.hideparmsel'} ne 'hidden') {
                   3986:            $r->print($parmselhiddenstyle);
                   3987:         }
                   3988:         $r->print('>'
                   3989:              .'<a href="javascript:parmsel_show()">'
                   3990:              .&mt('Change Parameter Selection')
                   3991:              .'</a>'
                   3992:              .'</p>');
1.44      albertel 3993:     } else {
1.478     amueller 3994:         # parameter screen for a single resource. 
1.486     www      3995:         my ($map,$iid,$resource)=&Apache::lonnet::decode_symb($pssymb);
1.473     amueller 3996:         my $title = &Apache::lonnet::gettitle($pssymb);
1.501     bisitz   3997:         $r->print(&mt('Specific Resource: [_1] ([_2])',
                   3998:                          $title,'<span class="LC_filename">'.$resource.'</span>').
1.472     amueller 3999:                 '<input type="hidden" value="'.$pssymb.'" name="symb" />'.
1.486     www      4000:                   '<br />');
                   4001:         $r->print(&Apache::lonhtmlcommon::topic_bar('',&mt('Additional Display Specification (optional)')));
                   4002:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  4003:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      4004:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   4005:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   4006:         $r->print('<p>'
1.459     bisitz   4007:              .'<input type="submit" name="dis"'
1.511     www      4008:              .' value="'.&mt('Update Display').'" />'
1.459     bisitz   4009:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
1.486     www      4010:              .'</p>');
1.459     bisitz   4011:     }
1.478     amueller 4012:     
1.486     www      4013:     # ----- End Parameter Selection
1.57      albertel 4014: 
1.459     bisitz   4015:     # Display Messages
                   4016:     $r->print('<div>'.$message.'</div>');
1.210     www      4017: 
1.57      albertel 4018: 
                   4019:     my @temp_pscat;
                   4020:     map {
                   4021:         my $cat = $_;
                   4022:         push(@temp_pscat, map { $_.'.'.$cat } @psprt);
                   4023:     } @pscat;
                   4024: 
                   4025:     @pscat = @temp_pscat;
                   4026: 
1.548     raeburn  4027: 
1.209     www      4028:     if (($env{'form.prevvisit'}) || ($pschp) || ($pssymb)) {
1.10      www      4029: # ----------------------------------------------------------------- Start Table
1.57      albertel 4030:         my @catmarker=map { tr|.|_|; 'parameter_'.$_; } @pscat;
1.190     albertel 4031:         my $csuname=$env{'user.name'};
                   4032:         my $csudom=$env{'user.domain'};
1.568     raeburn  4033:         my $readonly = 1;
                   4034:         if ($parm_permission->{'edit'}) {
                   4035:             undef($readonly); 
                   4036:         }
1.606     raeburn  4037:         $r->print('<div id="parmtable"'.$tabledivsty.'>');
1.57      albertel 4038: 
1.203     www      4039:         if ($parmlev eq 'full') {
1.506     www      4040: #
                   4041: # This produces the cascading table output of parameters
                   4042: #
1.578     raeburn  4043:             my $coursespan=$csec?8:5;
                   4044:             my $userspan=3;
1.560     damieng  4045:             if ($cgroup ne '') {
1.578     raeburn  4046:                 $coursespan += 3;
1.560     damieng  4047:             }
1.473     amueller 4048: 
1.560     damieng  4049:             $r->print(&Apache::loncommon::start_data_table());
                   4050:             #
                   4051:             # This produces the headers
                   4052:             #
                   4053:             $r->print('<tr><td colspan="5"></td>');
                   4054:             $r->print('<th colspan="'.($coursespan).'">'.&mt('Any User').'</th>');
                   4055:             if ($uname) {
1.473     amueller 4056:                 if (@usersgroups > 1) {
1.560     damieng  4057:                     $userspan ++;
                   4058:                 }
                   4059:                 $r->print('<th colspan="'.$userspan.'" rowspan="2">');
                   4060:                 $r->print(&mt('User [_1] at Domain [_2]',"'".$uname."'","'".$udom."'").'</th>');
                   4061:             }
                   4062:             my %lt=&Apache::lonlocal::texthash(
1.473     amueller 4063:                 'pie'    => "Parameter in Effect",
                   4064:                 'csv'    => "Current Session Value",
1.472     amueller 4065:                 'rl'     => "Resource Level",
1.473     amueller 4066:                 'ic'     => 'in Course',
                   4067:                 'aut'    => "Assessment URL and Title",
                   4068:                 'type'   => 'Type',
                   4069:                 'emof'   => "Enclosing Map or Folder",
                   4070:                 'part'   => 'Part',
1.472     amueller 4071:                 'pn'     => 'Parameter Name',
1.473     amueller 4072:                 'def'    => 'default',
                   4073:                 'femof'  => 'from Enclosing Map or Folder',
                   4074:                 'gen'    => 'general',
                   4075:                 'foremf' => 'for Enclosing Map or Folder',
                   4076:                 'fr'     => 'for Resource'
                   4077:             );
1.560     damieng  4078:             $r->print(<<ENDTABLETWO);
1.419     bisitz   4079: <th rowspan="3">$lt{'pie'}</th>
1.501     bisitz   4080: <th rowspan="3">$lt{'csv'}<br />($csuname:$csudom)</th>
1.578     raeburn  4081: </tr><tr><td colspan="5"></td><th colspan="2">$lt{'ic'}</th><th colspan="2">$lt{'rl'}</th>
1.419     bisitz   4082: <th colspan="1">$lt{'ic'}</th>
1.182     albertel 4083: 
1.10      www      4084: ENDTABLETWO
1.560     damieng  4085:             if ($csec) {
1.578     raeburn  4086:                 $r->print('<th colspan="3">'.
1.560     damieng  4087:                 &mt("in Section")." $csec</th>");
                   4088:             }
                   4089:             if ($cgroup) {
1.578     raeburn  4090:                 $r->print('<th colspan="3">'.
1.472     amueller 4091:                 &mt("in Group")." $cgroup</th>");
1.560     damieng  4092:             }
                   4093:             $r->print(<<ENDTABLEHEADFOUR);
1.133     www      4094: </tr><tr><th>$lt{'aut'}</th><th>$lt{'type'}</th>
                   4095: <th>$lt{'emof'}</th><th>$lt{'part'}</th><th>$lt{'pn'}</th>
1.578     raeburn  4096: <th>$lt{'gen'}</th><th>$lt{'foremf'}</th>
1.192     albertel 4097: <th>$lt{'def'}</th><th>$lt{'femof'}</th><th>$lt{'fr'}</th>
1.10      www      4098: ENDTABLEHEADFOUR
1.57      albertel 4099: 
1.560     damieng  4100:             if ($csec) {
1.578     raeburn  4101:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4102:             }
1.473     amueller 4103: 
1.560     damieng  4104:             if ($cgroup) {
1.578     raeburn  4105:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4106:             }
                   4107: 
                   4108:             if ($uname) {
                   4109:                 if (@usersgroups > 1) {
                   4110:                     $r->print('<th>'.&mt('Control by other group?').'</th>');
                   4111:                 }
1.578     raeburn  4112:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4113:             }
                   4114: 
                   4115:             $r->print('</tr>');
1.506     www      4116: #
                   4117: # Done with the headers
                   4118: # 
1.560     damieng  4119:             my $defbgone='';
                   4120:             my $defbgtwo='';
                   4121:             my $defbgthree = '';
1.57      albertel 4122: 
1.560     damieng  4123:             foreach my $rid (@ids) {
1.57      albertel 4124: 
                   4125:                 my ($inmapid)=($rid=~/\.(\d+)$/);
1.446     bisitz   4126:                 if ((!$pssymb &&
1.560     damieng  4127:                         (($pschp eq 'all') || ($allmaps{$pschp} eq $mapp{$rid})))
                   4128:                         ||
                   4129:                         ($pssymb && $pssymb eq $symbp{$rid})) {
1.4       www      4130: # ------------------------------------------------------ Entry for one resource
1.473     amueller 4131:                     if ($defbgone eq '#E0E099') {
                   4132:                         $defbgone='#E0E0DD';
1.57      albertel 4133:                     } else {
1.419     bisitz   4134:                         $defbgone='#E0E099';
1.57      albertel 4135:                     }
1.419     bisitz   4136:                     if ($defbgtwo eq '#FFFF99') {
1.473     amueller 4137:                         $defbgtwo='#FFFFDD';
1.57      albertel 4138:                     } else {
1.473     amueller 4139:                         $defbgtwo='#FFFF99';
1.57      albertel 4140:                     }
1.419     bisitz   4141:                     if ($defbgthree eq '#FFBB99') {
                   4142:                         $defbgthree='#FFBBDD';
1.269     raeburn  4143:                     } else {
1.419     bisitz   4144:                         $defbgthree='#FFBB99';
1.269     raeburn  4145:                     }
                   4146: 
1.57      albertel 4147:                     my $thistitle='';
                   4148:                     my %name=   ();
                   4149:                     undef %name;
                   4150:                     my %part=   ();
                   4151:                     my %display=();
                   4152:                     my %type=   ();
                   4153:                     my %default=();
1.196     www      4154:                     my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4155:                     my $toolsymb;
                   4156:                     if ($uri =~ /ext\.tool$/) {
                   4157:                         $toolsymb = $symbp{$rid};
                   4158:                     }
1.57      albertel 4159: 
1.506     www      4160:                     my $filter=$env{'form.filter'};
1.548     raeburn  4161:                     foreach my $tempkeyp (&keysplit($keyp{$rid})) {
1.57      albertel 4162:                         if (grep $_ eq $tempkeyp, @catmarker) {
1.584     raeburn  4163:                             my $parmname=&Apache::lonnet::metadata($uri,$tempkeyp.'.name',$toolsymb);
1.560     damieng  4164:     # We may only want certain parameters listed
                   4165:                             if ($filter) {
                   4166:                                 unless ($filter=~/\Q$parmname\E/) { next; }
                   4167:                             }
                   4168:                             $name{$tempkeyp}=$parmname;
1.584     raeburn  4169:                             $part{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.part',$toolsymb);
1.560     damieng  4170: 
1.584     raeburn  4171:                             my $parmdis=&Apache::lonnet::metadata($uri,$tempkeyp.'.display',$toolsymb);
1.560     damieng  4172:                             if ($allparms{$name{$tempkeyp}} ne '') {
                   4173:                                 my $identifier;
                   4174:                                 if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4175:                                     $identifier = $1;
                   4176:                                 }
                   4177:                                 $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4178:                             } else {
                   4179:                                 $display{$tempkeyp} = $parmdis;
                   4180:                             }
                   4181:                             unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4182:                             $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
1.584     raeburn  4183:                             $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp,$toolsymb);
                   4184:                             $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.type',$toolsymb);
                   4185:                             $thistitle=&Apache::lonnet::metadata($uri,$tempkeyp.'.title',$toolsymb);
1.57      albertel 4186:                         }
                   4187:                     }
1.548     raeburn  4188:                     my $totalparms=scalar(keys(%name));
1.57      albertel 4189:                     if ($totalparms>0) {
1.560     damieng  4190:                         my $firstrow=1;
1.473     amueller 4191:                         my $title=&Apache::lonnet::gettitle($symbp{$rid});
1.582     raeburn  4192:                         my $navmap = Apache::lonnavmaps::navmap->new();
                   4193:                         my @recurseup;
                   4194:                         if (ref($navmap) && $mapp{$rid}) {
                   4195:                             @recurseup = $navmap->recurseup_maps($mapp{$rid});
                   4196:                         }
1.419     bisitz   4197:                         $r->print('<tr><td style="background-color:'.$defbgone.';"'.
1.57      albertel 4198:                              ' rowspan='.$totalparms.
1.419     bisitz   4199:                              '><tt><font size="-1">'.
1.57      albertel 4200:                              join(' / ',split(/\//,$uri)).
                   4201:                              '</font></tt><p><b>'.
1.154     albertel 4202:                              "<a href=\"javascript:openWindow('".
1.473     amueller 4203:                           &Apache::lonnet::clutter($uri).'?symb='.
                   4204:                           &escape($symbp{$rid}).
1.336     albertel 4205:                              "', 'metadatafile', '450', '500', 'no', 'yes');\"".
                   4206:                              " target=\"_self\">$title");
1.57      albertel 4207: 
                   4208:                         if ($thistitle) {
1.473     amueller 4209:                             $r->print(' ('.$thistitle.')');
1.57      albertel 4210:                         }
                   4211:                         $r->print('</a></b></td>');
1.419     bisitz   4212:                         $r->print('<td style="background-color:'.$defbgtwo.';"'.
1.57      albertel 4213:                                       ' rowspan='.$totalparms.'>'.$typep{$rid}.
                   4214:                                       '</td>');
                   4215: 
1.419     bisitz   4216:                         $r->print('<td style="background-color:'.$defbgone.';"'.
1.57      albertel 4217:                                       ' rowspan='.$totalparms.
1.238     www      4218:                                       '>'.$maptitles{$mapp{$rid}}.'</td>');
1.548     raeburn  4219:                         foreach my $item (&keysinorder_bytype(\%name,\%keyorder)) {
1.57      albertel 4220:                             unless ($firstrow) {
                   4221:                                 $r->print('<tr>');
                   4222:                             } else {
                   4223:                                 undef $firstrow;
                   4224:                             }
1.548     raeburn  4225:                             &print_row($r,$item,\%part,\%name,\%symbp,$rid,\%default,
1.57      albertel 4226:                                        \%type,\%display,$defbgone,$defbgtwo,
1.269     raeburn  4227:                                        $defbgthree,$parmlev,$uname,$udom,$csec,
1.582     raeburn  4228:                                        $cgroup,\@usersgroups,$noeditgrp,$readonly,
                   4229:                                        \@recurseup,\%maptitles,\%allmaps_inverted,
                   4230:                                        \$numreclinks);
1.57      albertel 4231:                         }
                   4232:                     }
                   4233:                 }
                   4234:             } # end foreach ids
1.43      albertel 4235: # -------------------------------------------------- End entry for one resource
1.517     www      4236:             $r->print(&Apache::loncommon::end_data_table);
1.203     www      4237:         } # end of  full
1.57      albertel 4238: #--------------------------------------------------- Entry for parm level map
                   4239:         if ($parmlev eq 'map') {
1.419     bisitz   4240:             my $defbgone = '#E0E099';
                   4241:             my $defbgtwo = '#FFFF99';
                   4242:             my $defbgthree = '#FFBB99';
1.57      albertel 4243: 
                   4244:             my %maplist;
                   4245: 
                   4246:             if ($pschp eq 'all') {
1.446     bisitz   4247:                 %maplist = %allmaps;
1.57      albertel 4248:             } else {
                   4249:                 %maplist = ($pschp => $mapp{$pschp});
                   4250:             }
                   4251: 
                   4252: #-------------------------------------------- for each map, gather information
                   4253:             my $mapid;
1.607     raeburn  4254:             foreach $mapid (sort { $a <=> $b } keys(%maplist)) {
1.60      albertel 4255:                 my $maptitle = $maplist{$mapid};
1.57      albertel 4256: 
                   4257: #-----------------------  loop through ids and get all parameter types for map
                   4258: #-----------------------------------------          and associated information
                   4259:                 my %name = ();
                   4260:                 my %part = ();
                   4261:                 my %display = ();
                   4262:                 my %type = ();
                   4263:                 my %default = ();
                   4264:                 my $map = 0;
                   4265: 
1.473     amueller 4266: #        $r->print("Catmarker: @catmarker<br />\n");
1.446     bisitz   4267: 
1.548     raeburn  4268:                 foreach my $id (@ids) {
                   4269:                     ($map)=($id =~ /([\d]*?)\./);
                   4270:                     my $rid = $id;
1.446     bisitz   4271: 
1.57      albertel 4272: #                  $r->print("$mapid:$map:   $rid <br /> \n");
                   4273: 
1.560     damieng  4274:                     if ($map eq $mapid) {
1.473     amueller 4275:                         my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4276:                         my $toolsymb;
                   4277:                         if ($uri =~ /ext\.tool$/) {
                   4278:                             $toolsymb = $symbp{$rid};
                   4279:                         }
1.582     raeburn  4280: 
1.57      albertel 4281: #                    $r->print("Keys: $keyp{$rid} <br />\n");
                   4282: 
                   4283: #--------------------------------------------------------------------
                   4284: # @catmarker contains list of all possible parameters including part #s
                   4285: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4286: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4287: # When storing information, store as part 0
                   4288: # When requesting information, request from full part
                   4289: #-------------------------------------------------------------------
1.548     raeburn  4290:                         foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4291:                             my $tempkeyp = $fullkeyp;
                   4292:                             $tempkeyp =~ s/_\w+_/_0_/;
1.473     amueller 4293: 
1.548     raeburn  4294:                             if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4295:                                 $part{$tempkeyp}="0";
1.584     raeburn  4296:                                 $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4297:                                 my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4298:                                 if ($allparms{$name{$tempkeyp}} ne '') {
                   4299:                                     my $identifier;
                   4300:                                     if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4301:                                         $identifier = $1;
                   4302:                                     }
                   4303:                                     $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4304:                                 } else {
                   4305:                                     $display{$tempkeyp} = $parmdis;
                   4306:                                 }
                   4307:                                 unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4308:                                 $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4309:                                 $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4310:                                 $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4311:                                 $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.473     amueller 4312:                               }
                   4313:                         } # end loop through keys
1.560     damieng  4314:                     }
1.57      albertel 4315:                 } # end loop through ids
1.446     bisitz   4316: 
1.57      albertel 4317: #---------------------------------------------------- print header information
1.133     www      4318:                 my $foldermap=&mt($maptitle=~/^uploaded/?'Folder':'Map');
1.82      www      4319:                 my $showtitle=$maptitles{$maptitle}.($maptitle!~/^uploaded/?' ['.$maptitle.']':'');
1.401     bisitz   4320:                 my $tmp="";
1.57      albertel 4321:                 if ($uname) {
1.473     amueller 4322:                     my $person=&Apache::loncommon::plainname($uname,$udom);
1.401     bisitz   4323:                     $tmp.=&mt("User")." <font color=\"red\"><i>$uname \($person\) </i></font> ".
                   4324:                         &mt('in')." \n";
1.57      albertel 4325:                 } else {
1.401     bisitz   4326:                     $tmp.="<font color=\"red\"><i>".&mt('all').'</i></font> '.&mt('users in')." \n";
1.57      albertel 4327:                 }
1.269     raeburn  4328:                 if ($cgroup) {
1.401     bisitz   4329:                     $tmp.=&mt("Group")." <font color=\"red\"><i>$cgroup".
                   4330:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4331:                     $csec = '';
                   4332:                 } elsif ($csec) {
1.401     bisitz   4333:                     $tmp.=&mt("Section")." <font color=\"red\"><i>$csec".
                   4334:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4335:                 }
1.401     bisitz   4336:                 $r->print('<div align="center"><h4>'
                   4337:                          .&mt('Set Defaults for All Resources in [_1]Specifically for [_2][_3]'
1.404     bisitz   4338:                              ,$foldermap.'<br /><font color="red"><i>'.$showtitle.'</i></font><br />'
1.401     bisitz   4339:                              ,$tmp
                   4340:                              ,'<font color="red"><i>'.$coursename.'</i></font>'
                   4341:                              )
                   4342:                          ."<br /></h4>\n"
1.422     bisitz   4343:                 );
1.57      albertel 4344: #---------------------------------------------------------------- print table
1.419     bisitz   4345:                 $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4346:                          .&Apache::loncommon::start_data_table_header_row()
                   4347:                          .'<th>'.&mt('Parameter Name').'</th>'
1.578     raeburn  4348:                          .'<th>'.&mt('Value').'</th>'
1.419     bisitz   4349:                          .'<th>'.&mt('Parameter in Effect').'</th>'
                   4350:                          .&Apache::loncommon::end_data_table_header_row()
                   4351:                 );
1.57      albertel 4352: 
1.582     raeburn  4353:                 my $navmap = Apache::lonnavmaps::navmap->new();
                   4354:                 my @recurseup;
                   4355:                 if (ref($navmap)) {
                   4356:                      my $mapres = $navmap->getByMapPc($mapid);
                   4357:                      if (ref($mapres)) {
                   4358:                          @recurseup = $navmap->recurseup_maps($mapres->src());
                   4359:                      }
                   4360:                 }
                   4361: 
                   4362: 
1.548     raeburn  4363:                 foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.473     amueller 4364:                     $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4365:                     &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.269     raeburn  4366:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
1.568     raeburn  4367:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
1.582     raeburn  4368:                            $readonly,\@recurseup,\%maptitles,\%allmaps_inverted,
                   4369:                            \$numreclinks);
1.57      albertel 4370:                 }
1.422     bisitz   4371:                 $r->print(&Apache::loncommon::end_data_table().'</p>'
                   4372:                          .'</div>'
                   4373:                 );
1.57      albertel 4374:             } # end each map
                   4375:         } # end of $parmlev eq map
                   4376: #--------------------------------- Entry for parm level general (Course level)
                   4377:         if ($parmlev eq 'general') {
1.473     amueller 4378:             my $defbgone = '#E0E099';
1.419     bisitz   4379:             my $defbgtwo = '#FFFF99';
                   4380:             my $defbgthree = '#FFBB99';
1.57      albertel 4381: 
                   4382: #-------------------------------------------- for each map, gather information
                   4383:             my $mapid="0.0";
                   4384: #-----------------------  loop through ids and get all parameter types for map
                   4385: #-----------------------------------------          and associated information
                   4386:             my %name = ();
                   4387:             my %part = ();
                   4388:             my %display = ();
                   4389:             my %type = ();
                   4390:             my %default = ();
1.446     bisitz   4391: 
1.548     raeburn  4392:             foreach $id (@ids) {
                   4393:                 my $rid = $id;
1.446     bisitz   4394: 
1.196     www      4395:                 my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4396:                 my $toolsymb;
                   4397:                 if ($uri =~ /ext\.tool$/) {
                   4398:                     $toolsymb = $symbp{$rid};
                   4399:                 }
1.57      albertel 4400: 
                   4401: #--------------------------------------------------------------------
                   4402: # @catmarker contains list of all possible parameters including part #s
                   4403: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4404: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4405: # When storing information, store as part 0
                   4406: # When requesting information, request from full part
                   4407: #-------------------------------------------------------------------
1.548     raeburn  4408:                 foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4409:                     my $tempkeyp = $fullkeyp;
                   4410:                     $tempkeyp =~ s/_\w+_/_0_/;
                   4411:                     if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4412:                         $part{$tempkeyp}="0";
1.584     raeburn  4413:                         $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4414:                         my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4415:                         if ($allparms{$name{$tempkeyp}} ne '') {
                   4416:                             my $identifier;
                   4417:                             if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4418:                                 $identifier = $1;
                   4419:                             }
                   4420:                             $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4421:                         } else {
                   4422:                             $display{$tempkeyp} = $parmdis;
                   4423:                         }
                   4424:                         unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4425:                         $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4426:                         $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4427:                         $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4428:                         $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.560     damieng  4429:                     }
1.57      albertel 4430:                 } # end loop through keys
                   4431:             } # end loop through ids
1.446     bisitz   4432: 
1.57      albertel 4433: #---------------------------------------------------- print header information
1.473     amueller 4434:             my $setdef=&mt("Set Defaults for All Resources in Course");
1.57      albertel 4435:             $r->print(<<ENDMAPONE);
1.419     bisitz   4436: <center>
                   4437: <h4>$setdef
1.135     albertel 4438: <font color="red"><i>$coursename</i></font><br />
1.57      albertel 4439: ENDMAPONE
                   4440:             if ($uname) {
1.473     amueller 4441:                 my $person=&Apache::loncommon::plainname($uname,$udom);
1.135     albertel 4442:                 $r->print(" ".&mt("User")."<font color=\"red\"> <i>$uname \($person\) </i></font> \n");
1.57      albertel 4443:             } else {
1.135     albertel 4444:                 $r->print("<i><font color=\"red\"> ".&mt("ALL")."</i> ".&mt("USERS")."</font> \n");
1.57      albertel 4445:             }
1.446     bisitz   4446: 
1.135     albertel 4447:             if ($csec) {$r->print(&mt("Section")."<font color=\"red\"> <i>$csec</i></font>\n")};
1.306     albertel 4448:             if ($cgroup) {$r->print(&mt("Group")."<font color=\"red\"> <i>$cgroup</i></font>\n")};
1.135     albertel 4449:             $r->print("</h4>\n");
1.57      albertel 4450: #---------------------------------------------------------------- print table
1.419     bisitz   4451:             $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4452:                      .&Apache::loncommon::start_data_table_header_row()
                   4453:                      .'<th>'.&mt('Parameter Name').'</th>'
                   4454:                      .'<th>'.&mt('Default Value').'</th>'
                   4455:                      .'<th>'.&mt('Parameter in Effect').'</th>'
                   4456:                      .&Apache::loncommon::end_data_table_header_row()
                   4457:             );
1.57      albertel 4458: 
1.548     raeburn  4459:             foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.419     bisitz   4460:                 $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4461:                 &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.568     raeburn  4462:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
                   4463:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
                   4464:                            $readonly);
1.57      albertel 4465:             }
1.419     bisitz   4466:             $r->print(&Apache::loncommon::end_data_table()
                   4467:                      .'</p>'
                   4468:                      .'</center>'
                   4469:             );
1.57      albertel 4470:         } # end of $parmlev eq general
1.606     raeburn  4471:         $r->print('</div>');
1.43      albertel 4472:     }
1.507     www      4473:     $r->print('</form>');
1.582     raeburn  4474:     if ($numreclinks) {
                   4475:         $r->print(<<"END");
                   4476: <form name="recurseform" action="/adm/parmset?action=settable" method="post">
                   4477: <input type="hidden" name="pschp" />
                   4478: <input type="hidden" name="pscat" />
                   4479: <input type="hidden" name="psprt" />
                   4480: <input type="hidden" name="hideparmsel" value="hidden" />
                   4481: </form>
                   4482: <script type="text/javascript">
                   4483: function pjumprec(rid,name,part) {
                   4484:     document.forms.recurseform.pschp.value = rid;
                   4485:     document.forms.recurseform.pscat.value = name;
                   4486:     document.forms.recurseform.psprt.value = part;
                   4487:     document.forms.recurseform.submit();
                   4488:     return false;
                   4489: }
                   4490: </script>
                   4491: END
                   4492:     }
1.507     www      4493:     &endSettingsScreen($r);
                   4494:     $r->print(&Apache::loncommon::end_page());
1.57      albertel 4495: } # end sub assessparms
1.30      www      4496: 
1.560     damieng  4497: 
                   4498: 
1.120     www      4499: ##################################################
1.560     damieng  4500: # OVERVIEW MODE
1.207     www      4501: ##################################################
1.124     www      4502: 
1.563     damieng  4503: my $tableopen; # boolean, true if HTML table is already opened
                   4504: 
                   4505: # Returns HTML with the HTML table start tag and header, unless the table is already opened.
                   4506: # @param {boolean} $readonly - true if values cannot be edited (otherwise more columns are added)
                   4507: # @returns {string}
1.124     www      4508: sub tablestart {
1.576     raeburn  4509:     my ($readonly,$is_map) = @_;
1.124     www      4510:     if ($tableopen) {
1.552     raeburn  4511:         return '';
1.124     www      4512:     } else {
1.552     raeburn  4513:         $tableopen=1;
                   4514:         my $output = &Apache::loncommon::start_data_table().'<tr><th>'.&mt('Parameter').'</th>';
                   4515:         if ($readonly) {
                   4516:             $output .= '<th>'.&mt('Current value').'</th>';
                   4517:         } else {
1.576     raeburn  4518:             $output .= '<th>'.&mt('Delete').'</th>'.
                   4519:                        '<th>'.&mt('Set to ...').'</th>';
                   4520:             if ($is_map) {
                   4521:                 $output .= '<th>'.&mt('Recursive?').'</th>';
                   4522:             }
1.552     raeburn  4523:         }
                   4524:         $output .= '</tr>';
                   4525:         return $output;
1.124     www      4526:     }
                   4527: }
                   4528: 
1.563     damieng  4529: # Returns HTML with the HTML table end tag, unless the table is not opened.
                   4530: # @returns {string}
1.124     www      4531: sub tableend {
                   4532:     if ($tableopen) {
1.560     damieng  4533:         $tableopen=0;
                   4534:         return &Apache::loncommon::end_data_table();
1.124     www      4535:     } else {
1.560     damieng  4536:         return'';
1.124     www      4537:     }
                   4538: }
                   4539: 
1.563     damieng  4540: # Reads course and user information.
                   4541: # If the context is looking for a scalar, returns the course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db) with added student data from lonnet::get_userresdata (which reads the user's resourcedata.db).
                   4542: # The key for student data is modified with '[useropt:'.username.':'.userdomain.'].'.
                   4543: # If the context is looking for a list, returns a list with the scalar data and the class list.
                   4544: # @param {string} $crs - course number
                   4545: # @param {string} $dom - course domain
                   4546: # @returns {hash reference|Array}
1.207     www      4547: sub readdata {
                   4548:     my ($crs,$dom)=@_;
                   4549: # Read coursedata
                   4550:     my $resourcedata=&Apache::lonnet::get_courseresdata($crs,$dom);
                   4551: # Read userdata
                   4552: 
                   4553:     my $classlist=&Apache::loncoursedata::get_classlist();
1.548     raeburn  4554:     foreach my $user (keys(%$classlist)) {
                   4555:         if ($user=~/^($match_username)\:($match_domain)$/) {
                   4556:             my ($tuname,$tudom)=($1,$2);
                   4557:             my $useropt=&Apache::lonnet::get_userresdata($tuname,$tudom);
                   4558:             foreach my $userkey (keys(%{$useropt})) {
                   4559:                 if ($userkey=~/^\Q$env{'request.course.id'}\E/) {
1.207     www      4560:                     my $newkey=$userkey;
1.548     raeburn  4561:                     $newkey=~s/^($env{'request.course.id'}\.)/$1\[useropt\:$tuname\:$tudom\]\./;
                   4562:                     $$resourcedata{$newkey}=$$useropt{$userkey};
                   4563:                 }
                   4564:             }
1.473     amueller 4565:         }
                   4566:     }
1.552     raeburn  4567:     if (wantarray) {
                   4568:         return ($resourcedata,$classlist);
                   4569:     } else {
                   4570:         return $resourcedata;
                   4571:     }
1.207     www      4572: }
                   4573: 
                   4574: 
1.563     damieng  4575: # Stores parameter data, using form parameters directly.
                   4576: #
                   4577: # Uses the following form parameters. The variable part in the names is a resourcedata key (except for a modification for user data).
1.622     raeburn  4578: # set_* (except settext, setipallow, setipdeny, setdeeplink, setgrace) - set a parameter value
1.563     damieng  4579: # del_* - remove a parameter
                   4580: # datepointer_* - set a date parameter (value is key_* refering to a set of other form parameters)
                   4581: # dateinterval_* - set a date interval parameter (value refers to more form parameters)
                   4582: # key_* - date values
                   4583: # days_* - for date intervals
                   4584: # hours_* - for date intervals
                   4585: # minutes_* - for date intervals
                   4586: # seconds_* - for date intervals
                   4587: # done_* - for date intervals
                   4588: # typeof_* - parameter type
                   4589: # 
                   4590: # @param {Apache2::RequestRec} $r - the Apache request
                   4591: # @param {string} $crs - course number
                   4592: # @param {string} $dom - course domain
1.208     www      4593: sub storedata {
                   4594:     my ($r,$crs,$dom)=@_;
1.207     www      4595: # Set userlevel immediately
                   4596: # Do an intermediate store of course level
                   4597:     my $olddata=&readdata($crs,$dom);
1.124     www      4598:     my %newdata=();
                   4599:     undef %newdata;
                   4600:     my @deldata=();
1.576     raeburn  4601:     my @delrec=();
                   4602:     my @delnonrec=();
1.124     www      4603:     undef @deldata;
1.504     raeburn  4604:     my ($got_chostname,$chostname,$cmajor,$cminor);
1.546     raeburn  4605:     my $now = time;
1.560     damieng  4606:     foreach my $key (keys(%env)) {
                   4607:         if ($key =~ /^form\.([a-z]+)\_(.+)$/) {
                   4608:             my $cmd=$1;
                   4609:             my $thiskey=$2;
1.576     raeburn  4610:             my ($altkey,$recursive,$tkey,$tkeyrec,$tkeynonrec);
1.622     raeburn  4611:             next if ($cmd eq 'rec' || $cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny' || $cmd eq 'setdeeplink' || $cmd eq 'setgrace');
1.576     raeburn  4612:             if ((($cmd eq 'set') || ($cmd eq 'datepointer') || ($cmd eq 'dateinterval') || ($cmd eq 'del')) && 
                   4613:                  ($thiskey =~ /(?:sequence|page)\Q___(all)\E/)) {
                   4614:                 unless ($thiskey =~ /(encrypturl|hiddenresource)$/) {
                   4615:                     $altkey = $thiskey;
                   4616:                     $altkey =~ s/\Q___(all)\E/___(rec)/;
                   4617:                     if ($env{'form.rec_'.$thiskey}) {
                   4618:                         $recursive = 1;
                   4619:                     }
                   4620:                 }
                   4621:             }
1.560     damieng  4622:             my ($tuname,$tudom)=&extractuser($thiskey);
1.473     amueller 4623:             if ($tuname) {
1.576     raeburn  4624:                 $tkey=$thiskey;
1.560     damieng  4625:                 $tkey=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
1.576     raeburn  4626:                 if ($altkey) {
                   4627:                     $tkeynonrec = $tkey; 
                   4628:                     $tkeyrec = $altkey;
                   4629:                     $tkeyrec=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
                   4630:                 }
1.560     damieng  4631:             }
                   4632:             if ($cmd eq 'set' || $cmd eq 'datepointer' || $cmd eq 'dateinterval') {
1.563     damieng  4633:                 my ($data, $typeof, $text, $name, $valchk, $valmatch, $namematch);
                   4634:                 if ($cmd eq 'set') {
                   4635:                     $data=$env{$key};
                   4636:                     $valmatch = '';
                   4637:                     $valchk = $data;
                   4638:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4639:                     $text = &mt('Saved modified parameter for');
                   4640:                     if ($typeof eq 'string_questiontype') {
                   4641:                         $name = 'type';
1.588     raeburn  4642:                     } elsif (($typeof eq 'string_lenient') || ($typeof eq 'string_deeplink')) {
                   4643:                         ($name) = ($typeof =~ /^string_(lenient|deeplink)$/);
1.563     damieng  4644:                         my $stringmatch = &standard_string_matches($typeof);
                   4645:                         if (ref($stringmatch) eq 'ARRAY') {
                   4646:                             foreach my $item (@{$stringmatch}) {
                   4647:                                 if (ref($item) eq 'ARRAY') {
                   4648:                                     my ($regexpname,$pattern) = @{$item};
                   4649:                                     if ($pattern ne '') {
                   4650:                                         if ($data =~ /$pattern/) {
                   4651:                                             $valmatch = $regexpname;
                   4652:                                             $valchk = '';
                   4653:                                             last;
                   4654:                                         }
1.560     damieng  4655:                                     }
1.549     raeburn  4656:                                 }
                   4657:                             }
                   4658:                         }
1.563     damieng  4659:                     } elsif ($typeof eq 'string_discussvote') {
                   4660:                         $name = 'discussvote';
                   4661:                     } elsif ($typeof eq 'string_examcode') {
                   4662:                         $name = 'examcode';
                   4663:                         if (&Apache::lonnet::validCODE($data)) {
                   4664:                             $valchk = 'valid';
                   4665:                         }
                   4666:                     } elsif ($typeof eq 'string_yesno') {
                   4667:                         if ($thiskey =~ /\.retrypartial$/) {
                   4668:                             $name = 'retrypartial';
                   4669:                         }
1.621     raeburn  4670:                     } elsif ($typeof eq 'string_tex') {
                   4671:                         $name = 'texdisplay';
1.549     raeburn  4672:                     }
1.563     damieng  4673:                 } elsif ($cmd eq 'datepointer') {
                   4674:                     $data=&Apache::lonhtmlcommon::get_date_from_form($env{$key});
                   4675:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4676:                     $text = &mt('Saved modified date for');
                   4677:                     if ($typeof eq 'date_start') {
                   4678:                         if ($thiskey =~ /\.printstartdate$/) {
                   4679:                             $name = 'printstartdate';
                   4680:                             if (($data) && ($data > $now)) {
                   4681:                                 $valchk = 'future';
                   4682:                             }
1.560     damieng  4683:                         }
1.563     damieng  4684:                     } elsif ($typeof eq 'date_end') {
                   4685:                         if ($thiskey =~ /\.printenddate$/) {
                   4686:                             $name = 'printenddate';
                   4687:                             if (($data) && ($data < $now)) {
                   4688:                                 $valchk = 'past';
                   4689:                             }
1.560     damieng  4690:                         }
1.504     raeburn  4691:                     }
1.563     damieng  4692:                 } elsif ($cmd eq 'dateinterval') {
                   4693:                     $data=&get_date_interval_from_form($thiskey);
                   4694:                     if ($thiskey =~ /\.interval$/) {
                   4695:                         $name = 'interval';
                   4696:                         my $intervaltype = &get_intervaltype($name);
                   4697:                         my $intervalmatch = &standard_interval_matches($intervaltype);
                   4698:                         if (ref($intervalmatch) eq 'ARRAY') {
                   4699:                             foreach my $item (@{$intervalmatch}) {
                   4700:                                 if (ref($item) eq 'ARRAY') {
                   4701:                                     my ($regexpname,$pattern) = @{$item};
                   4702:                                     if ($pattern ne '') {
                   4703:                                         if ($data =~ /$pattern/) {
                   4704:                                             $valmatch = $regexpname;
                   4705:                                             $valchk = '';
                   4706:                                             last;
                   4707:                                         }
1.560     damieng  4708:                                     }
1.554     raeburn  4709:                                 }
                   4710:                             }
                   4711:                         }
                   4712:                     }
1.563     damieng  4713:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4714:                     $text = &mt('Saved modified date for');
1.554     raeburn  4715:                 }
1.576     raeburn  4716:                 if ($recursive) {
1.563     damieng  4717:                     $namematch = 'maplevelrecurse';
1.560     damieng  4718:                 }
1.563     damieng  4719:                 if (($name ne '') || ($namematch ne '')) {
                   4720:                     my ($needsrelease,$needsnewer);
                   4721:                     if ($name ne '') {
                   4722:                         $needsrelease = $Apache::lonnet::needsrelease{"parameter:$name:$valchk:$valmatch:"};
1.560     damieng  4723:                         if ($needsrelease) {
                   4724:                             unless ($got_chostname) {
1.563     damieng  4725:                                 ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.560     damieng  4726:                                 $got_chostname = 1;
                   4727:                             }
1.563     damieng  4728:                             $needsnewer = &parameter_releasecheck($name,$valchk,$valmatch,undef,
                   4729:                                                                 $needsrelease,
                   4730:                                                                 $cmajor,$cminor);
                   4731:                         }
                   4732:                     }
                   4733:                     if ($namematch ne '') {
                   4734:                         if ($needsnewer) {
                   4735:                             undef($namematch);
1.560     damieng  4736:                         } else {
1.563     damieng  4737:                             my $currneeded;
                   4738:                             if ($needsrelease) {
                   4739:                                 $currneeded = $needsrelease;
                   4740:                             }
                   4741:                             $needsrelease =
                   4742:                                 $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   4743:                             if (($needsrelease) &&
                   4744:                                     (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   4745:                                 unless ($got_chostname) {
                   4746:                                     ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   4747:                                     $got_chostname = 1;
                   4748:                                 }
                   4749:                                 $needsnewer = &parameter_releasecheck(undef,$valchk,$valmatch,
                   4750:                                     $namematch, $needsrelease,$cmajor,$cminor);
                   4751:                             } else {
                   4752:                                 undef($namematch);
                   4753:                             }
1.560     damieng  4754:                         }
1.557     raeburn  4755:                     }
1.563     damieng  4756:                     if ($needsnewer) {
                   4757:                         $r->print('<br />'.&oldversion_warning($name,$namematch,$data,
                   4758:                                                             $chostname,$cmajor,
                   4759:                                                             $cminor,$needsrelease));
                   4760:                         next;
                   4761:                     }
1.504     raeburn  4762:                 }
1.576     raeburn  4763:                 my ($reconlychg,$haschange,$storekey);
                   4764:                 if ($tuname) {
                   4765:                     my $ustorekey;
                   4766:                     if ($altkey) {
                   4767:                         if ($recursive) {
                   4768:                             if (exists($$olddata{$thiskey})) {
                   4769:                                 if ($$olddata{$thiskey} eq $data) {
                   4770:                                     $reconlychg = 1;
                   4771:                                 }
                   4772:                                 &Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname);
                   4773:                             }
                   4774:                             if (exists($$olddata{$altkey})) {
                   4775:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4776:                                     $haschange = 1;
                   4777:                                 }
                   4778:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4779:                                 $haschange = 1;
                   4780:                             }
                   4781:                             $ustorekey = $tkeyrec;
                   4782:                         } else {
                   4783:                             if (exists($$olddata{$altkey})) {
                   4784:                                 if ($$olddata{$altkey} eq $data) {
                   4785:                                     $reconlychg = 1;
                   4786:                                 }
                   4787:                                 &Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname);
                   4788:                             }
                   4789:                             if (exists($$olddata{$thiskey})) {
                   4790:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4791:                                     $haschange = 1;
                   4792:                                 }
                   4793:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4794:                                 $haschange = 1;
                   4795:                             }
                   4796:                             $ustorekey = $tkeynonrec;
                   4797:                         }
                   4798:                     } else {
                   4799:                         if (exists($$olddata{$tkey})) {
                   4800:                             if (defined($data) && $$olddata{$tkey} ne $data) {
                   4801:                                 $haschange = 1;
                   4802:                             }
                   4803:                             $ustorekey = $tkey;
                   4804:                         }
                   4805:                     }
                   4806:                     if ($haschange || $reconlychg)  {
                   4807:                         unless ($env{'form.del_'.$thiskey}) {
                   4808:                             if (&Apache::lonnet::put('resourcedata',{$ustorekey=>$data,
                   4809:                                                                      $ustorekey.'.type' => $typeof},
                   4810:                                                                      $tudom,$tuname) eq 'ok') {
                   4811:                                 &log_parmset({$ustorekey=>$data,$ustorekey.'.type' => $typeof},0,$tuname,$tudom);
                   4812:                                 $r->print('<br />'.$text.' '.
                   4813:                                           &Apache::loncommon::plainname($tuname,$tudom));
                   4814:                             } else {
                   4815:                                 $r->print('<div class="LC_error">'.
                   4816:                                           &mt('Error saving parameters').'</div>');
                   4817:                             }
                   4818:                             &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4819:                         }
                   4820:                     }
                   4821:                 } else {
                   4822:                     if ($altkey) {
                   4823:                         if ($recursive) {
                   4824:                             if (exists($$olddata{$thiskey})) {
                   4825:                                 if ($$olddata{$thiskey} eq $data) {
                   4826:                                     $reconlychg = 1;
                   4827:                                 }
                   4828:                                 push(@delnonrec,($thiskey,$thiskey.'.type'));
                   4829:                             }
                   4830:                             if (exists($$olddata{$altkey})) {
                   4831:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4832:                                     $haschange = 1;
                   4833:                                 }
                   4834:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4835:                                 $haschange = 1;
                   4836:                             }
                   4837:                             $storekey = $altkey;
1.563     damieng  4838:                         } else {
1.576     raeburn  4839:                             if (exists($$olddata{$altkey})) {
                   4840:                                 if ($$olddata{$altkey} eq $data) {
                   4841:                                     $reconlychg = 1;
                   4842:                                 }
                   4843:                                 push(@delrec,($altkey,$altkey.'.type'));
                   4844:                             } 
                   4845:                             if (exists($$olddata{$thiskey})) {
                   4846:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4847:                                     $haschange = 1;
                   4848:                                 }
                   4849:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4850:                                 $haschange = 1;
                   4851:                             }
                   4852:                             $storekey = $thiskey;
1.563     damieng  4853:                         }
1.560     damieng  4854:                     } else {
1.576     raeburn  4855:                         if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4856:                             $haschange = 1;
                   4857:                             $storekey = $thiskey;
                   4858:                         }
                   4859:                     }
                   4860:                 }
                   4861:                 if ($reconlychg || $haschange) {
                   4862:                     unless ($env{'form.del_'.$thiskey}) {
                   4863:                         $newdata{$storekey}=$data;
                   4864:                         $newdata{$storekey.'.type'}=$typeof;
1.560     damieng  4865:                     }
                   4866:                 }
                   4867:             } elsif ($cmd eq 'del') {
                   4868:                 if ($tuname) {
1.576     raeburn  4869:                     my $error;
                   4870:                     if ($altkey) {  
                   4871:                         if (exists($$olddata{$altkey})) {
                   4872:                             if (&Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4873:                                 &log_parmset({$tkeyrec=>''},1,$tuname,$tudom);
                   4874:                                 if ($recursive) {
                   4875:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4876:                                 }
                   4877:                             } elsif ($recursive) {
                   4878:                                 $error = 1;
                   4879:                             }
                   4880:                         }
                   4881:                         if (exists($$olddata{$thiskey})) {
                   4882:                             if (&Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4883:                                 &log_parmset({$tkeynonrec=>''},1,$tuname,$tudom);
                   4884:                                 unless ($recursive) {
                   4885:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4886:                                 }
                   4887:                             } elsif (!$recursive) {
                   4888:                                 $error = 1;
                   4889:                             }
                   4890:                         }
1.560     damieng  4891:                     } else {
1.576     raeburn  4892:                         if (exists($$olddata{$thiskey})) {
                   4893:                             if (&Apache::lonnet::del('resourcedata',[$tkey,$tkey.'.type'],$tudom,$tuname) eq 'ok') {
                   4894:                                 &log_parmset({$tkey=>''},1,$tuname,$tudom);
                   4895:                                 $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4896:                             } else {
                   4897:                                 $error = 1;
                   4898:                             }
                   4899:                         }
                   4900:                     }
                   4901:                     if ($error) { 
1.560     damieng  4902:                         $r->print('<div class="LC_error">'.
                   4903:                             &mt('Error deleting parameters').'</div>');
                   4904:                     }
                   4905:                     &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4906:                 } else {
1.576     raeburn  4907:                     if ($altkey) {
                   4908:                         if (exists($$olddata{$altkey})) {
                   4909:                             unless (grep(/^\Q$altkey\E$/,@delrec)) {
                   4910:                                 push(@deldata,($altkey,$altkey.'.type'));
                   4911:                             }
                   4912:                         }
                   4913:                         if (exists($$olddata{$thiskey})) {
                   4914:                             unless (grep(/^\Q$thiskey\E$/,@delnonrec)) {
                   4915:                                 push(@deldata,($thiskey,$thiskey.'.type'));
                   4916:                             }
                   4917:                         }
                   4918:                     } elsif (exists($$olddata{$thiskey})) {
                   4919:                         push(@deldata,($thiskey,$thiskey.'.type'));
                   4920:                     }
1.560     damieng  4921:                 }
1.473     amueller 4922:             }
                   4923:         }
                   4924:     }
1.207     www      4925: # Store all course level
1.144     www      4926:     my $delentries=$#deldata+1;
1.576     raeburn  4927:     my @alldels;
                   4928:     if (@delrec) {
                   4929:         push(@alldels,@delrec);
                   4930:     }
                   4931:     if (@delnonrec) {
                   4932:         push(@alldels,@delnonrec);
                   4933:     }
                   4934:     if (@deldata) {
                   4935:         push(@alldels,@deldata);
                   4936:     }
1.548     raeburn  4937:     my @newdatakeys=keys(%newdata);
1.144     www      4938:     my $putentries=$#newdatakeys+1;
1.576     raeburn  4939:     my ($delresult,$devalidate);
                   4940:     if (@alldels) {
                   4941:         if (&Apache::lonnet::del('resourcedata',\@alldels,$dom,$crs) eq 'ok') {
                   4942:             my %loghash=map { $_ => '' } @alldels;
1.560     damieng  4943:             &log_parmset(\%loghash,1);
1.576     raeburn  4944:             if ($delentries) {
                   4945:                 $r->print('<h2>'.&mt('Deleted [quant,_1,parameter]',$delentries/2).'</h2>');
                   4946:             }
                   4947:         } elsif ($delentries) {
1.560     damieng  4948:             $r->print('<div class="LC_error">'.
                   4949:                 &mt('Error deleting parameters').'</div>');
                   4950:         }
1.576     raeburn  4951:         $devalidate = 1; 
1.144     www      4952:     }
                   4953:     if ($putentries) {
1.560     damieng  4954:         if (&Apache::lonnet::put('resourcedata',\%newdata,$dom,$crs) eq 'ok') {
                   4955:                     &log_parmset(\%newdata,0);
                   4956:             $r->print('<h3>'.&mt('Saved [quant,_1,parameter]',$putentries/2).'</h3>');
                   4957:         } else {
                   4958:             $r->print('<div class="LC_error">'.
                   4959:                 &mt('Error saving parameters').'</div>');
                   4960:         }
1.576     raeburn  4961:         $devalidate = 1; 
                   4962:     }
                   4963:     if ($devalidate) {
1.560     damieng  4964:         &Apache::lonnet::devalidatecourseresdata($crs,$dom);
1.144     www      4965:     }
1.208     www      4966: }
1.207     www      4967: 
1.563     damieng  4968: # Returns the username and domain from a key created in readdata from a resourcedata key.
                   4969: #
                   4970: # @param {string} $key - the key
                   4971: # @returns {Array}
1.208     www      4972: sub extractuser {
                   4973:     my $key=shift;
1.350     albertel 4974:     return ($key=~/^$env{'request.course.id'}.\[useropt\:($match_username)\:($match_domain)\]\./);
1.208     www      4975: }
1.206     www      4976: 
1.563     damieng  4977: # Parses a parameter key and returns the components.
                   4978: #
                   4979: # @param {string} $key - 
                   4980: # @param {hash reference} $listdata - 
                   4981: # @return {Array} - (student, resource, part, parameter)
1.381     albertel 4982: sub parse_listdata_key {
                   4983:     my ($key,$listdata) = @_;
                   4984:     # split into student/section affected, and
                   4985:     # the realm (folder/resource part and parameter
1.446     bisitz   4986:     my ($student,$realm) =
1.473     amueller 4987:     ($key=~/^\Q$env{'request.course.id'}\E\.\[([^\.]+)\]\.(.+)$/);
1.381     albertel 4988:     # if course wide student would be undefined
                   4989:     if (!defined($student)) {
1.560     damieng  4990:         ($realm)=($key=~/^\Q$env{'request.course.id'}\E\.(.+)$/);
1.381     albertel 4991:     }
                   4992:     # strip off the .type if it's not the Question type parameter
                   4993:     if ($realm=~/\.type$/ && !exists($listdata->{$key.'.type'})) {
1.560     damieng  4994:         $realm=~s/\.type//;
1.381     albertel 4995:     }
                   4996:     # split into resource+part and parameter name
1.388     albertel 4997:     my ($res,    $parm) = ($realm=~/^(.*)\.(.*)$/);
                   4998:        ($res, my $part) = ($res  =~/^(.*)\.(.*)$/);
1.381     albertel 4999:     return ($student,$res,$part,$parm);
                   5000: }
                   5001: 
1.563     damieng  5002: # Prints HTML with forms for the given parameter data in overview mode (newoverview or overview).
                   5003: #
                   5004: # @param {Apache2::RequestRec} $r - the Apache request
                   5005: # @param {hash reference} $resourcedata - parameter data returned by readdata
                   5006: # @param {hash reference} $listdata - data created in secgroup_lister, course id.[section id].part.name -> 1 or course id.[section id].part.name.type -> parameter type
                   5007: # @param {string} $sortorder - realmstudent|studentrealm
                   5008: # @param {string} $caller - name of the calling sub (overview|newoverview)
                   5009: # @param {hash reference} $classlist - from loncoursedata::get_classlist
1.568     raeburn  5010: # @param {boolean} $readonly - true if editing not allowed
1.608     raeburn  5011: # @param {string} $parmlev - full|map
                   5012: # @param {hash reference} $hash_for_realm - keys: realm, values: numeric order  
                   5013: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  5014: # @returns{integer} - number of $listdata parameters processed
1.208     www      5015: sub listdata {
1.608     raeburn  5016:     my ($r,$resourcedata,$listdata,$sortorder,$caller,$classlist,$readonly,$parmlev,$hash_for_realm,$pschp)=@_;
1.552     raeburn  5017:     
1.207     www      5018: # Start list output
1.206     www      5019: 
1.122     www      5020:     my $oldsection='';
                   5021:     my $oldrealm='';
                   5022:     my $oldpart='';
1.123     www      5023:     my $pointer=0;
1.124     www      5024:     $tableopen=0;
1.145     www      5025:     my $foundkeys=0;
1.248     albertel 5026:     my %keyorder=&standardkeyorder();
1.594     raeburn  5027:     my $readonlyall = $readonly;
1.381     albertel 5028: 
1.552     raeburn  5029:     my ($secidx,%grouphash);
                   5030:     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5031:         $secidx = &Apache::loncoursedata::CL_SECTION();
1.553     raeburn  5032:         if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   5033:             %grouphash = &Apache::longroup::coursegroups();
                   5034:         } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  5035:             map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  5036:         }
1.552     raeburn  5037:     }
                   5038: 
1.576     raeburn  5039:     foreach my $key (sort {
1.560     damieng  5040:         my ($astudent,$ares,$apart,$aparm) = &parse_listdata_key($a,$listdata);
                   5041:         my ($bstudent,$bres,$bpart,$bparm) = &parse_listdata_key($b,$listdata);
1.608     raeburn  5042:         my ($aid,$bid);
                   5043:         if ($caller eq 'newoverview') {
                   5044:             if (ref($hash_for_realm) eq 'HASH') {
                   5045:                 if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5046:                     my ($aurl) = ($ares =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   5047:                     my ($burl) = ($bres =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   5048:                     $aid = $hash_for_realm->{$aurl};
                   5049:                     $bid = $hash_for_realm->{$burl};
                   5050:                 } elsif ($parmlev eq 'full') {
                   5051:                     $aid = $hash_for_realm->{$ares};
                   5052:                     $bid = $hash_for_realm->{$bres};
                   5053:                 }
                   5054:             }
                   5055:         }
1.381     albertel 5056: 
1.560     damieng  5057:         # get the numerical order for the param
                   5058:         $aparm=$keyorder{'parameter_0_'.$aparm};
                   5059:         $bparm=$keyorder{'parameter_0_'.$bparm};
1.381     albertel 5060: 
1.560     damieng  5061:         my $result=0;
1.381     albertel 5062: 
1.560     damieng  5063:         if ($sortorder eq 'realmstudent') {
1.381     albertel 5064:             if ($ares     ne $bres    ) {
1.608     raeburn  5065:                 if ($caller eq 'newoverview') {
                   5066:                     if (ref($hash_for_realm) eq 'HASH') {
                   5067:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5068:                             $result = ($aid <=> $bid);
                   5069:                         } elsif ($parmlev eq 'full') {
                   5070:                             $result = ($aid <=> $bid);
                   5071:                         } else {
                   5072:                             $result = ($ares cmp $bres);
                   5073:                         }
                   5074:                     } else {
                   5075:                         $result = ($ares cmp $bres);
                   5076:                     }
                   5077:                 } else {
                   5078:                     $result = ($ares cmp $bres);
                   5079:                 }
1.446     bisitz   5080:             } elsif ($astudent ne $bstudent) {
1.560     damieng  5081:                 $result = ($astudent cmp $bstudent);
                   5082:             } elsif ($apart    ne $bpart   ) {
                   5083:                 $result = ($apart    cmp $bpart);
                   5084:             }
                   5085:         } else {
                   5086:             if      ($astudent ne $bstudent) {
                   5087:                 $result = ($astudent cmp $bstudent);
                   5088:             } elsif ($ares     ne $bres    ) {
1.608     raeburn  5089:                 if ($caller eq 'newoverview') {
                   5090:                     if (ref($hash_for_realm) eq 'HASH') {
                   5091:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5092:                             $result = ($aid <=> $bid);
                   5093:                         } elsif ($parmlev eq 'full') {
                   5094:                             $result = ($aid <=> $bid);
                   5095:                         } else {
                   5096:                             $result = ($ares cmp $bres);
                   5097:                         }
                   5098:                     } else {
                   5099:                         $result = ($ares cmp $bres);
                   5100:                     }
                   5101:                 } else {
                   5102:                     $result = ($ares cmp $bres);
                   5103:                 }
1.560     damieng  5104:             } elsif ($apart    ne $bpart   ) {
                   5105:                 $result = ($apart    cmp $bpart);
                   5106:             }
1.473     amueller 5107:         }
1.446     bisitz   5108: 
1.560     damieng  5109:         if (!$result) {
1.381     albertel 5110:             if (defined($aparm) && defined($bparm)) {
1.560     damieng  5111:                 $result = ($aparm <=> $bparm);
1.381     albertel 5112:             } elsif (defined($aparm)) {
1.560     damieng  5113:                 $result = -1;
1.381     albertel 5114:             } elsif (defined($bparm)) {
1.560     damieng  5115:                 $result = 1;
                   5116:             }
1.473     amueller 5117:         }
1.381     albertel 5118: 
1.560     damieng  5119:         $result;
                   5120:         
1.576     raeburn  5121:     } keys(%{$listdata})) { # foreach my $key
                   5122:         my $thiskey = $key;
1.560     damieng  5123:         if ($$listdata{$thiskey.'.type'}) {
                   5124:             my $thistype=$$listdata{$thiskey.'.type'};
                   5125:             if ($$resourcedata{$thiskey.'.type'}) {
                   5126:                 $thistype=$$resourcedata{$thiskey.'.type'};
                   5127:             }
                   5128:             my ($middle,$part,$name)=
1.572     damieng  5129:                 ($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.560     damieng  5130:             my $section=&mt('All Students');
1.594     raeburn  5131:             $readonly = $readonlyall;
1.599     raeburn  5132:             my $userscope;
1.576     raeburn  5133:             my $showval = $$resourcedata{$thiskey}; 
1.560     damieng  5134:             if ($middle=~/^\[(.*)\]/) {
                   5135:                 my $issection=$1;
                   5136:                 if ($issection=~/^useropt\:($match_username)\:($match_domain)/) {
                   5137:                     my ($stuname,$studom) = ($1,$2);
                   5138:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5139:                         if (ref($classlist) eq 'HASH') {
                   5140:                             if (ref($classlist->{$stuname.':'.$studom}) eq 'ARRAY') {
                   5141:                                 next unless ($classlist->{$stuname.':'.$studom}->[$secidx] eq $env{'request.course.sec'}); 
                   5142:                             }
                   5143:                         }
                   5144:                     }
                   5145:                     $section=&mt('User').": ".&Apache::loncommon::plainname($stuname,$studom);
1.599     raeburn  5146:                     $userscope = 1;
1.560     damieng  5147:                 } else {
                   5148:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5149:                         if (exists($grouphash{$issection})) {
                   5150:                             $section=&mt('Group').': '.$issection;
                   5151:                         } elsif ($issection eq $env{'request.course.sec'}) {
                   5152:                             $section = &mt('Section').': '.$issection;
                   5153:                         } else {
                   5154:                             next; 
1.552     raeburn  5155:                         }
1.560     damieng  5156:                     } else {
                   5157:                         $section=&mt('Group/Section').': '.$issection;
1.552     raeburn  5158:                     }
                   5159:                 }
1.560     damieng  5160:                 $middle=~s/^\[(.*)\]//;
                   5161:             } elsif (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5162:                 $readonly = 1;
                   5163:             }
                   5164:             $middle=~s/\.+$//;
                   5165:             $middle=~s/^\.+//;
                   5166:             my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.576     raeburn  5167:             my ($is_map,$is_recursive,$mapurl,$maplevel);
                   5168:             if ($caller eq 'overview') {
                   5169:                 if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   5170:                     $mapurl = $1;
                   5171:                     $maplevel = $2;
                   5172:                     $is_map = 1;
                   5173:                 }
                   5174:             } elsif ($caller eq 'newoverview') {
                   5175:                 if ($middle=~/^(.+)\_\_\_\((all)\)$/) {
                   5176:                     $mapurl = $1;
                   5177:                     $maplevel = $2;
                   5178:                     $is_map = 1;
                   5179:                 }
                   5180:             }
                   5181:             if ($is_map) {
1.560     damieng  5182:                 my $leveltitle = &mt('Folder/Map');
1.615     raeburn  5183:                 my $title = &Apache::lonnet::gettitle($mapurl);
1.608     raeburn  5184:                 if (ref($hash_for_realm) eq 'HASH') {
                   5185:                     if ($hash_for_realm->{$mapurl} eq '1') {
                   5186:                         $title = &mt('Main Content');
                   5187:                     }
                   5188:                 }
1.576     raeburn  5189:                 unless (($name eq 'hiddenresource') || ($name eq 'encrypturl')) {   
                   5190:                     if ($caller eq 'newoverview') {
                   5191:                         my $altkey = $thiskey;
                   5192:                         $altkey =~ s/\Q___(all)\E/___(rec)/;
                   5193:                         if ((exists($$resourcedata{$altkey})) & (!exists($$resourcedata{$thiskey}))) {
                   5194:                             $is_recursive = 1;
                   5195:                             if ($$resourcedata{$altkey.'.type'}) {
                   5196:                                 $thistype=$$resourcedata{$altkey.'.type'};
                   5197:                             }
                   5198:                             $showval = $$resourcedata{$altkey};
                   5199:                         }
                   5200:                     } elsif (($caller eq 'overview') && ($maplevel eq 'rec')) {
                   5201:                         $thiskey =~ s/\Q___(rec)\E/___(all)/;
                   5202:                         $is_recursive = 1;
                   5203:                     }
1.560     damieng  5204:                 }
1.608     raeburn  5205:                 $realm='<span class="LC_parm_scope_folder">'.$leveltitle.': '.$title.' <br /><span class="LC_parm_folder">('.$mapurl.')</span></span>';
1.560     damieng  5206:             } elsif ($middle) {
                   5207:                 my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
1.609     raeburn  5208:                 next if (($url =~ /\.(page|sequence)$/) && ($parmlev eq 'full') && ($caller eq 'newoverview'));
1.560     damieng  5209:                 $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   5210:                     ': '.&Apache::lonnet::gettitle($middle).
                   5211:                     ' <br /><span class="LC_parm_symb">('.$url.' in '.$map.' id: '.
                   5212:                     $id.')</span></span>';
                   5213:             }
                   5214:             if ($sortorder eq 'realmstudent') {
                   5215:                 if ($realm ne $oldrealm) {
                   5216:                     $r->print(&tableend()."\n<hr /><h1>$realm</h1>");
                   5217:                     $oldrealm=$realm;
                   5218:                     $oldsection='';
                   5219:                 }
                   5220:                 if ($section ne $oldsection) {
                   5221:                     $r->print(&tableend()."\n<h2>$section</h2>");
                   5222:                     $oldsection=$section;
                   5223:                     $oldpart='';
                   5224:                 }
1.552     raeburn  5225:             } else {
1.560     damieng  5226:                 if ($section ne $oldsection) {
                   5227:                     $r->print(&tableend()."\n<hr /><h1>$section</h1>");
                   5228:                     $oldsection=$section;
                   5229:                     $oldrealm='';
                   5230:                 }
                   5231:                 if ($realm ne $oldrealm) {
                   5232:                     $r->print(&tableend()."\n<h2>$realm</h2>");
                   5233:                     $oldrealm=$realm;
                   5234:                     $oldpart='';
1.552     raeburn  5235:                 }
                   5236:             }
1.560     damieng  5237:             if ($part ne $oldpart) {
                   5238:                 $r->print(&tableend().
                   5239:                     "\n".'<span class="LC_parm_part">'.&mt('Part').": $part</span>");
                   5240:                 $oldpart=$part;
1.556     raeburn  5241:             }
1.560     damieng  5242:     #
                   5243:     # Ready to print
                   5244:     #
1.470     raeburn  5245:             my $parmitem = &standard_parameter_names($name);
1.619     raeburn  5246:             my $advice;
                   5247:             if (($name eq 'mapalias') && ($middle) && (!$is_map)) {
                   5248:                 if ($middle =~ m{^uploaded/}) {
                   5249:                     $advice = &mt('Use Course Editor to set this.');
                   5250:                 } else {
                   5251:                     $advice = &mt('Use Resource Assembly Tool to set this.');
                   5252:                 }
                   5253:                 $advice = '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   5254:             }
1.576     raeburn  5255:             $r->print(&tablestart($readonly,$is_map).
1.560     damieng  5256:                 &Apache::loncommon::start_data_table_row().
                   5257:                 '<td><b>'.&mt($parmitem).
1.619     raeburn  5258:                 '</b>'.$advice.'</td>');
1.560     damieng  5259:             unless ($readonly) {
1.599     raeburn  5260:                 my $disabled;
                   5261:                 if (($name eq 'availablestudent') &&
                   5262:                     (($showval eq '') || ($userscope))) {
                   5263:                     $disabled = ' disabled="disabled"';
1.619     raeburn  5264:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5265:                     $disabled = ' disabled="disabled"';
1.599     raeburn  5266:                 }
1.560     damieng  5267:                 $r->print('<td><input type="checkbox" name="del_'.
1.599     raeburn  5268:                         $thiskey.'"'.$disabled.' /></td>');
1.560     damieng  5269:             }
                   5270:             $r->print('<td>');
                   5271:             $foundkeys++;
                   5272:             if (&isdateparm($thistype)) {
                   5273:                 my $jskey='key_'.$pointer;
                   5274:                 my $state;
                   5275:                 $pointer++;
                   5276:                 if ($readonly) {
                   5277:                     $state = 'disabled';
                   5278:                 }
                   5279:                 $r->print(
                   5280:                     &Apache::lonhtmlcommon::date_setter('parmform',
                   5281:                                                         $jskey,
1.576     raeburn  5282:                                                         $showval,
1.560     damieng  5283:                                                         '',1,$state));
                   5284:                 unless  ($readonly) {
                   5285:                     $r->print(
                   5286:     '<input type="hidden" name="datepointer_'.$thiskey.'" value="'.$jskey.'" />'.
1.576     raeburn  5287:     (($showval!=0)?'<span class="LC_nobreak"><a href="/adm/parmset?&action=dateshift1&timebase='.$showval.'">'.
1.560     damieng  5288:     &mt('Shift all dates based on this date').'</a></span>':'').
1.576     raeburn  5289:     &date_sanity_info($showval)
1.560     damieng  5290:                     );
                   5291:                 }
                   5292:             } elsif ($thistype eq 'date_interval') {
                   5293:                 $r->print(&date_interval_selector($thiskey,$name,
1.576     raeburn  5294:                           $showval,$readonly));
1.560     damieng  5295:             } elsif ($thistype =~ m/^string/) {
1.599     raeburn  5296:                 if ($name eq 'availablestudent') {
                   5297:                     $readonly = 1;
1.619     raeburn  5298:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5299:                     $readonly = 1;
1.599     raeburn  5300:                 }
1.560     damieng  5301:                 $r->print(&string_selector($thistype,$thiskey,
1.576     raeburn  5302:                           $showval,$name,$readonly));
1.560     damieng  5303:             } else {
1.576     raeburn  5304:                 $r->print(&default_selector($thiskey,$showval,$readonly));
1.552     raeburn  5305:             }
1.560     damieng  5306:             unless ($readonly) {
                   5307:                 $r->print('<input type="hidden" name="typeof_'.$thiskey.'" value="'.
                   5308:                         $thistype.'" />');
1.552     raeburn  5309:             }
1.576     raeburn  5310:             $r->print('</td>');
                   5311:             if ($is_map) {
                   5312:                 if (($name eq 'encrypturl') || ($name eq 'hiddenresource')) {
                   5313:                     $r->print('<td><table><tr><td>'.&mt('Yes').'</td></tr></table></td>');
                   5314:                 } else {
                   5315:                     my ($disabled,$recon,$recoff);
                   5316:                     if ($readonly) {
                   5317:                         $disabled = ' disabled="disabled"';
                   5318:                     }
                   5319:                     if ($is_recursive) {
                   5320:                         $recon = ' checked="checked"';
                   5321:                     } else {
                   5322:                         $recoff = ' checked="checked"';
                   5323:                     }
                   5324:                     $r->print('<td><table><tr><td><label><input type="radio" name="rec_'.$thiskey.'" value="1"'.$recon.$disabled.' />'.&mt('Yes').'</label>'.
                   5325:                               '</td><td><label><input type="radio" name="rec_'.$thiskey.'" value="0"'.$recoff.$disabled.' />'.&mt('No').'</label></td></tr></table></td>');
                   5326:                 }
                   5327:             }
                   5328:             $r->print(&Apache::loncommon::end_data_table_row());
1.473     amueller 5329:         }
1.121     www      5330:     }
1.208     www      5331:     return $foundkeys;
                   5332: }
                   5333: 
1.563     damieng  5334: # Returns a string representing the interval, directly using form data matching the given key.
                   5335: # The returned string may also include information related to proctored exams.
                   5336: # Format: seconds['_done'[':'done button title':']['_proctor'['_'proctor key]]]
                   5337: #
                   5338: # @param {string} $key - suffix for form fields related to the interval
                   5339: # @returns {string}
1.385     albertel 5340: sub get_date_interval_from_form {
                   5341:     my ($key) = @_;
                   5342:     my $seconds = 0;
1.611     raeburn  5343:     my $numnotnull = 0;
1.385     albertel 5344:     foreach my $which (['days', 86400],
1.473     amueller 5345:                ['hours', 3600],
                   5346:                ['minutes', 60],
                   5347:                ['seconds',  1]) {
1.560     damieng  5348:         my ($name, $factor) = @{ $which };
                   5349:         if (defined($env{'form.'.$name.'_'.$key})) {
1.611     raeburn  5350:             unless ($env{'form.'.$name.'_'.$key} eq '') {
                   5351:                 $numnotnull ++;
                   5352:                 $seconds += $env{'form.'.$name.'_'.$key} * $factor;
                   5353:             }
1.560     damieng  5354:         }
1.473     amueller 5355:     }
1.560     damieng  5356:     if (($key =~ /\.interval$/) &&
                   5357:             (($env{'form.done_'.$key} eq '_done') || ($env{'form.done_'.$key} eq '_done_proctor'))) {
1.559     raeburn  5358:         if ($env{'form.done_'.$key.'_buttontext'}) {
                   5359:             $env{'form.done_'.$key.'_buttontext'} =~ s/\://g;
                   5360:             $seconds .= '_done:'.$env{'form.done_'.$key.'_buttontext'}.':';
                   5361:             if ($env{'form.done_'.$key} eq '_done_proctor') {
                   5362:                 $seconds .= '_proctor';
                   5363:             }
                   5364:         } else {
                   5365:             $seconds .= $env{'form.done_'.$key}; 
                   5366:         }
                   5367:         if (($env{'form.done_'.$key} eq '_done_proctor') && 
1.560     damieng  5368:                 ($env{'form.done_'.$key.'_proctorkey'})) {
1.558     raeburn  5369:             $seconds .= '_'.$env{'form.done_'.$key.'_proctorkey'};
                   5370:         }
1.554     raeburn  5371:     }
1.611     raeburn  5372:     return if (!$numnotnull);
1.385     albertel 5373:     return $seconds;
                   5374: }
                   5375: 
1.563     damieng  5376: # Returns HTML to enter a text value for a parameter.
                   5377: #
                   5378: # @param {string} $thiskey - parameter key
                   5379: # @param {string} $showval - the current value
                   5380: # @param {boolean} $readonly - true if the field should not be made editable
                   5381: # @returns {string}
1.383     albertel 5382: sub default_selector {
1.552     raeburn  5383:     my ($thiskey, $showval, $readonly) = @_;
                   5384:     my $disabled;
                   5385:     if ($readonly) {
                   5386:         $disabled = ' disabled="disabled"';
                   5387:     }
                   5388:     return '<input type="text" name="set_'.$thiskey.'" value="'.$showval.'"'.$disabled.' />';
1.383     albertel 5389: }
                   5390: 
1.563     damieng  5391: # Returns HTML to enter allow/deny rules related to IP addresses.
                   5392: #
                   5393: # @param {string} $thiskey - parameter key
                   5394: # @param {string} $showval - the current value
                   5395: # @param {boolean} $readonly - true if the fields should not be made editable
                   5396: # @returns {string}
1.549     raeburn  5397: sub string_ip_selector {
1.552     raeburn  5398:     my ($thiskey, $showval, $readonly) = @_;
1.549     raeburn  5399:     my %access = (
                   5400:                    allow => [],
                   5401:                    deny  => [],
                   5402:                  );
                   5403:     if ($showval ne '') {
                   5404:         my @current;
                   5405:         if ($showval =~ /,/) {
                   5406:             @current = split(/,/,$showval);
                   5407:         } else {
                   5408:             @current = ($showval);
                   5409:         }
                   5410:         foreach my $item (@current) {
                   5411:             if ($item =~ /^\!([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5412:                 push(@{$access{'deny'}},$1);
                   5413:             } elsif ($item =~ /^([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5414:                 push(@{$access{'allow'}},$item);
                   5415:             }
                   5416:         }
                   5417:     }
                   5418:     if (!@{$access{'allow'}}) {
                   5419:         @{$access{'allow'}} = ('');
                   5420:     }
                   5421:     if (!@{$access{'deny'}}) {
                   5422:         @{$access{'deny'}} = ('');
                   5423:     }
1.552     raeburn  5424:     my ($disabled,$addmore);
1.567     raeburn  5425:     if ($readonly) {
1.552     raeburn  5426:         $disabled=' disabled="disabled"';
                   5427:     } else {
                   5428:         $addmore = "\n".'<button class="LC_add_ipacc_button">'.&mt('Add more').'</button>';
                   5429:     }
1.549     raeburn  5430:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />
                   5431: <table><tr><th>'.&mt('Allow from').'</th><th>'.&mt('Deny from').'</th></tr><tr>';
                   5432:     foreach my $acctype ('allow','deny') {
                   5433:         $output .= '
                   5434: <td valign="top">
                   5435: <div class="LC_string_ipacc_wrap" id="LC_string_ipacc_'.$acctype.'_'.$thiskey.'">
                   5436:   <div class="LC_string_ipacc_inner">'."\n";
                   5437:         my $num = 0;
                   5438:         foreach my $curr (@{$access{$acctype}}) {
1.552     raeburn  5439:             $output .= '<div><input type="text" name="setip'.$acctype.'_'.$thiskey.'" value="'.$curr.'"'.$disabled.' />';
1.549     raeburn  5440:             if ($num > 0) {
                   5441:                 $output .= '<a href="#" class="LC_remove_ipacc">'.&mt('Remove').'</a>'; 
                   5442:             }
                   5443:             $output .= '</div>'."\n";
                   5444:             $num ++;
                   5445:         }
                   5446:         $output .= '
1.552     raeburn  5447:   </div>'.$addmore.'
1.549     raeburn  5448: </div>
                   5449: </td>';
                   5450:    }
                   5451:    $output .= '
                   5452: </tr>
                   5453: </table>'."\n";
                   5454:     return $output;
                   5455: }
                   5456: 
1.588     raeburn  5457: sub string_deeplink_selector {
                   5458:     my ($thiskey, $showval, $readonly) = @_;
1.616     raeburn  5459:     my (@tables,%values,@current,%titles,%options,%optiontext,%defaults,
                   5460:         %selectnull,%domlti,%crslti,@possmenus,%components);
                   5461:     @tables = ('upper','lower');
                   5462:     %components = (
                   5463:                     upper => ['state','others','listing','scope'],
                   5464:                     lower => ['protect','menus','target','exit'],
                   5465:                   );   
1.588     raeburn  5466:     %titles = &Apache::lonlocal::texthash (
1.601     raeburn  5467:                   state   => 'Access status',
                   5468:                   others  => 'Hide other resources',
1.588     raeburn  5469:                   listing => 'In Contents and/or Gradebook',
                   5470:                   scope   => 'Access scope for link',
1.601     raeburn  5471:                   protect => 'Link protection',
1.597     raeburn  5472:                   menus   => 'Menu Items Displayed',
1.613     raeburn  5473:                   target  => 'Embedded?',
1.616     raeburn  5474:                   exit    => 'Exit Tool Button?',
1.588     raeburn  5475:               );
                   5476:     %options = (
1.601     raeburn  5477:                    state   => ['only','off','both'],
                   5478:                    others  => ['hide','unhide'],
1.588     raeburn  5479:                    listing => ['full','absent','grades','details','datestatus'],
                   5480:                    scope   => ['res','map','rec'],
1.601     raeburn  5481:                    protect => ['none','key','ltid','ltic'],
1.597     raeburn  5482:                    menus   => ['std','colls'],
1.613     raeburn  5483:                    target  => ['_self','_top'],
1.616     raeburn  5484:                    exit    => ['no','yes','url'],
1.588     raeburn  5485:                );
                   5486:     %optiontext = &Apache::lonlocal::texthash (
1.601     raeburn  5487:                     only       => 'deep only',
                   5488:                     off        => 'deeplink off',
                   5489:                     both       => 'regular + deep',
                   5490:                     hide       => 'Hidden',
                   5491:                     unhide     => 'Unhidden',
1.588     raeburn  5492:                     full       => 'Listed (linked) in both',
                   5493:                     absent     => 'Not listed',
                   5494:                     grades     => 'Listed in grades only',
                   5495:                     details    => 'Listed (unlinked) in both',
                   5496:                     datestatus => 'Listed (unlinked) inc. status in both',
                   5497:                     res        => 'resource only',
                   5498:                     map        => 'enclosing map/folder',
                   5499:                     rec        => 'recursive map/folder',
1.601     raeburn  5500:                     none       => 'not in use',
                   5501:                     key        => 'key access',
                   5502:                     ltic       => 'LTI access (course)',
                   5503:                     ltid       => 'LTI access (domain)' ,
1.597     raeburn  5504:                     std        => 'Standard (all menus)',
                   5505:                     colls      => 'Numbered collection',
1.614     raeburn  5506:                     _self      => 'Embedded',
1.613     raeburn  5507:                     _top       => 'Not embedded',
1.616     raeburn  5508:                     no         => 'Not in use',
                   5509:                     yes        => 'In use, no URL redirect',
                   5510:                     url        => 'In use, redirect to URL',  
1.597     raeburn  5511:                   );
                   5512:     %selectnull = &Apache::lonlocal::texthash (
1.601     raeburn  5513:                     ltic => 'Select Launcher',
                   5514:                     ltid => 'Select Launcher', 
1.597     raeburn  5515:                     colls => 'Select',
1.588     raeburn  5516:                   );
                   5517:     if ($showval =~ /,/) {
1.597     raeburn  5518:         %values=();
1.588     raeburn  5519:         @current = split(/,/,$showval);
1.601     raeburn  5520:         ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/);
                   5521:         ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/);
                   5522:         ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/);
                   5523:         ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/);
                   5524:         ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/);
                   5525:         ($values{'menus'}) = ($current[5] =~ /^(\d+)$/);
1.613     raeburn  5526:         ($values{'target'}) = ($current[6] =~ /^(_self|_top)$/);
1.616     raeburn  5527:         ($values{'exit'}) = ($current[7] =~ /^((?:(?:yes|url)(?:|\:[^:;"',]+))|no)$/);
1.588     raeburn  5528:     } else {
1.601     raeburn  5529:         $defaults{'state'} = 'off',
                   5530:         $defaults{'others'} = 'unhide',
1.588     raeburn  5531:         $defaults{'listing'} = 'full';
                   5532:         $defaults{'scope'} = 'res';
1.601     raeburn  5533:         $defaults{'protect'} = 'none';
1.597     raeburn  5534:         $defaults{'menus'} = '0';
1.613     raeburn  5535:         $defaults{'target'} = '_top';
1.616     raeburn  5536:         $defaults{'exit'} = 'yes';
1.588     raeburn  5537:     }
                   5538:     my $disabled;
                   5539:     if ($readonly) {
                   5540:         $disabled=' disabled="disabled"';
                   5541:     }
1.601     raeburn  5542:     my %courselti =
                   5543:         &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'},
1.620     raeburn  5544:                                         $env{'course.'.$env{'request.course.id'}.'.domain'},
                   5545:                                         'provider');
1.601     raeburn  5546:     foreach my $item (keys(%courselti)) {
                   5547:         if (ref($courselti{$item}) eq 'HASH') {
                   5548:             $crslti{$item} = $courselti{$item}{'name'};
                   5549:         }
                   5550:     }
                   5551:     my %lti =
1.588     raeburn  5552:         &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  5553:                                         'linkprot');
1.588     raeburn  5554:     foreach my $item (keys(%lti)) {
1.604     raeburn  5555:         if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   5556:             $domlti{$item} = $lti{$item}{'name'};
1.588     raeburn  5557:         }
                   5558:     }
1.597     raeburn  5559:     if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   5560:         foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   5561:             my ($num,$value) = split(/\%/,$item);
                   5562:             if ($num =~ /^\d+$/) {
                   5563:                 push(@possmenus,$num);
                   5564:             }
                   5565:         }
                   5566:     }
                   5567: 
1.616     raeburn  5568:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />';
                   5569:     foreach my $table ('upper','lower') {
                   5570:         next unless (ref($components{$table}) eq 'ARRAY');
                   5571:         $output .= '<table width="100%"><tr>';
                   5572:         foreach my $item (@{$components{$table}}) {
                   5573:             $output .= '<th>'.$titles{$item}.'</th>';
                   5574:         }
                   5575:         $output .= '</tr><tr>';
                   5576:         foreach my $item (@{$components{$table}}) {
                   5577:             $output .= '<td>';
                   5578:             if (($item eq 'protect') || ($item eq 'menus') || ($item eq 'exit')) {
                   5579:                 my $selected = $values{$item};
                   5580:                 foreach my $option (@{$options{$item}}) {
                   5581:                     if ($item eq 'protect') { 
                   5582:                         if ($option eq 'ltid') {
                   5583:                             next unless (keys(%domlti));
                   5584:                         } elsif ($option eq 'ltic') {
                   5585:                             next unless (keys(%crslti));
                   5586:                         }
                   5587:                     } elsif (($item eq 'menus') && ($option eq 'colls')) {
                   5588:                         next unless (@possmenus);
                   5589:                     }
                   5590:                     my $checked;
                   5591:                     if ($item eq 'menus') {
                   5592:                         if (($selected =~ /^\d+$/) && (@possmenus) &&
                   5593:                             (grep(/^\Q$selected\E$/,@possmenus))) {
                   5594:                             if ($option eq 'colls') {
                   5595:                                 $checked = ' checked="checked"';
                   5596:                             }
                   5597:                         } elsif (($option eq 'std') && ($selected == 0) && ($selected ne '')) {
1.597     raeburn  5598:                             $checked = ' checked="checked"';
                   5599:                         }
1.616     raeburn  5600:                     } elsif ($selected =~ /^\Q$option\E/) {
1.597     raeburn  5601:                         $checked = ' checked="checked"';
                   5602:                     }
1.616     raeburn  5603:                     my $onclick;
                   5604:                     unless ($readonly) {
                   5605:                         my $esc_key = &js_escape($thiskey);
                   5606:                         $onclick = ' onclick="toggleDeepLink(this.form,'."'$item','$esc_key'".');"';
                   5607:                     }
                   5608:                     $output .= '<span class="LC_nobreak"><label>'.
                   5609:                                '<input type="radio" name="deeplink_'.$item.'_'.$thiskey.'" value="'.$option.'"'.$onclick.$disabled.$checked.' />'."\n".
                   5610:                                $optiontext{$option}.'</label>';
                   5611:                     if (($item eq 'protect') && ($option eq 'key')) {
                   5612:                         my $visibility="hidden";
                   5613:                         my $currkey;
                   5614:                         if ($checked) {
                   5615:                             $visibility = "text";
                   5616:                             $currkey = (split(/\:/,$values{$item}))[1];
                   5617:                         }
                   5618:                         $output .= '&nbsp;'.
                   5619:                                    '<input type="'.$visibility.'" name="deeplink_'.$option.'_'.$thiskey.'" id="deeplink_'.$option.'_'.$item.'_'.$thiskey.'" value="'.$currkey.'" size="10"'.$disabled.' />';
                   5620:                     } elsif (($option eq 'ltic') || ($option eq 'ltid') || ($option eq 'colls')) {
                   5621:                         my $display="none";
                   5622:                         my ($current,$blankcheck,@possibles);
                   5623:                         if ($checked) {
                   5624:                             $display = 'inline-block';
                   5625:                             if (($option eq 'ltic') || ($option eq 'ltid'))  {
                   5626:                                 $current = (split(/\:/,$selected))[1];
                   5627:                             } else {
                   5628:                                 $current = $selected;
                   5629:                             }
1.597     raeburn  5630:                         } else {
1.616     raeburn  5631:                             $blankcheck = ' selected="selected"';
1.597     raeburn  5632:                         }
1.601     raeburn  5633:                         if ($option eq 'ltid') {
1.616     raeburn  5634:                             @possibles = keys(%domlti);
1.601     raeburn  5635:                         } elsif ($option eq 'ltic') {
1.616     raeburn  5636:                             @possibles = keys(%crslti); 
                   5637:                         } else {
                   5638:                             @possibles = @possmenus;
                   5639:                         }
                   5640:                         $output .= '<div id="deeplinkdiv_'.$option.'_'.$item.'_'.$thiskey.'"'.
                   5641:                                    ' style="display: '.$display.'">&nbsp;<select name="'.
                   5642:                                    'deeplink_'.$option.'_'.$thiskey.'"'.$disabled.'>';
                   5643:                         if (@possibles > 1) {
                   5644:                             $output .= '<option value=""'.$blankcheck.'>'.$selectnull{$option}.
                   5645:                                        '</option>'."\n";
                   5646:                         }
                   5647:                         foreach my $poss (sort { $a <=> $b } @possibles) {
                   5648:                             my $selected;
                   5649:                             if (($poss == $current) || (scalar(@possibles) ==1)) {
                   5650:                                 $selected = ' selected="selected"';
                   5651:                             }
                   5652:                             my $shown = $poss;
                   5653:                             if ($option eq 'ltid') {
                   5654:                                 $shown = $domlti{$poss};
                   5655:                             } elsif ($option eq 'ltic') {
                   5656:                                 $shown = $crslti{$poss};
                   5657:                             }
                   5658:                             $output .= '<option value="'.$poss.'"'.$selected.'>'.$shown.'</option>';
                   5659:                         }
                   5660:                         $output .= '</select></div>';
                   5661:                     }
                   5662:                     $output .= '</span> ';
                   5663:                 }
                   5664:                 if ($item eq 'exit') {
                   5665:                     my $exitsty = 'none';
                   5666:                     my $displayval;
                   5667:                     if ($values{$item} =~ /^(yes|url)/) { 
                   5668:                         $exitsty = 'inline-block';
                   5669:                         my $currval = (split(/\:/,$values{$item}))[1];
                   5670:                         if ($currval eq '') {
                   5671:                             $displayval = 'Exit Tool';
                   5672:                         } else {
                   5673:                             $displayval = $currval;
1.597     raeburn  5674:                         }
1.588     raeburn  5675:                     }
1.616     raeburn  5676:                     $output .= '<div id="deeplinkdiv_'.$item.'_'.$thiskey.'"'.
                   5677:                                ' style="display: '.$exitsty.'"><br />'.&mt('Button text').': '.
                   5678:                                '<input type="text" name="deeplink_exittext_'.$thiskey.'"'.
                   5679:                                ' id="deeplink_exittext_'.$thiskey.'" value="'.$displayval.'"'.
                   5680:                                ' size="10"'.$disabled.' /></div>';
1.588     raeburn  5681:                 }
1.616     raeburn  5682:             } else {
                   5683:                 my $selected = $values{$item};
                   5684:                 my $defsel;
                   5685:                 if ($selected eq '') {
                   5686:                     $defsel = ' selected="selected"';
                   5687:                 }
                   5688:                 $output .= '<select name="deeplink_'.$item.'_'.$thiskey.'"'.$disabled.'>'."\n".
                   5689:                            '<option value=""'.$defsel.'>'.&mt('Please select').'</option>'."\n";
                   5690:                 foreach my $option (@{$options{$item}}) {
                   5691:                     $output .= '<option value="'.$option.'"';
                   5692:                     if ($option eq $selected) {
                   5693:                         $output .= ' selected="selected"';
                   5694:                     }
                   5695:                     $output .= '>'.$optiontext{$option}.'</option>';
1.588     raeburn  5696:                 }
1.616     raeburn  5697:                 $output .= '</select>';
1.588     raeburn  5698:             }
1.616     raeburn  5699:             $output .= '</td>';
                   5700:         }
                   5701:         $output .= '</tr></table>'."\n";
                   5702:         if ($table eq 'upper') {
                   5703:             $output .= '<br />';
1.588     raeburn  5704:         }
                   5705:     }
                   5706:     return $output;
                   5707: }
                   5708: 
1.622     raeburn  5709: sub string_grace_selector {
                   5710:     my ($thiskey, $showval, $readonly) = @_;
                   5711:     my $addmore;
                   5712:     unless ($readonly) {
                   5713:         $addmore = "\n".'<button class="LC_add_grace_button">'.&mt('Add more').'</button>';
                   5714:     }
                   5715:     my $output = '<input type="hidden" name="set_'.$thiskey.'" value="" />'.
                   5716:                  '<div class="LC_string_grace_wrap" id="LC_string_grace_'.$thiskey.'">'."\n".
                   5717:                  '<div class="LC_string_grace_inner">'."\n";
                   5718:     if ($showval ne '') {
                   5719:         my @current;
                   5720:         if ($showval =~ /,/) {
                   5721:             @current = split(/,/,$showval);
                   5722:         } else {
                   5723:             @current = ($showval);
                   5724:         }
                   5725:         my $num = scalar(@current);	
                   5726:         foreach my $item (@current) {
                   5727:             my ($delta,$fraction,$gradational) = split(/:/,$item);
                   5728:             if (($delta =~ /^\d+$/) && ($fraction =~ /^(0|1)\.?\d*$/) && 
                   5729:                 (($gradational eq 1) || ($gradational eq '0'))) {
                   5730:                 my $gradchk = '';
                   5731:                 if ($gradational) {
                   5732:                     $gradchk = ' checked="checked"';
                   5733:                 }
                   5734:                 $output .= &grace_form($thiskey,$delta,$fraction,$gradchk,
                   5735:                                        $readonly);
                   5736:             }
                   5737:         }
                   5738:     } elsif (!$readonly) {
                   5739:         $output .= &grace_form($thiskey,'','','',$readonly);
                   5740:     }
                   5741:     $output .= '</div>'.$addmore.'</div>';
                   5742:     return $output;
                   5743: }
                   5744: 
                   5745: sub grace_form {
                   5746:     my ($thiskey,$delta,$fraction,$gradchkon,$readonly) = @_;
                   5747:     my $disabled;
                   5748:     if ($readonly) {
                   5749:         $disabled = ' disabled="disabled"';
                   5750:     }
                   5751:     my %lt = &grace_titles();
                   5752:     my $output = '<div><input type="hidden" name="setgrace_'.$thiskey.'" value="" />'.
                   5753:                  '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
1.623     raeburn  5754:     foreach my $which (['weeks', 604800, 52],
                   5755:                        ['days', 86400, 6],
1.622     raeburn  5756:                        ['hours', 3600, 23],
1.623     raeburn  5757:                        ['minutes', 60, 59]) {
1.622     raeburn  5758:         my ($name, $factor, $max) = @{ $which };
                   5759:         my $amount;
1.623     raeburn  5760:         my %select = ((map {$_ => $_} (0..$max)),
                   5761:                       'select_form_order' => [0..$max]);
                   5762:         if ($delta eq '') {
                   5763:             unshift(@{$select{'select_form_order'}},'');
                   5764:             $select{''} = '';
                   5765:             $amount = '';
                   5766:         } else {
1.622     raeburn  5767:             $amount = int($delta/$factor);
                   5768:             $delta %= $factor;
                   5769:         }
                   5770:         $output .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
                   5771:                                                    \%select,'',$readonly);
                   5772:         $output .= '&nbsp;'.$lt{$name}.'&nbsp;&nbsp; ';
                   5773:     }
                   5774:     $output .= '</fieldset>'.
                   5775:                '<fieldset class="LC_grace"><legend>'.$lt{'pcr'}.'</legend>'.
                   5776:                '<input type="text" size="3" name="frac_'.$thiskey.'" value="'.$fraction.'"'.$disabled.' />'.
                   5777:                '&nbsp;&nbsp;<label><input type="checkbox" value="1" name="grad_'.$thiskey.'"'.$gradchkon.$disabled.' />'.
                   5778:                $lt{'grad'}.'</label></fieldset>';
                   5779:     unless ($readonly) {
                   5780:         $output .= '<a href="#" class="LC_remove_grace">'.$lt{'remo'}.'</a>';
                   5781:     }
                   5782:     $output .= '</div>'."\n";
                   5783:     return $output;
                   5784: }
                   5785: 
                   5786: sub grace_titles {
                   5787:     return &Apache::lonlocal::texthash (
                   5788:                                          sinc => 'Time past due',
                   5789:                                          remo => 'Remove',
                   5790:                                          pcr => 'Partial credit',
                   5791:                                          grad => 'gradual',
1.623     raeburn  5792:                                          weeks => 'weeks',
1.622     raeburn  5793:                                          days => 'days',
                   5794:                                          hours => 'hours',
                   5795:                                          minutes => 'minutes',
                   5796:     );
                   5797: }
1.560     damieng  5798: 
                   5799: { # block using some constants related to parameter types (overview mode)
                   5800: 
1.446     bisitz   5801: my %strings =
1.383     albertel 5802:     (
                   5803:      'string_yesno'
                   5804:              => [[ 'yes', 'Yes' ],
1.560     damieng  5805:                  [ 'no', 'No' ]],
1.383     albertel 5806:      'string_problemstatus'
                   5807:              => [[ 'yes', 'Yes' ],
1.473     amueller 5808:          [ 'answer', 'Yes, and show correct answer if they exceed the maximum number of tries.' ],
                   5809:          [ 'no', 'No, don\'t show correct/incorrect feedback.' ],
                   5810:          [ 'no_feedback_ever', 'No, show no feedback at all.' ]],
1.504     raeburn  5811:      'string_questiontype'
                   5812:              => [[ 'problem', 'Standard Problem'],
                   5813:                  [ 'survey', 'Survey'],
                   5814:                  [ 'anonsurveycred', 'Anonymous Survey (credit for submission)'],
1.530     bisitz   5815:                  [ 'exam', 'Bubblesheet Exam'],
1.504     raeburn  5816:                  [ 'anonsurvey', 'Anonymous Survey'],
                   5817:                  [ 'randomizetry', 'New Randomization Each N Tries (default N=1)'],
                   5818:                  [ 'practice', 'Practice'],
                   5819:                  [ 'surveycred', 'Survey (credit for submission)']],
1.514     raeburn  5820:      'string_lenient'
                   5821:              => [['yes', 'Yes' ],
                   5822:                  [ 'no', 'No' ],
1.549     raeburn  5823:                  [ 'default', 'Default - only bubblesheet grading is lenient' ],
                   5824:                  [ 'weighted', 'Yes, weighted (optionresponse in checkbox mode)' ]],
1.521     raeburn  5825:      'string_discussvote'
                   5826:              => [['yes','Yes'],
                   5827:                  ['notended','Yes, unless discussion ended'],
                   5828:                  ['no','No']],
1.549     raeburn  5829:      'string_ip'
                   5830:              => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'],
1.587     raeburn  5831:                  ['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']], 
                   5832:      'string_deeplink'
1.616     raeburn  5833:              => [['on','Set choices for link protection, resource listing, access scope, shown menu items, embedding, and exit link']],
1.621     raeburn  5834:      'string_tex'
                   5835:              => [['tth', 'tth (TeX to HTML)'],
                   5836:                  ['mathjax', 'MathJax']],
1.622     raeburn  5837:      'string_grace'
                   5838:              => [['on','Set grading scale and grace period for submissions after due date']],
1.587     raeburn  5839:     );
                   5840:    
1.383     albertel 5841: 
1.549     raeburn  5842: my %stringmatches = (
                   5843:          'string_lenient'
                   5844:               => [['weighted','^\-?[.\d]+,\-?[.\d]+,\-?[.\d]+,\-?[.\d]+$'],],
                   5845:          'string_ip'
                   5846:               => [['_allowfrom_','[^\!]+'],
                   5847:                   ['_denyfrom_','\!']],
1.588     raeburn  5848:          'string_deeplink'
1.616     raeburn  5849:               => [['on','^(only|off|both)\,(hide|unhide)\,(full|absent|grades|details|datestatus)\,(res|map|rec)\,(none|key\:\w+|ltic\:\d+|ltid\:\d+)\,(\d+|)\,_(self|top),(yes|url|no)(|:[^:;\'",]+)$']],
1.622     raeburn  5850:          'string_grace'
                   5851:               => [['on','^\d+,(0|1)\.?\d*,(0|1)']],
1.549     raeburn  5852:     );
                   5853: 
                   5854: my %stringtypes = (
                   5855:                     type         => 'string_questiontype',
                   5856:                     lenient      => 'string_lenient',
                   5857:                     retrypartial => 'string_yesno',
                   5858:                     discussvote  => 'string_discussvote',
                   5859:                     examcode     => 'string_examcode',
                   5860:                     acc          => 'string_ip',
1.587     raeburn  5861:                     deeplink     => 'string_deeplink',
1.622     raeburn  5862:                     grace        => 'string_grace',
1.621     raeburn  5863:                     texdisplay   => 'string_tex',
1.549     raeburn  5864:                   );
                   5865: 
1.563     damieng  5866: # Returns the possible values and titles for a given string type, or undef if there are none.
                   5867: # Used by courseprefs.
                   5868: #
                   5869: # @param {string} $string_type - a parameter type for strings
                   5870: # @returns {array reference} - 2D array, containing values and English titles
1.505     raeburn  5871: sub standard_string_options {
                   5872:     my ($string_type) = @_;
                   5873:     if (ref($strings{$string_type}) eq 'ARRAY') {
                   5874:         return $strings{$string_type};
                   5875:     }
                   5876:     return;
                   5877: }
1.383     albertel 5878: 
1.563     damieng  5879: # Returns regular expressions to match kinds of string types, or undef if there are none.
                   5880: #
                   5881: # @param {string} $string_type - a parameter type for strings
                   5882: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.549     raeburn  5883: sub standard_string_matches {
                   5884:     my ($string_type) = @_;
                   5885:     if (ref($stringmatches{$string_type}) eq 'ARRAY') {
                   5886:         return $stringmatches{$string_type};
                   5887:     }
                   5888:     return;
                   5889: }
                   5890: 
1.563     damieng  5891: # Returns a parameter type for a given parameter with a string type, or undef if not known.
                   5892: #
                   5893: # @param {string} $name - parameter name
                   5894: # @returns {string}
1.549     raeburn  5895: sub get_stringtype {
                   5896:     my ($name) = @_;
                   5897:     if (exists($stringtypes{$name})) {
                   5898:         return $stringtypes{$name};
                   5899:     }
                   5900:     return;
                   5901: }
                   5902: 
1.563     damieng  5903: # Returns HTML to edit a string parameter.
                   5904: #
                   5905: # @param {string} $thistype - parameter type
                   5906: # @param {string} $thiskey - parameter key
                   5907: # @param {string} $showval - parameter current value
                   5908: # @param {string} $name - parameter name
                   5909: # @param {boolean} $readonly - true if the values should not be made editable
                   5910: # @returns {string}
1.383     albertel 5911: sub string_selector {
1.552     raeburn  5912:     my ($thistype, $thiskey, $showval, $name, $readonly) = @_;
1.446     bisitz   5913: 
1.383     albertel 5914:     if (!exists($strings{$thistype})) {
1.552     raeburn  5915:         return &default_selector($thiskey,$showval,$readonly);
1.383     albertel 5916:     }
                   5917: 
1.504     raeburn  5918:     my %skiptype;
1.514     raeburn  5919:     if (($thistype eq 'string_questiontype') || 
1.560     damieng  5920:             ($thistype eq 'string_lenient') ||
                   5921:             ($thistype eq 'string_discussvote') ||
                   5922:             ($thistype eq 'string_ip') ||
1.588     raeburn  5923:             ($thistype eq 'string_deeplink') ||
1.621     raeburn  5924:             ($thistype eq 'string_tex') ||
1.622     raeburn  5925:             ($thistype eq 'string_grace') ||
1.560     damieng  5926:             ($name eq 'retrypartial')) {
1.504     raeburn  5927:         my ($got_chostname,$chostname,$cmajor,$cminor); 
                   5928:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5929:             next unless (ref($possibilities) eq 'ARRAY');
1.514     raeburn  5930:             my ($parmval, $description) = @{ $possibilities };
1.549     raeburn  5931:             my $parmmatch;
                   5932:             if (ref($stringmatches{$thistype}) eq 'ARRAY') {
                   5933:                 foreach my $item (@{$stringmatches{$thistype}}) {
                   5934:                     if (ref($item) eq 'ARRAY') {
                   5935:                         if ($parmval eq $item->[0]) {
                   5936:                             $parmmatch = $parmval;
                   5937:                             $parmval = '';
                   5938:                             last;
                   5939:                         }
                   5940:                     }
                   5941:                 }
                   5942:             }
                   5943:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"}; 
1.504     raeburn  5944:             if ($needsrelease) {
                   5945:                 unless ($got_chostname) {
1.514     raeburn  5946:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.504     raeburn  5947:                     $got_chostname = 1;
                   5948:                 }
1.557     raeburn  5949:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.549     raeburn  5950:                                                        $needsrelease,$cmajor,$cminor);
1.504     raeburn  5951:                 if ($needsnewer) {
1.549     raeburn  5952:                     if ($parmmatch ne '') {
                   5953:                         $skiptype{$parmmatch} = 1;
                   5954:                     } elsif ($parmval ne '') {
                   5955:                         $skiptype{$parmval} = 1;
                   5956:                     }
1.504     raeburn  5957:                 }
                   5958:             }
                   5959:         }
                   5960:     }
1.549     raeburn  5961: 
                   5962:     if ($thistype eq 'string_ip') {
1.622     raeburn  5963:         return &string_ip_selector($thiskey,$showval,$readonly);
                   5964:     } elsif ($thistype eq 'string_grace') {
                   5965:         return &string_grace_selector($thiskey,$showval,$readonly);
1.588     raeburn  5966:     } elsif ($thistype eq 'string_deeplink') {
                   5967:         return &string_deeplink_selector($thiskey,$showval,$readonly);
1.549     raeburn  5968:     }
1.504     raeburn  5969: 
1.552     raeburn  5970:     my ($result,$disabled);
                   5971: 
                   5972:     if ($readonly) {
                   5973:         $disabled = ' disabled="disabled"';
                   5974:     }
1.504     raeburn  5975:     my $numinrow = 3;
                   5976:     if ($thistype eq 'string_problemstatus') {
                   5977:         $numinrow = 2;
                   5978:     } elsif ($thistype eq 'string_questiontype') {
                   5979:         if (keys(%skiptype) > 0) {
                   5980:              $numinrow = 4;
                   5981:         }
                   5982:     }
                   5983:     my $rem;
                   5984:     if (ref($strings{$thistype}) eq 'ARRAY') {
                   5985:         my $i=0;
                   5986:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5987:             next unless (ref($possibilities) eq 'ARRAY');
                   5988:             my ($name, $description) = @{ $possibilities };
1.549     raeburn  5989:             next if ($skiptype{$name});
1.504     raeburn  5990:             $rem = $i%($numinrow);
                   5991:             if ($rem == 0) {
                   5992:                 if ($i > 0) {
                   5993:                     $result .= '</tr>';
                   5994:                 }
                   5995:                 $result .= '<tr>';
                   5996:             }
1.549     raeburn  5997:             my $colspan;
                   5998:             if ($i == @{ $strings{$thistype} }-1) {
                   5999:                 $rem = @{ $strings{$thistype} }%($numinrow);
                   6000:                 if ($rem) {
                   6001:                     my $colsleft = $numinrow - $rem;
                   6002:                     if ($colsleft) {
                   6003:                         $colspan = $colsleft+1;
                   6004:                         $colspan = ' colspan="'.$colspan.'"';
                   6005:                     }
                   6006:                 }
                   6007:             }
                   6008:             my ($add,$onchange,$css_class);
                   6009:             if ($thistype eq 'string_lenient') {
                   6010:                 if ($name eq 'weighted') {
                   6011:                     my $display;
                   6012:                     my %relatives = &Apache::lonlocal::texthash(
                   6013:                                         corrchkd     => 'Correct (checked)',
                   6014:                                         corrunchkd   => 'Correct (unchecked)',
                   6015:                                         incorrchkd   => 'Incorrect (checked)',
                   6016:                                         incorrunchkd => 'Incorrect (unchecked)',
                   6017:                     );
                   6018:                     my %textval = (
                   6019:                                     corrchkd     => '1.0',
                   6020:                                     corrunchkd   => '1.0',
                   6021:                                     incorrchkd   => '0.0',
                   6022:                                     incorrunchkd => '0.0',
                   6023:                     );
                   6024:                     if ($showval =~ /^([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)$/) {
                   6025:                         $textval{'corrchkd'} = $1;
                   6026:                         $textval{'corrunchkd'} = $2;
                   6027:                         $textval{'incorrchkd'} = $3;
                   6028:                         $textval{'incorrunchkd'} = $4;
                   6029:                         $display = 'inline';
                   6030:                         $showval = $name;
                   6031:                     } else {
                   6032:                         $display = 'none';
                   6033:                     }
                   6034:                     $add = ' <div id="LC_parmtext_'.$thiskey.'" style="display:'.$display.'"><table>'.
                   6035:                            '<tr><th colspan="2">'.&mt("Foil's submission status").'</th><th>'.&mt('Points').'</th></tr>';  
                   6036:                     foreach my $reltype ('corrchkd','corrunchkd','incorrchkd','incorrunchkd') {
                   6037:                         $add .= '<tr><td>&nbsp;</td><td>'.$relatives{$reltype}.'</td>'."\n".
                   6038:                                 '<td><input type="text" name="settext_'.$thiskey.'"'.
1.552     raeburn  6039:                                 ' value="'.$textval{$reltype}.'" size="3"'.$disabled.' />'.
1.549     raeburn  6040:                                 '</td></tr>';
                   6041:                     }
                   6042:                     $add .= '</table></div>'."\n";
                   6043:                 }
                   6044:                 $onchange = ' onclick="javascript:toggleParmTextbox(this.form,'."'$thiskey'".');"';
                   6045:                 $css_class = ' class="LC_lenient_radio"';
                   6046:             }
                   6047:             $result .= '<td class="LC_left_item"'.$colspan.'>'.
1.504     raeburn  6048:                        '<span class="LC_nobreak"><label>'.
                   6049:                        '<input type="radio" name="set_'.$thiskey.
1.552     raeburn  6050:                        '" value="'.$name.'"'.$onchange.$css_class.$disabled;
1.504     raeburn  6051:             if ($showval eq $name) {
                   6052:                 $result .= ' checked="checked"';
                   6053:             }
1.549     raeburn  6054:             $result .= ' />'.&mt($description).'</label>'.$add.'</span></td>';
1.504     raeburn  6055:             $i++;
                   6056:         }
                   6057:         $result .= '</tr>';
1.473     amueller 6058:     }
1.504     raeburn  6059:     if ($result) {
                   6060:         $result = '<table border="0">'.$result.'</table>';
1.383     albertel 6061:     }
                   6062:     return $result;
                   6063: }
                   6064: 
1.554     raeburn  6065: my %intervals =
                   6066:     (
                   6067:      'date_interval'
                   6068:              => [[ 'done', 'Yes' ],
1.558     raeburn  6069:                  [ 'done_proctor', 'Yes, with proctor key'],                  
1.554     raeburn  6070:                  [ '', 'No' ]],
                   6071:     );
                   6072: 
                   6073: my %intervalmatches = (
                   6074:          'date_interval'
1.559     raeburn  6075:               => [['done','\d+_done(|\:[^\:]+\:)$'],
                   6076:                   ['done_proctor','\d+_done(|\:[^\:]+\:)_proctor_']],
1.554     raeburn  6077:     );
                   6078: 
                   6079: my %intervaltypes = (
                   6080:                       interval => 'date_interval',
                   6081:     );
                   6082: 
1.563     damieng  6083: # Returns regular expressions to match kinds of interval type, or undef if there are none.
                   6084: #
                   6085: # @param {string} $interval_type - a parameter type for intervals
                   6086: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.554     raeburn  6087: sub standard_interval_matches {
                   6088:     my ($interval_type) = @_;
                   6089:     if (ref($intervalmatches{$interval_type}) eq 'ARRAY') {
                   6090:         return $intervalmatches{$interval_type};
                   6091:     }
                   6092:     return;
                   6093: }
                   6094: 
1.563     damieng  6095: # Returns a parameter type for a given parameter with an interval type, or undef if not known.
                   6096: #
                   6097: # @param {string} $name - parameter name
                   6098: # @returns {string}
1.554     raeburn  6099: sub get_intervaltype {
                   6100:     my ($name) = @_;
                   6101:     if (exists($intervaltypes{$name})) {
                   6102:         return $intervaltypes{$name};
                   6103:     }
                   6104:     return;
                   6105: }
                   6106: 
1.563     damieng  6107: # Returns the possible values and titles for a given interval type, or undef if there are none.
                   6108: # Used by courseprefs.
                   6109: #
                   6110: # @param {string} $interval_type - a parameter type for intervals
                   6111: # @returns {array reference} - 2D array, containing values and English titles
1.554     raeburn  6112: sub standard_interval_options {
                   6113:     my ($interval_type) = @_;
                   6114:     if (ref($intervals{$interval_type}) eq 'ARRAY') {
                   6115:         return $intervals{$interval_type};
                   6116:     }
                   6117:     return;
                   6118: }
                   6119: 
1.563     damieng  6120: # Returns HTML to edit a date interval parameter.
                   6121: #
                   6122: # @param {string} $thiskey - parameter key
                   6123: # @param {string} $name - parameter name
                   6124: # @param {string} $showval - parameter current value
                   6125: # @param {boolean} $readonly - true if the values should not be made editable
                   6126: # @returns {string}
1.554     raeburn  6127: sub date_interval_selector {
                   6128:     my ($thiskey, $name, $showval, $readonly) = @_;
                   6129:     my ($result,%skipval);
                   6130:     if ($name eq 'interval') {
                   6131:         my $intervaltype = &get_intervaltype($name);
                   6132:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   6133:         foreach my $possibilities (@{ $intervals{$intervaltype} }) {
                   6134:             next unless (ref($possibilities) eq 'ARRAY');
                   6135:             my ($parmval, $description) = @{ $possibilities };
                   6136:             my $parmmatch;
                   6137:             if (ref($intervalmatches{$intervaltype}) eq 'ARRAY') {
                   6138:                 foreach my $item (@{$intervalmatches{$intervaltype}}) {
                   6139:                     if (ref($item) eq 'ARRAY') {
                   6140:                         if ($parmval eq $item->[0]) {
                   6141:                             $parmmatch = $parmval;
                   6142:                             $parmval = '';
                   6143:                             last;
                   6144:                         }
                   6145:                     }
                   6146:                 }
                   6147:             }
                   6148:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"};
                   6149:             if ($needsrelease) {
                   6150:                 unless ($got_chostname) {
                   6151:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
                   6152:                     $got_chostname = 1;
                   6153:                 }
1.557     raeburn  6154:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.554     raeburn  6155:                                                        $needsrelease,$cmajor,$cminor);
                   6156:                 if ($needsnewer) {
                   6157:                     if ($parmmatch ne '') {
                   6158:                         $skipval{$parmmatch} = 1;
                   6159:                     } elsif ($parmval ne '') {
                   6160:                         $skipval{$parmval} = 1;
                   6161:                     }
                   6162:                 }
                   6163:             }
                   6164:         }
                   6165:     }
                   6166: 
                   6167:     my $currval = $showval;
                   6168:     foreach my $which (['days', 86400, 31],
                   6169:                ['hours', 3600, 23],
                   6170:                ['minutes', 60, 59],
                   6171:                ['seconds',  1, 59]) {
1.560     damieng  6172:         my ($name, $factor, $max) = @{ $which };
                   6173:         my $amount = int($showval/$factor);
                   6174:         $showval  %= $factor;
                   6175:         my %select = ((map {$_ => $_} (0..$max)),
                   6176:                 'select_form_order' => [0..$max]);
1.611     raeburn  6177:         if ($currval eq '') {
                   6178:             unshift(@{$select{'select_form_order'}},'');
                   6179:             $select{''} = '';
                   6180:             $amount = '';
                   6181:         }
1.560     damieng  6182:         $result .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
                   6183:                             \%select,'',$readonly);
                   6184:         $result .= ' '.&mt($name);
1.554     raeburn  6185:     }
                   6186:     if ($name eq 'interval') {
                   6187:         unless ($skipval{'done'}) {
                   6188:             my $checkedon = '';
1.611     raeburn  6189:             my $checkedoff = '';
1.558     raeburn  6190:             my $checkedproc = '';
                   6191:             my $currproctorkey = '';
                   6192:             my $currprocdisplay = 'hidden';
1.559     raeburn  6193:             my $currdonetext = &mt('Done');
                   6194:             if ($currval =~ /^(?:\d+)_done$/) {
                   6195:                 $checkedon = ' checked="checked"';
                   6196:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:$/) {
                   6197:                 $currdonetext = $1;
1.554     raeburn  6198:                 $checkedon = ' checked="checked"';
1.558     raeburn  6199:             } elsif ($currval =~ /^(?:\d+)_done_proctor_(.+)$/) {
                   6200:                 $currproctorkey = $1;
                   6201:                 $checkedproc = ' checked="checked"';
                   6202:                 $currprocdisplay = 'text';
1.559     raeburn  6203:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:_proctor_(.+)$/) {
                   6204:                 $currdonetext = $1;
                   6205:                 $currproctorkey = $2;
                   6206:                 $checkedproc = ' checked="checked"';
                   6207:                 $currprocdisplay = 'text';
1.611     raeburn  6208:             } elsif ($currval ne '') {
                   6209:                 $checkedoff = ' checked="checked"';
                   6210:             } else {
                   6211:                 $currdonetext = '';
1.554     raeburn  6212:             }
1.558     raeburn  6213:             my $onclick = ' onclick="toggleSecret(this.form,'."'done_','$thiskey'".');"';
1.567     raeburn  6214:             my $disabled;
                   6215:             if ($readonly) {
                   6216:                 $disabled = ' disabled="disabled"';
                   6217:             }
1.558     raeburn  6218:             $result .= '<br /><span class="LC_nobreak">'.&mt('Include "done" button').
1.567     raeburn  6219:                        '<label><input type="radio" value="" name="done_'.$thiskey.'"'.$checkedoff.$onclick.$disabled.' />'.
1.558     raeburn  6220:                        &mt('No').'</label>'.('&nbsp;'x2).
1.567     raeburn  6221:                        '<label><input type="radio" value="_done" name="done_'.$thiskey.'"'.$checkedon.$onclick.$disabled.' />'.
1.558     raeburn  6222:                        &mt('Yes').'</label>'.('&nbsp;'x2).
1.567     raeburn  6223:                        '<label><input type="radio" value="_done_proctor" name="done_'.$thiskey.'"'.$checkedproc.$onclick.$disabled.' />'.
1.558     raeburn  6224:                        &mt('Yes, with proctor key').'</label>'.
                   6225:                        '<input type="'.$currprocdisplay.'" id="done_'.$thiskey.'_proctorkey" '.
1.567     raeburn  6226:                        'name="done_'.$thiskey.'_proctorkey" value="'.&HTML::Entities::encode($currproctorkey,'"<>&').'"'.$disabled.' /></span><br />'.
1.559     raeburn  6227:                        '<span class="LC_nobreak">'.&mt('Button text').': '.
1.611     raeburn  6228:                        '<input type="text" name="done_'.$thiskey.'_buttontext" id="done_'.$thiskey.'_buttontext" value="'.
                   6229:                        &HTML::Entities::encode($currdonetext,'"<>&').'"'.$disabled.' /></span>';
1.554     raeburn  6230:         }
                   6231:     }
                   6232:     unless ($readonly) {
                   6233:         $result .= '<input type="hidden" name="dateinterval_'.$thiskey.'" />';
                   6234:     }
                   6235:     return $result;
                   6236: }
                   6237: 
1.563     damieng  6238: # Returns HTML with a warning if a parameter requires a more recent version of LON-CAPA.
                   6239: #
                   6240: # @param {string} $name - parameter name
                   6241: # @param {string} $namematch - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   6242: # @param {string} $value - parameter value
                   6243: # @param {string} $chostname - course server name
                   6244: # @param {integer} $cmajor - major version number
                   6245: # @param {integer} $cminor - minor version number
                   6246: # @param {string} $needsrelease - release version needed (major.minor)
                   6247: # @returns {string}
1.549     raeburn  6248: sub oldversion_warning {
1.557     raeburn  6249:     my ($name,$namematch,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_;
                   6250:     my $standard_name = &standard_parameter_names($name);
                   6251:     if ($namematch) {
                   6252:         my $level = &standard_parameter_levels($namematch);
                   6253:         my $msg = '';
                   6254:         if ($level) {
                   6255:             $msg = &mt('[_1] was [_2]not[_3] set at the level of: [_4].',
                   6256:                        $standard_name,'<b>','</b>','"'.$level.'"');
                   6257:         } else {
                   6258:             $msg = &mt('[_1] was [_2]not[_3] set.',
                   6259:                       $standard_name,'<b>','</b>');
                   6260:         }
                   6261:         return '<p class="LC_warning">'.$msg.'<br />'.
                   6262:                &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6263:                    $cmajor.'.'.$cminor,$chostname,
                   6264:                    $needsrelease).
                   6265:                    '</p>';
                   6266:     }
1.549     raeburn  6267:     my $desc;
                   6268:     my $stringtype = &get_stringtype($name);
                   6269:     if ($stringtype ne '') {
                   6270:         if ($name eq 'examcode') {
                   6271:             $desc = $value;
                   6272:         } elsif (ref($strings{$stringtypes{$name}}) eq 'ARRAY') {
                   6273:             foreach my $possibilities (@{ $strings{$stringtypes{$name}} }) {
                   6274:                 next unless (ref($possibilities) eq 'ARRAY');
                   6275:                 my ($parmval, $description) = @{ $possibilities };
                   6276:                 my $parmmatch;
                   6277:                 if (ref($stringmatches{$stringtypes{$name}}) eq 'ARRAY') {
                   6278:                     foreach my $item (@{$stringmatches{$stringtypes{$name}}}) {
                   6279:                         if (ref($item) eq 'ARRAY') {
                   6280:                             my ($regexpname,$pattern) = @{$item};
                   6281:                             if ($parmval eq $regexpname) {
                   6282:                                 if ($value =~ /$pattern/) {
                   6283:                                     $desc = $description; 
                   6284:                                     $parmmatch = 1;
                   6285:                                     last;
                   6286:                                 }
                   6287:                             }
                   6288:                         }
                   6289:                     }
                   6290:                     last if ($parmmatch);
                   6291:                 } elsif ($parmval eq $value) {
                   6292:                     $desc = $description;
                   6293:                     last;
                   6294:                 }
                   6295:             }
                   6296:         }
                   6297:     } elsif (($name eq 'printstartdate') || ($name eq 'printenddate')) {
                   6298:         my $now = time;
                   6299:         if ($value =~ /^\d+$/) {
                   6300:             if ($name eq 'printstartdate') {
                   6301:                 if ($value > $now) {
                   6302:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6303:                 }
                   6304:             } elsif ($name eq 'printenddate') {
                   6305:                 if ($value < $now) {
                   6306:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6307:                 }
                   6308:             }
                   6309:         }
                   6310:     }
                   6311:     return '<p class="LC_warning">'.
1.557     raeburn  6312:        &mt('[_1] was [_2]not[_3] set to [_4].',
                   6313:            $standard_name,'<b>','</b>','"'.$desc.'"').'<br />'.
                   6314:        &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6315:        $cmajor.'.'.$cminor,$chostname,
                   6316:        $needsrelease).
                   6317:        '</p>';
1.549     raeburn  6318: }
                   6319: 
1.560     damieng  6320: } # end of block using some constants related to parameter types
                   6321: 
1.549     raeburn  6322: 
1.563     damieng  6323: 
                   6324: # Shifts all start and end dates in the current course by $shift.
1.389     www      6325: #
1.563     damieng  6326: # @param {integer} $shift - time to shift, in seconds
                   6327: # @returns {string} - error name or 'ok'
1.389     www      6328: sub dateshift {
1.594     raeburn  6329:     my ($shift,$numchanges)=@_;
1.389     www      6330:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6331:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6332:     my $sec = $env{'request.course.sec'};
1.595     raeburn  6333:     my $secgrpregex;
                   6334:     if ($sec ne '') {
                   6335:         my @groups;
                   6336:         if ($env{'request.course.groups'} ne '') {
                   6337:             @groups = split(/:/,$env{'request.course.groups'});
                   6338:         }
                   6339:         if (@groups) {
                   6340:             $secgrpregex = '(?:'.join('|',($sec,@groups)).')';
                   6341:         } else {
                   6342:             $secgrpregex = $sec;
                   6343:         }
                   6344:     }
1.389     www      6345:     my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs);
                   6346: # ugly retro fix for broken version of types
1.548     raeburn  6347:     foreach my $key (keys(%data)) {
1.389     www      6348:         if ($key=~/\wtype$/) {
                   6349:             my $newkey=$key;
                   6350:             $newkey=~s/type$/\.type/;
                   6351:             $data{$newkey}=$data{$key};
                   6352:             delete $data{$key};
                   6353:         }
                   6354:     }
1.391     www      6355:     my %storecontent=();
1.389     www      6356: # go through all parameters and look for dates
1.548     raeburn  6357:     foreach my $key (keys(%data)) {
1.389     www      6358:        if ($data{$key.'.type'}=~/^date_(start|end)$/) {
1.594     raeburn  6359:           if ($sec ne '') {
1.595     raeburn  6360:               next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./);
1.594     raeburn  6361:           }
1.389     www      6362:           my $newdate=$data{$key}+$shift;
1.594     raeburn  6363:           $$numchanges ++;
1.391     www      6364:           $storecontent{$key}=$newdate;
1.389     www      6365:        }
                   6366:     }
1.391     www      6367:     my $reply=&Apache::lonnet::cput
                   6368:                 ('resourcedata',\%storecontent,$dom,$crs);
                   6369:     if ($reply eq 'ok') {
                   6370:        &log_parmset(\%storecontent);
                   6371:     }
                   6372:     &Apache::lonnet::devalidatecourseresdata($crs,$dom);
                   6373:     return $reply;
1.389     www      6374: }
                   6375: 
1.563     damieng  6376: # Overview mode UI to edit course parameters.
                   6377: #
                   6378: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6379: sub newoverview {
1.568     raeburn  6380:     my ($r,$parm_permission) = @_;
1.280     albertel 6381: 
1.208     www      6382:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6383:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6384:     my $crstype =  $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6385:     my $readonly = 1;
                   6386:     if ($parm_permission->{'edit'}) {
                   6387:         undef($readonly);
                   6388:     }
1.414     droeschl 6389:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6390:         text=>"Overview Mode"});
1.523     raeburn  6391: 
                   6392:     my %loaditems = (
1.549     raeburn  6393:                       'onload'   => "showHide_courseContent(); resize_scrollbox('mapmenuscroll','1','1'); showHideLenient();",
1.523     raeburn  6394:                     );
                   6395:     my $js = '
                   6396: <script type="text/javascript">
                   6397: // <![CDATA[
                   6398: '.
                   6399:             &Apache::lonhtmlcommon::resize_scrollbox_js('params')."\n".
                   6400:             &showhide_js()."\n".
1.549     raeburn  6401:             &toggleparmtextbox_js()."\n".
                   6402:             &validateparms_js()."\n".
                   6403:             &ipacc_boxes_js()."\n".
1.622     raeburn  6404:             &grace_js()."\n".
1.558     raeburn  6405:             &done_proctor_js()."\n".
1.588     raeburn  6406:             &deeplink_js()."\n".
1.523     raeburn  6407: '// ]]>
                   6408: </script>
                   6409: ';
1.549     raeburn  6410: 
1.523     raeburn  6411:     my $start_page = &Apache::loncommon::start_page('Set Parameters',$js,
                   6412:                                                     {'add_entries' => \%loaditems,});
1.298     albertel 6413:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6414:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6415:     &startSettingsScreen($r,'parmset',$crstype);
1.208     www      6416:     $r->print(<<ENDOVER);
1.624     raeburn  6417: <form method="post" action="/adm/parmset?action=newoverview" name="parmform" id="newoverviewform">
                   6418: <input type="hidden" name="newoverviewsubm" value="dis" id="newoverviewsubm" />
1.208     www      6419: ENDOVER
1.211     www      6420:     my @ids=();
                   6421:     my %typep=();
                   6422:     my %keyp=();
                   6423:     my %allparms=();
                   6424:     my %allparts=();
                   6425:     my %allmaps=();
                   6426:     my %mapp=();
                   6427:     my %symbp=();
                   6428:     my %maptitles=();
                   6429:     my %uris=();
                   6430:     my %keyorder=&standardkeyorder();
                   6431:     my %defkeytype=();
                   6432: 
                   6433:     my %alllevs=();
                   6434:     $alllevs{'Resource Level'}='full';
1.215     www      6435:     $alllevs{'Map/Folder Level'}='map';
1.211     www      6436:     $alllevs{'Course Level'}='general';
                   6437: 
                   6438:     my $csec=$env{'form.csec'};
1.269     raeburn  6439:     my $cgroup=$env{'form.cgroup'};
1.211     www      6440: 
                   6441:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
                   6442:     my $pschp=$env{'form.pschp'};
1.506     www      6443: 
1.211     www      6444:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      6445:     if (!@psprt) { $psprt[0]='all'; }
1.211     www      6446: 
1.446     bisitz   6447:     my @selected_sections =
1.473     amueller 6448:     &Apache::loncommon::get_env_multiple('form.Section');
1.211     www      6449:     @selected_sections = ('all') if (! @selected_sections);
1.374     albertel 6450:     foreach my $sec (@selected_sections) {
                   6451:         if ($sec eq 'all') {
1.211     www      6452:             @selected_sections = ('all');
                   6453:         }
                   6454:     }
1.552     raeburn  6455:     if ($env{'request.course.sec'} ne '') {
                   6456:         @selected_sections = ($env{'request.course.sec'});
                   6457:     }
1.269     raeburn  6458:     my @selected_groups =
                   6459:         &Apache::loncommon::get_env_multiple('form.Group');
1.211     www      6460: 
                   6461:     my $pssymb='';
                   6462:     my $parmlev='';
1.446     bisitz   6463: 
1.211     www      6464:     unless ($env{'form.parmlev'}) {
                   6465:         $parmlev = 'map';
                   6466:     } else {
                   6467:         $parmlev = $env{'form.parmlev'};
                   6468:     }
                   6469: 
1.446     bisitz   6470:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 6471:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  6472:                 \%keyorder,\%defkeytype,$pssymb);
1.211     www      6473: 
1.374     albertel 6474:     if (grep {$_ eq 'all'} (@psprt)) {
1.481     amueller 6475:         @psprt = keys(%allparts);
1.374     albertel 6476:     }
1.211     www      6477: # Menu to select levels, etc
                   6478: 
1.456     bisitz   6479:     $r->print('<div class="LC_Box">');
1.445     neumanie 6480:     #$r->print('<h2 class="LC_hcell">Step 1</h2>');
1.452     bisitz   6481:     $r->print('<div>');
1.523     raeburn  6482:     $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.211     www      6483:     &levelmenu($r,\%alllevs,$parmlev);
1.610     raeburn  6484:     $r->print(&Apache::lonhtmlcommon::row_closure());
                   6485:     &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.447     bisitz   6486:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6487:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6488:     $r->print('</div></div>');
1.446     bisitz   6489: 
1.456     bisitz   6490:     $r->print('<div class="LC_Box">');
1.452     bisitz   6491:     $r->print('<div>');
1.581     raeburn  6492:     &displaymenu($r,\%allparms,\@pscat,\%keyorder);
1.453     schualex 6493:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.446     bisitz   6494:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
1.553     raeburn  6495:     my $sectionselector = &sectionmenu(\@selected_sections);
                   6496:     my $groupselector = &groupmenu(\@selected_groups);
1.481     amueller 6497:     $r->print('<table>'.
1.553     raeburn  6498:               '<tr><th>'.&mt('Parts').'</th>');
                   6499:     if ($sectionselector) {
                   6500:         $r->print('<th>'.&mt('Section(s)').'</th>');
                   6501:     }
                   6502:     if ($groupselector) {
                   6503:         $r->print('<th>'.&mt('Group(s)').'</th>');
                   6504:     }
                   6505:     $r->print('</tr><tr><td>');
1.211     www      6506:     &partmenu($r,\%allparts,\@psprt);
1.553     raeburn  6507:     $r->print('</td>');
                   6508:     if ($sectionselector) { 
                   6509:         $r->print('<td>'.$sectionselector.'</td>');
                   6510:     }
                   6511:     if ($groupselector) {
                   6512:         $r->print('<td>'.$groupselector.'</td>');
                   6513:     }
                   6514:     $r->print('</tr></table>');
1.447     bisitz   6515:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6516:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6517:     $r->print('</div></div>');
                   6518: 
1.456     bisitz   6519:     $r->print('<div class="LC_Box">');
1.452     bisitz   6520:     $r->print('<div>');
1.214     www      6521:     my $sortorder=$env{'form.sortorder'};
                   6522:     unless ($sortorder) { $sortorder='realmstudent'; }
1.612     raeburn  6523:     &sortmenu($r,$sortorder,'newoverview');
1.445     neumanie 6524:     $r->print('</div></div>');
1.446     bisitz   6525: 
1.624     raeburn  6526:     $r->print('<p><input type="submit" name="dis" value="'.&mt('Display').'" id="newoverviewdis" /></p>');
1.446     bisitz   6527: 
1.211     www      6528: # Build the list data hash from the specified parms
                   6529: 
                   6530:     my $listdata;
                   6531:     %{$listdata}=();
                   6532: 
                   6533:     foreach my $cat (@pscat) {
1.269     raeburn  6534:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_sections,\%defkeytype,\%allmaps,\@ids,\%symbp);
                   6535:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_groups,\%defkeytype,\%allmaps,\@ids,\%symbp);
1.211     www      6536:     }
                   6537: 
1.624     raeburn  6538:     my $foundkeys;
                   6539:     if ($env{'form.newoverviewsubm'}) {
1.211     www      6540: 
1.624     raeburn  6541:         if ($env{'form.newoverviewsubm'} eq 'store') { &storedata($r,$crs,$dom); }
1.211     www      6542: 
                   6543: # Read modified data
                   6544: 
1.481     amueller 6545:         my $resourcedata=&readdata($crs,$dom);
1.211     www      6546: 
                   6547: # List data
                   6548: 
1.608     raeburn  6549:         my $hash_for_realm;
                   6550:         if (($parmlev eq 'map') && (keys(%allmaps))) {
                   6551:             %{$hash_for_realm} = reverse(%allmaps);
                   6552:         } elsif (($parmlev eq 'full') && (keys(%symbp))) {
                   6553:             for (my $i=0; $i<@ids; $i++) {
                   6554:                 $hash_for_realm->{$symbp{$ids[$i]}} = $i;
                   6555:             }
                   6556:         }
1.624     raeburn  6557:         $foundkeys = &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly,$parmlev,$hash_for_realm,$pschp);
1.568     raeburn  6558:     }
                   6559:     $r->print(&tableend());
1.624     raeburn  6560:     if ((!$readonly) && ($foundkeys)) {
                   6561:         $r->print( ($env{'form.newoverviewsubm'}? '<p><input type="submit" name="store" id="newoverviewstore" value="'.&mt('Save').'" /></p>':'') );
1.211     www      6562:     }
1.568     raeburn  6563:     $r->print('</form>');
1.624     raeburn  6564:     if ($env{'form.newoverviewsubm'}) {
                   6565:         $r->print(<<"END");
                   6566: <script type="text/javascript">
                   6567: const form = document.getElementById('newoverviewform');
                   6568: const storebutton = document.getElementById('newoverviewstore');
                   6569: const disbutton = document.getElementById('newoverviewdis');
                   6570: const submethod = document.getElementById('newoverviewsubm');
                   6571: if (storebutton) { 
                   6572:   storebutton.addEventListener('keydown', (e) => {
                   6573:     if (e.key === 'Enter') {
                   6574:       if (validateParms()) {
                   6575:         if (form) {
                   6576:           if (submethod) {
                   6577:             submethod.value='store';
                   6578:           }
                   6579:           form.submit();
                   6580:         }
                   6581:       }
                   6582:       e.preventDefault();
                   6583:       return;
                   6584:     }
                   6585:   });
                   6586:   storebutton.addEventListener('click', (e) => {
                   6587:     if (validateParms()) {
                   6588:       if (form) {
                   6589:         if (submethod) {
                   6590:           submethod.value='store';
                   6591:         }
                   6592:         form.submit();
                   6593:       }
                   6594:     }
                   6595:     e.preventDefault();
                   6596:     return;
                   6597:   });
                   6598: }
                   6599: if (disbutton) {
                   6600:   disbutton.addEventListener('keydown', (e) => {
                   6601:     if (e.key === 'Enter') {
                   6602:       if (form) {
                   6603:         if (submethod) {
                   6604:           submethod.value='dis';
                   6605:         }
                   6606:         form.submit();
                   6607:       }
                   6608:       e.preventDefault();
                   6609:     }
                   6610:   });
                   6611:   disbutton.addEventListener('click', (e) => {
                   6612:     if (form) {
                   6613:       if (submethod) {
                   6614:         submethod.value='dis';
                   6615:       }
                   6616:       form.submit();
                   6617:       return;
                   6618:     }
                   6619:     e.preventDefault();
                   6620:   });
                   6621: }
                   6622: 
                   6623: </script>
                   6624: 
                   6625: END
                   6626:     }
1.507     www      6627:     &endSettingsScreen($r);
                   6628:     $r->print(&Apache::loncommon::end_page());
1.208     www      6629: }
                   6630: 
1.563     damieng  6631: # Fills $listdata with parameter information.
                   6632: # Keys use the format course id.[section id].part.name and course id.[section id].part.name.type.
                   6633: # The non-type value is always 1.
                   6634: #
                   6635: # @param {string} $cat - parameter name
1.566     damieng  6636: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  6637: # @param {string} $parmlev - selected level value (full|map|general), or ''
                   6638: # @param {hash reference} $listdata - the parameter data that will be modified
                   6639: # @param {array reference} $psprt - selected parts
                   6640: # @param {array reference} $selections - selected sections
                   6641: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.566     damieng  6642: # @param {hash reference} $allmaps - hash map pc -> map src
                   6643: # @param {array reference} $ids - resource and map ids
                   6644: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.269     raeburn  6645: sub secgroup_lister {
                   6646:     my ($cat,$pschp,$parmlev,$listdata,$psprt,$selections,$defkeytype,$allmaps,$ids,$symbp) = @_;
                   6647:     foreach my $item (@{$selections}) {
                   6648:         foreach my $part (@{$psprt}) {
                   6649:             my $rootparmkey=$env{'request.course.id'};
                   6650:             if (($item ne 'all') && ($item ne 'none') && ($item)) {
                   6651:                 $rootparmkey.='.['.$item.']';
                   6652:             }
                   6653:             if ($parmlev eq 'general') {
                   6654: # course-level parameter
                   6655:                 my $newparmkey=$rootparmkey.'.'.$part.'.'.$cat;
                   6656:                 $$listdata{$newparmkey}=1;
                   6657:                 $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6658:             } elsif ($parmlev eq 'map') {
                   6659: # map-level parameter
1.548     raeburn  6660:                 foreach my $mapid (keys(%{$allmaps})) {
1.269     raeburn  6661:                     if (($pschp ne 'all') && ($pschp ne $mapid)) { next; }
                   6662:                     my $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(all).'.$part.'.'.$cat;
                   6663:                     $$listdata{$newparmkey}=1;
                   6664:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6665:                 }
                   6666:             } else {
                   6667: # resource-level parameter
                   6668:                 foreach my $rid (@{$ids}) {
                   6669:                     my ($map,$resid,$url)=&Apache::lonnet::decode_symb($$symbp{$rid});
                   6670:                     if (($pschp ne 'all') && ($$allmaps{$pschp} ne $map)) { next; }
                   6671:                     my $newparmkey=$rootparmkey.'.'.$$symbp{$rid}.'.'.$part.'.'.$cat;
                   6672:                     $$listdata{$newparmkey}=1;
                   6673:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6674:                 }
                   6675:             }
                   6676:         }
                   6677:     }
                   6678: }
                   6679: 
1.563     damieng  6680: # UI to edit parameter settings starting with a list of all existing parameters.
                   6681: # (called by setoverview action)
                   6682: #
                   6683: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6684: sub overview {
1.568     raeburn  6685:     my ($r,$parm_permission) = @_;
1.208     www      6686:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6687:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6688:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6689:     my $readonly = 1;
                   6690:     if ($parm_permission->{'edit'}) {
                   6691:         undef($readonly);
                   6692:     }
1.549     raeburn  6693:     my $js = '<script type="text/javascript">'."\n".
                   6694:              '// <![CDATA['."\n".
                   6695:              &toggleparmtextbox_js()."\n".
                   6696:              &validateparms_js()."\n".
                   6697:              &ipacc_boxes_js()."\n".
1.622     raeburn  6698:              &grace_js()."\n".
1.558     raeburn  6699:              &done_proctor_js()."\n".
1.588     raeburn  6700:              &deeplink_js()."\n".
1.549     raeburn  6701:              '// ]]>'."\n".
                   6702:              '</script>'."\n";
1.414     droeschl 6703:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6704:     text=>"Overview Mode"});
1.549     raeburn  6705:     my %loaditems = (
                   6706:                       'onload'   => "showHideLenient();",
                   6707:                     );
                   6708: 
                   6709:     my $start_page=&Apache::loncommon::start_page('Modify Parameters',$js,{'add_entries' => \%loaditems,});
1.298     albertel 6710:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6711:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6712:     &startSettingsScreen($r,'parmset',$crstype);
1.549     raeburn  6713:     $r->print('<form method="post" action="/adm/parmset?action=setoverview" name="parmform" onsubmit="return validateParms();">');
1.507     www      6714: 
1.208     www      6715: # Store modified
                   6716: 
1.568     raeburn  6717:     unless ($readonly) {
                   6718:         &storedata($r,$crs,$dom);
                   6719:     }
1.208     www      6720: 
                   6721: # Read modified data
                   6722: 
1.552     raeburn  6723:     my ($resourcedata,$classlist)=&readdata($crs,$dom);
1.208     www      6724: 
1.214     www      6725: 
                   6726:     my $sortorder=$env{'form.sortorder'};
                   6727:     unless ($sortorder) { $sortorder='realmstudent'; }
1.608     raeburn  6728:     &sortmenu($r,$sortorder,'overview');
1.214     www      6729: 
1.568     raeburn  6730:     my $submitbutton = '<input type="submit" value="'.&mt('Save').'" />';
                   6731: 
                   6732:     if ($readonly) {
                   6733:         $r->print('<p>'.$submitbutton.'</p>');
                   6734:     }
                   6735: 
1.208     www      6736: # List data
                   6737: 
1.568     raeburn  6738:     my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist,$readonly);
                   6739:     $r->print(&tableend().'<p>');
                   6740:     if ($foundkeys) {
                   6741:         unless ($readonly) {
                   6742:             $r->print('<p>'.$submitbutton.'</p>');
                   6743:         }
                   6744:     } else {
                   6745:         $r->print('<p class="LC_info">'.&mt('There are no parameters.').'</p>');
                   6746:     }
                   6747:     $r->print('</form>'.&Apache::loncommon::end_page());
1.120     www      6748: }
1.121     www      6749: 
1.560     damieng  6750: # Unused sub.
1.563     damieng  6751: #
                   6752: # @param {Apache2::RequestRec} $r - the Apache request
1.333     albertel 6753: sub clean_parameters {
                   6754:     my ($r) = @_;
                   6755:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6756:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6757: 
1.414     droeschl 6758:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=cleanparameters',
1.473     amueller 6759:         text=>"Clean Parameters"});
1.333     albertel 6760:     my $start_page=&Apache::loncommon::start_page('Clean Parameters');
                   6761:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Clean');
                   6762:     $r->print(<<ENDOVER);
                   6763: $start_page
                   6764: $breadcrumbs
                   6765: <form method="post" action="/adm/parmset?action=cleanparameters" name="parmform">
                   6766: ENDOVER
                   6767: # Store modified
                   6768: 
                   6769:     &storedata($r,$crs,$dom);
                   6770: 
                   6771: # Read modified data
                   6772: 
                   6773:     my $resourcedata=&readdata($crs,$dom);
                   6774: 
                   6775: # List data
                   6776: 
                   6777:     $r->print('<h3>'.
1.473     amueller 6778:           &mt('These parameters refer to resources that do not exist.').
                   6779:           '</h3>'.
                   6780:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.'<br />'.
                   6781:           '<br />');
1.333     albertel 6782:     $r->print(&Apache::loncommon::start_data_table().
1.473     amueller 6783:           '<tr>'.
                   6784:           '<th>'.&mt('Delete').'</th>'.
                   6785:           '<th>'.&mt('Parameter').'</th>'.
                   6786:           '</tr>');
1.333     albertel 6787:     foreach my $thiskey (sort(keys(%{$resourcedata}))) {
1.560     damieng  6788:         next if (!exists($resourcedata->{$thiskey.'.type'})
                   6789:             && $thiskey=~/\.type$/);
                   6790:         my %data = &parse_key($thiskey);
                   6791:         if (1) { #exists($data{'realm_exists'})
                   6792:             #&& !$data{'realm_exists'}) {
                   6793:             $r->print(&Apache::loncommon::start_data_table_row().
                   6794:                 '<tr>'.
                   6795:                 '<td><input type="checkbox" name="del_'.$thiskey.'" /></td>'              );
                   6796: 
                   6797:             $r->print('<td>');
                   6798:             my $display_value = $resourcedata->{$thiskey};
                   6799:             if (&isdateparm($resourcedata->{$thiskey.'.type'})) {
                   6800:             $display_value =
                   6801:                 &Apache::lonlocal::locallocaltime($display_value);
                   6802:             }
1.470     raeburn  6803:             my $parmitem = &standard_parameter_names($data{'parameter_name'});
                   6804:             $parmitem = &mt($parmitem);
1.560     damieng  6805:             $r->print(&mt('Parameter: "[_1]" with value: "[_2]"',
                   6806:                 $parmitem,$resourcedata->{$thiskey}));
                   6807:             $r->print('<br />');
                   6808:             if ($data{'scope_type'} eq 'all') {
                   6809:                 $r->print(&mt('All users'));
                   6810:             } elsif ($data{'scope_type'} eq 'user') {
                   6811:                 $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}})));
1.581     raeburn  6812:             } elsif ($data{'scope_type'} eq 'secgroup') {
                   6813:                 $r->print(&mt('Group/Section: [_1]',$data{'scope'}));
1.560     damieng  6814:             }
                   6815:             $r->print('<br />');
                   6816:             if ($data{'realm_type'} eq 'all') {
                   6817:                 $r->print(&mt('All Resources'));
                   6818:             } elsif ($data{'realm_type'} eq 'folder') {
                   6819:                 $r->print(&mt('Folder: [_1]'),$data{'realm'});
                   6820:             } elsif ($data{'realm_type'} eq 'symb') {
                   6821:             my ($map,$resid,$url) =
                   6822:                 &Apache::lonnet::decode_symb($data{'realm'});
                   6823:             $r->print(&mt('Resource: [_1]with ID: [_2]in folder [_3]',
                   6824:                         $url.' <br />&nbsp;&nbsp;&nbsp;',
                   6825:                         $resid.' <br />&nbsp;&nbsp;&nbsp;',$map));
                   6826:             }
                   6827:             $r->print(' <br />&nbsp;&nbsp;&nbsp;'.&mt('Part: [_1]',$data{'parameter_part'}));
                   6828:             $r->print('</td></tr>');
                   6829: 
1.473     amueller 6830:         }
1.333     albertel 6831:     }
                   6832:     $r->print(&Apache::loncommon::end_data_table().'<p>'.
1.473     amueller 6833:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.
1.507     www      6834:           '</p></form>');
                   6835:     &endSettingsScreen($r);
                   6836:     $r->print(&Apache::loncommon::end_page());
1.333     albertel 6837: }
                   6838: 
1.563     damieng  6839: # UI to shift all dates (called by dateshift1 action).
                   6840: # Used by overview mode.
                   6841: #
                   6842: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6843: sub date_shift_one {
                   6844:     my ($r) = @_;
                   6845:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6846:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6847:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.594     raeburn  6848:     my $sec = $env{'request.course.sec'};
1.414     droeschl 6849:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6850:         text=>"Shifting Dates"});
1.594     raeburn  6851:     my $submit_text = &mt('Shift all dates accordingly');
                   6852:     if ($sec ne '') {
1.595     raeburn  6853:         my @groups;
                   6854:         if ($env{'request.course.groups'} ne '') {
                   6855:             @groups = split(/:/,$env{'request.course.groups'});
                   6856:         }
                   6857:         if (@groups) {
                   6858:             $submit_text = &mt("Shift dates set just for your section/group(s), accordingly");
                   6859:         } else {
                   6860:             $submit_text = &mt("Shift dates set just for your section, accordingly");
                   6861:         }
1.594     raeburn  6862:     }
1.390     www      6863:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6864:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6865:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6866:     &startSettingsScreen($r,'parmset',$crstype);
1.538     bisitz   6867:     $r->print('<form name="shiftform" method="post" action="">'.
1.390     www      6868:               '<table><tr><td>'.&mt('Currently set date:').'</td><td>'.
                   6869:               &Apache::lonlocal::locallocaltime($env{'form.timebase'}).'</td></tr>'.
                   6870:               '<tr><td>'.&mt('Shifted date:').'</td><td>'.
1.541     bisitz   6871:                     &Apache::lonhtmlcommon::date_setter('shiftform',
1.390     www      6872:                                                         'timeshifted',
                   6873:                                                         $env{'form.timebase'},,
                   6874:                                                         '').
                   6875:               '</td></tr></table>'.
                   6876:               '<input type="hidden" name="action" value="dateshift2" />'.
                   6877:               '<input type="hidden" name="timebase" value="'.$env{'form.timebase'}.'" />'.
1.594     raeburn  6878:               '<input type="submit" value="'.$submit_text.'" /></form>');
1.507     www      6879:     &endSettingsScreen($r);
1.390     www      6880:     $r->print(&Apache::loncommon::end_page());
                   6881: }
                   6882: 
1.563     damieng  6883: # UI to shift all dates (second form).
                   6884: #
                   6885: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6886: sub date_shift_two {
                   6887:     my ($r) = @_;
                   6888:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6889:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6890:     my $sec = $env{'request.course.sec'};
1.531     raeburn  6891:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 6892:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6893:         text=>"Shifting Dates"});
1.390     www      6894:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6895:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6896:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6897:     &startSettingsScreen($r,'parmset',$crstype);
1.390     www      6898:     my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted');
1.594     raeburn  6899:     $r->print('<h2>'.&mt('Shift Dates').'</h2>');
                   6900:     if ($sec ne '') {
1.595     raeburn  6901:         my @groups;
                   6902:         if ($env{'request.course.groups'} ne '') {
                   6903:             @groups = split(/:/,$env{'request.course.groups'});
                   6904:         }
                   6905:         if (@groups) {
                   6906:             $r->print('<p>'.
                   6907:                       &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]",
                   6908:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6909:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6910:                       '</p>');
                   6911:         } else {
                   6912:             $r->print('<p>'.
                   6913:                       &mt("Shift dates set just for your section, such that [_1] becomes [_2]",
                   6914:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6915:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6916:                       '</p>');
                   6917:         }
1.594     raeburn  6918:     } else {
                   6919:         $r->print('<p>'.&mt('Shifting all dates such that [_1] becomes [_2]',
                   6920:                             &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6921:                             &Apache::lonlocal::locallocaltime($timeshifted)).
                   6922:                   '</p>');
                   6923:     }
1.390     www      6924:     my $delta=$timeshifted-$env{'form.timebase'};
1.594     raeburn  6925:     my $numchanges = 0;
                   6926:     my $result = &dateshift($delta,\$numchanges);
                   6927:     if ($result eq 'ok') {
                   6928:         $r->print(
                   6929:             &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]',
                   6930:                                                     $numchanges)));
                   6931:     } elsif ($result eq 'con_delayed') {
                   6932:         $r->print(
                   6933:             &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]',
                   6934:                                                         $numchanges)));
                   6935:     } else {
                   6936:         $r->print(
                   6937:             &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1));
                   6938:     }
1.543     bisitz   6939:     $r->print(
                   6940:         '<br /><br />'.
                   6941:         &Apache::lonhtmlcommon::actionbox(
                   6942:             ['<a href="/adm/parmset">'.&mt('Content and Problem Settings').'</a>']));
1.507     www      6943:     &endSettingsScreen($r);
1.390     www      6944:     $r->print(&Apache::loncommon::end_page());
                   6945: }
                   6946: 
1.563     damieng  6947: # Returns the different components of a resourcedata key.
                   6948: # Keys: scope_type, scope, realm_type, realm, realm_title,
                   6949: #       realm_exists, parameter_part, parameter_name.
                   6950: # Was used by clean_parameters (which is unused).
                   6951: #
                   6952: # @param {string} $key - the parameter key
                   6953: # @returns {hash}
1.333     albertel 6954: sub parse_key {
                   6955:     my ($key) = @_;
                   6956:     my %data;
                   6957:     my ($middle,$part,$name)=
1.572     damieng  6958:     ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.333     albertel 6959:     $data{'scope_type'} = 'all';
                   6960:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  6961:         $data{'scope'} = $1;
                   6962:         if ($data{'scope'}=~/^useropt\:($match_username)\:($match_domain)/) {
                   6963:             $data{'scope_type'} = 'user';
                   6964:             $data{'scope'} = [$1,$2];
                   6965:         } else {
1.581     raeburn  6966:             $data{'scope_type'} = 'secgroup';
1.560     damieng  6967:         }
                   6968:         $middle=~s/^\[(.*)\]//;
1.333     albertel 6969:     }
                   6970:     $middle=~s/\.+$//;
                   6971:     $middle=~s/^\.+//;
                   6972:     $data{'realm_type'}='all';
                   6973:     if ($middle=~/^(.+)\_\_\_\(all\)$/) {
1.560     damieng  6974:         $data{'realm'} = $1;
                   6975:         $data{'realm_type'} = 'folder';
                   6976:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6977:         ($data{'realm_exists'}) = &Apache::lonnet::is_on_map($data{'realm'});
1.333     albertel 6978:     } elsif ($middle) {
1.560     damieng  6979:         $data{'realm'} = $middle;
                   6980:         $data{'realm_type'} = 'symb';
                   6981:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6982:         my ($map,$resid,$url) = &Apache::lonnet::decode_symb($data{'realm'});
                   6983:         $data{'realm_exists'} = &Apache::lonnet::symbverify($data{'realm'},$url);
1.333     albertel 6984:     }
1.446     bisitz   6985: 
1.333     albertel 6986:     $data{'parameter_part'} = $part;
                   6987:     $data{'parameter_name'} = $name;
                   6988: 
                   6989:     return %data;
                   6990: }
                   6991: 
1.239     raeburn  6992: 
1.563     damieng  6993: # Calls loncommon::start_page with the "Settings" title.
1.416     jms      6994: sub header {
1.507     www      6995:     return &Apache::loncommon::start_page('Settings');
1.416     jms      6996: }
1.193     albertel 6997: 
                   6998: 
                   6999: 
1.560     damieng  7000: ##################################################
                   7001: # MAIN MENU
                   7002: ##################################################
                   7003: 
1.563     damieng  7004: # Content and problem settings main menu.
                   7005: #
                   7006: # @param {Apache2::RequestRec} $r - the Apache request
                   7007: # @param {boolean} $parm_permission - true if the user has permission to edit the current course or section
1.193     albertel 7008: sub print_main_menu {
                   7009:     my ($r,$parm_permission)=@_;
                   7010:     #
1.414     droeschl 7011:     $r->print(&header());
1.507     www      7012:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content and Problem Settings'));
1.531     raeburn  7013:     my $crstype = &Apache::loncommon::course_type();
                   7014:     my $lc_crstype = lc($crstype);
                   7015: 
                   7016:     &startSettingsScreen($r,'parmset',$crstype);
1.193     albertel 7017:     $r->print(<<ENDMAINFORMHEAD);
                   7018: <form method="post" enctype="multipart/form-data"
                   7019:       action="/adm/parmset" name="studentform">
                   7020: ENDMAINFORMHEAD
                   7021: #
1.195     albertel 7022:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7023:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
1.268     albertel 7024:     my $vgr  = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
1.366     albertel 7025:     my $mgr  = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
1.520     raeburn  7026:     my $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'});
1.568     raeburn  7027:     my $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'});
                   7028:     my $vpa = &Apache::lonnet::allowed('vpa',$env{'request.course.id'});
1.520     raeburn  7029:     if ((!$dcm) && ($env{'request.course.sec'} ne '')) {
                   7030:         $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}.
                   7031:                                         '/'.$env{'request.course.sec'});
                   7032:     }
1.568     raeburn  7033:     if ((!$vcb) && ($env{'request.course.sec'} ne '')) {
                   7034:         $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}.
                   7035:                                         '/'.$env{'request.course.sec'});
                   7036:     }
                   7037:     my (%linktext,%linktitle,%url);
                   7038:     if ($parm_permission->{'edit'}) {
                   7039:         %linktext = (
                   7040:                      newoverview     => 'Edit Resource Parameters - Overview Mode',
                   7041:                      settable        => 'Edit Resource Parameters - Table Mode',
                   7042:                      setoverview     => 'Modify Resource Parameters - Overview Mode',
                   7043:                     );
                   7044:         %linktitle = (
                   7045:                      newoverview     => 'Set/Modify resource parameters in overview mode.',
                   7046:                      settable        => 'Set/Modify resource parameters in table mode.',
                   7047:                      setoverview     => 'Set/Modify existing resource parameters in overview mode.',
                   7048:                      );
                   7049:     } else {
                   7050:         %linktext = (
                   7051:                      newoverview     => 'View Resource Parameters - Overview Mode',
                   7052:                      settable        => 'View Resource Parameters - Table Mode',
                   7053:                      setoverview     => 'View Resource Parameters - Overview Mode',
                   7054:                    );
                   7055:         %linktitle = (
                   7056:                      newoverview     => 'Display resource parameters in overview mode.',
                   7057:                      settable        => 'Display resource parameters in table mode.',
                   7058:                      setoverview     => 'Display existing resource parameters in overview mode.',
                   7059:                      );
                   7060:     }
                   7061:     if ($mgr) {
                   7062:         $linktext{'resettimes'} = 'Reset Student Access Times';
                   7063:         $linktitle{'resettimes'} = "Reset access times for folders/maps, resources or the $lc_crstype.";
                   7064:         $url{'resettimes'} = '/adm/helper/resettimes.helper';
                   7065:     } elsif ($vgr) {
                   7066:         $linktext{'resettimes'} = 'Display Student Access Times',
                   7067:         $linktitle{'resettimes'} = "Display access times for folders/maps, resources or the $lc_crstype.",
                   7068:         $url{'resettimes'} = '/adm/accesstimes';
                   7069:     }
1.193     albertel 7070:     my @menu =
1.507     www      7071:         ( { categorytitle=>"Content Settings for this $crstype",
1.473     amueller 7072:         items => [
                   7073:           { linktext => 'Portfolio Metadata',
                   7074:             url => '/adm/parmset?action=setrestrictmeta',
1.568     raeburn  7075:             permission => $parm_permission->{'setrestrictmeta'},
1.477     raeburn  7076:             linktitle => "Restrict metadata for this $lc_crstype." ,
1.473     amueller 7077:             icon =>'contact-new.png'   ,
                   7078:             },
1.568     raeburn  7079:           { linktext => $linktext{'resettimes'},
                   7080:             url => $url{'resettimes'},
                   7081:             permission => ($vgr || $mgr),
                   7082:             linktitle => $linktitle{'resettimes'},
                   7083:             icon => 'start-here.png',
1.473     amueller 7084:             },
1.520     raeburn  7085:           { linktext => 'Blocking Communication/Resource Access',
                   7086:             url => '/adm/setblock',
1.568     raeburn  7087:             permission => ($vcb || $dcm),
1.520     raeburn  7088:             linktitle => 'Configure blocking of communication/collaboration and access to resources during an exam',
                   7089:             icon => 'comblock.png',
                   7090:             },
1.473     amueller 7091:           { linktext => 'Set Parameter Setting Default Actions',
                   7092:             url => '/adm/parmset?action=setdefaults',
1.568     raeburn  7093:             permission => $parm_permission->{'setdefaults'},
1.473     amueller 7094:             linktitle =>'Set default actions for parameters.'  ,
                   7095:             icon => 'folder-new.png'  ,
                   7096:             }]},
                   7097:       { categorytitle => 'New and Existing Parameter Settings for Resources',
                   7098:         items => [
                   7099:           { linktext => 'Edit Resource Parameters - Helper Mode',
                   7100:             url => '/adm/helper/parameter.helper',
1.568     raeburn  7101:             permission => $parm_permission->{'helper'},
1.473     amueller 7102:             linktitle =>'Set/Modify resource parameters in helper mode.'  ,
                   7103:             icon => 'dialog-information.png'  ,
                   7104:             #help => 'Parameter_Helper',
                   7105:             },
1.568     raeburn  7106:           { linktext => $linktext{'newoverview'},
1.473     amueller 7107:             url => '/adm/parmset?action=newoverview',
1.568     raeburn  7108:             permission => $parm_permission->{'newoverview'},
                   7109:             linktitle => $linktitle{'newoverview'},
                   7110:             icon => 'edit-find.png',
1.473     amueller 7111:             #help => 'Parameter_Overview',
                   7112:             },
1.568     raeburn  7113:           { linktext => $linktext{'settable'},
1.473     amueller 7114:             url => '/adm/parmset?action=settable',
1.568     raeburn  7115:             permission => $parm_permission->{'settable'},
                   7116:             linktitle => $linktitle{'settable'},
                   7117:             icon => 'edit-copy.png',
1.473     amueller 7118:             #help => 'Table_Mode',
                   7119:             }]},
1.417     droeschl 7120:            { categorytitle => 'Existing Parameter Settings for Resources',
1.473     amueller 7121:          items => [
1.570     raeburn  7122:           { linktext => $linktext{'setoverview'},
1.473     amueller 7123:             url => '/adm/parmset?action=setoverview',
1.568     raeburn  7124:             permission => $parm_permission->{'setoverview'},
                   7125:             linktitle => $linktitle{'setoverview'},
                   7126:             icon => 'preferences-desktop-wallpaper.png',
1.473     amueller 7127:             #help => 'Parameter_Overview',
                   7128:             },
                   7129:           { linktext => 'Change Log',
                   7130:             url => '/adm/parmset?action=parameterchangelog',
1.568     raeburn  7131:             permission => $parm_permission->{'parameterchangelog'},
1.477     raeburn  7132:             linktitle =>"View parameter and $lc_crstype blog posting/user notification change log."  ,
1.487     wenzelju 7133:             icon => 'document-properties.png',
1.473     amueller 7134:             }]}
1.193     albertel 7135:           );
1.414     droeschl 7136:     $r->print(&Apache::lonhtmlcommon::generate_menu(@menu));
1.539     raeburn  7137:     $r->print('</form>');
1.507     www      7138:     &endSettingsScreen($r);
1.539     raeburn  7139:     $r->print(&Apache::loncommon::end_page());
1.193     albertel 7140:     return;
                   7141: }
1.414     droeschl 7142: 
1.416     jms      7143: 
                   7144: 
1.560     damieng  7145: ##################################################
                   7146: # PORTFOLIO METADATA
                   7147: ##################################################
                   7148: 
1.563     damieng  7149: # Prints HTML to edit an item of portfolio metadata. The HTML contains several td elements (no tr).
                   7150: # It looks like field titles are not localized.
                   7151: #
                   7152: # @param {Apache2::RequestRec} $r - the Apache request
                   7153: # @param {string} $field_name - metadata field name
                   7154: # @param {string} $field_text - metadata field title, in English unless manually added
                   7155: # @param {boolean} $added_flag - true if the field was manually added
1.252     banghart 7156: sub output_row {
1.347     banghart 7157:     my ($r, $field_name, $field_text, $added_flag) = @_;
1.252     banghart 7158:     my $output;
1.263     banghart 7159:     my $options=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'};
                   7160:     my $values=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.values'};
1.337     banghart 7161:     if (!defined($options)) {
1.254     banghart 7162:         $options = 'active,stuadd';
1.261     banghart 7163:         $values = '';
1.252     banghart 7164:     }
1.337     banghart 7165:     if (!($options =~ /deleted/)) {
                   7166:         my @options= ( ['active', 'Show to student'],
1.418     schafran 7167:                     ['stuadd', 'Provide text area for students to type metadata'],
1.351     banghart 7168:                     ['choices','Provide choices for students to select from']);
1.473     amueller 7169: #           ['onlyone','Student may select only one choice']);
1.337     banghart 7170:         if ($added_flag) {
                   7171:             push @options,['deleted', 'Delete Metadata Field'];
                   7172:         }
1.351     banghart 7173:        $output = &Apache::loncommon::start_data_table_row();
1.451     bisitz   7174:         $output .= '<td><strong>'.$field_text.':</strong></td>';
1.351     banghart 7175:         $output .= &Apache::loncommon::end_data_table_row();
1.337     banghart 7176:         foreach my $opt (@options) {
1.560     damieng  7177:             my $checked = ($options =~ m/$opt->[0]/) ? ' checked="checked" ' : '' ;
                   7178:             $output .= &Apache::loncommon::continue_data_table_row();
                   7179:             $output .= '<td>'.('&nbsp;' x 5).'<label>
                   7180:                     <input type="checkbox" name="'.
                   7181:                     $field_name.'_'.$opt->[0].'" value="yes"'.$checked.' />'.
                   7182:                     &mt($opt->[1]).'</label></td>';
                   7183:             $output .= &Apache::loncommon::end_data_table_row();
                   7184:         }
1.351     banghart 7185:         $output .= &Apache::loncommon::continue_data_table_row();
1.451     bisitz   7186:         $output .= '<td>'.('&nbsp;' x 10).'<input name="'.$field_name.'_values" type="text" value="'.$values.'" size="80" /></td>';
1.351     banghart 7187:         $output .= &Apache::loncommon::end_data_table_row();
                   7188:         my $multiple_checked;
                   7189:         my $single_checked;
                   7190:         if ($options =~ m/onlyone/) {
1.422     bisitz   7191:             $multiple_checked = '';
1.423     bisitz   7192:             $single_checked = ' checked="checked"';
1.351     banghart 7193:         } else {
1.423     bisitz   7194:             $multiple_checked = ' checked="checked"';
1.422     bisitz   7195:             $single_checked = '';
1.351     banghart 7196:         }
1.560     damieng  7197:         $output .= &Apache::loncommon::continue_data_table_row();
                   7198:         $output .= '<td>'.('&nbsp;' x 10).'
                   7199:                     <input type="radio" name="'.$field_name.'_onlyone" value="multiple"'.$multiple_checked .' />
                   7200:                     '.&mt('Student may select multiple choices from list').'</td>';
                   7201:         $output .= &Apache::loncommon::end_data_table_row();
                   7202:         $output .= &Apache::loncommon::continue_data_table_row();
                   7203:         $output .= '<td>'.('&nbsp;' x 10).'
                   7204:                     <input type="radio" name="'.$field_name.'_onlyone"  value="single"'.$single_checked.' />
                   7205:                     '.&mt('Student may select only one choice from list').'</td>';
                   7206:         $output .= &Apache::loncommon::end_data_table_row();
1.252     banghart 7207:     }
                   7208:     return ($output);
                   7209: }
1.416     jms      7210: 
                   7211: 
1.560     damieng  7212: # UI to order portfolio metadata fields.
1.563     damieng  7213: # Currently useless because addmetafield does not work.
                   7214: #
                   7215: # @param {Apache2::RequestRec} $r - the Apache request
1.340     banghart 7216: sub order_meta_fields {
                   7217:     my ($r)=@_;
                   7218:     my $idx = 1;
                   7219:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7220:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7221:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};;
1.341     banghart 7222:     $r->print(&Apache::loncommon::start_page('Order Metadata Fields'));
1.560     damieng  7223:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7224:         {href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7225:         text=>"Add Metadata Field"});
1.560     damieng  7226:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7227:         {href=>"/adm/parmset?action=setrestrictmeta",
                   7228:         text=>"Restrict Metadata"},
                   7229:         {text=>"Order Metadata"});
1.345     banghart 7230:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata'));
1.531     raeburn  7231:     &startSettingsScreen($r,'parmset',$crstype);
1.340     banghart 7232:     if ($env{'form.storeorder'}) {
                   7233:         my $newpos = $env{'form.newpos'} - 1;
                   7234:         my $currentpos = $env{'form.currentpos'} - 1;
                   7235:         my @neworder = ();
1.548     raeburn  7236:         my @oldorder = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7237:         my $i;
1.341     banghart 7238:         if ($newpos > $currentpos) {
1.340     banghart 7239:         # moving stuff up
                   7240:             for ($i=0;$i<$currentpos;$i++) {
1.560     damieng  7241:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7242:             }
                   7243:             for ($i=$currentpos;$i<$newpos;$i++) {
1.560     damieng  7244:                 $neworder[$i]=$oldorder[$i+1];
1.340     banghart 7245:             }
                   7246:             $neworder[$newpos]=$oldorder[$currentpos];
                   7247:             for ($i=$newpos+1;$i<=$#oldorder;$i++) {
1.560     damieng  7248:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7249:             }
                   7250:         } else {
                   7251:         # moving stuff down
1.473     amueller 7252:             for ($i=0;$i<$newpos;$i++) {
                   7253:                 $neworder[$i]=$oldorder[$i];
                   7254:             }
                   7255:             $neworder[$newpos]=$oldorder[$currentpos];
                   7256:             for ($i=$newpos+1;$i<$currentpos+1;$i++) {
                   7257:                 $neworder[$i]=$oldorder[$i-1];
                   7258:             }
                   7259:             for ($i=$currentpos+1;$i<=$#oldorder;$i++) {
                   7260:                 $neworder[$i]=$oldorder[$i];
                   7261:             }
1.340     banghart 7262:         }
1.560     damieng  7263:         my $ordered_fields = join ",", @neworder;
1.343     banghart 7264:         my $put_result = &Apache::lonnet::put('environment',
1.560     damieng  7265:                         {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7266:         &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.metadata.addedorder' => $ordered_fields});
1.340     banghart 7267:     }
1.357     raeburn  7268:     my $fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.341     banghart 7269:     my $ordered_fields;
1.548     raeburn  7270:     my @fields_in_order = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7271:     if (!@fields_in_order) {
                   7272:         # no order found, pick sorted order then create metadata.addedorder key.
1.548     raeburn  7273:         foreach my $key (sort(keys(%$fields))) {
1.340     banghart 7274:             push @fields_in_order, $key;
1.341     banghart 7275:             $ordered_fields = join ",", @fields_in_order;
1.340     banghart 7276:         }
1.341     banghart 7277:         my $put_result = &Apache::lonnet::put('environment',
1.446     bisitz   7278:                             {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7279:     }
1.340     banghart 7280:     $r->print('<table>');
                   7281:     my $num_fields = scalar(@fields_in_order);
                   7282:     foreach my $key (@fields_in_order) {
                   7283:         $r->print('<tr><td>');
                   7284:         $r->print('<form method="post" action="">');
1.537     bisitz   7285:         $r->print('<select name="newpos" onchange="this.form.submit()">');
1.340     banghart 7286:         for (my $i = 1;$i le $num_fields;$i ++) {
                   7287:             if ($i eq $idx) {
                   7288:                 $r->print('<option value="'.$i.'"  SELECTED>('.$i.')</option>');
                   7289:             } else {
                   7290:                 $r->print('<option value="'.$i.'">'.$i.'</option>');
                   7291:             }
                   7292:         }
                   7293:         $r->print('</select></td><td>');
                   7294:         $r->print('<input type="hidden" name="currentpos" value="'.$idx.'" />');
                   7295:         $r->print('<input type="hidden" name="storeorder" value="true" />');
                   7296:         $r->print('</form>');
                   7297:         $r->print($$fields{$key}.'</td></tr>');
                   7298:         $idx ++;
                   7299:     }
                   7300:     $r->print('</table>');
1.507     www      7301:     &endSettingsScreen($r);
1.340     banghart 7302:     return 'ok';
                   7303: }
1.416     jms      7304: 
                   7305: 
1.563     damieng  7306: # Returns HTML with a Continue button redirecting to the initial portfolio metadata screen.
                   7307: # @returns {string}
1.359     banghart 7308: sub continue {
                   7309:     my $output;
                   7310:     $output .= '<form action="" method="post">';
                   7311:     $output .= '<input type="hidden" name="action" value="setrestrictmeta" />';
1.586     raeburn  7312:     $output .= '<input type="submit" value="'.&mt('Continue').'" />';
1.359     banghart 7313:     return ($output);
                   7314: }
1.416     jms      7315: 
                   7316: 
1.563     damieng  7317: # UI to add a metadata field.
                   7318: # Currenly does not work because of an HTML error (the field is not visible).
                   7319: #
                   7320: # @param {Apache2::RequestRec} $r - the Apache request
1.334     banghart 7321: sub addmetafield {
                   7322:     my ($r)=@_;
1.414     droeschl 7323:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7324:         text=>"Add Metadata Field"});
1.334     banghart 7325:     $r->print(&Apache::loncommon::start_page('Add Metadata Field'));
                   7326:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Add Metadata Field'));
1.335     banghart 7327:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7328:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7329:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7330:     &startSettingsScreen($r,'parmset',$crstype);
1.339     banghart 7331:     if (exists($env{'form.undelete'})) {
1.358     banghart 7332:         my @meta_fields = &Apache::loncommon::get_env_multiple('form.undeletefield');
1.339     banghart 7333:         foreach my $meta_field(@meta_fields) {
                   7334:             my $options = $env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.options'};
                   7335:             $options =~ s/deleted//;
                   7336:             $options =~ s/,,/,/;
                   7337:             my $put_result = &Apache::lonnet::put('environment',
                   7338:                                         {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs);
1.446     bisitz   7339: 
1.586     raeburn  7340:             $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]',
                   7341:                           '<strong>'.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}.
                   7342:                           '</strong>',$put_result).
                   7343:                       '<br />');
1.339     banghart 7344:         }
1.359     banghart 7345:         $r->print(&continue());
1.339     banghart 7346:     } elsif (exists($env{'form.fieldname'})) {
1.335     banghart 7347:         my $meta_field = $env{'form.fieldname'};
                   7348:         my $display_field = $env{'form.fieldname'};
                   7349:         $meta_field =~ s/\W/_/g;
1.338     banghart 7350:         $meta_field =~ tr/A-Z/a-z/;
1.335     banghart 7351:         my $put_result = &Apache::lonnet::put('environment',
                   7352:                             {'metadata.'.$meta_field.'.values'=>"",
                   7353:                              'metadata.'.$meta_field.'.added'=>"$display_field",
                   7354:                              'metadata.'.$meta_field.'.options'=>""},$dom,$crs);
1.586     raeburn  7355:         $r->print(&mt('Added new Metadata Field [_1] with result [_2]',
                   7356:                       '<strong>'.$env{'form.fieldname'}.'</strong>',$put_result).
                   7357:                   '<br />');
1.359     banghart 7358:         $r->print(&continue());
1.335     banghart 7359:     } else {
1.357     raeburn  7360:         my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'});
1.339     banghart 7361:         if ($fields) {
1.586     raeburn  7362:             $r->print(&mt('You may undelete previously deleted fields.').
                   7363:                       '<br />'.
                   7364:                       &mt('Check those you wish to undelete and click Undelete.').
                   7365:                       '<br />');
1.339     banghart 7366:             $r->print('<form method="post" action="">');
                   7367:             foreach my $key(keys(%$fields)) {
1.581     raeburn  7368:                 $r->print('<label><input type="checkbox" name="undeletefield" value="'.$key.'" />'.$$fields{$key}.'</label><br /');
1.339     banghart 7369:             }
1.586     raeburn  7370:             $r->print('<input type="submit" name="undelete" value="'.&mt('Undelete').'" />');
1.339     banghart 7371:             $r->print('</form>');
                   7372:         }
1.586     raeburn  7373:         $r->print('<hr />'.
                   7374:                   &mt('[_1]Or[_2] you may enter a new metadata field name.',
                   7375:                       '<strong>','</strong>').
1.581     raeburn  7376:                   '<form method="post" action="/adm/parmset?action=addmetadata">');
1.335     banghart 7377:         $r->print('<input type="text" name="fieldname" /><br />');
1.586     raeburn  7378:         $r->print('<input type="submit" value="'.&mt('Add Metadata Field').'" />');
1.581     raeburn  7379:         $r->print('</form>');
1.334     banghart 7380:     }
1.507     www      7381:     &endSettingsScreen($r);
1.334     banghart 7382: }
1.416     jms      7383: 
                   7384: 
                   7385: 
1.560     damieng  7386: # Display or save portfolio metadata.
1.563     damieng  7387: #
                   7388: # @param {Apache2::RequestRec} $r - the Apache request
1.259     banghart 7389: sub setrestrictmeta {
1.240     banghart 7390:     my ($r)=@_;
1.242     banghart 7391:     my $next_meta;
1.244     banghart 7392:     my $output;
1.245     banghart 7393:     my $item_num;
1.246     banghart 7394:     my $put_result;
1.414     droeschl 7395:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setrestrictmeta',
1.473     amueller 7396:         text=>"Restrict Metadata"});
1.280     albertel 7397:     $r->print(&Apache::loncommon::start_page('Restrict Metadata'));
1.298     albertel 7398:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Restrict Metadata'));
1.240     banghart 7399:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7400:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7401:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7402:     &startSettingsScreen($r,'parmset',$crstype);
1.259     banghart 7403:     my $key_base = $env{'course.'.$env{'request.course.id'}.'.'};
1.252     banghart 7404:     my $save_field = '';
1.586     raeburn  7405:     my %lt = &Apache::lonlocal::texthash(
                   7406:                                            addm => 'Add Metadata Field',
                   7407:                                            ordm => 'Order Metadata Fields',
                   7408:                                            save => 'Save',
                   7409:                                         );
1.259     banghart 7410:     if ($env{'form.restrictmeta'}) {
1.254     banghart 7411:         foreach my $field (sort(keys(%env))) {
1.252     banghart 7412:             if ($field=~m/^form.(.+)_(.+)$/) {
1.254     banghart 7413:                 my $options;
1.252     banghart 7414:                 my $meta_field = $1;
                   7415:                 my $meta_key = $2;
1.253     banghart 7416:                 if ($save_field ne $meta_field) {
1.252     banghart 7417:                     $save_field = $meta_field;
1.473     amueller 7418:                     if ($env{'form.'.$meta_field.'_stuadd'}) {
                   7419:                         $options.='stuadd,';
                   7420:                     }
                   7421:                     if ($env{'form.'.$meta_field.'_choices'}) {
                   7422:                         $options.='choices,';
                   7423:                     }
                   7424:                     if ($env{'form.'.$meta_field.'_onlyone'} eq 'single') {
                   7425:                         $options.='onlyone,';
                   7426:                     }
                   7427:                     if ($env{'form.'.$meta_field.'_active'}) {
                   7428:                         $options.='active,';
                   7429:                     }
                   7430:                     if ($env{'form.'.$meta_field.'_deleted'}) {
                   7431:                         $options.='deleted,';
                   7432:                     }
1.259     banghart 7433:                     my $name = $save_field;
1.560     damieng  7434:                     $put_result = &Apache::lonnet::put('environment',
                   7435:                         {'metadata.'.$meta_field.'.options'=>$options,
                   7436:                         'metadata.'.$meta_field.'.values'=>$env{'form.'.$meta_field.'_values'},
                   7437:                         },$dom,$crs);
1.252     banghart 7438:                 }
                   7439:             }
                   7440:         }
                   7441:     }
1.296     albertel 7442:     &Apache::lonnet::coursedescription($env{'request.course.id'},
1.473     amueller 7443:                        {'freshen_cache' => 1});
1.335     banghart 7444:     # Get the default metadata fields
1.258     albertel 7445:     my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio');
1.335     banghart 7446:     # Now get possible added metadata fields
1.357     raeburn  7447:     my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.347     banghart 7448:     $output .= &Apache::loncommon::start_data_table();
1.258     albertel 7449:     foreach my $field (sort(keys(%metadata_fields))) {
1.265     banghart 7450:         if ($field ne 'courserestricted') {
1.586     raeburn  7451:             $output.= &output_row($r,$field,$metadata_fields{$field});
1.560     damieng  7452:         }
1.255     banghart 7453:     }
1.351     banghart 7454:     my $buttons = (<<ENDButtons);
1.586     raeburn  7455:         <input type="submit" name="restrictmeta" value="$lt{'save'}" />
1.351     banghart 7456:         </form><br />
                   7457:         <form method="post" action="/adm/parmset?action=addmetadata" name="form1">
1.586     raeburn  7458:         <input type="submit" name="restrictmeta" value="$lt{'addm'}" />
1.351     banghart 7459:         </form>
                   7460:         <br />
                   7461:         <form method="post" action="/adm/parmset?action=ordermetadata" name="form2">
1.586     raeburn  7462:         <input type="submit" name="restrictmeta" value="$lt{'ordm'}" />
1.351     banghart 7463: ENDButtons
1.337     banghart 7464:     my $added_flag = 1;
1.335     banghart 7465:     foreach my $field (sort(keys(%$added_metadata_fields))) {
1.586     raeburn  7466:         $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag);
1.335     banghart 7467:     }
1.347     banghart 7468:     $output .= &Apache::loncommon::end_data_table();
1.446     bisitz   7469:     $r->print(<<ENDenv);
1.259     banghart 7470:         <form method="post" action="/adm/parmset?action=setrestrictmeta" name="form">
1.244     banghart 7471:         $output
1.351     banghart 7472:         $buttons
1.340     banghart 7473:         </form>
1.244     banghart 7474: ENDenv
1.507     www      7475:     &endSettingsScreen($r);
1.280     albertel 7476:     $r->print(&Apache::loncommon::end_page());
1.240     banghart 7477:     return 'ok';
                   7478: }
1.416     jms      7479: 
                   7480: 
1.563     damieng  7481: # Returns metadata fields that have been manually added.
                   7482: #
                   7483: # @param {string} $cid - course id
                   7484: # @returns {hash reference} - hash field name -> field title (not localized)
1.335     banghart 7485: sub get_added_meta_fieldnames {
1.357     raeburn  7486:     my ($cid) = @_;
1.335     banghart 7487:     my %fields;
                   7488:     foreach my $key(%env) {
1.357     raeburn  7489:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.335     banghart 7490:             my $field_name = $1;
                   7491:             my ($display_field_name) = $env{$key};
                   7492:             $fields{$field_name} = $display_field_name;
                   7493:         }
                   7494:     }
                   7495:     return \%fields;
                   7496: }
1.416     jms      7497: 
                   7498: 
1.563     damieng  7499: # Returns metadata fields that have been manually added and deleted.
                   7500: #
                   7501: # @param {string} $cid - course id
                   7502: # @returns {hash reference} - hash field name -> field title (not localized)
1.339     banghart 7503: sub get_deleted_meta_fieldnames {
1.357     raeburn  7504:     my ($cid) = @_;
1.339     banghart 7505:     my %fields;
                   7506:     foreach my $key(%env) {
1.357     raeburn  7507:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.339     banghart 7508:             my $field_name = $1;
                   7509:             if ($env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/) {
                   7510:                 my ($display_field_name) = $env{$key};
                   7511:                 $fields{$field_name} = $display_field_name;
                   7512:             }
                   7513:         }
                   7514:     }
                   7515:     return \%fields;
                   7516: }
1.560     damieng  7517: 
                   7518: 
                   7519: ##################################################
                   7520: # PARAMETER SETTINGS DEFAULT ACTIONS
                   7521: ##################################################
                   7522: 
                   7523: # UI to change parameter setting default actions
1.563     damieng  7524: #
                   7525: # @param {Apache2::RequestRec} $r - the Apache request
1.220     www      7526: sub defaultsetter {
1.280     albertel 7527:     my ($r) = @_;
                   7528: 
1.414     droeschl 7529:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setdefaults',
1.473     amueller 7530:         text=>"Set Defaults"});
1.531     raeburn  7531:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7532:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7533:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.446     bisitz   7534:     my $start_page =
1.531     raeburn  7535:         &Apache::loncommon::start_page('Parameter Setting Default Actions');
1.298     albertel 7536:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Defaults');
1.507     www      7537:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  7538:     &startSettingsScreen($r,'parmset',$crstype);
1.507     www      7539:     $r->print('<form method="post" action="/adm/parmset?action=setdefaults" name="defaultform">');
1.280     albertel 7540: 
1.221     www      7541:     my @ids=();
                   7542:     my %typep=();
                   7543:     my %keyp=();
                   7544:     my %allparms=();
                   7545:     my %allparts=();
                   7546:     my %allmaps=();
                   7547:     my %mapp=();
                   7548:     my %symbp=();
                   7549:     my %maptitles=();
                   7550:     my %uris=();
                   7551:     my %keyorder=&standardkeyorder();
                   7552:     my %defkeytype=();
                   7553: 
1.446     bisitz   7554:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 7555:                 \%mapp, \%symbp,\%maptitles,\%uris,
                   7556:                 \%keyorder,\%defkeytype);
1.224     www      7557:     if ($env{'form.storerules'}) {
1.560     damieng  7558:         my %newrules=();
                   7559:         my @delrules=();
                   7560:         my %triggers=();
                   7561:         foreach my $key (keys(%env)) {
1.225     albertel 7562:             if ($key=~/^form\.(\w+)\_action$/) {
1.560     damieng  7563:                 my $tempkey=$1;
                   7564:                 my $action=$env{$key};
1.226     www      7565:                 if ($action) {
1.560     damieng  7566:                     $newrules{$tempkey.'_action'}=$action;
                   7567:                     if ($action ne 'default') {
                   7568:                         my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                   7569:                         $triggers{$whichparm}.=$tempkey.':';
                   7570:                     }
                   7571:                     $newrules{$tempkey.'_type'}=$defkeytype{$tempkey};
                   7572:                     if (&isdateparm($defkeytype{$tempkey})) {
                   7573:                         $newrules{$tempkey.'_days'}=$env{'form.'.$tempkey.'_days'};
                   7574:                         $newrules{$tempkey.'_hours'}=$env{'form.'.$tempkey.'_hours'};
                   7575:                         $newrules{$tempkey.'_min'}=$env{'form.'.$tempkey.'_min'};
                   7576:                         $newrules{$tempkey.'_sec'}=$env{'form.'.$tempkey.'_sec'};
                   7577:                     } else {
                   7578:                         $newrules{$tempkey.'_value'}=$env{'form.'.$tempkey.'_value'};
                   7579:                         $newrules{$tempkey.'_triggervalue'}=$env{'form.'.$tempkey.'_triggervalue'};
                   7580:                     }
                   7581:                 } else {
                   7582:                     push(@delrules,$tempkey.'_action');
                   7583:                     push(@delrules,$tempkey.'_type');
                   7584:                     push(@delrules,$tempkey.'_hours');
                   7585:                     push(@delrules,$tempkey.'_min');
                   7586:                     push(@delrules,$tempkey.'_sec');
                   7587:                     push(@delrules,$tempkey.'_value');
                   7588:                 }
1.473     amueller 7589:             }
                   7590:         }
1.560     damieng  7591:         foreach my $key (keys(%allparms)) {
                   7592:             $newrules{$key.'_triggers'}=$triggers{$key};
1.473     amueller 7593:         }
1.560     damieng  7594:         &Apache::lonnet::put('parmdefactions',\%newrules,$cdom,$cnum);
                   7595:         &Apache::lonnet::del('parmdefactions',\@delrules,$cdom,$cnum);
                   7596:         &resetrulescache();
1.224     www      7597:     }
1.227     www      7598:     my %lt=&Apache::lonlocal::texthash('days' => 'Days',
1.473     amueller 7599:                        'hours' => 'Hours',
                   7600:                        'min' => 'Minutes',
                   7601:                        'sec' => 'Seconds',
                   7602:                        'yes' => 'Yes',
                   7603:                        'no' => 'No');
1.222     www      7604:     my @standardoptions=('','default');
                   7605:     my @standarddisplay=('',&mt('Default value when manually setting'));
                   7606:     my @dateoptions=('','default');
                   7607:     my @datedisplay=('',&mt('Default value when manually setting'));
                   7608:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7609:         unless ($tempkey) { next; }
                   7610:         push @standardoptions,'when_setting_'.$tempkey;
                   7611:         push @standarddisplay,&mt('Automatically set when setting ').$tempkey;
                   7612:         if (&isdateparm($defkeytype{$tempkey})) {
                   7613:             push @dateoptions,'later_than_'.$tempkey;
                   7614:             push @datedisplay,&mt('Automatically set later than ').$tempkey;
                   7615:             push @dateoptions,'earlier_than_'.$tempkey;
                   7616:             push @datedisplay,&mt('Automatically set earlier than ').$tempkey;
                   7617:         }
1.222     www      7618:     }
1.563     damieng  7619:     $r->print(&mt('Manual setting rules apply to all interfaces.').'<br />'.
                   7620:         &mt('Automatic setting rules apply to table mode interfaces only.'));
1.318     albertel 7621:     $r->print("\n".&Apache::loncommon::start_data_table().
1.473     amueller 7622:           &Apache::loncommon::start_data_table_header_row().
                   7623:           "<th>".&mt('Rule for parameter').'</th><th>'.
                   7624:           &mt('Action').'</th><th>'.&mt('Value').'</th>'.
                   7625:           &Apache::loncommon::end_data_table_header_row());
1.221     www      7626:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7627:         unless ($tempkey) { next; }
                   7628:         $r->print("\n".&Apache::loncommon::start_data_table_row().
                   7629:             "<td>".$allparms{$tempkey}."\n<br />(".$tempkey.')</td><td>');
                   7630:         my $action=&rulescache($tempkey.'_action');
                   7631:         $r->print('<select name="'.$tempkey.'_action">');
                   7632:         if (&isdateparm($defkeytype{$tempkey})) {
                   7633:             for (my $i=0;$i<=$#dateoptions;$i++) {
                   7634:             if ($dateoptions[$i]=~/\_$tempkey$/) { next; }
                   7635:             $r->print("\n<option value='$dateoptions[$i]'".
                   7636:                 ($dateoptions[$i] eq $action?' selected="selected"':'').
                   7637:                 ">$datedisplay[$i]</option>");
                   7638:             }
                   7639:         } else {
                   7640:             for (my $i=0;$i<=$#standardoptions;$i++) {
                   7641:             if ($standardoptions[$i]=~/\_$tempkey$/) { next; }
                   7642:             $r->print("\n<option value='$standardoptions[$i]'".
                   7643:                 ($standardoptions[$i] eq $action?' selected="selected"':'').
                   7644:                 ">$standarddisplay[$i]</option>");
                   7645:             }
1.473     amueller 7646:         }
1.560     damieng  7647:         $r->print('</select>');
                   7648:         unless (&isdateparm($defkeytype{$tempkey})) {
                   7649:             $r->print("\n<br />".&mt('Triggering value(s) of other parameter (optional, comma-separated):').
                   7650:                 '<input type="text" size="20" name="'.$tempkey.'_triggervalue" value="'.&rulescache($tempkey.'_triggervalue').'" />');
1.473     amueller 7651:         }
1.560     damieng  7652:         $r->print("\n</td><td>\n");
1.222     www      7653: 
1.221     www      7654:         if (&isdateparm($defkeytype{$tempkey})) {
1.560     damieng  7655:             my $days=&rulescache($tempkey.'_days');
                   7656:             my $hours=&rulescache($tempkey.'_hours');
                   7657:             my $min=&rulescache($tempkey.'_min');
                   7658:             my $sec=&rulescache($tempkey.'_sec');
                   7659:             $r->print(<<ENDINPUTDATE);
                   7660:     <input name="$tempkey\_days" type="text" size="4" value="$days" />$lt{'days'}<br />
                   7661:     <input name="$tempkey\_hours" type="text" size="4" value="$hours" />$lt{'hours'}<br />
                   7662:     <input name="$tempkey\_min" type="text" size="4" value="$min" />$lt{'min'}<br />
                   7663:     <input name="$tempkey\_sec" type="text" size="4" value="$sec" />$lt{'sec'}
1.564     raeburn  7664: ENDINPUTDATE
1.560     damieng  7665:         } elsif ($defkeytype{$tempkey} eq 'string_yesno') {
                   7666:                 my $yeschecked='';
                   7667:                 my $nochecked='';
                   7668:                 if (&rulescache($tempkey.'_value') eq 'yes') { $yeschecked=' checked="checked"'; }
                   7669:                 if (&rulescache($tempkey.'_value') eq 'no') { $nochecked=' checked="checked"'; }
                   7670: 
                   7671:             $r->print(<<ENDYESNO);
                   7672:     <label><input type="radio" name="$tempkey\_value" value="yes"$yeschecked /> $lt{'yes'}</label><br />
                   7673:     <label><input type="radio" name="$tempkey\_value" value="no"$nochecked /> $lt{'no'}</label>
1.564     raeburn  7674: ENDYESNO
1.221     www      7675:         } else {
1.560     damieng  7676:             $r->print('<input type="text" size="20" name="'.$tempkey.'_value" value="'.&rulescache($tempkey.'_value').'" />');
                   7677:         }
1.318     albertel 7678:         $r->print('</td>'.&Apache::loncommon::end_data_table_row());
1.221     www      7679:     }
1.318     albertel 7680:     $r->print(&Apache::loncommon::end_data_table().
1.473     amueller 7681:           "\n".'<input type="submit" name="storerules" value="'.
1.507     www      7682:           &mt('Save').'" /></form>'."\n");
                   7683:     &endSettingsScreen($r);
                   7684:     $r->print(&Apache::loncommon::end_page());
1.220     www      7685:     return;
                   7686: }
1.193     albertel 7687: 
1.560     damieng  7688: ##################################################
                   7689: # PARAMETER CHANGES LOG
                   7690: ##################################################
                   7691: 
1.563     damieng  7692: # Returns some info for a parameter log entry.
                   7693: # Returned entries:
                   7694: # $realm - HTML title for the parameter level and resource
                   7695: # $section - parameter section
                   7696: # $name - parameter name
                   7697: # $part - parameter part
                   7698: # $what - $part.'.'.$name
                   7699: # $middle - resource symb ?
                   7700: # $uname - user name (same as given)
                   7701: # $udom - user domain (same as given)
                   7702: # $issection - section or group name
                   7703: # $realmdescription - title for the parameter level and resource (without using HTML)
                   7704: #
                   7705: # @param {string} $key - parameter log key
                   7706: # @param {string} $uname - user name
                   7707: # @param {string} $udom - user domain
                   7708: # @param {boolean} $typeflag - .type log entry
                   7709: # @returns {Array}
1.290     www      7710: sub components {
1.581     raeburn  7711:     my ($key,$uname,$udom,$typeflag)=@_;
1.330     albertel 7712: 
                   7713:     if ($typeflag) {
1.560     damieng  7714:         $key=~s/\.type$//;
1.290     www      7715:     }
1.330     albertel 7716: 
                   7717:     my ($middle,$part,$name)=
1.572     damieng  7718:         ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.291     www      7719:     my $issection;
1.330     albertel 7720: 
1.290     www      7721:     my $section=&mt('All Students');
                   7722:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  7723:         $issection=$1;
                   7724:         $section=&mt('Group/Section').': '.$issection;
                   7725:         $middle=~s/^\[(.*)\]//;
1.290     www      7726:     }
                   7727:     $middle=~s/\.+$//;
                   7728:     $middle=~s/^\.+//;
1.291     www      7729:     if ($uname) {
1.560     damieng  7730:         $section=&mt('User').": ".&Apache::loncommon::plainname($uname,$udom);
                   7731:         $issection='';
1.291     www      7732:     }
1.316     albertel 7733:     my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.446     bisitz   7734:     my $realmdescription=&mt('all resources');
1.556     raeburn  7735:     if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   7736:         my $mapurl = $1;
                   7737:         my $maplevel = $2;
                   7738:         my $leveltitle = &mt('Folder/Map');
                   7739:         if ($maplevel eq 'rec') {
                   7740:             $leveltitle = &mt('Recursive');
                   7741:         }
1.560     damieng  7742:         $realm='<span class="LC_parm_scope_folder">'.$leveltitle.
                   7743:             ': '.&Apache::lonnet::gettitle($mapurl).' <span class="LC_parm_folder"><br />('.
                   7744:             $mapurl.')</span></span>';
                   7745:         $realmdescription=&mt('folder').' '.&Apache::lonnet::gettitle($mapurl);
                   7746:     } elsif ($middle) {
                   7747:         my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
                   7748:         $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   7749:             ': '.&Apache::lonnet::gettitle($middle).' <br /><span class="LC_parm_symb">('.$url.
                   7750:             ' in '.$map.' id: '.$id.')</span></span>';
                   7751:         $realmdescription=&mt('resource').' '.&Apache::lonnet::gettitle($middle);
1.290     www      7752:     }
1.291     www      7753:     my $what=$part.'.'.$name;
1.330     albertel 7754:     return ($realm,$section,$name,$part,
1.473     amueller 7755:         $what,$middle,$uname,$udom,$issection,$realmdescription);
1.290     www      7756: }
1.293     www      7757: 
1.563     damieng  7758: my %standard_parms; # hash parameter name -> parameter title (not localized)
                   7759: my %standard_parms_types; # hash parameter name -> parameter type
1.416     jms      7760: 
1.563     damieng  7761: # Reads parameter info from packages.tab into %standard_parms.
1.328     albertel 7762: sub load_parameter_names {
1.583     raeburn  7763:     open(my $config,"<","$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab");
1.328     albertel 7764:     while (my $configline=<$config>) {
1.560     damieng  7765:         if ($configline !~ /\S/ || $configline=~/^\#/) { next; }
                   7766:         chomp($configline);
                   7767:         my ($short,$plain)=split(/:/,$configline);
                   7768:         my (undef,$name,$type)=split(/\&/,$short,3);
                   7769:         if ($type eq 'display') {
                   7770:             $standard_parms{$name} = $plain;
1.469     raeburn  7771:         } elsif ($type eq 'type') {
1.560     damieng  7772:                 $standard_parms_types{$name} = $plain;
1.469     raeburn  7773:         }
1.328     albertel 7774:     }
                   7775:     close($config);
                   7776:     $standard_parms{'int_pos'}      = 'Positive Integer';
                   7777:     $standard_parms{'int_zero_pos'} = 'Positive Integer or Zero';
1.575     raeburn  7778:     $standard_parms{'scoreformat'}  = 'Format for display of score';
1.328     albertel 7779: }
                   7780: 
1.563     damieng  7781: # Returns a parameter title for standard parameters, the name for others.
                   7782: #
                   7783: # @param {string} $name - parameter name
                   7784: # @returns {string}
1.292     www      7785: sub standard_parameter_names {
                   7786:     my ($name)=@_;
1.328     albertel 7787:     if (!%standard_parms) {
1.560     damieng  7788:         &load_parameter_names();
1.328     albertel 7789:     }
1.292     www      7790:     if ($standard_parms{$name}) {
1.560     damieng  7791:         return $standard_parms{$name};
1.446     bisitz   7792:     } else {
1.560     damieng  7793:         return $name;
1.292     www      7794:     }
                   7795: }
1.290     www      7796: 
1.563     damieng  7797: # Returns a parameter type for standard parameters, undef for others.
                   7798: #
                   7799: # @param {string} $name - parameter name
                   7800: # @returns {string}
1.469     raeburn  7801: sub standard_parameter_types {
                   7802:     my ($name)=@_;
                   7803:     if (!%standard_parms_types) {
                   7804:         &load_parameter_names();
                   7805:     }
                   7806:     if ($standard_parms_types{$name}) {
                   7807:         return $standard_parms_types{$name};
                   7808:     }
                   7809:     return;
                   7810: }
1.309     www      7811: 
1.563     damieng  7812: # Returns a parameter level title (not localized) from the parameter level name.
                   7813: #
                   7814: # @param {string} $name - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   7815: # @returns {string}
1.557     raeburn  7816: sub standard_parameter_levels {
                   7817:     my ($name)=@_;
                   7818:     my %levels = (
                   7819:                     'resourcelevel'   => 'a single resource',
                   7820:                     'maplevel'        => 'the enclosing map/folder', 
                   7821:                     'maplevelrecurse' => 'the enclosing map/folder (recursive into sub-folders)',
                   7822:                     'courselevel'     => 'the general (course) level',
                   7823:                  );
                   7824:     if ($levels{$name}) {
                   7825:         return $levels{$name};
                   7826:     }
                   7827:     return;
                   7828: }
                   7829: 
1.560     damieng  7830: # Display log for parameter changes, blog postings, user notification changes.
1.563     damieng  7831: #
                   7832: # @param {Apache2::RequestRec} $r - the Apache request
1.285     albertel 7833: sub parm_change_log {
1.568     raeburn  7834:     my ($r,$parm_permission)=@_;
1.531     raeburn  7835:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7836:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.569     raeburn  7837:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 7838:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
1.473     amueller 7839:     text=>"Parameter Change Log"});
1.522     raeburn  7840:     my $js = '<script type="text/javascript">'."\n".
                   7841:              '// <![CDATA['."\n".
                   7842:              &Apache::loncommon::display_filter_js('parmslog')."\n".
                   7843:              '// ]]>'."\n".
                   7844:              '</script>'."\n";
                   7845:     $r->print(&Apache::loncommon::start_page('Parameter Change Log',$js));
1.327     albertel 7846:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Parameter Change Log'));
1.531     raeburn  7847:     &startSettingsScreen($r,'parmset',$crstype);
                   7848:     my %parmlog=&Apache::lonnet::dump('nohist_parameterlog',$cdom,$cnum);
1.311     albertel 7849: 
1.301     www      7850:     if ((keys(%parmlog))[0]=~/^error\:/) { undef(%parmlog); }
1.311     albertel 7851: 
1.522     raeburn  7852:     $r->print('<div class="LC_left_float">'.
                   7853:               '<fieldset><legend>'.&mt('Display of Changes').'</legend>'.
                   7854:               '<form action="/adm/parmset?action=parameterchangelog"
1.327     albertel 7855:                      method="post" name="parameterlog">');
1.446     bisitz   7856: 
1.311     albertel 7857:     my %saveable_parameters = ('show' => 'scalar',);
                   7858:     &Apache::loncommon::store_course_settings('parameter_log',
                   7859:                                               \%saveable_parameters);
                   7860:     &Apache::loncommon::restore_course_settings('parameter_log',
                   7861:                                                 \%saveable_parameters);
1.522     raeburn  7862:     $r->print(&Apache::loncommon::display_filter('parmslog').'&nbsp;'."\n".
                   7863:               '<input type="submit" value="'.&mt('Display').'" />'.
                   7864:               '</form></fieldset></div><br clear="all" />');
1.301     www      7865: 
1.568     raeburn  7866:     my $readonly = 1;
                   7867:     if ($parm_permission->{'edit'}) {
                   7868:         undef($readonly);
                   7869:     }
1.531     raeburn  7870:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.301     www      7871:     $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
1.473     amueller 7872:           '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Extent').'</th><th>'.&mt('Users').'</th><th>'.
1.568     raeburn  7873:           &mt('Parameter').'</th><th>'.&mt('Part').'</th><th>'.&mt('New Value').'</th>');
                   7874:     unless ($readonly) {
                   7875:         $r->print('<th>'.&mt('Announce').'</th>');
                   7876:     }
                   7877:     $r->print(&Apache::loncommon::end_data_table_header_row());
1.309     www      7878:     my $shown=0;
1.349     www      7879:     my $folder='';
                   7880:     if ($env{'form.displayfilter'} eq 'currentfolder') {
1.560     damieng  7881:         my $last='';
                   7882:         if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                   7883:                 &GDBM_READER(),0640)) {
                   7884:             $last=$hash{'last_known'};
                   7885:             untie(%hash);
                   7886:         }
                   7887:         if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); }
                   7888:     }
1.595     raeburn  7889:     my $numgroups = 0;
                   7890:     my @groups;
                   7891:     if ($env{'request.course.groups'} ne '') {
                   7892:         @groups = split(/:/,$env{'request.course.groups'});
                   7893:         $numgroups = scalar(@groups);
                   7894:     }
1.560     damieng  7895:     foreach my $id (sort {
                   7896:                 if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) {
                   7897:                     return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'}
                   7898:                 }
                   7899:                 my $aid = (split('00000',$a))[-1];
                   7900:                 my $bid = (split('00000',$b))[-1];
                   7901:                 return $bid<=>$aid;
1.473     amueller 7902:             } (keys(%parmlog))) {
1.294     www      7903:         my @changes=keys(%{$parmlog{$id}{'logentry'}});
1.560     damieng  7904:         my $count = 0;
                   7905:         my $time =
                   7906:             &Apache::lonlocal::locallocaltime($parmlog{$id}{'exe_time'});
                   7907:         my $plainname =
                   7908:             &Apache::loncommon::plainname($parmlog{$id}{'exe_uname'},
                   7909:                         $parmlog{$id}{'exe_udom'});
                   7910:         my $about_me_link =
                   7911:             &Apache::loncommon::aboutmewrapper($plainname,
                   7912:                             $parmlog{$id}{'exe_uname'},
                   7913:                             $parmlog{$id}{'exe_udom'});
                   7914:         my $send_msg_link='';
1.568     raeburn  7915:         if ((!$readonly) && 
                   7916:             (($parmlog{$id}{'exe_uname'} ne $env{'user.name'})
1.560     damieng  7917:             || ($parmlog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
                   7918:             $send_msg_link ='<br />'.
                   7919:             &Apache::loncommon::messagewrapper(&mt('Send message'),
                   7920:                             $parmlog{$id}{'exe_uname'},
                   7921:                             $parmlog{$id}{'exe_udom'});
                   7922:         }
                   7923:         my $row_start=&Apache::loncommon::start_data_table_row();
                   7924:         my $makenewrow=0;
                   7925:         my %istype=();
                   7926:         my $output;
                   7927:         foreach my $changed (reverse(sort(@changes))) {
                   7928:                 my $value=$parmlog{$id}{'logentry'}{$changed};
                   7929:             my $typeflag = ($changed =~/\.type$/ &&
                   7930:                     !exists($parmlog{$id}{'logentry'}{$changed.'.type'}));
1.330     albertel 7931:             my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)=
1.581     raeburn  7932:                 &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},$typeflag);
1.560     damieng  7933:             if ($env{'request.course.sec'} ne '') {
1.595     raeburn  7934:                 next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) ||
                   7935:                                                   ($numgroups && (grep(/^\Q$issection\E$/,@groups))))));
1.560     damieng  7936:                 if ($uname ne '') {
                   7937:                     my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'});
                   7938:                     next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'})); 
                   7939:                 }
                   7940:             }
                   7941:             if ($env{'form.displayfilter'} eq 'currentfolder') {
                   7942:                 if ($folder) {
                   7943:                     if ($middle!~/^\Q$folder\E/) { next; }
                   7944:                 }
                   7945:             }
                   7946:             if ($typeflag) {
                   7947:                 $istype{$parmname}=$value;
                   7948:                 if (!$env{'form.includetypes'}) { next; }
                   7949:             }
                   7950:             $count++;
                   7951:             if ($makenewrow) {
                   7952:                 $output .= $row_start;
                   7953:             } else {
                   7954:                 $makenewrow=1;
                   7955:             }
1.470     raeburn  7956:             my $parmitem = &standard_parameter_names($parmname);
1.560     damieng  7957:             $output .='<td>'.$realm.'</td><td>'.$section.'</td><td>'.
                   7958:                 &mt($parmitem).'</td><td>'.
                   7959:                 ($part?&mt('Part: [_1]',$part):&mt('All Parts')).'</td><td>';
                   7960:             my $stillactive=0;
                   7961:             if ($parmlog{$id}{'delflag'}) {
                   7962:                 $output .= &mt('Deleted');
                   7963:             } else {
                   7964:                 if ($typeflag) {
1.470     raeburn  7965:                     my $parmitem = &standard_parameter_names($value); 
                   7966:                     $parmitem = &mt($parmitem);
1.560     damieng  7967:                     $output .= &mt('Type: [_1]',$parmitem);
                   7968:                 } else {
1.584     raeburn  7969:                     my $toolsymb;
                   7970:                     if ($middle =~ /ext\.tool$/) {
                   7971:                         $toolsymb = $middle;
                   7972:                     }
1.560     damieng  7973:                     my ($level,@all)=&parmval_by_symb($what,$middle,
1.584     raeburn  7974:                         &Apache::lonnet::metadata($middle,$what,$toolsymb),
1.560     damieng  7975:                         $uname,$udom,$issection,$issection,$courseopt);
1.469     raeburn  7976:                     my $showvalue = $value;
                   7977:                     if ($istype{$parmname} eq '') {
                   7978:                         my $type = &standard_parameter_types($parmname);
                   7979:                         if ($type ne '') {
                   7980:                             if (&isdateparm($type)) {
                   7981:                                 $showvalue =
                   7982:                                     &Apache::lonlocal::locallocaltime($value);
                   7983:                             }
                   7984:                         }
                   7985:                     } else {
1.560     damieng  7986:                         if (&isdateparm($istype{$parmname})) {
                   7987:                             $showvalue = &Apache::lonlocal::locallocaltime($value);
1.622     raeburn  7988:                         } elsif (($istype{$parmname} eq 'string_grace') ||
                   7989:                                  ($istype{$parmname} eq 'string_ip')) {
                   7990:                             $showvalue =~ s/,/, /g;
1.560     damieng  7991:                         }
1.469     raeburn  7992:                     }
                   7993:                     $output .= $showvalue;
1.560     damieng  7994:                     if ($value ne $all[$level]) {
                   7995:                         $output .= '<br /><span class="LC_warning">'.&mt('Not active anymore').'</span>';
                   7996:                     } else {
                   7997:                         $stillactive=1;
                   7998:                     }
                   7999:                 }
1.473     amueller 8000:             }
1.568     raeburn  8001:             $output .= '</td>';
                   8002: 
                   8003:             unless ($readonly) { 
                   8004:                 $output .= '<td>';
                   8005:                 if ($stillactive) {
                   8006:                     my $parmitem = &standard_parameter_names($parmname);
                   8007:                     $parmitem = &mt($parmitem);
                   8008:                     my $title=&mt('Changed [_1]',$parmitem);
                   8009:                     my $description=&mt('Changed [_1] for [_2] to [_3]',
                   8010:                         $parmitem,$realmdescription,
                   8011:                         (&isdateparm($istype{$parmname})?&Apache::lonlocal::locallocaltime($value):$value));
                   8012:                     if (($uname) && ($udom)) {
                   8013:                         $output .=
                   8014:                         &Apache::loncommon::messagewrapper('Notify User',
                   8015:                                                            $uname,$udom,$title,
                   8016:                                                            $description);
                   8017:                     } else {
                   8018:                         $output .=
                   8019:                             &Apache::lonrss::course_blog_link($id,$title,
                   8020:                                                               $description);
                   8021:                     }
1.560     damieng  8022:                 }
1.568     raeburn  8023:                 $output .= '</td>';
1.560     damieng  8024:             }
1.568     raeburn  8025:             $output .= &Apache::loncommon::end_data_table_row();
1.473     amueller 8026:         }
1.560     damieng  8027:         if ($env{'form.displayfilter'} eq 'containing') {
                   8028:             my $wholeentry=$about_me_link.':'.
                   8029:             $parmlog{$id}{'exe_uname'}.':'.$parmlog{$id}{'exe_udom'}.':'.
                   8030:             $output;
                   8031:             if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
1.473     amueller 8032:         }
1.349     www      8033:         if ($count) {
1.560     damieng  8034:             $r->print($row_start.'<td rowspan="'.$count.'">'.$time.'</td>
                   8035:                         <td rowspan="'.$count.'">'.$about_me_link.
                   8036:             '<br /><tt>'.$parmlog{$id}{'exe_uname'}.
                   8037:                         ':'.$parmlog{$id}{'exe_udom'}.'</tt>'.
                   8038:             $send_msg_link.'</td>'.$output);
                   8039:             $shown++;
                   8040:         }
                   8041:         if (!($env{'form.show'} eq &mt('all')
                   8042:             || $shown<=$env{'form.show'})) { last; }
1.286     www      8043:     }
1.301     www      8044:     $r->print(&Apache::loncommon::end_data_table());
1.507     www      8045:     &endSettingsScreen($r);
1.284     www      8046:     $r->print(&Apache::loncommon::end_page());
                   8047: }
                   8048: 
1.560     damieng  8049: ##################################################
                   8050: # MISC !
                   8051: ##################################################
                   8052: 
1.563     damieng  8053: # Stores slot information.
1.560     damieng  8054: # Used by table UI
1.563     damieng  8055: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   8056: #
                   8057: # @param {string} $slot_name - slot name
                   8058: # @param {string} $cdom - course domain
                   8059: # @param {string} $cnum - course number
                   8060: # @param {string} $symb - resource symb
                   8061: # @param {string} $uname - user name
                   8062: # @param {string} $udom - user domain
                   8063: # @returns {string} - 'ok' or error name
1.437     raeburn  8064: sub update_slots {
                   8065:     my ($slot_name,$cdom,$cnum,$symb,$uname,$udom) = @_;
                   8066:     my %slot=&Apache::lonnet::get_slot($slot_name);
                   8067:     if (!keys(%slot)) {
                   8068:         return 'error: slot does not exist';
                   8069:     }
                   8070:     my $max=$slot{'maxspace'};
                   8071:     if (!defined($max)) { $max=99999; }
                   8072: 
                   8073:     my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
                   8074:                                        "^$slot_name\0");
                   8075:     my ($tmp)=%consumed;
                   8076:     if ($tmp=~/^error: 2 / ) {
                   8077:         return 'error: unable to determine current slot status';
                   8078:     }
                   8079:     my $last=0;
                   8080:     foreach my $key (keys(%consumed)) {
                   8081:         my $num=(split('\0',$key))[1];
                   8082:         if ($num > $last) { $last=$num; }
                   8083:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8084:             return 'ok';
                   8085:         }
                   8086:     }
                   8087: 
                   8088:     if (scalar(keys(%consumed)) >= $max) {
                   8089:         return 'error: no space left in slot';
                   8090:     }
                   8091:     my $wanted=$last+1;
                   8092: 
                   8093:     my %reservation=('name'      => $uname.':'.$udom,
                   8094:                      'timestamp' => time,
                   8095:                      'symb'      => $symb);
                   8096: 
                   8097:     my $success=&Apache::lonnet::newput('slot_reservations',
                   8098:                                         {"$slot_name\0$wanted" =>
                   8099:                                              \%reservation},
                   8100:                                         $cdom, $cnum);
1.438     raeburn  8101:     if ($success eq 'ok') {
                   8102:         my %storehash = (
                   8103:                           symb    => $symb,
                   8104:                           slot    => $slot_name,
                   8105:                           action  => 'reserve',
                   8106:                           context => 'parameter',
                   8107:                         );
1.526     raeburn  8108:         &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8109:                                    '',$uname,$udom,$cnum,$cdom);
1.438     raeburn  8110: 
1.526     raeburn  8111:         &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8112:                                    '',$uname,$udom,$uname,$udom);
1.438     raeburn  8113:     }
1.437     raeburn  8114:     return $success;
                   8115: }
                   8116: 
1.563     damieng  8117: # Deletes a slot reservation.
1.560     damieng  8118: # Used by table UI
1.563     damieng  8119: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   8120: #
                   8121: # @param {string} $slot_name - slot name
                   8122: # @param {string} $cdom - course domain
                   8123: # @param {string} $cnum - course number
                   8124: # @param {string} $uname - user name
                   8125: # @param {string} $udom - user domain
                   8126: # @param {string} $symb - resource symb
                   8127: # @returns {string} - 'ok' or error name
1.437     raeburn  8128: sub delete_slots {
                   8129:     my ($slot_name,$cdom,$cnum,$uname,$udom,$symb) = @_;
                   8130:     my $delresult;
                   8131:     my %consumed = &Apache::lonnet::dump('slot_reservations',$cdom,
                   8132:                                          $cnum, "^$slot_name\0");
                   8133:     if (&Apache::lonnet::error(%consumed)) {
                   8134:         return 'error: unable to determine current slot status';
                   8135:     }
                   8136:     my ($tmp)=%consumed;
                   8137:     if ($tmp=~/^error: 2 /) {
                   8138:         return 'error: unable to determine current slot status';
                   8139:     }
                   8140:     foreach my $key (keys(%consumed)) {
                   8141:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8142:             my $num=(split('\0',$key))[1];
                   8143:             my $entry = $slot_name.'\0'.$num;
                   8144:             $delresult = &Apache::lonnet::del('slot_reservations',[$entry],
                   8145:                                               $cdom,$cnum);
                   8146:             if ($delresult eq 'ok') {
                   8147:                 my %storehash = (
                   8148:                                   symb    => $symb,
                   8149:                                   slot    => $slot_name,
                   8150:                                   action  => 'release',
                   8151:                                   context => 'parameter',
                   8152:                                 );
1.526     raeburn  8153:                 &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8154:                                            1,$uname,$udom,$cnum,$cdom);
1.526     raeburn  8155:                 &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8156:                                            1,$uname,$udom,$uname,$udom);
1.437     raeburn  8157:             }
                   8158:         }
                   8159:     }
                   8160:     return $delresult;
                   8161: }
                   8162: 
1.563     damieng  8163: # Returns true if there is a current course.
1.560     damieng  8164: # Used by handler
1.563     damieng  8165: #
                   8166: # @returns {boolean}
1.355     albertel 8167: sub check_for_course_info {
                   8168:     my $navmap = Apache::lonnavmaps::navmap->new();
                   8169:     return 1 if ($navmap);
                   8170:     return 0;
                   8171: }
                   8172: 
1.563     damieng  8173: # Returns the current course host and host LON-CAPA version.
                   8174: #
                   8175: # @returns {Array} - (course hostname, major version number, minor version number)
1.514     raeburn  8176: sub parameter_release_vars { 
1.504     raeburn  8177:    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   8178:    my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   8179:    my $chostname = &Apache::lonnet::hostname($chome);
                   8180:    my ($cmajor,$cminor) = 
                   8181:        split(/\./,&Apache::lonnet::get_server_loncaparev($cdom,$chome));
                   8182:    return ($chostname,$cmajor,$cminor);
                   8183: }
                   8184: 
1.563     damieng  8185: # Checks if the course host version can handle a parameter required version,
                   8186: # and if it does, stores the release needed for the course.
                   8187: #
                   8188: # @param {string} $name - parameter name
                   8189: # @param {string} $value - parameter value
                   8190: # @param {string} $valmatch - name of the test used for checking the value
                   8191: # @param {string} $namematch - name of the test used for checking the name
                   8192: # @param {string} $needsrelease - version needed by the parameter, major.minor
                   8193: # @param {integer} $cmajor - course major version number
                   8194: # @param {integer} $cminor - course minor version number
                   8195: # @returns {boolean} - true if a newer version is needed
1.514     raeburn  8196: sub parameter_releasecheck {
1.557     raeburn  8197:     my ($name,$value,$valmatch,$namematch,$needsrelease,$cmajor,$cminor) = @_;
1.504     raeburn  8198:     my $needsnewer;
                   8199:     my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
                   8200:     if (($cmajor < $needsmajor) || 
                   8201:         ($cmajor == $needsmajor && $cminor < $needsminor)) {
                   8202:         $needsnewer = 1;
1.557     raeburn  8203:     } elsif ($name) {
                   8204:         if ($valmatch) {
                   8205:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.'::'.$valmatch.':'});
                   8206:         } elsif ($value) { 
                   8207:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value.'::'});
                   8208:         }
                   8209:     } elsif ($namematch) {
                   8210:         &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter::::'.$namematch});
1.504     raeburn  8211:     }
                   8212:     return $needsnewer;
                   8213: }
                   8214: 
1.568     raeburn  8215: sub get_permission {
                   8216:     my %permission;
                   8217:     my $allowed = 0;
                   8218:     return (\%permission,$allowed) unless ($env{'request.course.id'});
                   8219:     if ((&Apache::lonnet::allowed('opa',$env{'request.course.id'})) ||
                   8220:         (&Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.
                   8221:                   $env{'request.course.sec'}))) {
                   8222:         %permission= (
                   8223:                        'edit'               => 1,
                   8224:                        'set'                => 1,
                   8225:                        'setoverview'        => 1,
                   8226:                        'addmetadata'        => 1,
                   8227:                        'ordermetadata'      => 1,
                   8228:                        'setrestrictmeta'    => 1,
                   8229:                        'newoverview'        => 1,
                   8230:                        'setdefaults'        => 1,
                   8231:                        'settable'           => 1,
                   8232:                        'parameterchangelog' => 1,
                   8233:                        'cleanparameters'    => 1,
                   8234:                        'dateshift1'         => 1,
                   8235:                        'dateshift2'         => 1,
                   8236:                        'helper'             => 1,
                   8237:          );
                   8238:     } elsif ((&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) ||
                   8239:              (&Apache::lonnet::allowed('vpa',$env{'request.course.id'}.'/'.
                   8240:                   $env{'request.course.sec'}))) {
                   8241:         %permission = (
                   8242:                        'set'                => 1,
                   8243:                        'settable'           => 1,
                   8244:                        'newoverview'        => 1,
                   8245:                        'setoverview'        => 1,
                   8246:                        'parameterchangelog' => 1,
                   8247:                       );
                   8248:     }
                   8249:     foreach my $perm (values(%permission)) {
                   8250:         if ($perm) { $allowed=1; last; }
                   8251:     }
                   8252:     return (\%permission,$allowed);
                   8253: }
                   8254: 
1.560     damieng  8255: ##################################################
                   8256: # HANDLER
                   8257: ##################################################
                   8258: 
                   8259: # Main handler for lonparmset.
                   8260: # Sub called based on request parameters action and command:
                   8261: # no command or action: print_main_menu
                   8262: # command 'set': assessparms (direct access to table mode for a resource)
                   8263: #                (this can also be accessed simply with the symb parameter)
                   8264: # action 'setoverview': overview (display all existing parameter settings)
                   8265: # action 'addmetadata': addmetafield (called to add a portfolio metadata field)
                   8266: # action 'ordermetadata': order_meta_fields (called to order portfolio metadata fields)
                   8267: # action 'setrestrictmeta': setrestrictmeta (display or save portfolio metadata)
                   8268: # action 'newoverview': newoverview (overview mode)
                   8269: # action 'setdefaults': defaultsetter (UI to change parameter setting default actions)
                   8270: # action 'settable': assessparms (table mode)
                   8271: # action 'parameterchangelog': parm_change_log (display log for parameter changes,
                   8272: #                              blog postings, user notification changes)
                   8273: # action 'cleanparameters': clean_parameters (unused)
                   8274: # action 'dateshift1': date_shift_one (overview mode, shift all dates)
                   8275: # action 'dateshift2': date_shift_two (overview mode, shift all dates)
1.30      www      8276: sub handler {
1.43      albertel 8277:     my $r=shift;
1.30      www      8278: 
1.376     albertel 8279:     &reset_caches();
                   8280: 
1.414     droeschl 8281:     &Apache::loncommon::content_type($r,'text/html');
                   8282:     $r->send_http_header;
                   8283:     return OK if $r->header_only;
                   8284: 
1.193     albertel 8285:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.473     amueller 8286:                         ['action','state',
1.205     www      8287:                                              'pres_marker',
                   8288:                                              'pres_value',
1.206     www      8289:                                              'pres_type',
1.506     www      8290:                                              'filter','part',
1.390     www      8291:                                              'udom','uname','symb','serial','timebase']);
1.131     www      8292: 
1.83      bowersj2 8293: 
1.193     albertel 8294:     &Apache::lonhtmlcommon::clear_breadcrumbs();
1.194     albertel 8295:     &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset",
1.507     www      8296:                         text=>"Content and Problem Settings",
1.473     amueller 8297:                         faq=>10,
                   8298:                         bug=>'Instructor Interface',
1.442     droeschl 8299:                                             help =>
                   8300:                                             'Parameter_Manager,Course_Environment,Parameter_Helper,Parameter_Overview,Table_Mode'});
1.203     www      8301: 
1.30      www      8302: # ----------------------------------------------------- Needs to be in a course
1.568     raeburn  8303:     my ($parm_permission,$allowed) = &get_permission();
1.355     albertel 8304:     my $exists = &check_for_course_info();
                   8305: 
1.568     raeburn  8306:     if ($env{'request.course.id'} && $allowed && $exists) {
1.193     albertel 8307:         #
                   8308:         # Main switch on form.action and form.state, as appropriate
                   8309:         #
                   8310:         # Check first if coming from someone else headed directly for
                   8311:         #  the table mode
1.568     raeburn  8312:         if (($parm_permission->{'set'}) && 
                   8313:             ((($env{'form.command'} eq 'set') && ($env{'form.url'})
                   8314:                 && (!$env{'form.dis'})) || ($env{'form.symb'}))) {
                   8315:             &assessparms($r,$parm_permission);
1.193     albertel 8316:         } elsif (! exists($env{'form.action'})) {
                   8317:             &print_main_menu($r,$parm_permission);
1.568     raeburn  8318:         } elsif (!$parm_permission->{$env{'form.action'}}) {
                   8319:             &print_main_menu($r,$parm_permission);
1.414     droeschl 8320:         } elsif ($env{'form.action'} eq 'setoverview') {
1.568     raeburn  8321:             &overview($r,$parm_permission);
1.560     damieng  8322:         } elsif ($env{'form.action'} eq 'addmetadata') {
                   8323:             &addmetafield($r);
                   8324:         } elsif ($env{'form.action'} eq 'ordermetadata') {
                   8325:             &order_meta_fields($r);
1.414     droeschl 8326:         } elsif ($env{'form.action'} eq 'setrestrictmeta') {
1.560     damieng  8327:             &setrestrictmeta($r);
1.414     droeschl 8328:         } elsif ($env{'form.action'} eq 'newoverview') {
1.568     raeburn  8329:             &newoverview($r,$parm_permission);
1.414     droeschl 8330:         } elsif ($env{'form.action'} eq 'setdefaults') {
1.560     damieng  8331:             &defaultsetter($r);
                   8332:         } elsif ($env{'form.action'} eq 'settable') {
1.568     raeburn  8333:             &assessparms($r,$parm_permission);
1.414     droeschl 8334:         } elsif ($env{'form.action'} eq 'parameterchangelog') {
1.568     raeburn  8335:             &parm_change_log($r,$parm_permission);
1.414     droeschl 8336:         } elsif ($env{'form.action'} eq 'cleanparameters') {
1.560     damieng  8337:             &clean_parameters($r);
1.414     droeschl 8338:         } elsif ($env{'form.action'} eq 'dateshift1') {
1.390     www      8339:             &date_shift_one($r);
1.414     droeschl 8340:         } elsif ($env{'form.action'} eq 'dateshift2') {
1.390     www      8341:             &date_shift_two($r);
1.446     bisitz   8342:         }
1.43      albertel 8343:     } else {
1.1       www      8344: # ----------------------------- Not in a course, or not allowed to modify parms
1.560     damieng  8345:         if ($exists) {
                   8346:             $env{'user.error.msg'}=
                   8347:             "/adm/parmset:opa:0:0:Cannot modify assessment parameters";
                   8348:         } else {
                   8349:             $env{'user.error.msg'}=
                   8350:             "/adm/parmset::0:1:Course environment gone, reinitialize the course";
                   8351:         }
                   8352:         return HTTP_NOT_ACCEPTABLE;
1.43      albertel 8353:     }
1.376     albertel 8354:     &reset_caches();
                   8355: 
1.43      albertel 8356:     return OK;
1.1       www      8357: }
                   8358: 
                   8359: 1;
                   8360: __END__
                   8361: 
                   8362: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>